Notify - BugFix version 16 Jul 14

118 posts in this topic

Posted (edited)

[bUGFIX VERSION] - 16 Jul 14

Fixed: Bug when adding a PNG in x64. Thanks to guinness and UEZ for the fix. :thumbsup:

New UDF and example in the zip below. :)

Previous changes: Changelog.txt


A while ago I was asked to help port an AHK UDF to AutoIt. This was not too difficult and I found it useful myself (as a replacement for ConsoleWrite when debugging compiled scripts among other things). I have been polishing it for a while and thought I might release it in case it proves useful to anyone else. ;)

The notifications produced by Notify are small 2-line boxes that pop out of the edge of the display one above the other (you can select which side and in which direction they appear) - you can have as many as you want at the same time as long as they all fit on your display. You can select whether they will retract after a certain time and/or when clicked. Colours and font are user-definable, and you can add an icon or image (bmp, jpg, gif or png) if you wish. When a notification retracts, the others move to leave space for more (you can select a smoooth slide or an instant move) - run the example to see them in action.

If you find the default sizing of the notifications is not to your liking you can change it by amending these values in the UDF (lines #333-335):

; Set default auto-sizing Notify dimensions
Local $iNotify_Width_max = 300
Local $iNotify_Width_min = 150
Local $iNotify_Height = 40
A zip containing the UDF, an example script and my StringSize UDF (which is also required): Notify.zip

As usual happy for comments and/or compliments. :D

M23

Edited by Melba23
Ivo, yahaosoft and Synapsee like this

Share this post


Link to post
Share on other sites



Posted

Nice!

I suggest you add a callback function that will be called when a user click on the window, something like NIN_BALLOONUSERCLICK.

_Notify_RegMsg($sCallback = '')

Share this post


Link to post
Share on other sites

Posted (edited)

When in Rome ... Great work, etc.

Edited by MvGulik

Share this post


Link to post
Share on other sites

Posted

Looks really nice! :)

Is it possible to move the notify windows smoother to the empty place when one of them is gone? Futher, can an image be used instead of an icon? Last but not least, can the border be changed to e.g. 3D border?

Br,

UEZ

Share this post


Link to post
Share on other sites

Posted (edited)

Hi Melba23,

looks great. Thanks for sharing.

Is it possible to include a "Yes" and "No" Button?

Greets and a happy new year.

Dizzy

Edited by Dizzy

Share this post


Link to post
Share on other sites

Posted

Dizzy,

These are for notification, not interaction. ;)

But look in the Toast thread where you asked a similar question - you might find a solution there. :)

M23

Share this post


Link to post
Share on other sites

Posted

UEZ,

I will look into your 3 requests - but do not hold your breath! ;)

Yashied,

I will look into that too. :D

MvGulik,

Suggested New Year resolution for you: Less time in the coffee shops, it is beginning to show. :)

M23

Share this post


Link to post
Share on other sites

Posted

Thanks for sharing, I like it. :)

Share this post


Link to post
Share on other sites

Posted

Suggested New Year resolution for you: Less time in the coffee shops, it is beginning to show. :)

... If you think so ...

Share this post


Link to post
Share on other sites

Posted

Thanks for sharing!

Very Nice!

Share this post


Link to post
Share on other sites

Posted

UEZ,

Lucky you - heavy showers so no golf and I could work on your requests.

You can use images (32x32 only - just use the full path as the parameter) and the notifications have a 3D border. I have added a further parameter to _Notify_Set to get the notifications to slide into place rather that moving instantly. They still move pretty quickly as they are actioned inside a message handler and I do not want to hold up the queue for longer than absolutely necessary. The more notifications there are to move the quicker they slide - on my machine it takes about 250ms to move 17 of them which seems not to cause any problems. But I still believe it will be a "user beware" option. ;)

Here is the new code - see if you like it:

#include-once

; #INDEX# ============================================================================================================
; Title .........: Notify
; AutoIt Version : 3.3.2.0+ - uses AdlibRegister/Unregister
; Language ......: English
; Description ...: Show and hides pop-out messages from the right side of the screen in user defined colours and fonts
; Author(s) .....: Melba23
; ====================================================================================================================

#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; #INCLUDES# =========================================================================================================
#include <StringSize.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Create array to hold data for Notifications
; [0][0] = Count			[n][0] = Handle
; [0][1] = Max avail		[n][1] = Timer duration
; [0][2] = X-coord          [n][2] = Timer stamp
; [0][3] = Low Y-coord		[n][3] = Clickable
; [0][4]					[n][4] = X-Coord
Global $aNotify_Data[1][5] = [[0, Int((@DesktopHeight - 60) / 50), @DesktopWidth - 10, @DesktopHeight - 10, 0]]
; Adjust values according to taskbar position
_Notify_Locate()

; Create array to hold default and current Notification values = [Style ($SS_CENTER), Col, BkCol, Font, Slide, TimerRun]
Global $aNotify_Settings[2][6] = [[1, 0, 0, _Notify_GetDefFont(), False, False]]
Global $aNotify_Ret = DllCall("User32.dll", "int", "GetSysColor", "int", 8) ; $COLOR_WINDOWTEXT = 8
$aNotify_Settings[0][1] = $aNotify_Ret[0]
$aNotify_Ret = DllCall("User32.dll", "int", "GetSysColor", "int", 5) ; $COLOR_WINDOW = 5
$aNotify_Settings[0][2] = $aNotify_Ret[0]
; Use the defaults as current settings
For $i = 0 To 3
	$aNotify_Settings[1][$i] = $aNotify_Settings[0][$i]
Next

; #CURRENT# ==========================================================================================================
; _Notify_Set:    Sets text justification and optionally colours and font, for _Notify_Show function calls
; _Notify_Show:   Shows a message from the right side of the screen
; _Notify_RegMsg: Registers the WM_MOUSEACTIVATE message to enable retraction of the message on clicking
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _Notify_Locate:           Find Systray and determine message start position and maximum number
; _Notify_Timer:            Checks whether a message has timed out
; _Notify_WM_MOUSEACTIVATE: Message handler to check if message clicked
; _Notify_Delete:           Retract a message when timed out or clicked
; _Notify_Reset;            Reposition remaining messages on screen
; _Notify_GetDefFont:       Determine system default MsgBox font
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Set
; Description ...: Sets text justification and optionally colours, font and movement for _Notify_Show function calls
; Syntax.........: _Notify_Set($vJust, [$iCol, [$iBkCol, [$iFont_Name, [$fSlide]]])
; Parameters ....: $vJust     - 0 = Left justified, 1 = Centred (Default), 2 = Right justified
;                                Can use $SS_LEFT, $SS_CENTER, $SS_RIGHT
;                       >>>>>    Setting this parameter to' Default' will reset ALL parameters to default values     <<<<<
;                       >>>>>    All optional parameters default to system MsgBox default values                     <<<<<
;                  $iCol   - [Optional] The colour for the message text
;                  $iBkCol - [Optional] The colour for the message background
;                                Omitting a colour parameter or setting it to -1 leaves it unchanged
;                                Setting a colour parameter to Default resets the system colour
;                  $sFont_Name - [Optional] The font to use for the Toast
;                       >>>>>    Omitting this parameter leaves it unchanged                                         <<<<<
;                       >>>>>    Setting this parameter to Default resets the system message box font                <<<<<
;                  $fSlide - [Optional] Movement of other notifications into new position when one below retracts
;                                False = Instant (default)
;                                True  = Slide
;                       >>>>>    Using this option increases the chances of a system crash - user beware!!           <<<<<
; Requirement(s).: v3.3.2.0 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success - Returns 1
;                  Failure - Returns 0 and sets @error to 1 with @extended set to parameter index number
; Author ........: Melba23
; Example........; Yes
;=====================================================================================================================
Func _Notify_Set($vJust, $iCol = -1, $iBkCol = -1, $sFont_Name = "", $fSlide = False)

	; Set parameters
	Switch $vJust
		Case Default
			For $i = 0 To 3
				$aNotify_Settings[1][$i] = $aNotify_Settings[0][$i]
			Next
			Return
		Case 0, 1, 2
			$aNotify_Settings[1][0] = $vJust
		Case Else
			Return SetError(1, 1, 0)
	EndSwitch

	Switch $iCol
		Case Default
			$aNotify_Settings[1][1] = $aNotify_Settings[0][1]
		Case 0 To 0xFFFFFF
			$aNotify_Settings[1][1] = $iCol
		Case -1
			; Do nothing
		Case Else
			Return SetError(1, 2, 0)
	EndSwitch

	Switch $iBkCol
		Case Default
			$aNotify_Settings[1][2] = $aNotify_Settings[0][2]
		Case 0 To 0xFFFFFF
			$aNotify_Settings[1][2] = $iBkCol
		Case -1
			; Do nothing
		Case Else
			Return SetError(1, 3, 0)
	EndSwitch

	Switch $sFont_Name
		Case Default
			$aNotify_Settings[1][3] = $aNotify_Settings[0][3]
		Case ""
			; Do nothing
		Case Else
			If IsString($sFont_Name) Then
				$aNotify_Settings[1][3] = $sFont_Name
			Else
				Return SetError(1, 4, 0)
			EndIf
	EndSwitch

	If $fSlide = True Then
		$aNotify_Settings[0][4] = True
	Else
		$aNotify_Settings[0][4] = False
	EndIf

	Return 1

EndFunc   ;==>_Notify_Set

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Show
; Description ...: Shows a message from the right side of the screen
; Syntax.........: _Notify_Show($vIcon, $sTitle, $sMessage, [$iDelay [, $iClick]])
; Parameters ....: $vIcon    - 0 - No icon, 8 - UAC, 16 - Stop, 32 - Query, 48 - Exclamation, 64 - Information
;                              The $MB_ICON constant can also be used for the last 4 above
;                              If set to the name of an exe, the main icon of that exe will be displayed
;                              If set to the name of an image file, that image will be displayed
;                              Any other value returns -1, error 1
;                  $sTitle   - Text to display as title in bold
;                  $sMessage - Text to display as message
;                              If $sTitle = "" then $sText can take 2 lines
;                  $iDelay   - The delay in seconds before the message retracts (Default = 0 = Remains indefinitely)
;                  $iClick   - If message will retact when clicked (Default = 1 = Clickable)
; Requirement(s).: v3.3.1.5 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success: Returns 1
;                  Failure:	Returns -1 and sets @error as follows:
;                           1 = Maximum number of messages already displayed
;                           2 = Icon parameter invalid
;                           3 = StringSize error
;                           4 = Title/text will not fit in widest message (@extended = 0/1 = Title/Text)
;                           5 = Notify GUI creation failed
; Author ........: Melba23
; Notes .........;
; Example........; Yes
;=====================================================================================================================

Func _Notify_Show($vIcon, $sTitle, $sMessage, $iDelay = 0, $iClick = 1)

	If $aNotify_Data[0][0] = $aNotify_Data[0][1] Then
		Return SetError(1, 0, -1)
	EndIf

	Local $aLabel_Pos, $iLabel_Width, $iLabel_Height = 20

	; Set default auto-sizing Notify dimensions
	Local $iNotify_Width_max = 300
	Local $iNotify_Width_min = 150
	Local $iNotify_Height = 40

	; Check for icon
	Local $iIcon_Style = 0
	Local $iIcon_Reduction = 36
	Local $sDLL = "user32.dll"
	Local $sImg = ""
	If StringIsDigit($vIcon) Then
		Switch $vIcon
			Case 0
				$iIcon_Reduction = 0
			Case 8
				$sDLL = "imageres.dll"
				$iIcon_Style = 78
			Case 16 ; Stop
				$iIcon_Style = -4
			Case 32 ; Query
				$iIcon_Style = -3
			Case 48 ; Exclam
				$iIcon_Style = -2
			Case 64 ; Info
				$iIcon_Style = -5
			Case Else
				Return SetError(1, 0, -1)
		EndSwitch
	Else
		Switch StringLower(StringRight($vIcon, 3))
			Case "exe", "ico"
				$sDLL = $vIcon
				$iIcon_Style = 0
			Case "bmp", "jpg", "gif"
				$sImg = $vIcon
		EndSwitch
	EndIf

	; Determine max message width
	Local $iMax_Label_Width = $iNotify_Width_max - $iIcon_Reduction - 8

	; Get text size
	If $sTitle Then
		; Measure title
		$aLabel_Pos = _StringSize($sTitle, 9, Default, Default, $aNotify_Settings[1][3])
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 0, -1)
		Else
			; Set width required
			$iLabel_Width = $aLabel_Pos[2]
		EndIf
		; Measure message
		$aLabel_Pos = _StringSize($sMessage, 9, Default, Default, $aNotify_Settings[1][3])
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 1, -1)
		Else
			; Adjust width required if needed
			If $aLabel_Pos[2] > $iLabel_Width Then
				$iLabel_Width = $aLabel_Pos[2]
			EndIf
		EndIf
	Else
		; Measure message
		$aLabel_Pos = _StringSize($sMessage, 9, Default, Default, $aNotify_Settings[1][3], $iMax_Label_Width)
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; If wrapped check still fits vertically
		If $aLabel_Pos[3] > 40 Then
			Return SetError(4, 1, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 1, -1)
		Else
			; Set Notification size and label position
			If $aLabel_Pos[2] > $iLabel_Width Then
				$iLabel_Width = $aLabel_Pos[2]
			EndIf
			$sMessage = $aLabel_Pos[0]
			; Adjust vertical position to centre lines
			Local $iLabel_Y = Int((40 - $aLabel_Pos[3]) / 2)
		EndIf
	EndIf

	; Set Notify size
	Local $iNotify_Width = $iLabel_Width + 8 + $iIcon_Reduction

	; Increase if below min size
	If $iNotify_Width < $iNotify_Width_min + $iIcon_Reduction Then
		$iNotify_Width = $iNotify_Width_min + $iIcon_Reduction
		$iLabel_Width = $iNotify_Width_min - 8
	EndIf

	; Set Notify coords
	Local $iNotify_X = $aNotify_Data[0][2] - $iNotify_Width
	Local $iNotify_Y = $aNotify_Data[0][3] - (50 * ($aNotify_Data[0][0] + 1))

	; Create Notify slice with $WS_POPUPWINDOW style and $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST and $WS_EX_STATICEDGE extended style
	Local $hNotify_Handle = GUICreate("", $iNotify_Width, $iNotify_Height, $iNotify_X, $iNotify_Y, 0x80880000, BitOR(0x00020000, 0x00000080, 0x00000008))
	If @error Then
		Return SetError(5, 0, -1)
	EndIf
	GUISetBkColor($aNotify_Settings[1][2])

	; Create icon
	If $iIcon_Reduction Then
		If $sImg Then
			GUICtrlCreatePic($sImg, 4, 4, 32, 32)
		Else
			GUICtrlCreateIcon($sDLL, $iIcon_Style, 4, 4)
		EndIf
	EndIf

	; Create labels
	If $sTitle Then
		; Title
		GUICtrlCreateLabel($sTitle, 4 + $iIcon_Reduction, 0, $iLabel_Width, $iLabel_Height)
		GUICtrlSetFont(-1, 9, 800, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
		; Message
		GUICtrlCreateLabel($sMessage, 4 + $iIcon_Reduction, 20, $iLabel_Width, $iLabel_Height)
		GUICtrlSetFont(-1, 9, 400, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
	Else
		; Message
		GUICtrlCreateLabel($sMessage, 4 + $iIcon_Reduction, $iLabel_Y, $iLabel_Width, 40 - $iLabel_Y)
		GUICtrlSetFont(-1, 9, 400, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
	EndIf

	; Slide Notify Slice into view from behind systray and activate
	DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $hNotify_Handle, "int", 1000, "long", 0x00040002) ; $AW_SLIDE_IN_RIGHT

	; Activate Notify without stealing focus
	GUISetState(@SW_SHOWNOACTIVATE, $hNotify_Handle)

	; Store Notify data
	$aNotify_Data[0][0] += 1
	ReDim $aNotify_Data[$aNotify_Data[0][0] + 1][5]
	$aNotify_Data[$aNotify_Data[0][0]][0] = $hNotify_Handle
	$aNotify_Data[$aNotify_Data[0][0]][1] = $iDelay * 1000
	$aNotify_Data[$aNotify_Data[0][0]][2] = TimerInit()
	$aNotify_Data[$aNotify_Data[0][0]][3] = $iClick
	$aNotify_Data[$aNotify_Data[0][0]][4] = $iNotify_X

	; Start Adlib function for Notify retraction
	If $aNotify_Data[0][0] = 1 Then
		AdlibRegister("_Notify_Timer", 1000)
	EndIf

EndFunc   ;==>_Notify_Show

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_RegMsg
; Description ...: Registers WM_MOUSEACTIVATE message needed for the UDF
; Syntax.........: _Notify_RegMsg()
; Parameters ....: None
; Requirement(s).: v3.3.1.5 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If another WM_MOUSEACTIVATE handler already registered, then call the _Notify_WM_MOUSEACTIVATE handler
;                  function from within that handler
;                  If messages are not to retract when clicked the WM_MOUSEACTIVATE message does not need to be registered
; Example........: Yes
;=====================================================================================================================
Func _Notify_RegMsg()

	GUIRegisterMsg(0x0021, "_Notify_WM_MOUSEACTIVATE") ; $WM_MOUSEACTIVATE
	$aNotify_Data[0][4] = 1

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Locate
; Description ...: Find Systray and determine message start position and maximum number
; Syntax ........: _Notify_Locate()
; Parameters ....: None
; Author ........: Melba23, based on some original code by GioVit
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Locate()

	Local $tWorkArea

	; Determine which struct syntax to use to use
	If @AutoItVersion < "3.3.8.0" Then
		$tWorkArea = DllStructCreate("long Left;long Top;long Right;long Bottom")
	Else
		$tWorkArea = DllStructCreate("struct;long Left;long Top;long Right;long Bottom;endstruct")
	EndIf

	; Check if Taskbar is visible
	Local $aRet = DllCall("shell32.dll", "uint", "SHAppBarMessage", "dword", 0x00000004, "ptr*", 0) ; $ABM_GETSTATE
	If Not BitAND($aRet[0], 0x01) Then

		; Determine available work area ; $SPI_GETWORKAREA = 48
		DllCall("user32.dll", "bool", "SystemParametersInfoW", "uint", 48, "uint", 0, "ptr", DllStructGetPtr($tWorkArea), "uint", 0)
		If @error Then Return SetError(2, 0, -1)
		Local $aWorkArea[4] = [DllStructGetData($tWorkArea, "Left"), DllStructGetData($tWorkArea, "Top"), _
			DllStructGetData($tWorkArea, "Right"), DllStructGetData($tWorkArea, "Bottom")]

		; Adjust data array if necessary
		$aNotify_Data[0][1] = Int(($aWorkArea[3] - $aWorkArea[1] - 60) / 50)
		If $aWorkArea[2] < @DesktopWidth Then
			$aNotify_Data[0][2] = $aWorkArea[2] - 10
		EndIf
		If $aWorkArea[3] < @DesktopHeight Then
			$aNotify_Data[0][3] = $aWorkArea[3] - 10
		EndIf

	EndIf

EndFunc   ;==>_Notify_Locate

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Timer
; Description ...: Checks whether a message has timed out
; Syntax ........: _Notify_Timer()
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Timer()

	Local $fMoved = False

	; Pause Adlib as retraction and movement could overrun delay time
	AdlibUnRegister("_Notify_Timer")
	; Prevent simultaneous click
	$aNotify_Settings[0][5] = True

	; Run through notifications
	For $i = $aNotify_Data[0][0] To 1 Step -1
		; Check timer if needed
		If $aNotify_Data[$i][1] And TimerDiff($aNotify_Data[$i][2]) > $aNotify_Data[$i][1] Then
			_Notify_Delete($i)
			$fMoved = True
			ExitLoop
		EndIf
	Next

	; Adjust positions of Notifications
	If $fMoved Then
		_Notify_Reset($i)
	EndIf

	; Restart Adlib if needed
	If $aNotify_Data[0][0] Then
		AdlibRegister("_Notify_Timer", 1000)
	EndIf
	; Re-enable clicks
	$aNotify_Settings[0][5] = False

EndFunc   ;==>_Notify_Timer

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_WM_MOUSEACTIVATE
; Description ...: Message handler to check if message clicked
; Syntax ........: _Notify_WM_MOUSEACTIVATE($hWnd, $Msg, $wParam, $lParam)
; Parameters ....: Standard message handler parameters
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_WM_MOUSEACTIVATE($hWnd, $iMsg, $wParam, $lParam)

	#forceref $iMsg, $wParam, $lParam

	; Declare flag to prevent multiple clicks until a Notification is retracted
	Static $fRunning
	If $fRunning Then Return

	; Check timer is not checking
	If $aNotify_Settings[0][5] Then Return

	; Declare flag
	Local $fMoved = False
	; Set Running flag
	$fRunning = True

	For $i = $aNotify_Data[0][0] To 1 Step -1
		If $aNotify_Data[$i][3] And $hWnd = $aNotify_Data[$i][0] Then
			_Notify_Delete($i)
			$fMoved = True
			ExitLoop
		EndIf
	Next

	; Adjust positions of Notifications
	If $fMoved Then
		_Notify_Reset($i)
	EndIf

	; Clear Running flag
	$fRunning = False

	Return 'GUI_RUNDEFMSG'

EndFunc   ;==>_Notify_WM_MOUSEACTIVATE

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Delete
; Description ...: Retract a message when timed out or clicked
; Syntax ........: _Notify_Delete($i)
; Parameters ....: $i - Index of message to be retracted
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Delete($i)

	; Retract and delete Notify
	DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $aNotify_Data[$i][0], "int", 500, "long", 0x00050001) ; $AW_SLIDE_OUT_RIGHT
	GUIDelete($aNotify_Data[$i][0])
	; Adjust array
	For $j = $i + 1 To $aNotify_Data[0][0]
		For $k = 0 To 4
			$aNotify_Data[$j - 1][$k] = $aNotify_Data[$j][$k]
		Next
	Next
	ReDim $aNotify_Data[$aNotify_Data[0][0]][5]
	$aNotify_Data[0][0] -= 1

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Reset
; Description ...: Reposition remaining messages on screen
; Syntax ........: _Notify_Reset($i)
; Parameters ....: $i - Index of message just retracted
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Reset($iIndex)

	If $aNotify_Settings[0][4] Then
		; Set step size depending on number of notifications to move
		Local $iStep = 1 + Int(($aNotify_Data[0][0] - $iIndex) / 3)
		; Slide notifications into new positions
		For $j = 1 To 50 Step $iStep
			For $i = $iIndex To $aNotify_Data[0][0]
				WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] - (50 * ($i + 1)) + $j)
			Next
		Next
	Else
		; Move notifications into new positions instantly
		For $i = 1 To $aNotify_Data[0][0]
			WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] - (50 * $i))
		Next
	EndIf

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_GetDefFont
; Description ...: Determine system default MsgBox font
; Syntax ........: _Notify_GetDefFont()
; Parameters ....: None
; Author ........: Melba23
; Modified.......:
; Remarks .......:
Func _Notify_GetDefFont()

	; Get default system font data
	Local $tNONCLIENTMETRICS = DllStructCreate("uint;int;int;int;int;int;byte[60];int;int;byte[60];int;int;byte[60];byte[60];byte[60]")
	DllStructSetData($tNONCLIENTMETRICS, 1, DllStructGetSize($tNONCLIENTMETRICS))
	DllCall("user32.dll", "int", "SystemParametersInfo", "int", 41, "int", DllStructGetSize($tNONCLIENTMETRICS), "ptr", DllStructGetPtr($tNONCLIENTMETRICS), "int", 0)
	; Read font data for MsgBox font
	Local $tLOGFONT = DllStructCreate("long;long;long;long;long;byte;byte;byte;byte;byte;byte;byte;byte;char[32]", DllStructGetPtr($tNONCLIENTMETRICS, 15))
	; Font name
	Return DllStructGetData($tLOGFONT, 14)

EndFunc   ;==>_Notify_GetDefFont

And comments also welcome from anyone else of course. :)

M23

Share this post


Link to post
Share on other sites

Posted

Looks good M23. :)

One time I tried your example and after clicking the clickable notifiucations I had this error

G:playNotify.au3 (503) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:

I tried to reproduced this but I couldn't remember the order in which I clicked things and I can't do it again.

Share this post


Link to post
Share on other sites

Posted

Thanks for the update! I will have a closer look when I'am at home.

Br,

UEZ

Share this post


Link to post
Share on other sites

Posted

I was just wondering if it is worth while adding parameters to allow the notifications to appear on the left, stacked up from the bottom or listed below from the top of the screen. Perhaps using x/y start position parameters.

Share this post


Link to post
Share on other sites

Posted

martin,

Thanks - I had noticed that a couple of times too. It seems that you can get click/timer interference despite the code I put in to stop it. ;)

Here is a version with (I hope) more efficient non-interference code to stop clicks and the timer trying to delete notifications at the same time. When I have tried it it seems more stable:

#include-once

; #INDEX# ============================================================================================================
; Title .........: Notify
; AutoIt Version : 3.3.2.0+ - uses AdlibRegister/Unregister
; Language ......: English
; Description ...: Show and hides pop-out messages from the right side of the screen in user defined colours and fonts
; Author(s) .....: Melba23
; ====================================================================================================================

#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; #INCLUDES# =========================================================================================================
#include <StringSize.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Create array to hold data for Notifications
; [0][0] = Count			[n][0] = Handle
; [0][1] = Max avail		[n][1] = Timer duration
; [0][2] = X-coord          [n][2] = Timer stamp
; [0][3] = Low Y-coord		[n][3] = Clickable
; [0][4]					[n][4] = X-Coord
Global $aNotify_Data[1][5] = [[0, Int((@DesktopHeight - 60) / 50), @DesktopWidth - 10, @DesktopHeight - 10, 0]]
; Adjust values according to taskbar position
_Notify_Locate()

; Create array to hold default and current Notification values = [Style ($SS_CENTER), Col, BkCol, Font, Slide, Interference]
; [0][5] = Timer running, [1][5] = Click running
Global $aNotify_Settings[2][6] = [[1, 0, 0, _Notify_GetDefFont(), False, False], [0, 0, 0, 0, 0, False]]
Global $aNotify_Ret = DllCall("User32.dll", "int", "GetSysColor", "int", 8) ; $COLOR_WINDOWTEXT = 8
$aNotify_Settings[0][1] = $aNotify_Ret[0]
$aNotify_Ret = DllCall("User32.dll", "int", "GetSysColor", "int", 5) ; $COLOR_WINDOW = 5
$aNotify_Settings[0][2] = $aNotify_Ret[0]
; Use the defaults as current settings
For $i = 0 To 3
	$aNotify_Settings[1][$i] = $aNotify_Settings[0][$i]
Next

; #CURRENT# ==========================================================================================================
; _Notify_Set:    Sets text justification and optionally colours and font, for _Notify_Show function calls
; _Notify_Show:   Shows a message from the right side of the screen
; _Notify_RegMsg: Registers the WM_MOUSEACTIVATE message to enable retraction of the message on clicking
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _Notify_Locate:           Find Systray and determine message start position and maximum number
; _Notify_Timer:            Checks whether a message has timed out
; _Notify_WM_MOUSEACTIVATE: Message handler to check if message clicked
; _Notify_Delete:           Retract a message when timed out or clicked
; _Notify_Reset;            Reposition remaining messages on screen
; _Notify_GetDefFont:       Determine system default MsgBox font
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Set
; Description ...: Sets text justification and optionally colours, font and movement for _Notify_Show function calls
; Syntax.........: _Notify_Set($vJust, [$iCol, [$iBkCol, [$iFont_Name, [$fSlide]]])
; Parameters ....: $vJust     - 0 = Left justified, 1 = Centred (Default), 2 = Right justified
;                                Can use $SS_LEFT, $SS_CENTER, $SS_RIGHT
;                       >>>>>    Setting this parameter to' Default' will reset ALL parameters to default values     <<<<<
;                       >>>>>    All optional parameters default to system MsgBox default values                     <<<<<
;                  $iCol   - [Optional] The colour for the message text
;                  $iBkCol - [Optional] The colour for the message background
;                                Omitting a colour parameter or setting it to -1 leaves it unchanged
;                                Setting a colour parameter to Default resets the system colour
;                  $sFont_Name - [Optional] The font to use for the Toast
;                       >>>>>    Omitting this parameter leaves it unchanged                                         <<<<<
;                       >>>>>    Setting this parameter to Default resets the system message box font                <<<<<
;                  $fSlide - [Optional] Movement of other notifications into new position when one below retracts
;                                False = Instant (default)
;                                True  = Slide
;                       >>>>>    Using this option increases the chances of a system crash - user beware!!           <<<<<
; Requirement(s).: v3.3.2.0 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success - Returns 1
;                  Failure - Returns 0 and sets @error to 1 with @extended set to parameter index number
; Author ........: Melba23
; Example........; Yes
;=====================================================================================================================
Func _Notify_Set($vJust, $iCol = -1, $iBkCol = -1, $sFont_Name = "", $fSlide = False)

	; Set parameters
	Switch $vJust
		Case Default
			For $i = 0 To 3
				$aNotify_Settings[1][$i] = $aNotify_Settings[0][$i]
			Next
			Return
		Case 0, 1, 2
			$aNotify_Settings[1][0] = $vJust
		Case Else
			Return SetError(1, 1, 0)
	EndSwitch

	Switch $iCol
		Case Default
			$aNotify_Settings[1][1] = $aNotify_Settings[0][1]
		Case 0 To 0xFFFFFF
			$aNotify_Settings[1][1] = $iCol
		Case -1
			; Do nothing
		Case Else
			Return SetError(1, 2, 0)
	EndSwitch

	Switch $iBkCol
		Case Default
			$aNotify_Settings[1][2] = $aNotify_Settings[0][2]
		Case 0 To 0xFFFFFF
			$aNotify_Settings[1][2] = $iBkCol
		Case -1
			; Do nothing
		Case Else
			Return SetError(1, 3, 0)
	EndSwitch

	Switch $sFont_Name
		Case Default
			$aNotify_Settings[1][3] = $aNotify_Settings[0][3]
		Case ""
			; Do nothing
		Case Else
			If IsString($sFont_Name) Then
				$aNotify_Settings[1][3] = $sFont_Name
			Else
				Return SetError(1, 4, 0)
			EndIf
	EndSwitch

	If $fSlide = True Then
		$aNotify_Settings[0][4] = True
	Else
		$aNotify_Settings[0][4] = False
	EndIf

	Return 1

EndFunc   ;==>_Notify_Set

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Show
; Description ...: Shows a message from the right side of the screen
; Syntax.........: _Notify_Show($vIcon, $sTitle, $sMessage, [$iDelay [, $iClick]])
; Parameters ....: $vIcon    - 0 - No icon, 8 - UAC, 16 - Stop, 32 - Query, 48 - Exclamation, 64 - Information
;                              The $MB_ICON constant can also be used for the last 4 above
;                              If set to the name of an exe, the main icon of that exe will be displayed
;                              If set to the name of an image file, that image will be displayed
;                              Any other value returns -1, error 1
;                  $sTitle   - Text to display as title in bold
;                  $sMessage - Text to display as message
;                              If $sTitle = "" then $sText can take 2 lines
;                  $iDelay   - The delay in seconds before the message retracts (Default = 0 = Remains indefinitely)
;                  $iClick   - If message will retact when clicked (Default = 1 = Clickable)
; Requirement(s).: v3.3.1.5 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success: Returns 1
;                  Failure:	Returns -1 and sets @error as follows:
;                           1 = Maximum number of messages already displayed
;                           2 = Icon parameter invalid
;                           3 = StringSize error
;                           4 = Title/text will not fit in widest message (@extended = 0/1 = Title/Text)
;                           5 = Notify GUI creation failed
; Author ........: Melba23
; Notes .........;
; Example........; Yes
;=====================================================================================================================

Func _Notify_Show($vIcon, $sTitle, $sMessage, $iDelay = 0, $iClick = 1)

	If $aNotify_Data[0][0] = $aNotify_Data[0][1] Then
		Return SetError(1, 0, -1)
	EndIf

	Local $aLabel_Pos, $iLabel_Width, $iLabel_Height = 20

	; Set default auto-sizing Notify dimensions
	Local $iNotify_Width_max = 300
	Local $iNotify_Width_min = 150
	Local $iNotify_Height = 40

	; Check for icon
	Local $iIcon_Style = 0
	Local $iIcon_Reduction = 36
	Local $sDLL = "user32.dll"
	Local $sImg = ""
	If StringIsDigit($vIcon) Then
		Switch $vIcon
			Case 0
				$iIcon_Reduction = 0
			Case 8
				$sDLL = "imageres.dll"
				$iIcon_Style = 78
			Case 16 ; Stop
				$iIcon_Style = -4
			Case 32 ; Query
				$iIcon_Style = -3
			Case 48 ; Exclam
				$iIcon_Style = -2
			Case 64 ; Info
				$iIcon_Style = -5
			Case Else
				Return SetError(1, 0, -1)
		EndSwitch
	Else
		Switch StringLower(StringRight($vIcon, 3))
			Case "exe", "ico"
				$sDLL = $vIcon
				$iIcon_Style = 0
			Case "bmp", "jpg", "gif"
				$sImg = $vIcon
		EndSwitch
	EndIf

	; Determine max message width
	Local $iMax_Label_Width = $iNotify_Width_max - $iIcon_Reduction - 8

	; Get text size
	If $sTitle Then
		; Measure title
		$aLabel_Pos = _StringSize($sTitle, 9, Default, Default, $aNotify_Settings[1][3])
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 0, -1)
		Else
			; Set width required
			$iLabel_Width = $aLabel_Pos[2]
		EndIf
		; Measure message
		$aLabel_Pos = _StringSize($sMessage, 9, Default, Default, $aNotify_Settings[1][3])
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 1, -1)
		Else
			; Adjust width required if needed
			If $aLabel_Pos[2] > $iLabel_Width Then
				$iLabel_Width = $aLabel_Pos[2]
			EndIf
		EndIf
	Else
		; Measure message
		$aLabel_Pos = _StringSize($sMessage, 9, Default, Default, $aNotify_Settings[1][3], $iMax_Label_Width)
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; If wrapped check still fits vertically
		If $aLabel_Pos[3] > 40 Then
			Return SetError(4, 1, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 1, -1)
		Else
			; Set Notification size and label position
			If $aLabel_Pos[2] > $iLabel_Width Then
				$iLabel_Width = $aLabel_Pos[2]
			EndIf
			$sMessage = $aLabel_Pos[0]
			; Adjust vertical position to centre lines
			Local $iLabel_Y = Int((40 - $aLabel_Pos[3]) / 2)
		EndIf
	EndIf

	; Set Notify size
	Local $iNotify_Width = $iLabel_Width + 8 + $iIcon_Reduction

	; Increase if below min size
	If $iNotify_Width < $iNotify_Width_min + $iIcon_Reduction Then
		$iNotify_Width = $iNotify_Width_min + $iIcon_Reduction
		$iLabel_Width = $iNotify_Width_min - 8
	EndIf

	; Set Notify coords
	Local $iNotify_X = $aNotify_Data[0][2] - $iNotify_Width
	Local $iNotify_Y = $aNotify_Data[0][3] - (50 * ($aNotify_Data[0][0] + 1))

	; Create Notify slice with $WS_POPUPWINDOW style and $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST and $WS_EX_STATICEDGE extended style
	Local $hNotify_Handle = GUICreate("", $iNotify_Width, $iNotify_Height, $iNotify_X, $iNotify_Y, 0x80880000, BitOR(0x00020000, 0x00000080, 0x00000008))
	If @error Then
		Return SetError(5, 0, -1)
	EndIf
	GUISetBkColor($aNotify_Settings[1][2])

	; Create icon
	If $iIcon_Reduction Then
		If $sImg Then
			GUICtrlCreatePic($sImg, 4, 4, 32, 32)
		Else
			GUICtrlCreateIcon($sDLL, $iIcon_Style, 4, 4)
		EndIf
	EndIf

	; Create labels
	If $sTitle Then
		; Title
		GUICtrlCreateLabel($sTitle, 4 + $iIcon_Reduction, 0, $iLabel_Width, $iLabel_Height)
		GUICtrlSetFont(-1, 9, 800, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
		; Message
		GUICtrlCreateLabel($sMessage, 4 + $iIcon_Reduction, 20, $iLabel_Width, $iLabel_Height)
		GUICtrlSetFont(-1, 9, 400, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
	Else
		; Message
		GUICtrlCreateLabel($sMessage, 4 + $iIcon_Reduction, $iLabel_Y, $iLabel_Width, 40 - $iLabel_Y)
		GUICtrlSetFont(-1, 9, 400, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
	EndIf

	; Slide Notify Slice into view from behind systray and activate
	DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $hNotify_Handle, "int", 1000, "long", 0x00040002) ; $AW_SLIDE_IN_RIGHT

	; Activate Notify without stealing focus
	GUISetState(@SW_SHOWNOACTIVATE, $hNotify_Handle)

	; Store Notify data
	$aNotify_Data[0][0] += 1
	ReDim $aNotify_Data[$aNotify_Data[0][0] + 1][5]
	$aNotify_Data[$aNotify_Data[0][0]][0] = $hNotify_Handle
	$aNotify_Data[$aNotify_Data[0][0]][1] = $iDelay * 1000
	$aNotify_Data[$aNotify_Data[0][0]][2] = TimerInit()
	$aNotify_Data[$aNotify_Data[0][0]][3] = $iClick
	$aNotify_Data[$aNotify_Data[0][0]][4] = $iNotify_X

	; Start Adlib function for Notify retraction
	If $aNotify_Data[0][0] = 1 Then
		AdlibRegister("_Notify_Timer", 1000)
	EndIf

EndFunc   ;==>_Notify_Show

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_RegMsg
; Description ...: Registers WM_MOUSEACTIVATE message needed for the UDF
; Syntax.........: _Notify_RegMsg()
; Parameters ....: None
; Requirement(s).: v3.3.1.5 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If another WM_MOUSEACTIVATE handler already registered, then call the _Notify_WM_MOUSEACTIVATE handler
;                  function from within that handler
;                  If messages are not to retract when clicked the WM_MOUSEACTIVATE message does not need to be registered
; Example........: Yes
;=====================================================================================================================
Func _Notify_RegMsg()

	GUIRegisterMsg(0x0021, "_Notify_WM_MOUSEACTIVATE") ; $WM_MOUSEACTIVATE
	$aNotify_Data[0][4] = 1

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Locate
; Description ...: Find Systray and determine message start position and maximum number
; Syntax ........: _Notify_Locate()
; Parameters ....: None
; Author ........: Melba23, based on some original code by GioVit
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Locate()

	Local $tWorkArea

	; Determine which struct syntax to use to use
	If @AutoItVersion < "3.3.8.0" Then
		$tWorkArea = DllStructCreate("long Left;long Top;long Right;long Bottom")
	Else
		$tWorkArea = DllStructCreate("struct;long Left;long Top;long Right;long Bottom;endstruct")
	EndIf

	; Check if Taskbar is visible
	Local $aRet = DllCall("shell32.dll", "uint", "SHAppBarMessage", "dword", 0x00000004, "ptr*", 0) ; $ABM_GETSTATE
	If Not BitAND($aRet[0], 0x01) Then

		; Determine available work area ; $SPI_GETWORKAREA = 48
		DllCall("user32.dll", "bool", "SystemParametersInfoW", "uint", 48, "uint", 0, "ptr", DllStructGetPtr($tWorkArea), "uint", 0)
		If @error Then Return SetError(2, 0, -1)
		Local $aWorkArea[4] = [DllStructGetData($tWorkArea, "Left"), DllStructGetData($tWorkArea, "Top"), _
			DllStructGetData($tWorkArea, "Right"), DllStructGetData($tWorkArea, "Bottom")]

		; Adjust data array if necessary
		$aNotify_Data[0][1] = Int(($aWorkArea[3] - $aWorkArea[1] - 60) / 50)
		If $aWorkArea[2] < @DesktopWidth Then
			$aNotify_Data[0][2] = $aWorkArea[2] - 10
		EndIf
		If $aWorkArea[3] < @DesktopHeight Then
			$aNotify_Data[0][3] = $aWorkArea[3] - 10
		EndIf

	EndIf

EndFunc   ;==>_Notify_Locate

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Timer
; Description ...: Checks whether a message has timed out
; Syntax ........: _Notify_Timer()
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Timer()

	If $aNotify_Settings[1][5] Then
		Return
	EndIf

	If $aNotify_Settings[0][5] Then
		Return
	EndIf

	; Set Prevent simultaneous click
	$aNotify_Settings[0][5] = True
	
	; Pause Adlib as retraction and movement could overrun delay time
	AdlibUnRegister("_Notify_Timer")

	Local $fMoved = False

	; Run through notifications
	For $i = $aNotify_Data[0][0] To 1 Step -1
		; Check timer if needed
		If $aNotify_Data[$i][1] And TimerDiff($aNotify_Data[$i][2]) > $aNotify_Data[$i][1] Then
			_Notify_Delete($i)
			$fMoved = True
			ExitLoop
		EndIf
	Next

	; Adjust positions of Notifications
	If $fMoved Then
		_Notify_Reset($i)
	EndIf

	; Restart Adlib if needed
	If $aNotify_Data[0][0] Then
		AdlibRegister("_Notify_Timer", 1000)
	EndIf
	; Re-enable clicks
	$aNotify_Settings[0][5] = False
	
EndFunc   ;==>_Notify_Timer

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_WM_MOUSEACTIVATE
; Description ...: Message handler to check if message clicked
; Syntax ........: _Notify_WM_MOUSEACTIVATE($hWnd, $Msg, $wParam, $lParam)
; Parameters ....: Standard message handler parameters
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_WM_MOUSEACTIVATE($hWnd, $iMsg, $wParam, $lParam)

	#forceref $iMsg, $wParam, $lParam

	; Check timer is not checking
	If $aNotify_Settings[0][5] Then
		Return
	EndIf
	; Check handler not already retracting
	If $aNotify_Settings[1][5] Then
		Return
	EndIf
	; Set flag to show handler retracting
	$aNotify_Settings[1][5] = True
	
	; Declare flag
	Local $fMoved = False

	For $i = $aNotify_Data[0][0] To 1 Step -1
		If $aNotify_Data[$i][3] And $hWnd = $aNotify_Data[$i][0] Then
			_Notify_Delete($i)
			$fMoved = True
			ExitLoop
		EndIf
	Next

	; Adjust positions of Notifications
	If $fMoved Then
		_Notify_Reset($i)
	EndIf

	; Clear Running flag
	$aNotify_Settings[1][5] = False
	
	Return 'GUI_RUNDEFMSG'

EndFunc   ;==>_Notify_WM_MOUSEACTIVATE

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Delete
; Description ...: Retract a message when timed out or clicked
; Syntax ........: _Notify_Delete($i)
; Parameters ....: $i - Index of message to be retracted
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Delete($i)

	; Retract and delete Notify
	DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $aNotify_Data[$i][0], "int", 500, "long", 0x00050001) ; $AW_SLIDE_OUT_RIGHT
	GUIDelete($aNotify_Data[$i][0])
	; Adjust array
	For $j = $i + 1 To $aNotify_Data[0][0]
		For $k = 0 To 4
			$aNotify_Data[$j - 1][$k] = $aNotify_Data[$j][$k]
		Next
	Next
	ReDim $aNotify_Data[$aNotify_Data[0][0]][5]
	$aNotify_Data[0][0] -= 1

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Reset
; Description ...: Reposition remaining messages on screen
; Syntax ........: _Notify_Reset($i)
; Parameters ....: $i - Index of message just retracted
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Reset($iIndex)

	If $aNotify_Settings[0][4] Then
		; Set step size depending on number of notifications to move
		Local $iStep = 1 + Int(($aNotify_Data[0][0] - $iIndex) / 3)
		; Slide notifications into new positions
		For $j = 1 To 50 Step $iStep
			For $i = $iIndex To $aNotify_Data[0][0]
				WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] - (50 * ($i + 1)) + $j)
			Next
		Next
	Else
		; Move notifications into new positions instantly
		For $i = 1 To $aNotify_Data[0][0]
			WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] - (50 * $i))
		Next
	EndIf

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_GetDefFont
; Description ...: Determine system default MsgBox font
; Syntax ........: _Notify_GetDefFont()
; Parameters ....: None
; Author ........: Melba23
; Modified.......:
; Remarks .......:
Func _Notify_GetDefFont()

	; Get default system font data
	Local $tNONCLIENTMETRICS = DllStructCreate("uint;int;int;int;int;int;byte[60];int;int;byte[60];int;int;byte[60];byte[60];byte[60]")
	DllStructSetData($tNONCLIENTMETRICS, 1, DllStructGetSize($tNONCLIENTMETRICS))
	DllCall("user32.dll", "int", "SystemParametersInfo", "int", 41, "int", DllStructGetSize($tNONCLIENTMETRICS), "ptr", DllStructGetPtr($tNONCLIENTMETRICS), "int", 0)
	; Read font data for MsgBox font
	Local $tLOGFONT = DllStructCreate("long;long;long;long;long;byte;byte;byte;byte;byte;byte;byte;byte;char[32]", DllStructGetPtr($tNONCLIENTMETRICS, 15))
	; Font name
	Return DllStructGetData($tLOGFONT, 14)

EndFunc   ;==>_Notify_GetDefFont

czardas,

I was just wondering if it is worth while adding parameters

You mean:

"I was just wondering if it is worth while you adding parameters"

I will take a look but no promises as I am very happy with them going up on the right! :)

M23

Share this post


Link to post
Share on other sites

Posted

:)

I'll give it a go later.

Share this post


Link to post
Share on other sites

Posted (edited)

czardas,

Try this version - you can select the location/direction of the notifications by calling the new function _Notify_Locate:

; Syntax ........: _Notify_Locate($iLocation)
; Parameters ....: $iLocation - Start point and direction for Notifications
;							   0 = Bottom right upwards (default)
;							   1 = Top right downwards
;							   2 = Top left downwards
;							   3 = Bottom left upwards

Here is an example to show it working - look for the <<<<<<<<<<<<<<<<<<<<< line

#include "Notify.au3"

; Press ESC to exit script
HotKeySet("{ESC}", "On_Exit")

Opt("TrayAutoPause", 0)

; Register message for click event
_Notify_RegMsg()

; Set notification location
_Notify_Locate(1) ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; Set notifications

_Notify_Set(Default)
_Notify_Show("M:ProgramAu3 ScriptsImagesToastX.bmp", "Not Clickable", "Retracts after 20 secs", 20, 0)
_Notify_Set(0, 0xFF0000, 0xFFFF00, "Courier New");, True)
_Notify_Show(0, "Clickable", "Coloured - stays 40 secs if not clicked", 40)
_Notify_Set(Default)
_Notify_Show(0, "Clickable", "Reset to default colours")
_Notify_Set(2, 0x0000FF, 0xCCCCFF, "Comic MS")
_Notify_Show(48, "Not Clickable", "With an icon - stays 30 secs", 30, 0)
_Notify_Set(0, Default, 0xCCFF00, "Arial");, True)
_Notify_Show(0, "", "No title so the message can span both lines without problem if it is long enough to need it")

While 1
	Sleep(10)
WEnd

Func On_Exit()
	Exit
EndFunc

And here is the new UDF:

#include-once

; #INDEX# ============================================================================================================
; Title .........: Notify
; AutoIt Version : 3.3.2.0+ - uses AdlibRegister/Unregister
; Language ......: English
; Description ...: Show and hides pop-out messages from the right side of the screen in user defined colours and fonts
; Author(s) .....: Melba23
; ====================================================================================================================

;#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; #INCLUDES# =========================================================================================================
#include <stringsize.au3>

; #GLOBAL VARIABLES# =================================================================================================
; Create array to hold data for Notifications
; [0][0] = Count			[n][0] = Handle
; [0][1] = Max avail		[n][1] = Timer duration
; [0][2] = X-coord		  [n][2] = Timer stamp
; [0][3] = Low Y-coord		[n][3] = Clickable
; [0][4] = Location			[n][4] = X-Coord
Global $aNotify_Data[1][5] = [[0, Int((@DesktopHeight - 60) / 50), @DesktopWidth - 10, @DesktopHeight - 10, 0]]
; Adjust values according to taskbar position and desired location
_Notify_Locate(0)

; Create array to hold default and current Notification values = [Style ($SS_CENTER), Col, BkCol, Font, Slide, Interference]
; [0][5] = Timer running, [1][5] = Click running
Global $aNotify_Settings[2][6] = [[1, 0, 0, _Notify_GetDefFont(), False, False], [0, 0, 0, 0, 0, False]]
Global $aNotify_Ret = DllCall("User32.dll", "int", "GetSysColor", "int", 8) ; $COLOR_WINDOWTEXT = 8
$aNotify_Settings[0][1] = $aNotify_Ret[0]
$aNotify_Ret = DllCall("User32.dll", "int", "GetSysColor", "int", 5) ; $COLOR_WINDOW = 5
$aNotify_Settings[0][2] = $aNotify_Ret[0]
; Use the defaults as current settings
For $i = 0 To 3
	$aNotify_Settings[1][$i] = $aNotify_Settings[0][$i]
Next

; #CURRENT# ==========================================================================================================
; _Notify_Locate: Determine notification start position, direction of movement and maximum number
; _Notify_Set:	Sets text justification and optionally colours and font for notifications
; _Notify_Show:   Shows a notification
; _Notify_RegMsg: Registers the WM_MOUSEACTIVATE message to enable retraction of the notification on clicking
; ====================================================================================================================

; #INTERNAL_USE_ONLY#=================================================================================================
; _Notify_Timer:			Checks whether a notification has timed out
; _Notify_WM_MOUSEACTIVATE: Message handler to check if notification clicked
; _Notify_Delete:		   Retract a notification when timed out or clicked
; _Notify_Reset;			Reposition remaining notifications on screen
; _Notify_GetDefFont:	   Determine system default MsgBox font
; ====================================================================================================================

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Locate
; Description ...: Determine notification start position, direction of movement and maximum number
; Syntax ........: _Notify_Locate($iLocation)
; Parameters ....: $iLocation - Start point and direction for Notifications
;							   0 = Bottom right upwards (default)
;							   1 = Top right downwards
;							   2 = Top left downwards
;							   3 = Bottom left upwards
; Requirement(s).: v3.3.2.0 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success - Returns 1
;				  Failure - Returns 0 and sets @error as follows
;							1 = Notificatiosn displayed
;							2 = Invalid parameter
; Author ........: Melba23
; Remarks .......: This function will only set or reset the location if no notificatiosn are displayed
; Example........: Yes
; ===============================================================================================================================
Func _Notify_Locate($iLocation)

	; Can only reset notification location when no notifications are displayed
	If $aNotify_Data[0][0] Then
		Return SetError(1, 0, 0)
	EndIf

	; Check valid parameter
	Switch $iLocation
		Case 0 To 3
			$aNotify_Data[0][4] = $iLocation
		Case Else
			Return SetError(2, 0, 0)
	EndSwitch

	Local $tWorkArea
	; Determine which struct syntax to use to use
	If @AutoItVersion < "3.3.8.0" Then
		$tWorkArea = DllStructCreate("long Left;long Top;long Right;long Bottom")
	Else
		$tWorkArea = DllStructCreate("struct;long Left;long Top;long Right;long Bottom;endstruct")
	EndIf
	; Check if Taskbar is hidden
	Local $aRet = DllCall("shell32.dll", "uint", "SHAppBarMessage", "dword", 0x00000004, "ptr*", 0) ; $ABM_GETSTATE
	If BitAND($aRet[0], 0x01) Then

		; Set max number available
		$aNotify_Data[0][1] = Int((@DesktopHeight - 60) / 50)

		; Adjust data array depending on required location
		Switch $iLocation
			Case 0 ; From bottom right
				$aNotify_Data[0][3] = @DesktopHeight - 10 ; bottom Y
				$aNotify_Data[0][2] = @DesktopWidth - 10  ; right X
			Case 1 ; From top right
				$aNotify_Data[0][3] = 10				  ; top Y
				$aNotify_Data[0][2] = @DesktopWidth - 10  ; right X
			Case 2 ; From top left
				$aNotify_Data[0][3] = 10				  ; top Y
				$aNotify_Data[0][2] = 10				  ; left X
			Case 3 ; From bottom left
				$aNotify_Data[0][3] = @DesktopHeight - 10 ; bottom Y
				$aNotify_Data[0][2] = 10				  ; left X
		EndSwitch

	Else

		; Determine available work area ; $SPI_GETWORKAREA = 48
		DllCall("user32.dll", "bool", "SystemParametersInfoW", "uint", 48, "uint", 0, "ptr", DllStructGetPtr($tWorkArea), "uint", 0)
		If @error Then Return SetError(2, 0, -1)
		Local $aWorkArea[4] = [DllStructGetData($tWorkArea, "Left"), DllStructGetData($tWorkArea, "Top"), _
			DllStructGetData($tWorkArea, "Right"), DllStructGetData($tWorkArea, "Bottom")]

		; Set max number available
		$aNotify_Data[0][1] = Int(($aWorkArea[3] - $aWorkArea[1] - 60) / 50)

		; Adjust data array depending on required location
		Switch $iLocation
			Case 0 ; From bottom right
				$aNotify_Data[0][3] = $aWorkArea[3] - 10 ; bottom Y
				$aNotify_Data[0][2] = $aWorkArea[2] - 10 ; right X
			Case 1 ; From top right
				$aNotify_Data[0][3] = $aWorkArea[1] + 10 ; top Y
				$aNotify_Data[0][2] = $aWorkArea[2] - 10 ; right X
			Case 2 ; From top left
				$aNotify_Data[0][3] = $aWorkArea[1] + 10 ; top Y
				$aNotify_Data[0][2] = $aWorkArea[0] + 10 ; left X
			Case 3 ; From bottom left
				$aNotify_Data[0][3] = $aWorkArea[3] - 10 ; bottom Y
				$aNotify_Data[0][2] = $aWorkArea[0] + 10 ; left X
		EndSwitch

	EndIf

	Return 1

EndFunc   ;==>_Notify_Locate

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Set
; Description ...: Sets text justification and optionally colours, font and movement for notifications
; Syntax.........: _Notify_Set($vJust, [$iCol, [$iBkCol, [$iFont_Name, [$fSlide]]])
; Parameters ....: $vJust	 - 0 = Left justified, 1 = Centred (Default), 2 = Right justified
;								Can use $SS_LEFT, $SS_CENTER, $SS_RIGHT
;					   >>>>>	Setting this parameter to' Default' will reset ALL parameters to default values	 <<<<<
;					   >>>>>	All optional parameters default to system MsgBox default values					 <<<<<
;				  $iCol   - [Optional] The colour for the notification text
;				  $iBkCol - [Optional] The colour for the notification background
;								Omitting a colour parameter or setting it to -1 leaves it unchanged
;								Setting a colour parameter to Default resets the system colour
;				  $sFont_Name - [Optional] The font to use for the notification
;					   >>>>>	Omitting this parameter leaves it unchanged										 <<<<<
;					   >>>>>	Setting this parameter to Default resets the system message box font				<<<<<
;				  $fSlide - [Optional] Movement of notifications into new position when one retracts
;								False = Instant (default)
;								True  = Slide
;					   >>>>>	Using this option increases the chances of a system crash - user beware!!		   <<<<<
; Requirement(s).: v3.3.2.0 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success - Returns 1
;				  Failure - Returns 0 and sets @error to 1 with @extended set to parameter index number
; Author ........: Melba23
; Example........; Yes
;=====================================================================================================================
Func _Notify_Set($vJust, $iCol = -1, $iBkCol = -1, $sFont_Name = "", $fSlide = False)

	; Set parameters
	Switch $vJust
		Case Default
			For $i = 0 To 3
				$aNotify_Settings[1][$i] = $aNotify_Settings[0][$i]
			Next
			Return
		Case 0, 1, 2
			$aNotify_Settings[1][0] = $vJust
		Case Else
			Return SetError(1, 1, 0)
	EndSwitch

	Switch $iCol
		Case Default
			$aNotify_Settings[1][1] = $aNotify_Settings[0][1]
		Case 0 To 0xFFFFFF
			$aNotify_Settings[1][1] = $iCol
		Case -1
			; Do nothing
		Case Else
			Return SetError(1, 2, 0)
	EndSwitch

	Switch $iBkCol
		Case Default
			$aNotify_Settings[1][2] = $aNotify_Settings[0][2]
		Case 0 To 0xFFFFFF
			$aNotify_Settings[1][2] = $iBkCol
		Case -1
			; Do nothing
		Case Else
			Return SetError(1, 3, 0)
	EndSwitch

	Switch $sFont_Name
		Case Default
			$aNotify_Settings[1][3] = $aNotify_Settings[0][3]
		Case ""
			; Do nothing
		Case Else
			If IsString($sFont_Name) Then
				$aNotify_Settings[1][3] = $sFont_Name
			Else
				Return SetError(1, 4, 0)
			EndIf
	EndSwitch

	If $fSlide = True Then
		$aNotify_Settings[0][4] = True
	Else
		$aNotify_Settings[0][4] = False
	EndIf

	Return 1

EndFunc   ;==>_Notify_Set

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_Show
; Description ...: Shows a notification
; Syntax.........: _Notify_Show($vIcon, $sTitle, $sMessage, [$iDelay [, $iClick]])
; Parameters ....: $vIcon	- 0 - No icon, 8 - UAC, 16 - Stop, 32 - Query, 48 - Exclamation, 64 - Information
;							  The $MB_ICON constant can also be used for the last 4 above
;							  If set to the name of an exe, the main icon of that exe will be displayed
;							  If set to the name of an image file, that image will be displayed
;							  Any other value returns -1, error 1
;				  $sTitle   - Text to display as title in bold
;				  $sMessage - Text to display as message
;							  If $sTitle = "" then $sText can take 2 lines
;				  $iDelay   - The delay in seconds before the notification retracts (Default = 0 = Remains indefinitely)
;				  $iClick   - If notification will retact when clicked (Default = 1 = Clickable)
; Requirement(s).: v3.3.1.5 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: Success: Returns 1
;				  Failure:	Returns -1 and sets @error as follows:
;						   1 = Maximum number of notification that can be displayed
;						   2 = Icon parameter invalid
;						   3 = StringSize error
;						   4 = Title/text will not fit in widest message (@extended = 0/1 = Title/Text)
;						   5 = Notification GUI creation failed
; Author ........: Melba23
; Notes .........;
; Example........; Yes
;=====================================================================================================================

Func _Notify_Show($vIcon, $sTitle, $sMessage, $iDelay = 0, $iClick = 1)

	If $aNotify_Data[0][0] = $aNotify_Data[0][1] Then
		Return SetError(1, 0, -1)
	EndIf

	Local $aLabel_Pos, $iLabel_Width, $iLabel_Height = 20

	; Set default auto-sizing Notify dimensions
	Local $iNotify_Width_max = 300
	Local $iNotify_Width_min = 150
	Local $iNotify_Height = 40

	; Check for icon
	Local $iIcon_Style = 0
	Local $iIcon_Reduction = 36
	Local $sDLL = "user32.dll"
	Local $sImg = ""
	If StringIsDigit($vIcon) Then
		Switch $vIcon
			Case 0
				$iIcon_Reduction = 0
			Case 8
				$sDLL = "imageres.dll"
				$iIcon_Style = 78
			Case 16 ; Stop
				$iIcon_Style = -4
			Case 32 ; Query
				$iIcon_Style = -3
			Case 48 ; Exclam
				$iIcon_Style = -2
			Case 64 ; Info
				$iIcon_Style = -5
			Case Else
				Return SetError(1, 0, -1)
		EndSwitch
	Else
		Switch StringLower(StringRight($vIcon, 3))
			Case "exe", "ico"
				$sDLL = $vIcon
				$iIcon_Style = 0
			Case "bmp", "jpg", "gif"
				$sImg = $vIcon
		EndSwitch
	EndIf

	; Determine max message width
	Local $iMax_Label_Width = $iNotify_Width_max - $iIcon_Reduction - 8

	; Get text size
	If $sTitle Then
		; Measure title
		$aLabel_Pos = _StringSize($sTitle, 9, Default, Default, $aNotify_Settings[1][3])
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 0, -1)
		Else
			; Set width required
			$iLabel_Width = $aLabel_Pos[2]
		EndIf
		; Measure message
		$aLabel_Pos = _StringSize($sMessage, 9, Default, Default, $aNotify_Settings[1][3])
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 1, -1)
		Else
			; Adjust width required if needed
			If $aLabel_Pos[2] > $iLabel_Width Then
				$iLabel_Width = $aLabel_Pos[2]
			EndIf
		EndIf
	Else
		; Measure message
		$aLabel_Pos = _StringSize($sMessage, 9, Default, Default, $aNotify_Settings[1][3], $iMax_Label_Width)
		If @error Then
			Return SetError(3, 0, -1)
		EndIf
		; If wrapped check still fits vertically
		If $aLabel_Pos[3] > 40 Then
			Return SetError(4, 1, -1)
		EndIf
		; Check fits horizontally
		If $aLabel_Pos[2] > $iMax_Label_Width Then
			Return SetError(4, 1, -1)
		Else
			; Set Notification size and label position
			If $aLabel_Pos[2] > $iLabel_Width Then
				$iLabel_Width = $aLabel_Pos[2]
			EndIf
			$sMessage = $aLabel_Pos[0]
			; Adjust vertical position to centre lines
			Local $iLabel_Y = Int((40 - $aLabel_Pos[3]) / 2)
		EndIf
	EndIf

	; Set Notify size
	Local $iNotify_Width = $iLabel_Width + 8 + $iIcon_Reduction

	; Increase if below min size
	If $iNotify_Width < $iNotify_Width_min + $iIcon_Reduction Then
		$iNotify_Width = $iNotify_Width_min + $iIcon_Reduction
		$iLabel_Width = $iNotify_Width_min - 8
	EndIf

	; Set Notify coords depending on location
	Local $iNotify_X, $iNotify_Y
	Switch $aNotify_Data[0][4]
		Case 0 ; From bottom right
			$iNotify_X = $aNotify_Data[0][2] - $iNotify_Width
			$iNotify_Y = $aNotify_Data[0][3] - (50 * ($aNotify_Data[0][0] + 1))
		Case 1 ; From top right
			$iNotify_X = $aNotify_Data[0][2] - $iNotify_Width
			$iNotify_Y = $aNotify_Data[0][3] + (50 * ($aNotify_Data[0][0]))
		Case 2 ; From top left
			$iNotify_X = $aNotify_Data[0][2]
			$iNotify_Y = $aNotify_Data[0][3] + (50 * ($aNotify_Data[0][0]))
		Case 3 ; From bottom left
			$iNotify_X = $aNotify_Data[0][2]
			$iNotify_Y = $aNotify_Data[0][3] - (50 * ($aNotify_Data[0][0] + 1))
	EndSwitch

	; Create Notify slice with $WS_POPUPWINDOW style and $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST and $WS_EX_STATICEDGE extended style
	Local $hNotify_Handle = GUICreate("", $iNotify_Width, $iNotify_Height, $iNotify_X, $iNotify_Y, 0x80880000, BitOR(0x00020000, 0x00000080, 0x00000008))
	If @error Then
		Return SetError(5, 0, -1)
	EndIf
	GUISetBkColor($aNotify_Settings[1][2])

	; Create icon
	If $iIcon_Reduction Then
		If $sImg Then
			GUICtrlCreatePic($sImg, 4, 4, 32, 32)
		Else
			GUICtrlCreateIcon($sDLL, $iIcon_Style, 4, 4)
		EndIf
	EndIf

	; Create labels
	If $sTitle Then
		; Title
		GUICtrlCreateLabel($sTitle, 4 + $iIcon_Reduction, 0, $iLabel_Width, $iLabel_Height)
		GUICtrlSetFont(-1, 9, 800, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
		; Message
		GUICtrlCreateLabel($sMessage, 4 + $iIcon_Reduction, 20, $iLabel_Width, $iLabel_Height)
		GUICtrlSetFont(-1, 9, 400, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
	Else
		; Message
		GUICtrlCreateLabel($sMessage, 4 + $iIcon_Reduction, $iLabel_Y, $iLabel_Width, 40 - $iLabel_Y)
		GUICtrlSetFont(-1, 9, 400, 0, $aNotify_Settings[1][3])
		GUICtrlSetBkColor(-1, $aNotify_Settings[1][2])
		GUICtrlSetColor(-1, $aNotify_Settings[1][1])
		GUICtrlSetStyle(-1, $aNotify_Settings[1][0])
	EndIf

	; Slide Notify Slice into view and activate
	Switch $aNotify_Data[0][4]
		Case 0, 1
			DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $hNotify_Handle, "int", 1000, "long", 0x00040002) ; $AW_SLIDE_IN_RIGHT
		Case 2, 3
			DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $hNotify_Handle, "int", 1000, "long", 0x00040001) ; $AW_SLIDE_IN_LEFT
	EndSwitch

	; Activate Notify without stealing focus
	GUISetState(@SW_SHOWNOACTIVATE, $hNotify_Handle)

	; Store Notify data
	$aNotify_Data[0][0] += 1
	ReDim $aNotify_Data[$aNotify_Data[0][0] + 1][5]
	$aNotify_Data[$aNotify_Data[0][0]][0] = $hNotify_Handle
	$aNotify_Data[$aNotify_Data[0][0]][1] = $iDelay * 1000
	$aNotify_Data[$aNotify_Data[0][0]][2] = TimerInit()
	$aNotify_Data[$aNotify_Data[0][0]][3] = $iClick
	$aNotify_Data[$aNotify_Data[0][0]][4] = $iNotify_X

	; Start Adlib function for Notify retraction
	If $aNotify_Data[0][0] = 1 Then
		AdlibRegister("_Notify_Timer", 1000)
	EndIf

EndFunc   ;==>_Notify_Show

; #FUNCTION# =========================================================================================================
; Name...........: _Notify_RegMsg
; Description ...: Registers WM_MOUSEACTIVATE message needed for the UDF
; Syntax.........: _Notify_RegMsg()
; Parameters ....: None
; Requirement(s).: v3.3.1.5 or higher - AdlibRegister/Unregister used in _Notify_Show
; Return values .: None
; Author ........: Melba23
; Modified ......:
; Remarks .......: If another WM_MOUSEACTIVATE handler already registered, call the _Notify_WM_MOUSEACTIVATE handler
;				  function from within that handler
;				  If notifications not to retract when clicked the WM_MOUSEACTIVATE message need not be registered
; Example........: Yes
;=====================================================================================================================
Func _Notify_RegMsg()

	GUIRegisterMsg(0x0021, "_Notify_WM_MOUSEACTIVATE") ; $WM_MOUSEACTIVATE
	$aNotify_Data[0][4] = 1

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Timer
; Description ...: Checks whether a notification has timed out
; Syntax ........: _Notify_Timer()
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Timer()

	If $aNotify_Settings[1][5] Then
		Return
	EndIf

	If $aNotify_Settings[0][5] Then
		Return
	EndIf

	; Set Prevent simultaneous click
	$aNotify_Settings[0][5] = True

	; Pause Adlib as retraction and movement could overrun delay time
	AdlibUnRegister("_Notify_Timer")

	Local $fMoved = False

	; Run through notifications
	For $i = $aNotify_Data[0][0] To 1 Step -1
		; Check timer if needed
		If $aNotify_Data[$i][1] And TimerDiff($aNotify_Data[$i][2]) > $aNotify_Data[$i][1] Then
			_Notify_Delete($i)
			$fMoved = True
			ExitLoop
		EndIf
	Next

	; Adjust positions of Notifications
	If $fMoved Then
		_Notify_Reset($i)
	EndIf

	; Restart Adlib if needed
	If $aNotify_Data[0][0] Then
		AdlibRegister("_Notify_Timer", 1000)
	EndIf
	; Re-enable clicks
	$aNotify_Settings[0][5] = False

EndFunc   ;==>_Notify_Timer

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_WM_MOUSEACTIVATE
; Description ...: Message handler to check if notification clicked
; Syntax ........: _Notify_WM_MOUSEACTIVATE($hWnd, $Msg, $wParam, $lParam)
; Parameters ....: Standard message handler parameters
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_WM_MOUSEACTIVATE($hWnd, $iMsg, $wParam, $lParam)

	#forceref $iMsg, $wParam, $lParam

	; Check timer is not checking
	If $aNotify_Settings[0][5] Then
		Return
	EndIf
	; Check handler not already retracting
	If $aNotify_Settings[1][5] Then
		Return
	EndIf
	; Set flag to show handler retracting
	$aNotify_Settings[1][5] = True

	; Declare flag
	Local $fMoved = False

	For $i = $aNotify_Data[0][0] To 1 Step -1
		If $aNotify_Data[$i][3] And $hWnd = $aNotify_Data[$i][0] Then
			_Notify_Delete($i)
			$fMoved = True
			ExitLoop
		EndIf
	Next

	; Adjust positions of Notifications
	If $fMoved Then
		_Notify_Reset($i)
	EndIf

	; Clear Running flag
	$aNotify_Settings[1][5] = False

	Return 'GUI_RUNDEFMSG'

EndFunc   ;==>_Notify_WM_MOUSEACTIVATE

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Delete
; Description ...: Retract a notification when timed out or clicked
; Syntax ........: _Notify_Delete($i)
; Parameters ....: $i - Index of notification to be retracted
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Delete($i)

	; Retract and delete notification
	Switch $aNotify_Data[0][4]
		Case 0, 1
			DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $aNotify_Data[$i][0], "int", 500, "long", 0x00050001) ; $AW_SLIDE_OUT_RIGHT
		Case 2, 3
			DllCall("user32.dll", "int", "AnimateWindow", "hwnd", $aNotify_Data[$i][0], "int", 500, "long", 0x00050002) ; $AW_SLIDE_OUT_LEFT
	EndSwitch
	GUIDelete($aNotify_Data[$i][0])
	; Adjust array
	For $j = $i + 1 To $aNotify_Data[0][0]
		For $k = 0 To 4
			$aNotify_Data[$j - 1][$k] = $aNotify_Data[$j][$k]
		Next
	Next
	ReDim $aNotify_Data[$aNotify_Data[0][0]][5]
	$aNotify_Data[0][0] -= 1

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_Reset
; Description ...: Reposition remaining notifications on screen
; Syntax ........: _Notify_Reset($i)
; Parameters ....: $i - Index of notification just retracted
; Author ........: Melba23
; Modified.......:
; Remarks .......:
; ===============================================================================================================================
Func _Notify_Reset($iIndex)

	If $aNotify_Settings[0][4] Then
		; Set step size depending on number of notifications to move
		Local $iStep = 1 + Int(($aNotify_Data[0][0] - $iIndex) / 3)
		; Slide notifications into new positions depending on location
		Switch $aNotify_Data[0][4]
			Case 0, 3
				For $j = 1 To 50 Step $iStep
					For $i = $iIndex To $aNotify_Data[0][0]
						WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] - (50 * ($i + 1)) + $j)
					Next
				Next
			Case 1, 2
				For $j = 1 To 50 Step $iStep
					For $i = $iIndex To $aNotify_Data[0][0]
						WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] + (50 * $i) - $j)
					Next
				Next
		EndSwitch
	Else
		; Move notifications into new positions instantly depending on location
		Switch $aNotify_Data[0][4]
			Case 0, 3
				For $i = 1 To $aNotify_Data[0][0]
					WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] - (50 * $i))
				Next
			Case 1, 2
				For $i = 1 To $aNotify_Data[0][0]
					WinMove($aNotify_Data[$i][0], "", $aNotify_Data[$i][4], $aNotify_Data[0][3] + (50 * ($i - 1)))
				Next
		EndSwitch
	EndIf

EndFunc

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _Notify_GetDefFont
; Description ...: Determine system default MsgBox font
; Syntax ........: _Notify_GetDefFont()
; Parameters ....: None
; Author ........: Melba23
; Modified.......:
; Remarks .......:
Func _Notify_GetDefFont()

	; Get default system font data
	Local $tNONCLIENTMETRICS = DllStructCreate("uint;int;int;int;int;int;byte[60];int;int;byte[60];int;int;byte[60];byte[60];byte[60]")
	DllStructSetData($tNONCLIENTMETRICS, 1, DllStructGetSize($tNONCLIENTMETRICS))
	DllCall("user32.dll", "int", "SystemParametersInfo", "int", 41, "int", DllStructGetSize($tNONCLIENTMETRICS), "ptr", DllStructGetPtr($tNONCLIENTMETRICS), "int", 0)
	; Read font data for MsgBox font
	Local $tLOGFONT = DllStructCreate("long;long;long;long;long;byte;byte;byte;byte;byte;byte;byte;byte;char[32]", DllStructGetPtr($tNONCLIENTMETRICS, 15))
	; Font name
	Return DllStructGetData($tLOGFONT, 14)

EndFunc   ;==>_Notify_GetDefFont

As usual, grateful for comments from anyone else as well. If there are no problems I will release it. :)

M23

Edited by Melba23
Fixed code tags

Share this post


Link to post
Share on other sites

Posted

M23, you have surpassed yourself yet again. I suggested this inclusion since you requested suggestions. I think it's totally excellent. I'll definately find a use for it. Thanks for making the effort.

:)

Share this post


Link to post
Share on other sites

Posted (edited)

[New Version] - 7 Jan 12

New: - _Notify_Locate function allows user to select location and direction of notifications:

; Syntax ........: _Notify_Locate($iLocation)
; Parameters ....: $iLocation - Start point and direction for Notifications
;                              0 = Bottom right upwards (default)
;                              1 = Top right downwards
;                              2 = Top left downwards
;                              3 = Bottom left upwards

Changed:

- Notifications can show images (32x32 only - just use the full path as the parameter). Thanks to UEZ and Yashied for the code to enable PNG images to be used. :)

- _Notify_Set has a further parameter to get the notifications to slide into place rather that moving instantly. They still move pretty quickly as they are actioned inside a message handler and I do not want to hold up the queue for longer than absolutely necessary. The more notifications there are to move the quicker they slide - on my machine it takes about 250ms to move 17 of them which seems not to cause any problems. CYA: This a "user beware" option. Thanks to czardas for the feature request. ;)

New UDF, example and zip in first post. :D

M23

Edited by Melba23

Share this post


Link to post
Share on other sites

Posted

FYI, the title of the thread is spelled wrong. :)

Notifiy < extra I in there.

Share this post


Link to post
Share on other sites

Posted

This is great.

I'm definetely including this within my software deployments.

Software success = notify "Software Installed."

MsgBox wouldn't be as elegant of an option.. but this springs ideas.

Thanks a lot.

- tessa

Share this post


Link to post
Share on other sites

Posted

I have made use of this in my extended ascii keyboard. Thanks again!

Share this post


Link to post
Share on other sites

Posted

melba - this is great. I already use your toast udf.

So.... I know I can add a progress bar using the toast udf (already done it - thanks!)...

but I think from an aesthetic standpoint, I have a need (desire) to use a notification instead, and put a small progress bar inside of it.

Any thoughts? Good idea, bad idea?

Share this post


Link to post
Share on other sites

Posted

z0iid,

Of course you can add controls - you do something like this: :)

#include "Notify_Mod.au3"
#include <ProgressConstants.au3>

HotKeySet("{ESC}", "On_Exit")

_Notify_RegMsg()

_Notify_Locate(0)

_Notify_Show(0, "Progress", "", 0, 1)

GUICtrlCreateProgress(20, 25, 100, 10, $PBS_MARQUEE)
GUICtrlSendMsg(-1, $PBM_SETMARQUEE, True, 50)

While 1
	Sleep(10)
WEnd

Func On_Exit()
	Exit
EndFunc

Just remember to use GUISwitch if you want to create controls on an existing GUI later in the script. ;)

M23

Share this post


Link to post
Share on other sites

Posted

z0iid, Of course you can add controls - you do something like this: :)

 #include "Notify_Mod.au3" #include  HotKeySet("{ESC}", "On_Exit") _Notify_RegMsg() _Notify_Locate(0) _Notify_Show(0, "Progress", "", 0, 1) GUICtrlCreateProgress(20, 25, 100, 10, $PBS_MARQUEE) GUICtrlSendMsg(-1, $PBM_SETMARQUEE, True, 50) While 1 Sleep(10) WEnd Func On_Exit() Exit EndFunc 
Just remember to use GUISwitch if you want to create controls on an existing GUI later in the script. ;) M23
Thank you - that is what I'm looking for.

Are these notification boxes resizable, or static sized? I can't seem to stuff more information, ie, 2 lines of info, or 1 line of info + progress bar.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now