KUMOS/Client/Includes/Notify.sbi
2026-05-02 15:49:06 +02:00

241 lines
6.2 KiB
Plaintext

Module Notify
EnableExplicit
;- Toast constants
#Toast_W = 300
#Toast_H = 60
#Toast_Margin = 10
#Accent_W = 4
#Toast_Timer = 0
#MaxToasts = 5
;- Globals
Global _Font = LoadFont(#PB_Any, "sans-serif", 12)
; Toast state
Global Dim _Wins.i(#MaxToasts)
Global Dim _Canvases.i(#MaxToasts)
Global Dim _Types.i(#MaxToasts)
Global Dim _Messages.s(#MaxToasts)
Global _Count
; Confirm state
Global _ConfirmWin
Global _ConfirmOkBtn
Global _ConfirmCancelBtn
Global *_ConfirmCb
;- Private declarations
Declare _TypeColor(Type)
Declare _DrawToast(Slot)
Declare _Dismiss(Slot)
Declare _Reposition()
Declare _FindByWindow(Win)
Declare _FindByCanvas(Canvas)
Declare _CloseConfirm()
Declare _FireConfirm(Result)
Declare Handler_ToastTimer()
Declare Handler_ToastClick()
Declare Handler_ConfirmOK()
Declare Handler_ConfirmCancel()
Declare Handler_ConfirmClose()
;- Public procedures
; Show a toast in the bottom-right corner. Dismisses after Duration ms or on click.
Procedure Toast(Message.s, Type = #Info, Duration = 4000)
Protected Slot, DW, DH, X, Y, Win, Canvas
If _Count >= #MaxToasts : ProcedureReturn : EndIf
Slot = _Count
DW = DesktopWidth(0)
DH = DesktopHeight(0)
X = DW - #Toast_W - #Toast_Margin
Y = DH - (Slot + 1) * (#Toast_H + #Toast_Margin)
Win = OpenWindow(#PB_Any, X, Y, #Toast_W, #Toast_H, "", #PB_Window_BorderLess)
StickyWindow(Win, #True)
Canvas = CanvasGadget(#PB_Any, 0, 0, #Toast_W, #Toast_H)
_Wins(Slot) = Win
_Canvases(Slot) = Canvas
_Types(Slot) = Type
_Messages(Slot) = Message
_Count + 1
_DrawToast(Slot)
BindGadgetEvent(Canvas, @Handler_ToastClick())
AddWindowTimer(Win, #Toast_Timer, Duration)
BindEvent(#PB_Event_Timer, @Handler_ToastTimer(), Win)
EndProcedure
; Show a modal confirm dialog. *Callback(Result) is called with 1 for OK, 0 for Cancel.
; Only one confirm can be open at a time — subsequent calls are ignored.
Procedure Confirm(Title.s, Message.s, *Callback)
Protected W, H, DW, DH
If IsWindow(_ConfirmWin) : ProcedureReturn : EndIf
W = 340
H = 130
DW = DesktopWidth(0)
DH = DesktopHeight(0)
_ConfirmWin = OpenWindow(#PB_Any, (DW - W) / 2, (DH - H) / 2, W, H, Title, #PB_Window_TitleBar | #PB_Window_SystemMenu)
StickyWindow(_ConfirmWin, #True)
*_ConfirmCb = *Callback
TextGadget(#PB_Any, 20, 20, W - 40, 50, Message)
_ConfirmOkBtn = ButtonGadget(#PB_Any, W - 190, H - 45, 80, 30, "OK")
_ConfirmCancelBtn = ButtonGadget(#PB_Any, W - 100, H - 45, 80, 30, "Cancel")
BindGadgetEvent(_ConfirmOkBtn, @Handler_ConfirmOK())
BindGadgetEvent(_ConfirmCancelBtn, @Handler_ConfirmCancel())
BindEvent(#PB_Event_CloseWindow, @Handler_ConfirmClose(), _ConfirmWin)
EndProcedure
;- Private procedures
Procedure _TypeColor(Type)
Select Type
Case #Success : ProcedureReturn RGB( 60, 180, 100)
Case #Warning : ProcedureReturn RGB(220, 160, 40)
Case #Error : ProcedureReturn RGB(210, 65, 65)
Default : ProcedureReturn RGB( 50, 130, 220) ; #Info
EndSelect
EndProcedure
Procedure _DrawToast(Slot)
Protected W, H, MaxW
Protected Msg.s
If Not IsGadget(_Canvases(Slot)) : ProcedureReturn : EndIf
If Not StartDrawing(CanvasOutput(_Canvases(Slot))) : ProcedureReturn : EndIf
W = OutputWidth()
H = OutputHeight()
; Background
Box(0, 0, W, H, RGB(38, 38, 54))
; Accent bar
Box(0, 0, #Accent_W, H, _TypeColor(_Types(Slot)))
; Message — truncate with ellipsis if too wide
DrawingMode(#PB_2DDrawing_Transparent)
If IsFont(_Font) : DrawingFont(FontID(_Font)) : EndIf
Msg = _Messages(Slot)
MaxW = W - #Accent_W - 24
While Len(Msg) > 3 And TextWidth(Msg) > MaxW
Msg = Left(Msg, Len(Msg) - 4) + "..."
Wend
DrawText(#Accent_W + 14, (H - TextHeight("A")) / 2, Msg, RGB(220, 220, 220))
StopDrawing()
EndProcedure
Procedure _Dismiss(Slot)
Protected i
If Not IsWindow(_Wins(Slot)) : ProcedureReturn : EndIf
UnbindEvent(#PB_Event_Timer, @Handler_ToastTimer(), _Wins(Slot))
UnbindGadgetEvent(_Canvases(Slot), @Handler_ToastClick())
CloseWindow(_Wins(Slot))
For i = Slot To _Count - 2
_Wins(i) = _Wins(i + 1)
_Canvases(i) = _Canvases(i + 1)
_Types(i) = _Types(i + 1)
_Messages(i) = _Messages(i + 1)
Next
_Wins(_Count - 1) = 0
_Canvases(_Count - 1) = 0
_Types(_Count - 1) = 0
_Messages(_Count - 1) = ""
_Count - 1
_Reposition()
EndProcedure
Procedure _Reposition()
Protected DW, DH, i
DW = DesktopWidth(0)
DH = DesktopHeight(0)
For i = 0 To _Count - 1
ResizeWindow(_Wins(i), DW - #Toast_W - #Toast_Margin, DH - (i + 1) * (#Toast_H + #Toast_Margin), #PB_Ignore, #PB_Ignore)
Next
EndProcedure
Procedure _FindByWindow(Win)
Protected i
For i = 0 To _Count - 1
If _Wins(i) = Win : ProcedureReturn i : EndIf
Next
ProcedureReturn -1
EndProcedure
Procedure _FindByCanvas(Canvas)
Protected i
For i = 0 To _Count - 1
If _Canvases(i) = Canvas : ProcedureReturn i : EndIf
Next
ProcedureReturn -1
EndProcedure
Procedure _CloseConfirm()
UnbindGadgetEvent(_ConfirmOkBtn, @Handler_ConfirmOK())
UnbindGadgetEvent(_ConfirmCancelBtn, @Handler_ConfirmCancel())
UnbindEvent(#PB_Event_CloseWindow, @Handler_ConfirmClose(), _ConfirmWin)
CloseWindow(_ConfirmWin)
_ConfirmWin = 0
EndProcedure
Procedure _FireConfirm(Result)
_CloseConfirm()
If *_ConfirmCb
!notify$g__confirmcb(v_result);
*_ConfirmCb = 0
EndIf
EndProcedure
;- Event handlers
Procedure Handler_ToastTimer()
Protected Slot = _FindByWindow(EventWindow())
If Slot >= 0 : _Dismiss(Slot) : EndIf
EndProcedure
Procedure Handler_ToastClick()
Protected Slot
If EventType() <> #PB_EventType_LeftButtonUp : ProcedureReturn : EndIf
Slot = _FindByCanvas(EventGadget())
If Slot >= 0 : _Dismiss(Slot) : EndIf
EndProcedure
Procedure Handler_ConfirmOK()
_FireConfirm(1)
EndProcedure
Procedure Handler_ConfirmCancel()
_FireConfirm(0)
EndProcedure
Procedure Handler_ConfirmClose()
_FireConfirm(0)
EndProcedure
EndModule
; IDE Options = SpiderBasic 3.20 (Windows - x86)
; CursorPosition = 13
; Folding = BAw
; iOSAppOrientation = 0
; AndroidAppCode = 0
; AndroidAppOrientation = 0
; EnableXP
; DPIAware
; CompileSourceDirectory