A Personal *Event Coundown Reminder* (Feedback Welcome)
Posted: Sat Jan 28, 2012 12:42 pm
Thanks to the many here who have helped me in the past and continue to do so. Here is a little 'something back' and hope some of you will find it useful. Please feel free to comment on results. In particular, I would be interested to know how it performs in various Windows flavors. Specific modifications required to adapt to other flavors, etc.
BTW: My intent here was to produce a plain and simple, cut and dry event reminder. Nothing glorious, nothing fancy to distract from the items in the list ... just a basic list. Going for the *Less is More* effect so I'm not really interested in how I could enhance it or how it may fall short of some feature packed utility. Only thing I'm really interested in is cross-platform performance on various flavors of Windows, and if you happen to like it, then that's just icing on the cake 
Originally written and tested on Windows XP Pro using jaPBe v3.12 and PureBasic v4.60
[EDIT] 11/09/34 -- 2 modifications as noted in comments below:
[EDIT] 11/11/34 -- added patch to force listing to bottom when event count exceeds display area
[Updated] 11/27/24 -- Details inside code.
[EDIT] 11/30/24 -- added code at top of file to prevent more than one instance <<VERY CRITICAL


Originally written and tested on Windows XP Pro using jaPBe v3.12 and PureBasic v4.60
[EDIT] 11/09/34 -- 2 modifications as noted in comments below:
[EDIT] 11/11/34 -- added patch to force listing to bottom when event count exceeds display area
[Updated] 11/27/24 -- Details inside code.
[EDIT] 11/30/24 -- added code at top of file to prevent more than one instance <<VERY CRITICAL
Code: Select all
; Snipppet from 'Fluid byte' over there in the German forum
; used here as base starting point for 'Event Coundown Reminder':
; http://www.purebasic.fr/german/viewtopic.php?t=17692&start=4
; With special thanks to members of this thread:
; http://www.purebasic.fr/english/viewtopic.php?f=13&t=38387
;11/09/24 -- Further modified to run cleanly on v5.40 and look nice on v6.12 so I could read it without a magnifier, although on v6.12 it will crash on first line following the CallDebugger command line if you double click an existing event or click [add event] and NO idea why.
;11/09/34 -- Modified [Discard all changes] to truly discard all changes from point of launch.
;11/10/24 -- fix a bug with ESC on existing calendar event.
;11/26/24 -- Modified color for events on target date snd day before.
;11/26/24 -- Disabled ListIconGadget on close window click so it's obvious you clicked close.
;BIG Thanks to the RSBasic Moderator for showing me how to enlarge CalenderGadget
;https://www.purebasic.fr/english/viewtopic.php?p=509399&hilit=change+font+CalendarGadget#p509399
SetClipboardText("92122") ; PCH search string
Global active.W, targetWindow$, hWin.i
Procedure ReallySetForegroundWindow(m_hWnd.i)
; http://www.drdobbs.com/184405755
hOtherWnd.i = GetForegroundWindow_()
;
; get thread handles on our window and foreground window
hMyThread.i = GetWindowThreadProcessId_(m_hWnd, 0)
hOtherThread.i = GetWindowThreadProcessId_(hOtherWnd,0)
;
; attach our thread to foreground thread, take foreground, and detach threads
AttachThreadInput_(hMyThread,hOtherThread, #True)
SetForegroundWindow_(m_hWnd)
AttachThreadInput_(hMyThread,hOtherThread, #False)
; AttachThreadInput_(hOtherThread,hMyThread, #True); backward set
; SetForegroundWindow_(m_hWnd)
; AttachThreadInput_(hOtherThread,hMyThread, #False)
;
; Now that our window "thread" has fisrt place in the queue...
; make sure our "window" is visible
If IsIconic_(m_hWnd)
ShowWindow_(m_hWnd,#SW_RESTORE)
Else
ShowWindow_(m_hWnd,#SW_SHOW)
EndIf
SetActiveWindow(GetDlgCtrlID_(m_hWnd))
WaitWindowEvent()
SetForegroundWindow_(m_hWnd)
EndProcedure
Procedure.i ListWindows(Window, Parameter) ; used inside Gt_Prog()
WindowTitle.s = Space(255)
GetWindowText_(Window, WindowTitle, 255)
WindowTitle = LCase(WindowTitle)
If LCase(WindowTitle) = targetWindow$
active.W = 1
hWin.i = Window
ElseIf Left(WindowTitle,9) = targetWindow$
active.W = 1
hWin.i = Window
EndIf
ProcedureReturn #True
EndProcedure
Procedure Gt_Prog(dmy$) ; input : 11 char PROCESS name , active.w = true if running : hWin.i holds Window handle
targetWindow$ = LCase(dmy$)
active.W = 0
hWin.i = 0
EnumWindows_(@ListWindows(), 0) ; Windows CallBack operation.
ProcedureReturn active.W
EndProcedure
If Gt_Prog(" reminder") ; Prevent 2nd instance if already running
SetForegroundWindow_(hWin.i) ; and bring current instance into foreground.
ShowWindow_(hWin.i, #SW_RESTORE)
Delay(250)
End ; Quit from this duplicate instance.
EndIf
; <dpiAware>True/PM</dpiAware>
; <dpiAwareness>PerMonitorV2, PerMonitor</dpiAwareness>
#MainWindow = 1
#DateWindow = 0
Global timeNow.l, AnimateReminder.l, _x, _y, fontVerd9B.i
_x = GetSystemMetrics_(#SM_CXSCREEN)
_y = GetSystemMetrics_(#SM_CYSCREEN)
Debug Str(_x) +" "+Str(_y)
Global lippi.LASTINPUTINFO ; Wow! Who understands this stuff??!
lippi\cbSize = SizeOf(LASTINPUTINFO) ; Compensating for "dumb" API I guess??
#MCM_HITTEST = #MCM_FIRST + 14
#MCHT_CALENDAR = $20000
#MCHT_CALENDARDATE = #MCHT_CALENDAR | $0001
lvc.LV_COLUMN ; set up structure for global use to format ListIconGadget columns
lvc\mask = #LVCF_FMT
lvc\fmt = #LVCFMT_RIGHT
Global lpPrevFunc, WnHdl.l, now.l, selected.l, eventFile$
TAG_CR$ = Chr(13)+Chr(10)
eventFile$=GetEnvironmentVariable("USERPROFILE") + "\MyEvents.txt"
eventBack$=GetEnvironmentVariable("USERPROFILE") + "\MyEvents.bak"
CopyFile(eventFile$,eventBack$) ; make backup so we can discard all changes
Debug eventFile$
If FileSize(eventFile$)= -1
CreateFile(0,eventFile$)
CloseFile(0)
EndIf
Structure Cells
chronos.l
Descript$
EndStructure
Global NewList Ocassion.Cells()
Procedure FixTitle()
s$ = " Reminder" + FormatDate("%mm/%dd/%yyyy",Date())
SetWindowTitle(1,s$)
EndProcedure
Procedure TopOfToday()
Protected TODAY$
TODAY$ = Str(Month(Date()))
TODAY$ + "/" + Str(Day(Date()))
TODAY$ + "/" + Str(Year(Date()))
Debug TODAY$
now=ParseDate("%mm/%dd/%yyyy", TODAY$)
ProcedureReturn now
EndProcedure
Procedure reList()
Protected place
;FixTitle()
TopOfToday()
SortStructuredList(Ocassion(), 0, OffsetOf(Cells\chronos), #PB_Long)
place = 0
ForEach Ocassion()
date1 = Ocassion()\chronos
days = (date1 - now) /86400
If days = 0
dayZero.l = #True
GetLastInputInfo_(@lippi) ; no recent user activity so let show and animate 'reminder'
timeNow.l = ElapsedMilliseconds() ; get current timestamp value for comparison calculations
If timeNow.l - lippi\dwTime > 100
AnimateReminder.l = #True
EndIf
event$ = "TODAY is"
If IsWindowVisible_(WindowID(0))
ResizeWindow(0, WindowX(1)+112, WindowY(1), #PB_Ignore, #PB_Ignore)
HideWindow(1,0)
ShowWindow_(WindowID(1),#SW_RESTORE)
HideWindow(0,0)
Else
HideWindow(1,0)
ShowWindow_(WindowID(1),#SW_RESTORE)
EndIf ; BBGGRR
SetGadgetItemColor(2, place, #PB_Gadget_BackColor, $0F48FF, -1)
ElseIf days = 1
event$ = Str(days) + " day until"
SetGadgetItemColor(2, place, #PB_Gadget_BackColor, $10F8F8, -1)
ElseIf days < 2
event$ = Str(days) + " day until"
SetGadgetItemColor(2, place, #PB_Gadget_BackColor, $0AE0F0, -1)
ElseIf days < 35
event$ = Str(days) + " days until"
SetGadgetItemColor(2, place, #PB_Gadget_BackColor, -1, -1)
Else
event$ = Str(days/7) + " weeks until"
SetGadgetItemColor(2, place, #PB_Gadget_BackColor, -1, -1)
EndIf
SetGadgetItemText(2,place,event$,0)
SetGadgetItemText(2,place,Ocassion()\Descript$,1)
place + 1
Next
EndProcedure
Procedure ModEntry()
date1 = ParseDate("%mm/%dd/%yyyy",FormatDate("%mm/%dd/%yyyy",GetGadgetState(0)))
SelectElement(Ocassion(), selected)
Ocassion()\chronos = date1
s$ = GetGadgetText(1)
If s$ = ""
s$ = "undefined event"
EndIf
Ocassion()\Descript$ = s$
reList()
DisableGadget(3,0)
SetGadgetState(2,-1) ; deselect all items
EndProcedure
Procedure LoadEvents()
Protected F1.l, F2$
If ReadFile(0,eventFile$)
If Lof(0) > 10
Repeat
F2$ = ReadString(0,#PB_Ascii)
F1.l = Val(F2$)
F2$ = ReadString(0,#PB_Ascii)
AddElement(Ocassion())
Ocassion()\chronos = F1
Ocassion()\Descript$ = F2$
AddGadgetItem(2,-1,"Loading...")
Until Eof(0)
reList()
n = CountGadgetItems(2)-1
SetGadgetState(2, n)
SetGadgetItemState(2, n,0)
EndIf
CloseFile(0)
EndIf
EndProcedure
Procedure SaveEvents()
If CreateFile(0,eventFile$)
ForEach Ocassion()
F1 = Ocassion()\chronos
F2$ = Str(F1)
WriteStringN(0,F2$,#PB_Ascii)
F2$ = Ocassion()\Descript$
WriteStringN(0,F2$,#PB_Ascii)
Next
CloseFile(0)
EndIf
EndProcedure
Procedure OLDJogReminder()
Protected x, y
Repeat
x = Random(_x - 317)
Until Abs(WindowX(1) - Abs(x)) > 100
Repeat
y = Random(_y - 199)
Until Abs(WindowY(1) - Abs(y)) > 100
ResizeWindow(1, Abs(x),Abs(y), #PB_Ignore,#PB_Ignore)
EndProcedure
Procedure JogReminder()
Protected x, y
Repeat
x = Random(_x - 317,200)
Until Abs(WindowX(1) - Abs(x)) > 100
Repeat
y = Random(_y - 199,200)
Until Abs(WindowY(1) - Abs(y)) > 100
Debug Str(x) +" "+Str(y)
ResizeWindow(1, Abs(x),Abs(y), #PB_Ignore,#PB_Ignore)
EndProcedure
Procedure TripTimer() ;system regulated - failproof interval trigger
; Goofy internal Timer_() callback workaround
tripTimer1 = #True ; allows timer event to occur ONLY once on queue.
SECOND.W = Second(Date())
; Required to prevent sluggish system after oneLook terminaltes.
EndProcedure
; &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
Structure MCHITTESTINFO
cbSize.l
pt.POINT
uHIt.l
st.SYSTEMTIME
EndStructure
Procedure WinCallback(WindowID1.l,message.l,wParam.l,lParam.l)
Result.l = #PB_ProcessPureBasicEvents
If WindowID1.l = WnHdl.l
Select message
Case #WM_LBUTTONDBLCLK
mcht.MCHITTESTINFO\cbSize = SizeOf(MCHITTESTINFO)
mcht\pt\x = DesktopMouseX()
mcht\pt\y = DesktopMouseY()
ScreenToClient_(GadgetID(0), @mcht\pt)
SendMessage_(GadgetID(0),#MCM_HITTEST,0,mcht)
If mcht\uHIt = #MCHT_CALENDARDATE
Debug "Date selected through double-click : " + FormatDate("%mm/%dd/%yyyy",GetGadgetState(0))
ModEntry()
HideWindow(0,1)
SetActiveGadget(2)
SaveEvents()
EndIf
EndSelect
CallDebugger
Result = CallWindowProc_(lpPrevFunc,WindowID1.l,message,wParam,lParam)
EndIf
ProcedureReturn Result
EndProcedure
; &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
; Locate 24hr crossover in milliseconds for title change and list update
crossover.l = TopOfToday() + 86400 ; one full day into the future
; CREATE WINDOWS CREATE WINDOWS CREATE WINDOWS CREATE WINDOWS CREATE WINDOWS
If OpenWindow(#DateWindow,440,113,355,320,"Edit event and DoubleClick",#PB_Window_SystemMenu | #PB_Window_Invisible)
LoadFont(1, "Segoe UI", 14)
WnHdl.l = CalendarGadget(0,5,35,345,280)
SetWindowTheme_(GadgetID(0), @"", @"")
SetGadgetFont(0, FontID(1))
lpPrevFunc = SetWindowLong_(GadgetID(0),#GWL_WNDPROC,@WinCallback())
SetClassLong_(GadgetID(0),#GCL_STYLE,GetClassLong_(GadgetID(0),#GCL_STYLE) | #CS_DBLCLKS)
StringGadget(1, 5, 10, 160, 20, "") ;, #ES_MULTILINE|#ES_AUTOVSCROLL|$10000000)
SetGadgetAttribute(1,#PB_String_MaximumLength,24)
fontVerd9B.i = LoadFont(#PB_Default,"Verdana",34,#PB_Font_Bold)
HWND1 = OpenWindow(#MainWindow, 312, 113, 570, 336, " Reminder", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar)
If HWND1
LIG_Yval = 5
; SetGadgetFont(2,FontID(fontVerd9B.i))
If LoadFont(0, "Arial", 16)
SetGadgetFont(#PB_Default, FontID(0)) ; Set the loaded Arial 16 font as new standard
EndIf
hLIG = ListIconGadget(2, 10, LIG_Yval, 553, 290, "", 170, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect | #LVS_NOCOLUMNHEADER)
AddGadgetColumn ( 2 ,1 , "" ,377 )
GadgetToolTip(2, "This is my tip.")
;SendMessage_(GadgetID(2), #LVM_SETEXTENDEDLISTVIEWSTYLE, 0, #LVS_EX_LABELTIP)
SendMessage_(GadgetID(2), #LVM_SETCOLUMN, 0, @lvc) ; Right justify column 1
If LoadFont(1, "Arial", 12)
SetGadgetFont(#PB_Default, FontID(1)) ; Set the loaded Arial 16 font as new standard
EndIf
ButtonGadget(3,10,300,155,23,"Add New Event")
ButtonGadget(4,185,300,150,23,"Discard Event")
ButtonGadget(5,350,300,195,23,"Discard All Changes")
SetForegroundWindow_(WindowID(1))
SetActiveWindow(1)
LoadEvents()
check.l = 10000 ; used to monitor ElapsedMilliseconds status
; Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
; End
Repeat ; drop into timer initialization on first "even" second!
Until (Second(Date()) % 2) = 0
trip.l = SetTimer_(WindowID(1),0,2000,@TripTimer()) ; Timer set at 2000 = 2 seconds
; TOP OF LOOP TOP OF LOOP TOP OF LOOP TOP OF LOOP TOP OF LOOP
Repeat
EventID.l=WaitWindowEvent(check.l)
If GetForegroundWindow_() <> WindowID(#DateWindow)
If IsWindowVisible_(WindowID(#DateWindow))
HideWindow(0,1)
DisableGadget(3,0)
SetGadgetState(2,-1) ; deselect all items
EndIf
ElseIf EventID = #PB_Event_CloseWindow
;MessageRequester("LKJHGF","Good")
EventID = 0
HideWindow(0,1)
reList()
DisableGadget(3,0)
SetGadgetState(2,-1) ; deselect all items
EndIf
Select EventID
Case #WM_KEYDOWN ; PRESSED THE [ENTER} KEY
Select EventwParam()
Case #VK_ESCAPE
If GetForegroundWindow_() = WindowID(#DateWindow)
EventID = 0
HideWindow(0,1)
reList()
DisableGadget(3,0)
SetGadgetState(2,-1) ; deselect all items
;
;
If AllowESC
selected.l = 0
SelectElement(Ocassion(), selected)
DeleteElement(Ocassion())
RemoveGadgetItem(2, selected)
SaveEvents()
AllowESC = #False
EndIf
EndIf
Case #VK_RETURN
Select GetActiveWindow()
Case #MainWindow
h.l = GetGadgetState(2) ; first selected item
If h.l > -1 ;Something selected so edit
ResizeWindow(#DateWindow, WindowX(1)+112, WindowY(1), #PB_Ignore, #PB_Ignore)
HideWindow(#DateWindow,0)
DisableGadget(3,1)
selected.l = GetGadgetState(2)
SelectElement(Ocassion(), selected)
date1 = Ocassion()\chronos
s$ = Ocassion()\Descript$
SetGadgetState(0, date1)
SetGadgetText(1,s$)
SetActiveGadget(1)
h.l = Len(GetGadgetText(1))
SendMessage_(GadgetID(1), #EM_SETSEL, h, h) ;
Repeat
WaitWindowEvent()
Until IsWindow(#DateWindow)
Repeat
WaitWindowEvent()
Until IsGadget(0)
While WindowEvent(): Wend
EndIf
Case #DateWindow
ModEntry()
HideWindow(0,1)
SetActiveGadget(2)
SaveEvents()
EndSelect
EndSelect
Case #PB_EventType_LostFocus ; useless message... so do nothing
Case #PB_Event_Gadget
If GetActiveGadget() = 1
s$=GetGadgetText(1)
h.l=FindString(s$,TAG_CR$,1) ; Stop CR/Esc Ding
If h.l<>0 ; Was Enter pressed on the StringGadget?
Debug "Pressed Enter on Calendar"
SetGadgetText(1,ReplaceString(s$,TAG_CR$,"")) ; Yes, so remove CR+LF.
SendMessage_(GadgetID(1), #EM_SETSEL, h.l-1, h.l-1) ; Set cursor position back.
While WindowEvent(): Wend
Debug "Date selected through Enter Key : " + FormatDate("%mm/%dd/%yyyy",GetGadgetState(0))
Debug GetGadgetState(0)
ModEntry()
HideWindow(0,1)
SaveEvents()
EndIf
EndIf
Select EventGadget()
Case 1
While WindowEvent(): Wend
Case 2 ; DOUBLECLICK TO EDIT EVENT
If EventType() = #PB_EventType_LeftDoubleClick
If GetGadgetState(2) > -1
ResizeWindow(#DateWindow, WindowX(1)+112, WindowY(1), #PB_Ignore, #PB_Ignore)
HideWindow(#DateWindow,0)
DisableGadget(3,1)
selected.l = GetGadgetState(2)
If selected > -1
SelectElement(Ocassion(), selected)
date1 = Ocassion()\chronos
s$ = Ocassion()\Descript$
SetGadgetState(0, date1)
SetGadgetText(1,s$)
SetActiveGadget(1)
h.l = Len(GetGadgetText(1))
SendMessage_(GadgetID(1), #EM_SETSEL, h, h) ;
Repeat
WaitWindowEvent()
Until IsWindow(#DateWindow)
Repeat
WaitWindowEvent()
Until IsGadget(0)
While WindowEvent(): Wend
EndIf
EndIf
EndIf
Case 3 ; ADD NEW EVENT
If GetForegroundWindow_() = WindowID(1)
AllowESC = #True
Debug "add event"
DisableGadget(3,1)
AddGadgetItem(2,0,"1 day until")
SetGadgetItemText(2,0,"undefined event",1)
selected.l = 0
SelectElement(Ocassion(), selected)
InsertElement(Ocassion())
TopOfToday()
date1 = ParseDate("%mm/%dd/%yyyy",FormatDate("%mm/%dd/%yyyy",now + 86400))
SetGadgetState(0, date1)
Debug now
Debug date1
Debug date1 - now
SelectElement(Ocassion(), selected)
Ocassion()\chronos = date1
Ocassion()\Descript$ = "undefined event"
date1 = Ocassion()\chronos
days = (date1 - now) /86400
event$ = Str(days) + " days until"
SetGadgetItemText(2,0,event$,0)
SetGadgetItemText(2,0,Ocassion()\Descript$,1)
ResizeWindow(#DateWindow, WindowX(1)+112, WindowY(1), #PB_Ignore, #PB_Ignore)
HideWindow(#DateWindow,0)
SetGadgetText(1,"undefined event")
SetActiveGadget(2)
SetActiveGadget(1)
h.l = Len(GetGadgetText(1))
SendMessage_(GadgetID(1), #EM_SETSEL, 0, h.l) ;
Repeat
WaitWindowEvent()
Until IsWindow(#DateWindow)
Repeat
WaitWindowEvent()
Until IsGadget(0)
While WindowEvent(): Wend
EndIf
Case 4 ; DISCARD SELECTED EVENT
Debug "discard event"
If GetGadgetState(2) = -1
MessageRequester(" Nothing To Do", "Please highlight an item in the list and try again. ", #MB_OK)
Else
Select MessageRequester(" Delete Event From The List", "Are you sure you want to delete the selected event? ", #MB_YESNO)
Case #IDYES
selected.l = GetGadgetState(2)
SelectElement(Ocassion(), selected)
DeleteElement(Ocassion())
RemoveGadgetItem(2, selected)
SaveEvents()
EndSelect
SetGadgetState(2,-1) ; deselect all items
EndIf
SetActiveGadget(2)
Case 5 ; FULL REVERT
Debug "discard all changes"
Select MessageRequester(" Discard All Changes", " Discard all changes" + Chr(10) + " and revert to original list? ", #MB_YESNO)
Case #IDYES
ClearList(Ocassion())
ClearGadgetItems(2)
CopyFile(eventBack$,eventFile$) ; make backup so we can discard all changes
LoadEvents()
EndSelect
SetActiveGadget(2)
EndSelect
Default
If AnimateReminder = #True
Debug "should be Jogging"
GetLastInputInfo_(@lippi)
timeNow.l = ElapsedMilliseconds() ; get current timestamp value for comparison calculations
If timeNow.l - lippi\dwTime > 1500 ; user fell asleep so jog the reminder window
If tripTimer1
jog + 1
tripTimer1 = #False ; disable timer events.
EndIf
If jog > 1
JogReminder()
jog = 0
EndIf
Else
HideWindow(#MainWindow,0)
SetForegroundWindow_(HWND1)
SetActiveWindow(1)
ResizeWindow(#MainWindow, _x/2-160, _y/2-100, #PB_Ignore,#PB_Ignore)
AnimateReminder.l = #False
check.l = 1000 ; restore normal monitoring on main loop
EndIf
Else
Debug "Not Jogging"
If dayZero.l = #True
If GetForegroundWindow_() <> HWND1 ; don't bother if already doing HWND1 'reminder'
GetLastInputInfo_(@lippi)
timeNow.l = ElapsedMilliseconds() ; get current timestamp value for comparison calculations
If timeNow.l - lippi\dwTime > 300000 ; No recent user activity so lets show and animate 'reminder'
HideWindow(1,0)
ReallySetForegroundWindow(WindowID(1))
SetActiveWindow(1)
AnimateReminder.l = #True
check.l = 50 ; expidite monitoring so we can quickly restore normal monitoring
EndIf
EndIf
EndIf
GetCursorPos_(@CursorPosition.POINT)
a1.l = WindowFromPoint_(CursorPosition\y<< 32 + CursorPosition\x) ;where on the screen?
If a1 = hLIG ; using a1 to validate mouse inside #MyGadget
Debug " _ _ _ _ INSIDE THE LIST _ _ _ _"
y = ((WindowMouseY(1)) - LIG_Yval)
Debug "y = " + Str(y)
If y > 2 ; Adjust y value to compensate for column_header_height
y - 3 ; Adjust y value to compensate for column_header_height
itemLine = y / 14 ; Divide y by pixel_height given to single_line_item.
Debug "itemLine = " + Str(itemLine)
If lastLine <> itemLine ; Anti-Flicker -- update tooltip only if required
If itemLine < CountGadgetItems(2) ; Range restriction
SelectElement(Ocassion(), itemLine)
date1 = Ocassion()\chronos
s$ = " " + FormatDate("%mm/%dd/%yyyy",date1) + " is " + Ocassion()\Descript$ + " "
Else ; out of range
s$ = " DoubleClick item to edit an event or Single click" +Chr(13)+Chr(10)+ "To highlight an event And press enter To edit," +Chr(13)+Chr(10)+ "Or click [Delete eevent] To remove it. "
EndIf
Debug itemLine
GadgetToolTip(2, s$)
EndIf
lastLine = itemLine
EndIf
EndIf
EndIf
Debug "check"
If crossover.l - Date() < check.l ; <<< Check value is usesd in WaitWindowEvent() to force time checks
check.l = 500 ; expidite monitoring when approaching crossover to new day
EndIf
If Date() >= crossover.l
Debug "Crossover to next day"
reList() ; will adjust title date and countdown values in the list
crossover.l + 86400 ; increment trigger to next day
check.l = 10000 ; revert to non-aggressive ElapsedMilliseconds monitoring
EndIf
EndSelect
If EventID=#PB_Event_CloseWindow
DisableGadget(2,1)
Select MessageRequester(" Event Reminder", " Reminder will Minimize or Quit." + Chr(10) + " Do you really want to Quit?", #MB_YESNOCANCEL)
Case #IDNO
DisableGadget(2,0)
SetWindowState(1,#PB_Window_Minimize)
EventID.l=WaitWindowEvent(check.l)
Case #IDCANCEL
DisableGadget(2,0)
EventID=0
EndSelect
EndIf
Until EventID=#PB_Event_CloseWindow
; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;eventFile$="E:\Temp\MyEvent.txt"
SaveEvents()
CloseWindow(1)
CloseWindow(0)
EndIf
EndIf