myTrayTip() - custom TrayTip - _ - collaborate?

Post your working scripts, libraries and tools.
User avatar
RUBn
Posts: 51
Joined: 27 Nov 2013, 05:12
Contact:

myTrayTip() - custom TrayTip - _ - collaborate?

16 Sep 2023, 15:47

Latest code version always in this first post.
  • For those like me where Traytip always stops working after a certain time
    (on any PC, even fresh Windows install, even with all the solutions proposed on this forum)
  • Or for anyone wanting a different (better?) TrayTip
Improvements appreciated and I will update the latest version in this top post.






Last edited by RUBn on 09 Nov 2023, 03:44, edited 10 times in total.
User avatar
Shareef Fayed
Posts: 1
Joined: 18 Feb 2023, 03:13

Re: myTrayTip() - custom TrayTip - _ - collaborate?

23 Sep 2023, 14:40

Nice idea, I made the todos

Code: Select all

#Requires AutoHotkey v2.0

;https://www.autohotkey.com/boards/viewtopic.php?f=83&t=121509

/*TODO:	- get Windows accent color [✓]
		- QUEUE IF TOO MANY ON TOP OF EACH OTHER: if  trays.Length > A_ScreenHeight/103 {} [✓]
*/

#SingleInstance force ; Allow only one instance of this script to be running.

global trays := []

myTrayTip(tip, titl:="Autohotkey", secs:=1) {
	;do traytip even tho it doesn't show balloon, so it also shows in action centre
	;TrayTip(tip, titl)
	g := Gui("+AlwaysOnTop -Caption +ToolWindow +LastFound")
	WinSetTransparent 200
	systemAccentColor := RegRead("HKCU\SOFTWARE\Microsoft\Windows\DWM", "ColorizationColor")
	g.BackColor := systemAccentColor
	g.SetFont("Bold ccccccc s14")
	g.AddText("x0 w200 Center", titl)
	g.SetFont("norm s12")
	g.AddText("x0 w200 Center", tip)
	g.AddProgress("x0 Y+12 w200 h20 caa33aa Background0x663366 vprogress")
	g.marginY:=0
	;To get width & height we show/hide
	g.Show("Hide")
	g.GetPos(,,&W, &H)
	trays.Push({
		g: g,
		secs: secs * 1000,
		start: A_TickCount
		})
	if trays.Length = 1
		SetTimer(myTrayTipUpdate, 100 )
}

myTrayTipUpdate() {
	For i,tray in trays {

		tray.g.GetPos( , , &W, &H)
		trayTop := A_ScreenHeight - i * (H + 5)
		; break if there is no room
		if trayTop < 0
			break
		; show tray & move down if necessary
		tray.g.Show("X" (A_ScreenWidth - W) " Y" trayTop )
		
		elapsedTime := A_TickCount - tray.start
		timeLeft := tray.secs - elapsedTime
		if timeLeft <= 0 {
			tray.g.Destroy
			trays.removeAt(i)
			if trays.Length = 0
				SetTimer , 0	
		} else	{
			tray.g["progress"].Value := 100 - 100 * timeLeft / tray.secs 
		}	
	}
}
User avatar
RUBn
Posts: 51
Joined: 27 Nov 2013, 05:12
Contact:

Re: myTrayTip() - custom TrayTip - _ - collaborate?

01 Oct 2023, 04:28

Shareef Fayed wrote:
23 Sep 2023, 14:40
Nice idea, I made the todos
Thanks.
I changed it a bit because the repeating Show() made everything flicker on my end. So I showed at start and moved later. The ones out of the screen are still shown but we don't see them until moved. I don't think there is a problem with that.
Updated in top post.

I am also: Image-motiv for professional, volunteer & open source (web) development
Ark565
Posts: 1
Joined: 27 Aug 2019, 02:00
Contact:

Re: myTrayTip() - custom TrayTip - _ - collaborate?

12 Oct 2023, 06:27

Thank you! This is just what I was looking for!
User avatar
emmanuel d
Posts: 90
Joined: 17 Nov 2013, 04:45

Re: myTrayTip() - custom TrayTip - _ - collaborate?

19 Oct 2023, 07:54

Single function, and fixed it for dpiscaling

Code: Select all

;https://www.autohotkey.com/boards/viewtopic.php?f=83&t=121509

#SingleInstance force                             ; Allow only one instance of this script to be running.
#Requires AutoHotkey v2


myTrayTip(tip, titl:="Autohotkey", secs:=3) {
  Static trays := []
  ; TrayTip(tip, titl) ; verry anoying
  g := Gui("+AlwaysOnTop -Caption +ToolWindow +LastFound")
  WinSetTransparent(240)
  systemAccentColor := RegRead("HKCU\SOFTWARE\Microsoft\Windows\DWM", "ColorizationColor")
  g.BackColor := systemAccentColor
  g.SetFont("Bold ccccccc s13")
  g.AddText("x0 w200 Center", titl)
  g.SetFont("norm s11")
  g.AddText("x0 w200 Center", tip)
  g.AddProgress("x0 Y+12 w200 h5 caa33aa Background0x663366 vprogress")
  ; g.marginY:=0                                  ; this has no purpose
  g.Show("Hide")                                  ; To get width & height we show/hide
  WinGetPos(&X, &Y, &W, &H,g.Hwnd)                ; Works well with dpiscaling
  g.Show("X" (A_ScreenWidth - W) " Y" (A_ScreenHeight - (trays.Length+1) * (H + 5) ) )	; (A_ScreenHeight - trays.Length * H))
  trays.Push({
    g: g,
    secs: secs * 1000,
    start: A_TickCount
    })
  if trays.Length = 1
    SetTimer(Update, 100)
  Update() {                                      ; Nested Function
    For i,tray in trays {
      WinGetPos(&X, &Y, &W, &H,tray.g.Hwnd)       ; Works well with dpiscaling
      trayTop := A_ScreenHeight - i * (H + 5)
      if trayTop < 0 {                            ; break if there is no room
        tray.g.Show("Hide")
        break
        }
      if Y != trayTop                             ; If the item moved
        tray.g.Show( " Y"  trayTop )              ; show tray & move down if necessary works ok for DPIScaling
      elapsedTime := A_TickCount - tray.start
      timeLeft    := tray.secs - elapsedTime
      if timeLeft <= 0 {
        tray.g.Destroy
        trays.removeAt(i)
        if trays.Length = 0
          SetTimer , 0	
      } else	{
        tray.g["progress"].Value := 100 - 100 * timeLeft / tray.secs 
        }	
      }
    }
  }

;Testing
^!t::
{
  myTrayTip("Testing myTrayTip","1 second",1)
  myTrayTip("Testing myTrayTip","3 second",3)
  myTrayTip("Testing myTrayTip",,4)
  myTrayTip("Testing myTrayTip","5 second",5)
  myTrayTip("Testing myTrayTip","6 second",6)
  myTrayTip("Testing myTrayTip","7 second",7)
  myTrayTip("Testing myTrayTip","8 second",8)
  myTrayTip("Testing myTrayTip","9 second",9)
  myTrayTip("Testing myTrayTip","10 second",10)
  myTrayTip("Testing myTrayTip","12 second",11)
  myTrayTip("Testing myTrayTip","12 second",12)
  myTrayTip("Testing myTrayTip","13 second",13)
  myTrayTip("Testing myTrayTip","14 second",14)
  ; myTrayTip("Testing myTrayTip","15 second",15)
  ; myTrayTip("Testing myTrayTip","16 second",16)
  ; myTrayTip("Testing myTrayTip","17 second",17)
  ; myTrayTip("Testing myTrayTip","18 second",18)
  ; myTrayTip("Testing myTrayTip","19 second",19)
  ; myTrayTip("Testing myTrayTip","20 second",20)
  ; myTrayTip("Testing myTrayTip","21 second",21)
  ; myTrayTip("Testing myTrayTip","22 second",22)
  ; myTrayTip("Testing myTrayTip","23 second",23)
}
User avatar
emmanuel d
Posts: 90
Joined: 17 Nov 2013, 04:45

Re: myTrayTip() - custom TrayTip - _ - collaborate?

19 Oct 2023, 08:00

Also noticed that it takes focus from the active window.
Fixed:

Code: Select all

;https://www.autohotkey.com/boards/viewtopic.php?f=83&t=121509

#SingleInstance force                             ; Allow only one instance of this script to be running.
#Requires AutoHotkey v2


myTrayTip(tip, titl:="Autohotkey", secs:=3) {
  Static trays := []
  ; TrayTip(tip, titl) ; verry anoying
  g := Gui("+AlwaysOnTop -Caption +ToolWindow +LastFound")
  WinSetTransparent(240)
  systemAccentColor := RegRead("HKCU\SOFTWARE\Microsoft\Windows\DWM", "ColorizationColor")
  g.BackColor := systemAccentColor
  g.SetFont("Bold ccccccc s13")
  g.AddText("x0 w200 Center", titl)
  g.SetFont("norm s11")
  g.AddText("x0 w200 Center", tip)
  g.AddProgress("x0 Y+12 w200 h5 caa33aa Background0x663366 vprogress")
  g.marginY:=0                                  ; this has no purpose
  g.Show("Hide")                                  ; To get width & height we show/hide
  WinGetPos(&X, &Y, &W, &H,g.Hwnd)                ; Works well with dpiscaling
  g.Show("NA W200 X" (A_ScreenWidth - W) " Y" (A_ScreenHeight - (trays.Length+1) * (H + 5) ) )	; (A_ScreenHeight - trays.Length * H))
  trays.Push({
    g: g,
    secs: secs * 1000,
    start: A_TickCount
    })
  if trays.Length = 1
    SetTimer(Update, 100)
  Update() {                                      ; Nested Function
    For i,tray in trays {
      WinGetPos(&X, &Y, &W, &H,tray.g.Hwnd)       ; Works well with dpiscaling
      trayTop := A_ScreenHeight - i * (H + 5)
      if trayTop < 0 {                            ; break if there is no room
        tray.g.Show("NA Hide")
        break
        }
      if Y != trayTop                             ; If the item moved
        tray.g.Show( "NA Y"  trayTop )              ; show tray & move down if necessary works ok for DPIScaling
      elapsedTime := A_TickCount - tray.start
      timeLeft    := tray.secs - elapsedTime
      if timeLeft <= 0 {
        tray.g.Destroy
        trays.removeAt(i)
        if trays.Length = 0
          SetTimer , 0	
      } else	{
        tray.g["progress"].Value := 100 - 100 * timeLeft / tray.secs 
        }	
      }
    }
  }

;Testing
^!t::
{
  myTrayTip("Testing myTrayTip","1 second",1)
  myTrayTip("Testing myTrayTip","3 second",3)
  myTrayTip("Testing myTrayTip",,4)
  myTrayTip("Testing myTrayTip","5 second",5)
  myTrayTip("Testing myTrayTip","6 second",6)
  myTrayTip("Testing myTrayTip","7 second",7)
  myTrayTip("Testing myTrayTip","8 second",8)
  myTrayTip("Testing myTrayTip","9 second",9)
  myTrayTip("Testing myTrayTip","10 second",10)
  myTrayTip("Testing myTrayTip","12 second",11)
  myTrayTip("Testing myTrayTip","12 second",12)
  myTrayTip("Testing myTrayTip","13 second",13)
  myTrayTip("Testing myTrayTip","14 second",14)
  ; myTrayTip("Testing myTrayTip","15 second",15)
  ; myTrayTip("Testing myTrayTip","16 second",16)
  ; myTrayTip("Testing myTrayTip","17 second",17)
  ; myTrayTip("Testing myTrayTip","18 second",18)
  ; myTrayTip("Testing myTrayTip","19 second",19)
  ; myTrayTip("Testing myTrayTip","20 second",20)
  ; myTrayTip("Testing myTrayTip","21 second",21)
  ; myTrayTip("Testing myTrayTip","22 second",22)
  ; myTrayTip("Testing myTrayTip","23 second",23)
}
User avatar
RUBn
Posts: 51
Joined: 27 Nov 2013, 05:12
Contact:

Re: myTrayTip() - custom TrayTip - _ - collaborate?

20 Oct 2023, 12:13

emmanuel d wrote:
19 Oct 2023, 07:54
Single function, and fixed it for dpiscaling
Thanks. I was hesitant to try that one function possibility. Appears to be very simple in the end.
emmanuel d wrote:
19 Oct 2023, 08:00
Also noticed that it takes focus from the active window.
Fixed:
I updated the script in the OP.
Some remarks:
  • Any reason why you didn't use the last version in OP? I put some things back. Could you comment if there was a reason for not using those things? I'll adjust if so.
  • g.marginY:=0 is there for aesthetic reasons. It makes the progress bar at bottom without margin.
  • Why the W200 ? Don't we want to auto size?
  • The break prevented newer shorter traytips from removing in time. Since I used the updated script, it's not an issue, but if you had a reason not to use it, you'll have to rearrange it.
  • Added a notification sound (Didn't that do it before if you allow the action centre option or is it my imagination?)

I am also: Image-motiv for professional, volunteer & open source (web) development
User avatar
emmanuel d
Posts: 90
Joined: 17 Nov 2013, 04:45

Re: myTrayTip() - custom TrayTip - _ - collaborate?

20 Oct 2023, 12:51

[*]Any reason why you didn't use the last version in OP? I put some things back. Could you comment if there was a reason for not using those things? I'll adjust if so.
hehe no :roll:
[*]g.marginY:=0 is there for aesthetic reasons. It makes the progress bar at bottom without margin.
I know, made some changes aftar the fact, also for X Because the gui adds pixels after that too
[*]Why the W200 ? Don't we want to auto size?
We do, but i just copy pasted it :oops:
Also that is more complex, get the size of both controls and than resize the whole thing.
On the other hand it would be ugly if they don't all have the same width. So maybe reflow is in order.
[*]The break prevented newer shorter traytips from removing in time. Since I used the updated script, it's not an issue, but if you had a reason not to use it, you'll have to rearrange it.
i am sorry, just cant remember it, and you already updated the original.
[*]Added a notification sound (Didn't that do it before if you allow the action centre option or is it my imagination?)
OK , Maybe optional

Ended up yesterday with:(added sound now)

Code: Select all

MyTrayTip(L_TrayTip,L_Title:="Autohotkey",L_Sec:=3,L_Sound:=0) {
  Static S_W     := 200
  Static S_Trays := []
  L_g := Gui("+AlwaysOnTop -Caption +ToolWindow +LastFound")
  WinSetTransparent(240)
  L_g.BackColor := RegRead("HKCU\SOFTWARE\Microsoft\Windows\DWM","ColorizationColor")
  L_g.marginX   := 0                              ; prevent gui show from adding a margin
  L_g.marginY   := 0                              ; prevent gui show from adding a margin
  L_g.SetFont("Bold ccccccc s13")
  L_g.AddText("x0 y5 w" S_W " Center", L_Title)
  L_g.SetFont("norm s11")
  L_g.AddText("x0 y+5 w" S_W " Center",L_TrayTip)
  L_g.AddProgress("x0 Y+12 w" S_W " h5 caa33aa Background0x663366 vprogress Range0-" S_W) ; Set the range equal to the pixels
  L_g.Show("Hide")                                ; To get width & height we show/hide
  WinGetPos(,, &L_W, &L_H,L_g.Hwnd)               ; Works well with dpiscaling
  L_g.Show("NA X" (A_ScreenWidth - L_W-5 ) " Y" (A_ScreenHeight - (S_Trays.Length+1) * (L_H + 5) ) )  
  S_Trays.Push({                                  ; Add the TrayBalloonTip to the array
    g: L_g,                                       ; Store the object of the GuiControl
    MSecs: L_Sec * 1000,                          ; And the milliseconds
    start: A_TickCount                            ; And the start time
    })
  if S_Trays.Length = 1                           ; If we have a TrayBalloonTip
    SetTimer(Update, 10)                          ; Call the update function every 10 milliseconds
  Update() {                                      ; Nested Update Function
    For L_i,L_Tray in S_Trays {                   ; Loop all TrayBalloonTip's
      WinGetPos(,&L_Y,,&L_H,L_Tray.g.Hwnd)        ; Works well with dpiscaling
      L_TrayTop := A_ScreenHeight - L_i * (L_H+5) ; get the location for the TrayBalloonTip
      L_TimeElapsed := A_TickCount - L_Tray.start ; Calculate the time that has past
      if L_TrayTop < 0 {                          ; If there is no more room on the screen
        L_Tray.g.Show("NA Hide")                  ; Hide the gui that has no space
        break                                     ; No need to add the other TrayBalloonTip's, so break the loop
        }
      if L_Y != L_TrayTop                         ; If the item moved
        L_Tray.g.Show("NA Y" L_TrayTop)           ; Show tray & move down if necessary (g.Show works ok for DPIScaling)
      if L_Tray.MSecs - L_TimeElapsed <= 0 {      ; If TimeLeft <= 0
        L_Tray.g.Destroy                          ; Remove the TrayBalloonTip
        S_Trays.removeAt(L_i)                     ; And remove it from the array
        If L_Sound                                ; If we want a sound
          SoundPlay("*-1")                        ; Play it
        if S_Trays.Length = 0                     ; If we have no more TrayBalloonTip's
          SetTimer(,0)                            ; Stop the updating
      } else	{
        L_Tray.g["progress"].Value := S_W  * L_TimeElapsed / L_Tray.MSecs
        }	
      }
    }
  }
Note that i always start local variables with L_ so they will never interfere with global ones.
User avatar
RUBn
Posts: 51
Joined: 27 Nov 2013, 05:12
Contact:

Re: myTrayTip() - custom TrayTip - _ - collaborate?

21 Oct 2023, 04:15

I haven't updated yet this time. First I'd like to finish the things below.

emmanuel d wrote:
20 Oct 2023, 12:51
[*]Any reason why you didn't use the last version in OP? I put some things back. Could you comment if there was a reason for not using those things? I'll adjust if so.
hehe no :roll:
Did you do it again? Or partly? Some things you did take over and others not without mentioning why or if it was a remainder of before. :crazy:

emmanuel d wrote:
20 Oct 2023, 12:51
[*]g.marginY:=0 is there for aesthetic reasons. It makes the progress bar at bottom without margin.
I know, made some changes aftar the fact, also for X Because the gui adds pixels after that too
Thanks, but now Range0-" S_W) ; Set the range equal to the pixels is not necessary anymore either since it does it automatically or is this a dpiscaling thing again?

emmanuel d wrote:
20 Oct 2023, 12:51
[*]Why the W200 ? Don't we want to auto size?
We do, but i just copy pasted it :oops:
Also that is more complex, get the size of both controls and than resize the whole thing.
On the other hand it would be ugly if they don't all have the same width. So maybe reflow is in order.
On one occasion your code had an extra one than the then last updated code (which is gone now). But neither does it in your new last one now. So no problem here anymore.

emmanuel d wrote:
20 Oct 2023, 12:51
[*]The break prevented newer shorter traytips from removing in time. Since I used the updated script, it's not an issue, but if you had a reason not to use it, you'll have to rearrange it.
i am sorry, just cant remember it, and you already updated the original.
Yes, I rearranged it after I answered this. Sorry. And it has to be a continue instead of break, but I'll fix it after we finish these topics
But I also took your break out since I preferred some extra milliseconds loop above 2 ahk lines, bc the times we would have more traytips than screen height is very low and the chance of having very many of them is even lower.

emmanuel d wrote:
20 Oct 2023, 12:51
[*]Added a notification sound (Didn't that do it before if you allow the action centre option or is it my imagination?)
OK , Maybe optional
OK, but since ahk and windows default with a sound, I'd prefer to make it true by default. Still not sure why it dissappeared since it did it before for me without the explicit code SoundPlay if you took the action centre option. :crazy:

emmanuel d wrote:
20 Oct 2023, 12:51
Note that i always start local variables with L_ so they will never interfere with global ones.
I noticed, but it's not necessary since the manual says Global Variables: However, if a variable is used in an assignment or with the reference operator (&), it is automatically local by default.
It's the same for function parameters. It doesn't say in the doc, but I tested it.
User avatar
emmanuel d
Posts: 90
Joined: 17 Nov 2013, 04:45

Re: myTrayTip() - custom TrayTip - _ - collaborate?

21 Oct 2023, 11:10

Did you do it again? Or partly?
No i just continued with what i have. not going to start over
Thanks, but now Range0-" S_W) ; Set the range equal to the pixels is not necessary anymore either since it does it automatically or is this a dpiscaling thing again?
That has nothing to do with DPI or autowidth, but in your case with the width like 200 it wil jump jerky every 2 pixels because you use the default like 100% or 100 pixels. in my case it will smoothly jump every pixel. so if the control is W200 u use range 200. if it is W500 the range would need to be 500. See progress options >> Range
The break prevented newer shorter traytips from removing in time.
Indeed, fixed now.
I noticed, but it's not necessary since the manual says Global Variables: However, if a variable is used in an assignment or with the reference operator (&), it is automatically local by default.
It's the same for function parameters. It doesn't say in the doc, but I tested it.
It does not matter If u use "#Warn All" you will get tired and start using appropriate naming.

This is how i curently use it, it replaces the build in Traytip() function and i wil attempt to add all optional parameters and some extra like sec. also the height of the Gui is now dynamic

Code: Select all

;https://www.autohotkey.com/boards/viewtopic.php?f=83&t=121509

#SingleInstance force                             ; Allow only one instance of this script to be running.
#Requires AutoHotkey v2
TrayTip(L_Text?,L_Title?,L_Options?) {    ; OverWrite the BuildIn Function
  ; Options
  ;Todo:  Info icon                             1 0x1 Iconi 
  ;Todo:  Warning icon                          2 0x2 Icon! 
  ;Todo:  Error icon                            3 0x3 Iconx 
  ;Todo:  Tray icon                             4 0x4 N/A 
  ;OK:    Do not play the notification sound.  16 0x10 Mute 
  ;Todo: Use the large version of the icon.   32 0x20 N/A 
  ;PartialOK: Seconds                                 Sec##
  Static S_BackColor := RegRead("HKCU\SOFTWARE\Microsoft\Windows\DWM","ColorizationColor") ; Read from registry only once
  Static S_W     := 250
  Static S_Trays := []
  Static S_RemoveAll
  If (IsSet(L_Text) + IsSet(L_Title) = 0) {        ; No parameters will remove all traytips
    S_RemoveAll := 1
    Return                                        ; No need to continue this function, the updater will handle it
    }
  S_RemoveAll := 0
  If L_Options ?? 0 {                             ; If there are options
    ; Needs lots mor work
    L_Sec     := RegExReplace(L_Options,"i).*Sec([0-9]*).*?", "$1") 
    L_Sound   := InStr(L_Options,"Mute") ? 0 : 1
    ; L_Options := RegExReplace(L_Options,"i)\s*Sec[0-9]+\s*","") ; remove it from options
    ; Msgbox L_Options
    ; Msgbox L_Sound   := RegExReplace(L_Options,"i).*?\s*Sound([0-9]*).*?", "$1") 
    }
  L_g            := Gui("+AlwaysOnTop -Caption +ToolWindow +LastFound")
  L_g.BackColor  := S_BackColor
  L_g.marginX    := 0                             ; prevent gui show from adding a margin
  L_g.marginY    := 0                             ; prevent gui show from adding a margin
  WinSetTransparent(240)                          ; Set transparentie of the window
  If L_Title ?? 0 {                               ; If we want a title 
    L_g.SetFont("Bold ccccccc s13")               ; Font options for the title/Traytip
    L_g.AddText("x0 y5 w" S_W " Center", L_Title) ; Add It to the Gui
    }
  L_g.SetFont("norm ccccccc s11")
  L_g.AddText("x0 y+5 w" S_W " Center",L_Text)
  L_g.AddProgress("x0 Y+12 w" S_W " h5 caa33aa Background0x663366 vprogress Range0-" S_W) ; Set the range equal to the pixels
  L_g.Show("Hide")                                ; To get width & height we show/hide
  L_TrayTop := A_ScreenHeight                     ; Start location of the balloontip
  For L_i,L_Tray in S_Trays {                     ; Loop all TrayBalloonTip's
    WinGetPos(,,,&L_H,L_Tray.g.Hwnd)              ; Get position of previous controlsWorks well with dpiscaling
    L_TrayTop -= L_H + 5                          ; Add it's location
    }
  WinGetPos(,, &L_W, &L_H,L_g.Hwnd)               ; Get position of the new control Works well with dpiscaling
  L_g.Show("NA X" (A_ScreenWidth - L_W-5 ) " Y" (L_TrayTop - L_H + 5 ) )  
  S_Trays.Push({                                  ; Add the TrayBalloonTip to the array
    g:     L_g,                                   ; Store the object of the GuiControl
    MSecs: 1000 * (L_Sec ?? 3),                   ; And the milliseconds
    start: A_TickCount,                           ; And the start time
    Sound: L_Sound ?? 0
    })
  if S_Trays.Length = 1                           ; If we have a TrayBalloonTip
    SetTimer(Update, 10)                          ; Call the update function every 10 milliseconds
  Update() {                                      ; Nested Update Function
    L_TrayTop := A_ScreenHeight                   ; Start location of the balloontip
    For L_i,L_Tray in S_Trays {                   ; Loop all TrayBalloonTip's
      WinGetPos(,&L_Y,,&L_H,L_Tray.g.Hwnd)        ; Works well with dpiscaling
      L_TimeElapsed := A_TickCount - L_Tray.start ; Calculate the time that has past
      if S_RemoveAll || L_Tray.MSecs - L_TimeElapsed <= 0 {      ; If TimeLeft <= 0
        L_Tray.g.Destroy                          ; Remove the TrayBalloonTip
        S_Trays.removeAt(L_i)                     ; And remove it from the array
        L_Tray.Sound   ? SoundPlay("*-1") : ""    ; If we want a sound, Play it
        S_Trays.Length ? "" : SetTimer(,0)        ; If we have no more TrayBalloonTip's ; Stop the updating
        Continue                                  ; all the code below is irellevant
        } 
      Else L_Tray.g["progress"].Value := S_W  * L_TimeElapsed / L_Tray.MSecs
      L_TrayTop -= L_H + 5                        ; get the location for the TrayBalloonTip
      If L_TrayTop < 0                            ; If there is no more room on the screen
        L_Tray.g.Show("NA Hide")                  ; Hide the gui that has no space
      Else If L_Y != L_TrayTop                    ; If the item moved
        L_Tray.g.Show("NA Y" L_TrayTop)           ; Show tray & move down if necessary (g.Show works ok for DPIScaling)
      }
    }
  }

;Testing
^!à::TrayTip() ; Remove all traytips
^!t::
{
  TrayTip("Testing myTrayTip Text`nWasaaaay","Title 5 second","Mute Sec5")
  TrayTip("Testing myTrayTip","Default 3 second")
  TrayTip("Testing No title","Mute Sec4")
  TrayTip("Testing myTrayTip with some verry long line on this one","5 second","Sec5")
  TrayTip("Testing myTrayTip`nnewline`nnewline`nnewline","6 second","Sec6")
  TrayTip("Testing myTrayTip with sound","7 second","Sec7")
}
User avatar
RUBn
Posts: 51
Joined: 27 Nov 2013, 05:12
Contact:

Re: myTrayTip() - custom TrayTip - _ - collaborate?

25 Oct 2023, 10:00

emmanuel d wrote:
21 Oct 2023, 11:10
Did you do it again? Or partly?
No i just continued with what i have. not going to start over
:cry: Real pitty. But OK,we will have two versions now, with extra work for me. :cry: Pitty this forum can't work like github: Forked versions and pulled in features..

emmanuel d wrote:
21 Oct 2023, 11:10
Thanks, but now Range0-" S_W) ; Set the range equal to the pixels is not necessary anymore either since it does it automatically or is this a dpiscaling thing again?
That has nothing to do with DPI or autowidth, but in your case with the width like 200 it wil jump jerky every 2 pixels because you use the default like 100% or 100 pixels. in my case it will smoothly jump every pixel. so if the control is W200 u use range 200. if it is W500 the range would need to be 500. See progress options >> Range
Hmm, I didn't know specifying the range instead ofthe automatic 100% is smoother. Are you sure it's not just smoother because you lowered the timer to 10 ms? I didn't find any mention of it in doc.

emmanuel d wrote:
21 Oct 2023, 11:10
I noticed, but it's not necessary since the manual says Global Variables: However, if a variable is used in an assignment or with the reference operator (&), it is automatically local by default.
It's the same for function parameters. It doesn't say in the doc, but I tested it.
It does not matter If u use "#Warn All" you will get tired and start using appropriate naming.
I don't use #Warn All. I also think it should not warn for the same cases in the above sentence from the docs . And it could do that since it says where it is done and other errors can say where a variable is never assigned. Is there a feedback forum topic where I could feature request this for Authotkey.exe?

emmanuel d wrote:
21 Oct 2023, 11:10

This is how i curently use it, it replaces the build in Traytip() function and i wil attempt to add all optional parameters and some extra like sec. also the height of the Gui is now dynamic
Grats and thanks. I will take over your improvements, but continue with the OP (argumented) version. Keep your updated code coming..
Could you tell me why the height in previous version was not dynamic? Because of the if title ?

I am also: Image-motiv for professional, volunteer & open source (web) development
User avatar
emmanuel d
Posts: 90
Joined: 17 Nov 2013, 04:45

Re: myTrayTip() - custom TrayTip - _ - collaborate?

25 Oct 2023, 11:16

Hmm, I didn't know specifying the range instead ofthe automatic 100% is smoother. Are you sure it's not just smoother because you lowered the timer to 10 ms? I didn't find any mention of it in doc.
The timer is irrelevant, The width of the gui is 250px, how is the control that only allows 100 positions in that not going to jump? he will go like 0px 2px 5px 7px equal to 0% 1% 2% 3%
Could you tell me why the height in previous version was not dynamic? Because of the if title ?
No, i don't remember

Some thoughts, I did not like the gui's moving down, verry hard to read like that.
Also multiple scripts will mess it up completely i expect.
And no need to be compatible with the buildIn function so parameters are OK.


The latesd version:

Code: Select all

;https://www.autohotkey.com/boards/viewtopic.php?f=83&t=121509

#SingleInstance force                             ; Allow only one instance of this script to be running.
#Requires AutoHotkey v2

TrayTip(L_Text?,L_Title?,L_Progress:=0,L_Icon:=0,L_Sec:=6,L_Mute:=0) {    ; OverWrite the BuildIn Function
  Static S_W            := 250
  Static S_Radius       := 12
  Static S_Transparency := 240
  Static S_BackColor    := RegRead("HKCU\SOFTWARE\Microsoft\Windows\DWM","ColorizationColor") ; Read from registry only once
  Static S_Trays        := []
  Static S_RemoveAll 
  If (IsSet(L_Text) + IsSet(L_Title) = 0)         ; No parameters will remove all traytips
    Return S_RemoveAll := 1                       ; No need to continue this function, the updater will handle it
  S_RemoveAll := 0                                ; If we are here, we don't want to remove everything
  L_Mute ? "" : SoundPlay("*-1")                  ; If we want a sound, Play it
  L_TrayTop   := MonitorGetWorkArea(1,,, &L_WaR, &L_WaB) ? L_WaB -10 : A_ScreenHeight
  If WinExist(A_ThisFunc "Gui"){  ; Find Notifications of a Previous scripts, for placement
    WinGetPos(&L_PrevX,&L_PrevY,&L_PrevW, &L_PrevH)
    L_TrayTop := L_PrevY - 10
    }
  L_g            := Gui("+AlwaysOnTop -Caption +ToolWindow +LastFound -Border",A_ThisFunc "Gui")
  L_g.BackColor  := S_BackColor
  L_g.marginX    := 5                             ; default margin of 5 pixels
  L_g.marginY    := 5                             ; default margin of 5 pixels
  If L_Icon {
    If      L_Icon = 1                            ; 1 77 = i info
      L_g.Add("Picture","w48 h48 Icon" 77 ,"C:\Windows\system32\imageres.dll")
    Else If L_Icon = 2                            ; 2 80 = ! warning
      L_g.Add("Picture","w48 h48 Icon" 80 ,"C:\Windows\system32\imageres.dll")
    Else If L_Icon = 3                            ; 3 94 = x Error
      L_g.Add("Picture","w48 h48 Icon" 94 ,"C:\Windows\system32\imageres.dll")
    Else If L_Icon = 4                            ; 4 A_IconNumber and A_IconFile
      L_g.Add("Picture","w48 h48 Icon" A_IconNumber?A_IconNumber:1 ,A_IconFile?A_IconFile:A_AhkPath)
    Else If FileExist(L_Icon)
      Try L_g.Add("Picture","w48 h48 Icon1",L_Icon)
    }
  If L_Title ?? 0 {                               ; If we want a title 
    L_g.SetFont("Bold ccccccc s13")               ; Font options for the title/Traytip
    ; L_g.AddText("x+0 y5 w" (L_Icon?S_W-48:S_W) " Center", L_Title) ; Add It to the Gui
    If L_Icon
      L_g.AddText("x+m  w" (S_W-L_g.marginX-48-L_g.marginX-L_g.marginX) " 0x80 Center", L_Title) ; Add It to the Gui
    Else L_g.AddText("xm w" (S_W-L_g.marginX-L_g.marginX) " 0x80 Center", L_Title) ; Add It to the Gui
    }
  If L_Text ?? 0 {                               ; If we want the text
    L_g.SetFont("norm ccccccc s11")
    L_g.AddText("xm y" (L_Icon ? 58 : "+" L_g.marginX) " w" (S_W-10) " 0x80 Center",L_Text "`nTimout: " L_Sec " S_W: " S_W)
    ; L_g.AddText("x5 y" (L_Icon?58:"+5") " w" (S_W-10) " 0x80 Center +Wrap",L_Text "`nTimout: " L_Sec " S_W: " S_W)
    ; If L_Icon
      ; L_g.AddText("x5 y" (L_Icon?58:"+5") " w" (S_W-10) " 0x80 Center +Wrap",L_Text "`nTimout: " L_Sec " S_W: " S_W)
    ; Else L_g.AddText("x0 y+5 w" S_W " 0x80 Center +Wrap",L_Text "`nTimout: " L_Sec " S_W: " S_W)
    ; L_g.AddText("x0 y+5 w" S_W " 0x80 Center +Wrap",L_Text ) ;"`nTimout: " L_Sec " S_W: " S_W)
    }
  L_g.marginX    := 0                             ; Progress must occupy the full width
  If L_Progress
    L_g.AddProgress("x0 Y+m w" S_W " h5 caa33aa Background0x663366 vprogress Range0-" S_W) ; Set the range equal to the pixels
  Else L_g.AddText( "x0 y+m h0 w" S_W)            ; Added to ensure the width is respected If there is no progress
  L_g.marginY    := 0                             ; prevent gui show from adding a margin below the progress
  L_g.Show("Hide")                                ; To get width & height we show/hide
  WinGetPos(,, &L_W, &L_H,L_g.Hwnd)               ; Get position of the new control Works well with dpiscaling
  WinSetTransparent(S_Transparency)               ; Set transparentie of the window
  WinSetRegion("0-0 w" L_W " h" L_H " R" S_Radius "-" S_Radius, L_g)
  L_g.AddText("vClick x0 y0 w" L_W " h" L_H " BackgroundTrans") ; Clickable
  L_g.Show("Hide NA X" (L_WaR - L_W-5 ) " Y" (L_TrayTop - L_H + 5 ) ) 
  L_g["Click"].OnEvent("Click", Click, 1)         ; clickerdeclickerdeclick
  S_Trays.Push({                                  ; Add the TrayBalloonTip to the array
    g:     L_g,                                   ; Store the object of the GuiControl
    MSecs: 1000 * (L_Sec ?? 3),                   ; And the milliseconds
    start: A_TickCount,                           ; And the start time
    })
  if S_Trays.Length = 1                           ; If we have a TrayBalloonTip
    SetTimer(Update, 100)                          ; Call the update function every 10 milliseconds
  Click(L_oCtrl, Info){
    While GetKeyState("LButton")
      Continue
    L_oGui := L_oCtrl.Gui
    L_oGui.Destroy
    }
  Update() {                                      ; Nested Update Function
    For L_i,L_Tray in S_Trays {                   ; Loop all TrayBalloonTip's
      Try WinGetPos(,,,,L_Tray.g.Hwnd)            ; Check If the window still exist
      Catch                                       ; the gui was destroid by click
        L_RemoveThis := 1                         ; Indicate removal for this traytip
      Else L_RemoveThis := 0
      L_TimeElapsed := A_TickCount - L_Tray.start ; Calculate the time that has past
      if L_RemoveThis || S_RemoveAll || L_Tray.MSecs - L_TimeElapsed <= 0 { ; If TimeLeft <= 0
        L_Tray.g.Destroy                          ; Remove the TrayBalloonTip
        S_Trays.removeAt(L_i)                     ; And remove it from the array
        If S_Trays.Length = 0
          SetTimer(,0)                            ; If we have no more TrayBalloonTip's ; Stop the updating
        Continue                                  ; all the code below is irellevant
        } 
      ; If L_Tray.Progress
      Try L_Tray.g["progress"].Value := S_W  * L_TimeElapsed / L_Tray.MSecs
      }
    }
  }


^!y::TrayTip()                                    ; Ctrl+Alt+Y = Remove all traytips
^!t::                                             ; Ctrl+Alt+T = Testing
  {
  TrayTip("Testing Icon 0","Title",1)
  TrayTip("Testing Icon 1","Title",1,1)
  TrayTip("Testing Icon 2","Title",1,2)
  TrayTip("Testing Icon 3","Title",1,3)
  TrayTip("Testing Icon 4","Title",,4)
  TrayTip("Testing Icon 4","Title",1,"E:\Documents\My_Apps\EMDK Xplorer\MenuIcons\MI_New__.ico")
  ; Sleep(5000)
  TrayTip("Testing 5","Title Looooongghjgjgjgjhgjygjygggg`nLine2",,4,5,1)
  TrayTip("Testing 6 Looooongghjgjgjgjhgjygjyggggjhhk hkhjkhkjhkhkkazerty","Title",,4,5,1)
  ; TrayTip("","","Mute Sec1",)
  ; Sleep(1000)
  TrayTip("Text ","Only","Mute Sec1")
  ; Sleep(1000)
  ; TrayTip("","Title Only","Mute Sec1")
  ; Sleep(1000)
  ; TrayTip("Testing myTrayTip Text`nWasaaaay","Title 5 second","Mute Sec5 progress")
  ; TrayTip("Testing myTrayTip","Default second","Mute")
  ; TrayTip("Testing No title ",,"Mute Sec2")
  ; Sleep(2000)
  ; TrayTip("Testing myTrayTip with some verry long line on this one","Title 5sec","Sec5")
  ; TrayTip("Testing myTrayTip`nnewline`nnewline`nnewline","6 second","Sec6")
  ; TrayTip("Testing myTrayTip with sound","7 second","Sec7 progress")
  }
User avatar
RUBn
Posts: 51
Joined: 27 Nov 2013, 05:12
Contact:

Re: myTrayTip() - custom TrayTip - _ - collaborate?

01 Nov 2023, 06:53

Script updated in first post.
  • All traytips same width, text wraps (word- ánd letter-wrapping)
  • Added round corners (Tx Emmanuel)
  • Different sound options (anything SoundPlay can)
  • Rewrote update loop against unsafe array operations and other improvements
  • More icon options (default, index, file, same as trayicon) (Partly Tx Emmanuel)
  • Added more tests in Testing
  • Using monitor work area (instead of monitor edges) (Tx Emmanuel with some improvements)
_________________________________________________

emmanuel d wrote:
25 Oct 2023, 11:16
Some thoughts, I did not like the gui's moving down, verry hard to read like that.
I don't have any problem to read them. What are you talking about? And how else do you make hidden traytips visible?

emmanuel d wrote:
25 Oct 2023, 11:16
Also multiple scripts will mess it up completely i expect.
I tested with multiple scripts. But I always start my scripts from one script and since I include these functions, I experienced no problems. You probably start different scripts from outside, or is there another use case?

emmanuel d wrote:
25 Oct 2023, 11:16
And no need to be compatible with the buildIn function so parameters are OK.
?

emmanuel d wrote:
25 Oct 2023, 11:16
About this: Try WinGetPos(,,,,L_Tray.g.Hwnd)
Try, so in which case wouldn't the gui exist anymore?

For somoeone who uses warnall, you should know that L_WaR is never assigned if your MonitorGetWorkArea fails.

I am also: Image-motiv for professional, volunteer & open source (web) development

Return to “Scripts and Functions (v2)”

Who is online

Users browsing this forum: pedro45_vs and 63 guests