File "Toast.inc"
                                Path: /Translater/inc/Toast.inc
                File size: 17.09 KB
                MIME-type: 
                Charset: utf-8
            
%LOGME = 0
'--------------------------------------------------------------------------------
'   ** Constants **
'--------------------------------------------------------------------------------
%TICK                       = 15 ' smaller amount of time(ms) used in transitions
%TIMER_SHOW                 = 2001
%TIMER_PAUSE                = 2002
%TIMER_HIDE                 = 2003
%ITALIC                     = 2
%UNDERLINE                  = 4
%STRIKETHROUGH              = 8
%BOLD                       = 16
%GWL_STYLE                  = -16
%GWL_EXSTYLE                = -20
%HWND_TOPMOST               = &HFFFFFFFF???
%SWP_NOSIZE                 = &H0001
%SWP_NOMOVE                 = &H0002
%LWA_COLORKEY               = &H00000001
%LWA_ALPHA                  = &H00000002
%SEE_MASK_NOCLOSEPROCESS    = &H00000040
%SEE_MASK_FLAG_NO_UI        = &H00000400
%SEE_MASK_UNICODE           = &H00004000
%WM_SETICON                 = &H80
'--------------------------------------------------------------------------------
%INVALID_HANDLE_VALUE       = &HFFFFFFFF???
'%TRUE                       = -1
'%FALSE                      = 0
%INFINITE                   = &HFFFFFFFF???   ' Infinite timeout
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
'   ** Globals **
'--------------------------------------------------------------------------------
GLOBAL toast_hFnt       AS DWORD ' fonts
GLOBAL toast_width      AS LONG
GLOBAL toast_height     AS LONG
GLOBAL toast_alpha      AS LONG
GLOBAL toast_colf       AS LONG
GLOBAL toast_colb       AS LONG
GLOBAL toast_text       AS STRING
GLOBAL toast_pause      AS LONG
GLOBAL toast_dialog()   AS DWORD
GLOBAL toast_thread()   AS DWORD
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
'   ** Constructors **
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetFont (family AS STRING, siz AS LONG, weight AS LONG)
    LOGME "          Toast_SetFont: " + family + ", " + FORMAT$(siz) + ", " + FORMAT$(weight)
    ' weight: 0 normal, 2 italic, 4 bold
    IF toast_hFnt <> 0 THEN FONT END toast_hFnt ' new font -> release previous one
    FONT NEW family, siz, weight TO toast_hFnt
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetWidth (w AS LONG) ' w in pixels
    LOGME "          Toast_SetWidth: " + FORMAT$(w)
    toast_width = w
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetHeight (h AS LONG) ' h in pixels
    LOGME "          Toast_SetHeight: " + FORMAT$(h)
    toast_height = h
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetAlpha (a AS LONG) ' 0 <= a <= 255
    LOGME "          Toast_SetAlpha: " + FORMAT$(a)
    toast_alpha = a
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetText (t AS STRING)
    LOGME "          Toast_SetText: " + $DQ + t + $DQ
    toast_text = t
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetDuration (p AS LONG)
    LOGME "          Toast_SetDuration: " + FORMAT$(p) + " ms"
    toast_pause = p
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
FUNCTION RGB2BGR(rgb_c AS STRING) AS STRING ' convert a RGB color to a BGR color
    LOCAL bgr_c AS STRING
    bgr_c = RIGHT$(rgb_c,2) + MID$(rgb_c,3,2) + LEFT$(rgb_c,2)
    FUNCTION = bgr_c
END FUNCTION
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetTextColor (c AS STRING) ' c = hexadecimal color "RRGGBB"
    LOGME "          Toast_SetTextColor: &H" + c
    toast_colf = VAL("&H00" + RGB2BGR(c))
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_SetBackgroundColor (c AS STRING) ' c = hexadecimal color "RRGGBB"
    LOGME "          Toast_SetBackgroundColor: &H" + c
    toast_colb = VAL("&H00" + RGB2BGR(c))
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
'   ** Functions and Subs **
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
MACRO TOAST_MAKEDLG  ' (internal) common to Toast_Show_Sync() & Toast_Show_Async()
  LOCAL hDlg AS DWORD
  DIALOG NEW PIXELS, 0, EXE.NAME$, 0, 0, toast_width, toast_height TO hDlg
  DIALOG SET COLOR     hDlg, -1, %RGB_MAGENTA
  CONTROL ADD GRAPHIC, hDlg, 1000, "", 0, 0, toast_width, toast_height
END MACRO
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_Show_Sync ()  ' Synchronous (blocking) call
  LOCAL i AS LONG
  TOAST_MAKEDLG
  i = Toast_Create(hDlg)
  LOGME "Toast NO_" + FORMAT$(i) + " (" + FORMAT$(hDlg) _
    + ") has been created as a new Synchronous (blocking) toast"
  DIALOG SHOW MODAL hDlg CALL Toast_CB
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_Show_Async () ' Asynchronous (non-blocking) call
  LOCAL hThread AS DWORD
  LOCAL i AS LONG
  THREAD CREATE Toast_NewThread(0) TO hThread
  ARRAY SCAN toast_thread(), =0, TO i
  toast_thread(i) = hThread
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
THREAD FUNCTION Toast_NewThread (BYVAL h AS DWORD) AS LONG ' thread used by Async
  LOCAL i AS LONG
  TOAST_MAKEDLG
  i = Toast_Create(hDlg)
  LOGME "Toast NO_" + FORMAT$(i) + " (" + FORMAT$(hDlg) _
    + ") has ben created as a new Asynchronous (NON-blocking) toast"
  DIALOG SHOW MODAL hDlg CALL Toast_CB
  FUNCTION = -1
END FUNCTION
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
FUNCTION Toast_Create (BYVAL hDlg AS DWORD) AS LONG
  IF UBOUND(toast_dialog) < 0 THEN
    REDIM toast_dialog(1 TO 99)
    REDIM toast_thread(1 TO 99)
  END IF
  LOCAL i AS LONG
  ARRAY SCAN toast_dialog(), =0, TO i
  toast_dialog(i) = hDlg
  FUNCTION = i
END FUNCTION
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
FUNCTION Toast_Find (BYVAL hDlg AS DWORD) AS LONG
  LOCAL i AS LONG
  ARRAY SCAN toast_dialog(), =hDlg, TO i
  FUNCTION = i
END FUNCTION
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_Release (BYVAL hDlg AS DWORD)
  LOCAL i, lRes AS LONG
  ARRAY SCAN toast_dialog(), =hDlg, TO i
  toast_dialog(i) = 0
  IF toast_thread(i) <> 0 THEN
    THREAD CLOSE toast_thread(i) TO lRes
    toast_thread(i) = 0
  END IF
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_Enumerate ()
  LOCAL i AS LONG
  LOGME "Enumerating toasts..."
  FOR i = 1 TO 99
    IF toast_dialog(i) = 0 THEN EXIT FOR
    LOGME "     - Toast NO_" + FORMAT$(i) + " (" + FORMAT$(toast_dialog(i)) + ")"
  NEXT
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
'DECLARE FUNCTION SetTimer LIB "User32.dll" ALIAS "SetTimer" _
'    (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS DWORD, BYVAL uElapse AS DWORD, _
'    OPTIONAL BYVAL lpTimerFunc AS DWORD) AS DWORD
'--------------------------------------------------------------------------------
DECLARE FUNCTION KillTimer LIB "User32.dll" ALIAS "KillTimer" _
    (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS DWORD) AS LONG
'--------------------------------------------------------------------------------
DECLARE FUNCTION WaitForSingleObject LIB "Kernel32.dll" _
    ALIAS "WaitForSingleObject" (BYVAL hHandle AS DWORD, _
    BYVAL dwMilliseconds AS DWORD) AS DWORD
'--------------------------------------------------------------------------------
DECLARE FUNCTION CloseHandle LIB "Kernel32.dll" ALIAS "CloseHandle" _
    (BYVAL hObject AS DWORD) AS LONG
'--------------------------------------------------------------------------------
DECLARE FUNCTION SetWindowLong LIB "User32.dll" ALIAS "SetWindowLongW" _
    (BYVAL hWnd AS DWORD, BYVAL nIndex AS LONG, BYVAL lNewLong AS LONG) AS LONG
'--------------------------------------------------------------------------------
DECLARE FUNCTION GetWindowLong LIB "User32.dll" ALIAS "GetWindowLongW" _
    (BYVAL hWnd AS DWORD, BYVAL nIndex AS LONG) AS LONG
'--------------------------------------------------------------------------------
DECLARE FUNCTION SetWindowPos LIB "User32.dll" ALIAS "SetWindowPos" _
    (BYVAL hWnd AS DWORD, BYVAL hWndInsertAfter AS DWORD, BYVAL x AS LONG, _
    BYVAL y AS LONG, BYVAL cx AS LONG, BYVAL cy AS LONG, _
    BYVAL wFlags AS DWORD) AS LONG
'--------------------------------------------------------------------------------
DECLARE FUNCTION SetLayeredWindowAttributes LIB "User32.dll" _
    ALIAS "SetLayeredWindowAttributes" (BYVAL hwnd AS DWORD, _
    BYVAL crKey AS DWORD, BYVAL bAlpha AS BYTE, BYVAL dwFlags AS DWORD) AS LONG
'--------------------------------------------------------------------------------
DECLARE FUNCTION SendMessage LIB "User32.dll" ALIAS "SendMessageW" _
    (BYVAL hWnd AS DWORD, BYVAL dwMsg AS DWORD, BYVAL wParam AS DWORD, _
    BYVAL lParam AS LONG) AS LONG
'--------------------------------------------------------------------------------
'DECLARE FUNCTION SetWindowsHookEx LIB "User32.dll" ALIAS "SetWindowsHookExW" _
'    (BYVAL idHook AS LONG, BYVAL lpfn AS DWORD, BYVAL hMod AS DWORD, _
'    BYVAL dwThreadId AS DWORD) AS DWORD
'--------------------------------------------------------------------------------
DECLARE FUNCTION GetCurrentThreadId LIB "Kernel32.dll" _
    ALIAS "GetCurrentThreadId" () AS DWORD
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
MACRO CreateTimer (evt, tid)
  evt = SetTimer(CB.HNDL, tid, %TICK, BYVAL 0)
  DIALOG POST CB.HNDL, %WM_TIMER, tid, 0
END MACRO
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
CALLBACK FUNCTION Toast_CB ' Common Toast CallBack
  STATIC x, y, t, evtShow, evtPause, evtHide AS LONG
  STATIC t0 AS DOUBLE
  LOCAL e AS STRING
  LOCAL i AS LONG
  SELECT CASE CB.MSG
    CASE %WM_INITDIALOG
      t0 = TIMER
      Toast_Fill CB.HNDL                        ' Set toast properties & initialize its content
      i = Toast_Find(CB.HNDL)
      x = (i - 1) * (toast_width + 1)
      y = -toast_height
      CreateTimer (evtShow, %TIMER_SHOW)        ' Start timer event for dialog show
    CASE %WM_DESTROY
      e = "Toast NO_" + FORMAT$(Toast_Find(CB.HNDL)) + " (" + FORMAT$(CB.HNDL) + ")"
      LOGME e + " destroyed after displaying for " + FORMAT$(INT((TIMER-t0)*1000)) + " ms"
      Toast_Release CB.HNDL
    CASE %WM_TIMER
      ' Timer to show the toast
      IF CB.WPARAM = %TIMER_SHOW THEN
        IF y < 0 THEN
          y += 5
          DIALOG SET LOC CB.HNDL, x, y
        ELSE
          KillTimer CB.HNDL, evtShow
          t = 1
          CreateTimer (evtPause, %TIMER_PAUSE)  ' Start timer event to pause the toast
        END IF
      ' Timer to pause the toast
      ELSEIF CB.WPARAM = %TIMER_PAUSE THEN
        IF t = 0 THEN EXIT FUNCTION             ' Cannot pause until toast is fully shown
        IF t < toast_pause THEN
          t += %TICK
        ELSE
          KillTimer CB.HNDL, evtPause
          CreateTimer (evtHide, %TIMER_HIDE)    ' Start timer event to hide the toast
        END IF
      ' Timer to hide the toast
      ELSEIF CB.WPARAM = %TIMER_HIDE THEN
        IF y > -toast_height THEN
          y -= 5
          DIALOG SET LOC CB.HNDL, x, y
        ELSE
          KillTimer CB.HNDL, evtHide
          DIALOG END CB.HNDL
        END IF
      END IF
  END SELECT
END FUNCTION
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
SUB Toast_Fill (BYVAL hDlg AS DWORD)
      LOCAL w, h AS LONG
      ' Initialize Styles and Extended Styles of dialog
      SetWindowLong hDlg, %GWL_style, %WS_POPUP OR %WS_BORDER OR %DS_NOFAILCREATE _
                    OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_3DLOOK _
                    OR %DS_MODALFRAME OR %WS_DLGFRAME OR %DS_SETFONT OR %WS_CAPTION
      SetWindowLong hDlg, %GWL_EXstyle, %WS_EX_WINDOWEDGE OR %WS_EX_CONTROLPARENT _
                    OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR _
                    OR %WS_EX_TOOLWINDOW
      ' Set Always On Top
      SetWindowPos hDlg, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOMOVE OR %SWP_NOSIZE
      ' Remove Caption
      SetWindowLong hDlg, %GWL_style, GetWindowLong(hDlg, %GWL_style) XOR %WS_CAPTION
      ' Set Dialog alpha / Transparent Font / Transparent Background
      SetWindowLong hDlg, %GWL_EXSTYLE, GetWindowLong(hDlg, %GWL_EXstyle) OR %WS_EX_LAYERED
      SetLayeredWindowAttributes hDlg, %RGB_MAGENTA, toast_alpha, %LWA_Colorkey OR %LWA_ALPHA
      ' Initialize Dialog Content
      GRAPHIC ATTACH hDlg, 1000, REDRAW
      GRAPHIC COLOR toast_colf, toast_colb
      GRAPHIC SET FONT toast_hFnt
      GRAPHIC CLEAR
      CONTROL GET SIZE hDlg, 1000 TO w, h
      WRAP toast_text, w
      GRAPHIC REDRAW
END SUB
'--------------------------------------------------------------------------------
'-----------------------------------------------------------------------------------------------
SUB WRAP (FullString AS STRING, w AS LONG)
   LOCAL Part1, Part2 AS STRING
   gbSplitWord FullString, w, Part1, Part2
   WHILE LEN(Part2)
      GRAPHIC PRINT Part1
      gbSplitWord Part2, w, Part1, Part2
   WEND
   GRAPHIC PRINT Part1
END SUB
'-----------------------------------------------------------------------------------------------
'-----------------------------------------------------------------------------------------------
SUB gbSplitWord(BYVAL FullString AS STRING, BYVAL w AS LONG, Part1 AS STRING, Part2 AS STRING)
   LOCAL i, ww, hh AS LONG
   LOCAL PreviousWords, CurrentWord AS STRING
   'if only one word is in the string (no delimiter), use the entire string as Part1
   i = INSTR(FullString, $SPC)
   IF i = 0 THEN Part1 = FullString : Part2 = "" : EXIT SUB
   'if first word is wider than available width, use that word as Part1
   Part1 = LEFT$(FullString, i-1)
   GRAPHIC TEXT SIZE Part1 TO ww, hh
   IF ww > w THEN Part2 = MID$(FullString, i+1) : EXIT SUB
   'go through all words
   FOR i = 1 TO PARSECOUNT(FullString, $SPC) 'cycle through all words
      CurrentWord = PARSE$(FullString, $SPC, i)
      GRAPHIC TEXT SIZE PreviousWords + IIF$(i=1,"",$SPC) + CurrentWord TO ww, hh
      IF ww > w THEN
         'adding CurrentWord WILL exceed available width
         Part1 = PreviousWords
         Part2 = MID$(FullString, LEN(Part1)+2)
         EXIT SUB
      ELSE
         'adding CurrentWord WILL NOT exceed available width
         PreviousWords += IIF$(i=1,"",$SPC) + CurrentWord
         Part1 = PreviousWords
         Part2 = ""
      END IF
   NEXT
 END SUB
'-----------------------------------------------------------------------------------------------
'-----------------------------------------------------------------------------------------------
SUB LOGME (e AS STRING)
    IF ISFALSE %LOGME THEN EXIT SUB
    LOCAL ff AS LONG
    LOCAL d, t AS STRING
    ' Create TimeStamp
    d = DATE$
    d = RIGHT$(d,4) + LEFT$(d,2) + MID$(d, 4, 2)
    t = TIME$
    REPLACE ":" WITH "" IN t
    t = d + "-" + t + ","
    t = t + FORMAT$((TIMER*1000) MOD 1000, "000")
    ' Write To Log File
    ff = FREEFILE
    OPEN EXE.PATH$ + EXE.NAME$ + ".log" FOR APPEND AS #ff
    PRINT #ff, "[" + t + "] " + e
    CLOSE #ff
END SUB
'-----------------------------------------------------------------------------------------------