hey hugov:
try this out and let me know what you think... use Options=
GR=0 ;sets gui radius off
BR=0 ;sets background radius off
BT=255 ;sets background transparency off
BW=1 ;sets thickness to 1 like a tooltip
to make it look like a tooltip, and negative duration kills app again (and is per notify, so a newer notify that doesnt have exit won't kill until the first is clicked or times out... so yo ucan haveone up that says "click me to exit" and others can come and go in the meantime
edit: latest version in original post, this version here for detailed comments
Code:
; Notify() Version 0.29 - made by gwarble - sept 09
; for displaying multiple customizable tray area notifications
;
; Notify([Message,Title,Duration,Options,Image])
;
; thanks to Rhys and engunneer [Toaster Popups]
; test with [Ctrl-Shift-F12] if Notify.ahk is run
;
;=== To Fix:
;=== fill gaps from removed notifications if fit (might not be worth the wingetpos processing...?, and may not be desireable)
;=== or shift left a "column" width for more than monitor height allows
;=== or collapse open not's on new not or on close not (with delay)
;=== one last global to remove for label name... don't know if its possible
;=== flashing could be improved with options
;=== position could be controlable, could be moveable once open (stickies, reminders, etc)
;=== GN/maxcount need to be made parametric (for now it starts at 11: and allows 40)
;=== flash only works with odd number of flashing not's (easy to fix but may change functionality instead)
;=== have an Options parameter, for color/size/font stuff, position/size stuff, time action, click action, instead of so many parameters, parse internally...
;===
;====================================================================================
;====================================================================================
Notify_Demo1: ;=== in case Notify.ahk is run instead of #include-d
OptionsList := "GF=11`nGL=30`nGC=FFFFAA`n
GR=9`nGT=0`n
TS=8`nTW=625`nTC=Black`nTF=Arial`nMS=8`n
MW=550`nMC=Black`nMF=Arial`nBC=Black`n
BW=2`nBR=9`nBT=105`nBF=150`nSC=300`nSI=250`n
ST=100`nAC=`nAT="
Options := "TC=Red MC=Blue GC=Silver"
Notify("","Fake Tooltip 1",5,"GR=0 BR=0 BT=255 BW=1")
Notify("Fake Tooltip 2")
Options := "TC=Red MC=Blue GC=Silver"
Notify("Options:",OptionsList,7,Options)
Options := "GC=FFFFAA GR=9 GT=Off
TS=8 TW=625 TC=Black TF=Arial MS=8
MW=550 MC=Black MF=Arial BC=Black
BW=2 BR=9 BT=105 BF=150"
Notify("Options:","Default",10,Options)
Notify("Notification:","This one won't go away unless clicked!",0)
Notify("Notification:","This one won't go away unless clicked!",0,"","Off.ico")
Hotkey, ^+F12, Notify_Demo2
Return
Notify_Demo2:
Notify("Title","Message",2,"GC=CCCC44")
Notify("Title","Message",3,"GR=20")
Notify("Title","Message",5,"BT=10")
Notify("Title","Message",7,"GC=FFFFAA GR=9
GT=Off BT=205 TC=Black MC=Black")
Notify()
Notify("Title","Message",8,"GR=24 BR=25")
Notify("Title","Message",9,"BW=4")
Notify("Title","Message",10,"BR=0")
Notify("Title","Message",11,"GR=0 MW=550")
Notify("Title","Message",12,"BW=1")
Notify("Title","Message",13,"MW=550")
Notify("Title","Message",15,"SI=1000 SO=1000 SC=500") ;=== slow
Hotkey, ^+F12, Notify_Demo3
Return
Notify_Demo3:
Notify()
Notify()
Notify()
Notify()
Notify("Notify()","Exiting in 10`nor if clicked...",-10,"GC=Lime TC=Black MC=White MW=625")
Hotkey, ^+F12, Notify_Demo1
Return
;====================================================================================
;====================================================================================
Notify(Title="Notification!!!",Message="",Duration=15,Options="",Image="")
{
Static ;=== assume-static mode for arrays of options
Critical ;=== don't allow interruption
static GF := 11 ;GF is Gui First Number ;=== defaults if no options
static GL := 30 ;GM is Gui Last Number ;=== options are saved between calls (ie only set once and changed if in Options)
static GC := "FFFFAA" ;GC is Gui Color
static GR := 9 ;GR is Gui Radius
static GT := "Off" ;GT is Gui Transparency
static TS := 8 ;TS is Title Font Size
static TW := 625 ;TW is Title Font Weight
static TC := "Black" ;TC is Title Font Color
static TF := "Arial" ;TF is Title Font
static MS := 8 ;MS is Message Font Size
static MW := 550 ;MW is Message Font Weight
static MC := "Black" ;MC is Message Font Color
static MF := "Arial" ;MF is Message Font
static BC := "Black" ;BC is Border Colors
static BW := 2 ;BW is Border Width/Thickness ;=== hugov, note option (BW BT) change
static BR := 9 ;BR is Border Radius
static BT := 105 ;BT is Border Transpacency
static BF := 150 ;BF is Border Flash Speed
static SC := 300 ;SC is Speed Clicked (AnimateWindow time)
static SI := 250 ;SI is Speed In (AnimateWindow time)
static ST := 100 ;SO is Speed TimeOut (AnimateWindow time)
static IW := 32 ;IW is Image Width
static IH := 32 ;IH is Image Height
Global AC := 0 ;AC is Action Clicked (gosub label when clicked) ;=== Global Notify_Action removed for now
Global AT := 0 ;AT is Action Timeout (gosub label when timeout)
local ImageShift = ""
If (Options) ;=== parse Options parameter
Loop,Parse,Options,%A_Space%
If (Option:= SubStr(A_LoopField,1,2))
%Option%:= SubStr(A_LoopField,4) ;=== two letter option and = (ie GF=) takes 3 chars, so value starts at 4 (needs to strip quotes if used)
GN := GF ;=== GuiNumber[GN] starts at GF[FirstGuiNumber]
Loop ;=== max notifications, Notify() uses twice the max (for background) so 5 notifications use 10 gui numbers
IfNotInString, NotifyList, % "|" GN ;=== check if this notification exists
Break ;=== if not, make it
Else ;=== if so
If (++GN > GL) ;=== increment GN, check if under maxcount
Return 0 ;GN := GF ;=== If so, recheck, if not, return 0 ERROR (process by your script, if succedes returns guiID) (should save somehow and show when possible)
NotifyList .= "|" GN ;=== add GN to list of open guis, | delimeted
GN2 := GN + GL - GF + 1 ;=== gui number for background gui
Prev_DetectHiddenWindows := A_DetectHiddenWindows ;=== save current DetectHiddenWindows settings
Prev_TitleMatchMode := A_TitleMatchMode ;=== save current TitleMatchMode settings
DetectHiddenWindows On ;=== needed for winexist()
SetTitleMatchMode 1 ;=== needed for winexist()
If (WinExist("NotifyGui")) ;=== find all Notify() gui's from any scripts for placement
WinGetPos, OtherX, OtherY ;=== change this to a loop for all windows, not just first found by winexist()
DetectHiddenWindows %Prev_DetectHiddenWindows% ;=== restore script settings
SetTitleMatchMode %Prev_TitleMatchMode% ;=== restore script settings
Gui, %GN2%:Destroy ; - remove these once unnecessary
Gui, %GN%:Destroy ; - remove these once unnecessary
Gui, %GN%:-Caption +ToolWindow +AlwaysOnTop -Border ;=== notification gui creation
Gui, %GN%:Color, %GC%
Gui, %GN%:Font, w%TW% s%TS% c%TC%
If ((Image) && FileExist(Image))
{
Gui, %GN%:Add, Picture, w%IW% h%IH%, % Image
ImageShift = x+10
}
If (Title)
Gui, %GN%:Add, Text, % ImageShift, % Title
Gui, %GN%:Font, w%MW% s%MS% c%MC%
If ((Title) && (Message))
Gui, %GN%:Margin, , -5
If (Message)
Gui, %GN%:Add, Text,, % Message
If ((Title) && (Message))
Gui, %GN%:Margin, , 8
Gui, %GN%:Show, Hide, NotifyGui
Gui %GN%:+LastFound
WinGetPos, GX, GY, GW, GH ;=== get notification size/position
Gui, %GN%:Add, Text, x0 y0 w%GW% h%GH% gNotify_Action BackgroundTrans ;=== for clicking anywhere on the notification instead of just the text
If (GR)
WinSet, Region, % "0-0 w" GW " h" GH " R" GR "-" GR ;=== round corners of notification, notification gui creation END
WinSet, Transparent, % GT
SysGet, Workspace, MonitorWorkArea ;=== initial placement
NewX := WorkSpaceRight-GW-5
If (OtherY)
NewY := OtherY-GH-5
Else
NewY := WorkspaceBottom-GH-5
If NewY < % WorkspaceTop
NewY := WorkspaceBottom-GH-5 ;=== initial placement END
Gui, %GN2%:-Caption +ToolWindow +AlwaysOnTop -Border +E0x20 ;=== background gui
Gui, %GN2%:Color, %BC%
Gui %GN2%:+LastFound
If (BR)
WinSet, Region, % "0-0 w" GW+(BW*2) " h" GH+(BW*2) " R" BR "-" BR
WinSet, Transparent, % BT
Gui, %GN2%:Show, % "Hide x" NewX-BW " y" NewY-BW " w" GW+(BW*2) " h" GH+(BW*2)
Gui, %GN%:Show, % "Hide x" NewX " y" NewY, NotifyGui
Gui %GN%:+LastFound
NotifyGuiID := WinExist()
DllCall("AnimateWindow","UInt",NotifyGuiID,"Int",250,"UInt","0x00040008") ;=== slide up new notifications
Gui, %GN2%:Show, NA ;=== show background gui
WinSet, AlwaysOnTop, On
If Duration < 0
Exit := GN
If (Duration) ;=== set timeout for notification
SetTimer, NotifyKill%GN%, % - Abs(Duration) * 1000
Else
SetTimer, NotifyFlash%GN%, 150 ;=== flash border/icon for permanent notification (add option for flash/noflash)
Return NotifyGuiID ;=== change to return gui number
;====================================================================================
;====================================================================================
;=== when a notification is clicked:
Notify_Action:
SetTimer, NotifyKill%A_Gui%, Off
Gui, % A_Gui + 20 ":Destroy"
Gui %A_Gui%:+LastFound
NotifyGuiID := WinExist()
DllCall("AnimateWindow","UInt",NotifyGuiID,"Int",100,"UInt", "0x00050001") ;=== slide right FAST clicked notifications
Gui, %A_Gui%:Destroy
If IsLabel(Notify_Action)
Gosub, %Notify_Action%
StringReplace, NotifyList, NotifyList, % "|" GN, , All
SetTimer, % "NotifyFlash" A_Gui, Off
If (Exit = A_Gui)
ExitApp
Return
;=== when a notification times out:
NotifyKill:
NotifyKill11:
NotifyKill12:
NotifyKill13:
NotifyKill14:
NotifyKill15:
NotifyKill16:
NotifyKill17:
NotifyKill18:
NotifyKill19: ;=== there's gotta be a better way to do this, bueller?, bueller?
NotifyKill20:
NotifyKill21:
NotifyKill22:
NotifyKill23:
NotifyKill24:
NotifyKill25:
NotifyKill26:
NotifyKill27:
NotifyKill28:
NotifyKill29:
NotifyKill30:
StringReplace, GK, A_ThisLabel, NotifyKill
SetTimer, NotifyFlash%GK%, Off
Gui, % GK + 20 ":Destroy"
Gui %GK%:+LastFound
NotifyGuiID := WinExist()
DllCall("AnimateWindow","UInt",NotifyGuiID,"Int",300,"UInt", "0x00050001") ;=== slide right SLOW timed-out notifications
Gui, %GK%:Destroy
StringReplace, NotifyList, NotifyList, % "|" GK
If (Exit = GK)
ExitApp
Return
;=== flashes a permanent notification [buggy]
NotifyFlash11:
NotifyFlash12:
NotifyFlash13:
NotifyFlash14:
NotifyFlash15:
NotifyFlash16:
NotifyFlash17:
NotifyFlash18:
NotifyFlash19:
NotifyFlash20: ;=== maybe instead use one timer and a FlashList like notifylist
NotifyFlash21: ;=== maybe they should just all flash
NotifyFlash22:
NotifyFlash23:
NotifyFlash24:
NotifyFlash25:
NotifyFlash26:
NotifyFlash27:
NotifyFlash28:
NotifyFlash29:
NotifyFlash30:
NotifyFlash:
StringReplace, FlashGN, A_ThisLabel, NotifyFlash
FlashGN2 := FlashGN + 20
If Flashed := !Flashed
Gui, %FlashGN2%:Color, Silver
Else
Gui, %FlashGN2%:Color, Black
Return
} ;=== end of Notify() ===
;=== use in OnExit (or elsewhere) to wait for notifications to close before doing something [buggy]
;=== fix: Reference GN instead of GuiID, use negative forcetime to kill all open notifications (not yet implemented)
Notify_Wait(ForceTime="", GN=11, MaxNotifications=20)
{
Loop % MaxNotifications
{
Gui %GN%:+LastFound
If NotifyGuiID := WinExist()
{
WinWaitClose, , , % ForceTime
If ErrorLevel
{
Gui, % GN + 20 ":Destroy"
DllCall("AnimateWindow","UInt",NotifyGuiID,"Int",200,"UInt", "0x00050001") ;=== slide right FAST clicked notifications
Gui, %GN%:Destroy
}
Break
}
GN++
}
Return 1
}