MacOS New DateGadget (Big Date Range)

Share your advanced PureBasic knowledge/code with the community.
User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

MacOS New DateGadget (Big Date Range)

Post by mk-soft »

The DateGadget from PB only works in the Unix time range.

This was not enough for me and I wrote a new DateGadget. This must be explicitly deleted with FreeDateGadget to release all resources.

Update v1.02.1
- Fix calendar position

MyDateGadget

Code: Select all

;-TOP

; Comment : MyDateGadget (Big Date Range)
; Author  : mk-soft
; Version : v1.02.1
; create  : 21.03.2021
; Update  : 
;
; OS      : macOS

; *******

EnableExplicit

;- MacOS Date funtions

; Mask:
;   Year   = yyyy
;   Month  = MM (1..12), MMM (Short Name), MMMM (Long Name)
;   Day    = dd
;   Hour   = hh (0..23), HH (0..11); a = period (AM, PM)
;   Minute = mm
;   Second = ss
;   
;   Day ot the year   = DDD (1..3)
;   Week of Year      = ww
;   Week of Month     = W

Macro CocoaString(NSString)
  PeekS(CocoaMessage(0, NSString, "UTF8String"), -1, #PB_UTF8)
EndMacro

Procedure.s GetStringFromDate(Date, Mask.s = "yyyy-MM-dd")
  Protected NSPool, NSDateFormatter, NSString
  Protected r1.s
  
  NSPool = CocoaMessage(0, 0, "NSAutoreleasePool new")
  NSDateFormatter = CocoaMessage(0, 0, "NSDateFormatter new")
  
  ; Convert PB date format
  If FindString(Mask, "%")
    mask = LCase(mask)
    mask = ReplaceString(mask, "m", "M")
    mask = ReplaceString(mask, "i", "m")
    mask = RemoveString(mask, "%")
  EndIf
    
  If Date = 0
    Date = CocoaMessage(0, 0, "NSDate date")
  EndIf
  
  CocoaMessage(0, NSDateFormatter, "setDateFormat:$", @Mask)
  NSString = CocoaMessage(0, NSDateFormatter, "stringFromDate:@", @Date)
  r1 = CocoaString(NSString)
  
  CocoaMessage(0, NSDateFormatter, "release")
  CocoaMessage(0, NSPool, "release")
  
  ProcedureReturn r1
EndProcedure

Procedure GetDateFromString(Date.s, Mask.s = "yyyy-MM-dd")
  Protected NSPool, NSDate, NSDateFormatter
  Protected r1
  
  NSPool = CocoaMessage(0, 0, "NSAutoreleasePool new")
  NSDateFormatter = CocoaMessage(0, 0, "NSDateFormatter new")
  
  ; Convert PB date format
  If FindString(Mask, "%")
    mask = LCase(mask)
    mask = ReplaceString(mask, "m", "M")
    mask = ReplaceString(mask, "i", "m")
    mask = RemoveString(mask, "%")
  EndIf
  
  CocoaMessage(0, NSDateFormatter, "setDateFormat:$", @Mask)
  r1 = CocoaMessage(0, NSDateFormatter, "dateFromString:$", @Date)
  CocoaMessage(0, NSDateFormatter, "release")
  CocoaMessage(0, NSPool, "release")
  
  ProcedureReturn r1
EndProcedure

; ----

Structure udtMyDateGadget
  Gadget.i
  Button.i
  Calendar.i
  Mask.s
EndStructure

;- Events

Procedure MyDateGadget_CalendarEvent()
  Protected *Data.udtMyDateGadget
  Protected date
  Static click
  
  With *Data
    click + 1
    If click >= 3
      *Data.udtMyDateGadget = GetGadgetData(EventGadget())
      date = CocoaMessage(0, GadgetID(\Calendar), "dateValue")
      SetGadgetText(\Gadget, GetStringFromDate(date, \Mask))
      FreeGadget(\Calendar)
      \Calendar = 0
      click = 0
    EndIf
  EndWith
  
EndProcedure

Procedure MyDateGadget_ButtonEvent()
  Protected *Data.udtMyDateGadget
  Protected NSCurrentLocale, NSLocale, NSString
  Protected button, x, y, dx, dy, date
  
  button = EventGadget()
  *Data.udtMyDateGadget = GetGadgetData(button)
  
  With *Data
    If \Calendar
      FreeGadget(\Calendar)
      \Calendar = 0
    Else
      \Calendar = CalendarGadget(#PB_Any, GadgetX(\Gadget), GadgetY(\Gadget) + GadgetHeight(\Gadget), 0, 0)
      ; Set Language
      NSCurrentLocale = CocoaMessage(0, 0, "NSLocale currentLocale")
      NSString = CocoaMessage(0, NSCurrentLocale, "localeIdentifier")
      If CocoaString(NSString) = "en_DE"
        NSLocale = CocoaMessage(0, 0, "NSLocale localeWithLocaleIdentifier:$", @"de_DE")
      Else
        NSLocale = NSCurrentLocale
      EndIf
      CocoaMessage(0, GadgetID(\Calendar), "setLocale:", NSLocale)
      ; Resize Gadget
      dx = GadgetWidth(\Calendar, #PB_Gadget_RequiredSize)
      dy = GadgetHeight(\Calendar, #PB_Gadget_RequiredSize)
      x = GadgetX(\Gadget) + GadgetWidth(\Gadget) + GadgetWidth(\Button) - dx
      ResizeGadget(\Calendar, x, #PB_Ignore, dx, dy)
      ; Set date
      date = GetDateFromString(GetGadgetText(\Gadget), \Mask)
      CocoaMessage(0, GadgetID(\Calendar), "setDateValue:", date)
      SetGadgetData(\Calendar, *Data)
      ; Bind Event
      BindGadgetEvent(\Calendar, @MyDateGadget_CalendarEvent())
    EndIf
  EndWith
EndProcedure

;- Create DateGadget

Procedure MyDateGadget(Gadget, x, y, Width, Height, Mask.s = "YYYY-MM-dd", Date = 0)
  Protected id, *Data.udtMyDateGadget
  
  With *Data
    id = StringGadget(Gadget, x, y, Width - Height * 1.5, Height, "")
    If id
      ; allocate data
      *Data = AllocateStructure(udtMydateGadget)
      If Gadget = #PB_Any
        \Gadget = id
      Else
        \Gadget = Gadget
      EndIf
      SetGadgetData(\Gadget, *Data)
      \Mask = Mask
      SetGadgetText(\Gadget, GetStringFromDate(Date, \Mask))
      ; Create button for open calendar
      \Button = ButtonGadget(#PB_Any, x + Width - Height * 1.5, y + 2, Height * 1.5, Height, ">")
      SetGadgetData(\Button, *Data)
      ; Bind events
      BindGadgetEvent(\Button, @MyDateGadget_ButtonEvent(), #PB_EventType_LeftClick)
      
    EndIf
  EndWith
  
  ProcedureReturn id
  
EndProcedure

;- Free DateGadget

Procedure FreeDateGadget(Gadget)
  Protected *Data.udtMyDateGadget
  
  With *Data
    *Data = GetGadgetData(Gadget)
    If *Data
      If IsGadget(\Calendar) : FreeGadget(\Calendar) : EndIf
      If IsGadget(\Button) : FreeGadget(\Button) : EndIf
      If IsGadget(\Gadget) : FreeGadget(\Gadget) : EndIf
    EndIf
    FreeStructure(*Data)
  EndWith
EndProcedure

; ********

;-Example

CompilerIf #PB_Compiler_IsMainFile
  
  Define Date
  If OpenWindow(0, 0, 0, 250, 250, "DateGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    
    Date = GetDateFromString("1965-08-20")
    MyDateGadget(0, 10, 10, 220, 25, "%dd.%mm.%yyyy", Date)
    ;MyDateGadget(0, 10, 10, 180, 25, "dd. MMM yyyy", Date)
    
    Repeat
    Until WaitWindowEvent() = #PB_Event_CloseWindow
  EndIf
  
CompilerEndIf
Last edited by mk-soft on Sun Mar 21, 2021 7:24 pm, edited 2 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Saki
Addict
Addict
Posts: 830
Joined: Sun Apr 05, 2020 11:28 am
Location: Pandora

Re: MacOS New DateGadget (Big Date Range)

Post by Saki »

Hi,
that's good !
Now a solution for Windows and Linux, in one small module, time is running . . . :wink:
地球上の平和
User avatar
mk-soft
Always Here
Always Here
Posts: 5406
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: MacOS New DateGadget (Big Date Range)

Post by mk-soft »

The windows version is already being worked on.

Update v1.02.0
- Added: Covert PB date mask token (%YYYY-%mm-%dd)

Update v1.02.1
- Fix calendar gadget position
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: MacOS New DateGadget (Big Date Range)

Post by davido »

@mk-soft,

Thank you for sharing. :D

It works perfectly on my 'm1' system.

I presume it will still work when Apple have fully transitioned to the m1 systems?


Model Name: MacBook Pro
Model Identifier: MacBookPro17,1
Chip: Apple M1
Total Number of Cores: 8 (4 performance and 4 efficiency)
Memory: 8 GB
System Version: macOS 11.2.2 (20D80)
Kernel Version: Darwin 20.3.0
DE AA EB
Post Reply