Leaderboard
Popular Content
Showing content with the highest reputation on 09/03/2025 in Posts
-
WinRT - WinUI3
WildByDesign and one other reacted to argumentum for a topic
... #AutoIt3Wrapper_UseX64=Y #AutoIt3Wrapper_Au3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 If Not @AutoItX64 And Not @Compiled Then ShellExecute(StringTrimRight(@AutoItExe, 4) & "_x64.exe", '"' & @ScriptFullPath & '"') Exit EndIf #include <GUIConstants.au3> ... It asked me to GetRuntime() but I installed it yesterday so, the above is a good solution for those not in SciTE, just click-clicking the file from explorer2 points -
WinRT - WinUI3
WildByDesign and one other reacted to MattyD for a topic
This is the same example - but I'm playing around with adding another layer of functions on top of the interface libraries. It should make building GUIs quite a bit simpler, and introduce some semblance of resource management. At this stage its just a rough proof of concept, so I'm not worried about naming conventions etc, or any mistakes in these functions. They'll all probably be rewritten anyway! So anyway, as an example: I'm now doing this to add rows and columns to the grid. ;Params - $pGrid, $fValue, $vUnit ("Auto", "Pixel" or "Star") ;$vUnit can also be the enum in its numeric form. (Microsoft.UI.Xaml.GridUnitType) GridAddRow($pGrid, 2, "Star") GridAddRow($pGrid, 1, "Star") GridAddColumn($pGrid, 3, "Star") GridAddColumn($pGrid, 5, "Star") And the underlying func. Func GridAddColumn($pGrid, $fWidth = 1, $vUnit = "Star") _WinRT_SwitchInterface($pGrid, $sIID_IGrid) If @error Then Return SetError(@error, @extended, False) Local $tGridLen = DllStructCreate("align 4;double Value;ulong GridUnitType") $tGridLen.Value = $fWidth $tGridLen.GridUnitType = IsString($vUnit) ? $mGridUnitType[$vUnit] : $vUnit Local $pColDef, $pColDefs = IGrid_GetColumnDefinitions($pGrid) $pColDef = _WinRT_ActivateInstance("Microsoft.UI.Xaml.Controls.ColumnDefinition") _WinRT_SwitchInterface($pColDef, $sIID_IColumnDefinition) IRowDefinition_SetHeight($pColDef, $tGridLen) Local $iError = @error If Not $iError Then IVector_Append($pColDefs, $pColDef) IUnknown_Release($pColDef) IUnknown_Release($pColDefs) Return SetError($iError, 0, $iError = $S_OK) EndFunc ;==>GridAddColumn Most funcs that accept an object will start with a SwitchInterface() - this serves 2 purposes: in your main script you don't need to bother about setting the correct interface on the object. and also if you feed the func an invalid pointer (to the wrong object for eg.), it should gracefully fail. Factories and other supporting objects used in these funcs are all released before returning. This is probably not be the most efficient thing to do if you're creating a bunch of instances of something - but it does mean you're cleaning up after yourself as you go. I'm getting way ahead of myself - but this new layer wouldn't be a comprehensive wrapper. It'd probably just some basic/common functionality to improve quality of life. I figure people can always jump down to the interface libraries if need be. Whether this will form part of an "official" release I don't know (if I ever get my act together!) - but I think building a full project without anything would just be downright tedious... And hey, if anyone else wants write/drive some of it I won't be complaining!!! WindowTest Grid.zip2 points -
_GUICtrlTab_GetItemText the target crashes on dissimilar architecture
Danyfirex reacted to pixelsearch for a topic
@ioa747 Hi When you call _GUICtrlTab_GetItemText, then _GUICtrlTab_GetItem is called And _GuiCtrlTab_GetItem had issues as seen on Trac Ticket 3903 and in this post. In the post, @Danyfirex worked on this x86-x64 issue and maybe he could give an advice here if he got time ? Also I notice code in _GUICtrlTab_GetItem has been updated in new release 3.3.17.1 (beta) . Did you check your script with 3.3.17.1 , maybe it's solved with the new release ? Fingers crossed & good luck1 point -
_QuoteAutoIt() for strings in code that contain quote
Trong reacted to AspirinJunkie for a topic
Are you aware that you can escape the respective quote characters in AutoIt string definitions by simply doubling them? So to create an AutoIt-compliant string definition for the AutoIt code itself from a string, you do not need to split it into individual strings and reassemble them, but simply double the quotes. This would be shorter, probably clearer and also better performing. In concrete terms, the following should also achieve your actual goal $result = '"' & StringReplace($raw, '"', '""', 0, 1) & '"' ; or equally: $result = "'" & StringReplace($raw, "'", "''", 0, 1) & "'"1 point -
I played around a bit, and ended up with this analog clock. ; https://www.autoitscript.com/forum/topic/213036-%F0%9F%95%91-analog-clock/ ;---------------------------------------------------------------------------------------- ; Title...........: AnalogClockGdi.au3 ; Description.....: A simple AutoIt script creating a digital analog clock GUI. ; AutoIt Version..: 3.3.16.1 Author: ioa747 Script Version: 0.1 ; Note............: Testet in Win10 22H2 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <GDIPlus.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include <Math.au3> #include <Array.au3> #include <StaticConstants.au3> Global $hGUI, $hGraphic ; main GUI Global $hGUIBack, $hGraphicBack ; background GUI Global $hPenSeconds, $hPenMinutes, $hPenHours, $hBrushCenter _GDIPlus_Startup() _CreateClock(600) Func _DrawClock($iWidth, $iX = -1, $iY = -1) Local $iHeight = $iWidth $hGUI = GUICreate("Analog Clock", $iWidth, $iHeight, $iX, $iY, $WS_POPUP, $WS_EX_LAYERED, $hGUIBack) GUISetBkColor(0x00FFFF) ; 0x00FFFF _WinAPI_SetLayeredWindowAttributes($hGUI, 0x00FFFF) ; 0x00FFFF GUISetState(@SW_SHOW) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) $hPenSeconds = _GDIPlus_PenCreate(0xFFFF0000, 2) $hPenMinutes = _GDIPlus_PenCreate(0xFF0000FF, 8) $hPenHours = _GDIPlus_PenCreate(0xFF00FF00, 12) $hBrushCenter = _GDIPlus_BrushCreateSolid(0xFF000000) Local $sTime, $Tick = -1 While True If $Tick <> @SEC Then $sTime = @HOUR & ":" & @MIN & ":" & @SEC ConsoleWrite("- " & $sTime & @CRLF) $Tick = @SEC _RedrawClock($iWidth) EndIf Switch GUIGetMsg() Case -3 ; $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd _GDIPlus_GraphicsDispose($hGraphicBack) _GDIPlus_PenDispose($hPenSeconds) _GDIPlus_PenDispose($hPenMinutes) _GDIPlus_PenDispose($hPenHours) _GDIPlus_BrushDispose($hBrushCenter) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() EndFunc ;==>_DrawClock Func _RedrawClock($iWidth) Local $iHeight = $iWidth Local $iCenterX = $iWidth / 2 Local $iCenterY = $iHeight / 2 Local $iClockRadius = $iWidth * 0.5 Local $hTransparentBrush = _GDIPlus_BrushCreateSolid(0xFF00FFFF) _GDIPlus_GraphicsFillRect($hGraphic, 0, 0, $iWidth, $iHeight, $hTransparentBrush) _GDIPlus_BrushDispose($hTransparentBrush) Local $iCurrentHour = @HOUR Local $iCurrentMinute = @MIN Local $iCurrentSecond = @SEC Local $iDisplayHour = $iCurrentHour If $iDisplayHour > 12 Then $iDisplayHour -= 12 Local $fAngleHours = ($iDisplayHour * 30) - 90 _DrawHand($hGraphic, $hPenHours, $iCenterX, $iCenterY, $iClockRadius * 0.5, $fAngleHours) Local $fAngleMinutes = ($iCurrentMinute * 6) - 90 _DrawHand($hGraphic, $hPenMinutes, $iCenterX, $iCenterY, $iClockRadius * 0.7, $fAngleMinutes) Local $fAngleSeconds = ($iCurrentSecond * 6) - 90 _DrawHand($hGraphic, $hPenSeconds, $iCenterX, $iCenterY, $iClockRadius * 0.8, $fAngleSeconds) Local $iBulletRadius = 10 _GDIPlus_GraphicsFillEllipse($hGraphic, $iCenterX - $iBulletRadius, $iCenterY - $iBulletRadius, $iBulletRadius * 2, $iBulletRadius * 2, $hBrushCenter) EndFunc ;==>_RedrawClock Func _DrawHand($hGraphic, $hPen, $iX1, $iY1, $iLength, $fAngleDegrees) Local $fAngleRadians = _Radian($fAngleDegrees) Local $iX2 = $iX1 + ($iLength * Cos($fAngleRadians)) Local $iY2 = $iY1 + ($iLength * Sin($fAngleRadians)) _GDIPlus_GraphicsDrawLine($hGraphic, $iX1, $iY1, $iX2, $iY2, $hPen) EndFunc ;==>_DrawHand Func _CreateClock($iWidth, $iX = -1, $iY = -1) Local $iHeight = $iWidth $hGUIBack = GUICreate("Clock Background", $iWidth, $iHeight, $iX, $iY, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOOLWINDOW)) GUISetBkColor(0x00FFFF) ; 0x00FFFF _WinAPI_SetLayeredWindowAttributes($hGUIBack, 0x00FFFF) ; 0x00FFFF GUISetState(@SW_SHOW) ; Get the graphic context for the background GUI $hGraphicBack = _GDIPlus_GraphicsCreateFromHWND($hGUIBack) _GDIPlus_GraphicsSetSmoothingMode($hGraphicBack, $GDIP_SMOOTHINGMODE_HIGHQUALITY) Local $iCenterX = $iWidth / 2 Local $iCenterY = $iHeight / 2 Local $iClockRadius = $iWidth * 0.5 Local $iTextRadius = $iClockRadius * 0.90 ; Adjust this value for number placement (closer to edge) For $i = 1 To 12 Local $sDigit = $i Local $fAngleDegrees = ($i * 30) - 90 Local $fAngleRadians = _Radian($fAngleDegrees) Local $iTextX = $iCenterX + ($iTextRadius * Cos($fAngleRadians)) Local $iTextY = $iCenterY + ($iTextRadius * Sin($fAngleRadians)) Local $iDigitWidth = 36 ; Estimate based on font size 30 Local $iDigitHeight = 30 ; Estimate based on font size 30 ; Draw the number - 0xFFFFFFFF = White color for numbers (ARGB) _GDIPlus_GraphicsDrawString($hGraphicBack, $sDigit, $iTextX - ($iDigitWidth / 2), $iTextY - ($iDigitHeight / 2), "Arial", 30, Default, 0xFFFFFFFF) Next _DrawClock($iWidth, $iX, $iY) EndFunc ;==>_DrawStaticClockBackground Which I "tweaked" a bit, and ended up with this ; https://www.autoitscript.com/forum/topic/213036-%F0%9F%95%91-analog-clock/ ;---------------------------------------------------------------------------------------- ; Title...........: Analog_Clock.au3 ; Description.....: A simple AutoIt script creating a digital analog clock GUI with alarm functionality. ; AutoIt Version..: 3.3.16.1 Author: ioa747 Script Version: 0.1 ; Note............: Testet in Win10 22H2 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include <Math.au3> #include <Array.au3> #include <StaticConstants.au3> #include <TrayConstants.au3> #include <Misc.au3> Opt("TrayMenuMode", 3) ; 0=append, 1=no default menu, 2=no automatic check, 4=menuitemID not return Global $hGuiParent, $hGUIBack, $idBackTheme ; Parent GUI & background GUI Global $hGUI, $hGraphic ; main clock GUI Global $hPenSeconds, $hPenMinutes, $hPenHours, $hBrushCenter Global $mAlarm = _GetClockSetting(StringTrimRight(@ScriptFullPath, 4) & ".ini") _GDIPlus_Startup() _CreateClock($mAlarm.width, $mAlarm.x, $mAlarm.y) ;--------------------------------------------------------------------------------------- Func _DrawClock($iWidth, $iX = -1, $iY = -1) Local $hDLL = DllOpen("user32.dll") ; for _IsPressed ; Tray Menou Local $idMove = TrayCreateItem("Move") Local $idSetAlarm = TrayCreateItem("Alarm Setting") Local $idAlarmActive = TrayCreateItem("Alarm Enable/Disable") TrayItemSetState($idAlarmActive, ($mAlarm.active = "1" ? $TRAY_CHECKED : $TRAY_UNCHECKED)) Local $idClockSetting = TrayCreateItem("Clock Setting") TrayCreateItem("") ; separator ----------------------- Local $idClose = TrayCreateItem("Close") TraySetClick($TRAY_CLICK_SECONDARYUP) TraySetIcon("mmcndmgr.dll", -15) TraySetToolTip("Analog Clock") TraySetState($TRAY_ICONSTATE_SHOW) ; Show the tray menu. ; Clock GUI $hGUI = GUICreate("Analog Clock", $iWidth, $iWidth, $iX, $iY, $WS_POPUP, $WS_EX_LAYERED, $hGuiParent) GUISetBkColor(0x00FFFF) ; 0x00FFFF _WinAPI_SetLayeredWindowAttributes($hGUI, 0x00FFFF) ; 0x00FFFF GUISetState(@SW_SHOW) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI) $hPenSeconds = _GDIPlus_PenCreate(0xFFFF0000, 2) ; 0xFFFF0000 $hPenMinutes = _GDIPlus_PenCreate(0xFF0000FF, 8) ; 0xFF0000FF $hPenHours = _GDIPlus_PenCreate(0xFF008000, 12) ; 0xFF00FF00 $hBrushCenter = _GDIPlus_BrushCreateSolid(0xFF000000) ; 0xFF000000 Local $Tick = -1, $Tack = -1 While True If $Tick <> @SEC Then $Tick = @SEC _RedrawClock($iWidth) EndIf If $Tack <> @MIN Then $Tack = @MIN _CheckAlarm() EndIf Switch TrayGetMsg() Case $idClose ExitLoop Case $idMove WinActivate($hGuiParent) While 1 Local $aMpos = MouseGetPos() WinMove($hGuiParent, '', $aMpos[0], $aMpos[1]) ToolTip("click to drop it", $aMpos[0] + 30, $aMpos[1] - 10) If _IsPressed("01", $hDLL) Then ExitLoop ; 01 Left mouse button Sleep(10) WEnd ToolTip("") $mAlarm.x = $aMpos[0] $mAlarm.y = $aMpos[1] IniWrite($mAlarm.file, "ClockSetting", "x", $aMpos[0]) IniWrite($mAlarm.file, "ClockSetting", "y", $aMpos[1]) Case $idAlarmActive If BitAND(TrayItemGetState($idAlarmActive), $TRAY_CHECKED) Then ; If $TRAY_CHECKED TrayItemSetState($idAlarmActive, $TRAY_UNCHECKED) IniWrite($mAlarm.file, "ClockSetting", "active", "0") $mAlarm.active = "0" Else ; If $TRAY_UNCHECKED TrayItemSetState($idAlarmActive, $TRAY_CHECKED) IniWrite($mAlarm.file, "ClockSetting", "active", "1") $mAlarm.active = "1" EndIf Case $idSetAlarm _SetAlarm() Case $idClockSetting ShellExecute($mAlarm.file) Case $TRAY_EVENT_PRIMARYDOUBLE WinActivate($hGuiParent) EndSwitch WEnd DllClose($hDLL) _GDIPlus_PenDispose($hPenSeconds) _GDIPlus_PenDispose($hPenMinutes) _GDIPlus_PenDispose($hPenHours) _GDIPlus_BrushDispose($hBrushCenter) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() EndFunc ;==>_DrawClock ;--------------------------------------------------------------------------------------- Func _RedrawClock($iWidth) Local $iHeight = $iWidth Local $iCenterX = $iWidth / 2 Local $iCenterY = $iHeight / 2 Local $iClockRadius = $iWidth * 0.45 Local $hTransparentBrush = _GDIPlus_BrushCreateSolid(0xFF00FFFF) ;0xFF00FFFF _GDIPlus_GraphicsFillRect($hGraphic, 0, 0, $iWidth, $iHeight, $hTransparentBrush) _GDIPlus_BrushDispose($hTransparentBrush) Local $iCurrentHour = @HOUR Local $iCurrentMinute = @MIN Local $iCurrentSecond = @SEC Local $iDisplayHour = $iCurrentHour If $iDisplayHour > 12 Then $iDisplayHour -= 12 Local $fAngleHours = ($iDisplayHour * 30) - 90 _DrawHand($hGraphic, $hPenHours, $iCenterX, $iCenterY, $iClockRadius * 0.5, $fAngleHours) Local $fAngleMinutes = ($iCurrentMinute * 6) - 90 _DrawHand($hGraphic, $hPenMinutes, $iCenterX, $iCenterY, $iClockRadius * 0.7, $fAngleMinutes) Local $fAngleSeconds = ($iCurrentSecond * 6) - 90 _DrawHand($hGraphic, $hPenSeconds, $iCenterX, $iCenterY, $iClockRadius * 0.8, $fAngleSeconds) Local $iBulletRadius = 10 _GDIPlus_GraphicsFillEllipse($hGraphic, $iCenterX - $iBulletRadius, $iCenterY - $iBulletRadius, $iBulletRadius * 2, $iBulletRadius * 2, $hBrushCenter) EndFunc ;==>_RedrawClock ;--------------------------------------------------------------------------------------- Func _DrawHand($hGraphic, $hPen, $iX1, $iY1, $iLength, $fAngleDegrees) Local $fAngleRadians = _Radian($fAngleDegrees) Local $iX2 = $iX1 + ($iLength * Cos($fAngleRadians)) Local $iY2 = $iY1 + ($iLength * Sin($fAngleRadians)) _GDIPlus_GraphicsDrawLine($hGraphic, $iX1, $iY1, $iX2, $iY2, $hPen) EndFunc ;==>_DrawHand ;--------------------------------------------------------------------------------------- Func _CreateClock($iWidth, $iX = -1, $iY = -1) $hGuiParent = GUICreate("GuiParent", 10, 10, $iX, $iY, $WS_POPUP, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TRANSPARENT)) $hGUIBack = GUICreate("GUIBack", $iWidth, $iWidth, 10 - ($iWidth / 2), 10 - ($iWidth / 2), $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_MDICHILD), $hGuiParent) $idBackTheme = GUICtrlCreatePic(@ScriptDir & "\Clock-600.gif", 0, 0, $iWidth, $iWidth) GUISetState(@SW_SHOW, $hGUIBack) GUISetState(@SW_SHOW, $hGuiParent) Local $aPos = WinGetPos($hGuiParent) _DrawClock($iWidth, $aPos[0] - ($iWidth / 2) + 5, $aPos[1] - ($iWidth / 2) + 5) EndFunc ;==>_CreateClock ;--------------------------------------------------------------------------------------- Func _GetClockSetting($sIniPath) If Not FileExists($sIniPath) Then ; make one Local $sTxt = "" ; Write Example data to the ini file $sTxt &= "[ClockSetting]" & @CRLF $sTxt &= "file=" & $sIniPath & @CRLF $sTxt &= "width=600" & @CRLF $sTxt &= "x=-1" & @CRLF $sTxt &= "y=-1" & @CRLF $sTxt &= "sound=C:\Windows\Media\ringout.wav" & @CRLF $sTxt &= "day=1,2,3,4,5" & @CRLF $sTxt &= "active=1" & @CRLF $sTxt &= "time=17:30" & @CRLF FileWrite($sIniPath, $sTxt) EndIf ; Read the INI section labelled 'ClockSetting'. This will return a 2 dimensional array. Local $aArray = IniReadSection($sIniPath, "ClockSetting") Local $mMap[] If Not @error Then For $i = 1 To $aArray[0][0] $mMap[$aArray[$i][0]] = $aArray[$i][1] Next EndIf Return $mMap EndFunc ;==>_GetClockSetting ;--------------------------------------------------------------------------------------- Func _CheckAlarm() If $mAlarm.active <> "1" Then Return Local $iPos = StringInStr($mAlarm.day, @WDAY) If Not @error And $iPos > 0 Then If $mAlarm.time = @HOUR & ":" & @MIN Then ShellExecute($mAlarm.sound) EndIf EndFunc ;==>_CheckAlarm ;--------------------------------------------------------------------------------------- Func _SetAlarm() Local Const $MARGIN = 10 Local $hGUI = GUICreate("Set Alarm", 300, 260, -1, -1, -1, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW)) GUICtrlCreateLabel("Select Days:", $MARGIN, $MARGIN, 100, 20) GUICtrlSetFont(-1, 9, 800) Local $a_idDays[7] Local $aDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] Local $iY = $MARGIN + 25 For $i = 0 To UBound($aDays) - 1 $a_idDays[$i] = GUICtrlCreateCheckbox($aDays[$i], 10, $iY, 90, 20) Local $iPos = StringInStr($mAlarm.day, $i + 1) If Not @error And $iPos > 0 Then GUICtrlSetState(-1, $GUI_CHECKED) $iY += (20 + 2) Next GUICtrlCreateLabel("Set Time (HH:MM):", 170, $MARGIN, 150, 20) GUICtrlSetFont(-1, 9, 800) ; Bold Local $idInputTime = GUICtrlCreateInput($mAlarm.time, 180, 35, 80, 20) GUICtrlSetFont(-1, 10) Local $idInfo = GUICtrlCreateLabel("", 100, 65, 190, 100) GUICtrlSetFont(-1, 10) $iY += $MARGIN GUICtrlCreateLabel("Select Sound File:", $MARGIN, $iY, 150, 20) GUICtrlSetFont(-1, 9, 800) ; Bold Local $idInputSoundFile = GUICtrlCreateInput($mAlarm.sound, $MARGIN, $iY + 25, 240, 20) Local $idBtnBrowse = GUICtrlCreateButton("...", 260, $iY + 25, 30, 20) Local $idBtnSetAlarm = GUICtrlCreateButton("Set Alarm", 190, 170, 100, 20 + 5) GUICtrlSetFont(-1, 10, 800) GUISetState(@SW_SHOW) While 1 Local $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop Case $idBtnBrowse Local $sSoundFile = FileOpenDialog("Select Alarm Sound", @WorkingDir, "Sound Files (*.mp3;*.wav)|All Files (*.*)") If Not @error Then GUICtrlSetData($idInputSoundFile, $sSoundFile) Case $idBtnSetAlarm Local $sTime , $sSoundPath, $sDays = "", $sInfo = "" GUICtrlSetData($idInfo, "") For $i = 0 To UBound($a_idDays) - 1 If GUICtrlRead($a_idDays[$i]) = $GUI_CHECKED Then $sDays &= $i + 1 & "," Next $sDays = StringTrimRight($sDays, 1) ; remove last "," If $sDays = "" Then $sInfo &= "âš Please select at least one day." & @CRLF $sTime = GUICtrlRead($idInputTime) If Not StringRegExp($sTime, "^\d{2}:\d{2}$") Then $sInfo &= "âš Please enter time in HH:MM format (e.g., 07:30)." & @CRLF $sSoundPath = GUICtrlRead($idInputSoundFile) If $sSoundPath = "" Then $sInfo &= "âš Please select an sound file." GUICtrlSetData($idInfo, $sInfo) If $sInfo <> "" Then ContinueCase ; checks if everything is valid $mAlarm.day = $sDays $mAlarm.time = $sTime $mAlarm.sound = $sSoundPath IniWrite($mAlarm.file, "ClockSetting", "day", $sDays) IniWrite($mAlarm.file, "ClockSetting", "time", $sTime) IniWrite($mAlarm.file, "ClockSetting", "sound", $sSoundPath) ExitLoop EndSwitch WEnd GUIDelete($hGUI) EndFunc ;==>_SetAlarm ...but I didn't stop there and ended up with this Release 0.12 ; https://www.autoitscript.com/forum/topic/213036-%F0%9F%95%91-analog-clock/ ;---------------------------------------------------------------------------------------- ; Title...........: Analog_Clock.au3 ; Description.....: Analog clock GUI with alarm functionality. ; AutoIt Version..: 3.3.16.1 Author: ioa747 Script Version: 0.12 ; Note............: Testet in Win10 22H2 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <GDIPlus.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> #include <Math.au3> #include <Array.au3> #include <GUIConstantsEx.au3> #include <TrayConstants.au3> #include <Misc.au3> #include <Timers.au3> Opt("TrayMenuMode", 3) ; 0=append, 1=no default menu, 2=no automatic check, 4=menuitemID not return ; Global Constants Global Const $AC_SRC_ALPHA = 0x01 Global Const $GDIP_TEXTRENDERINGHINT_CLEARTYPEGRIDFIT = 5 Global Const $GDIP_STRINGFORMAT_ALIGNMENT_CENTER = 1 Global Const $GDIP_STRINGFORMAT_LINEALIGNMENT_CENTER = 1 ; Global Variables Global $hGUIClock Global $hImageBuffer, $hGraphicBuffer Global $hClockImage = 0 Global $hPenSeconds, $hPenMinutes, $hPenHours, $hBrushCenter Global $iClockWidth = 600, $iClockHeight = 600 Global $mClock = _GetClockSetting(StringTrimRight(@ScriptFullPath, 4) & ".ini") _GDIPlus_Startup() ; Try to load a clock background image _GetClockImage($mClock.Image) ; Start the Clock GUI _CreateClock($mClock.Width, $mClock.X, $mClock.Y) Exit ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ; Try to load the clock background image Func _GetClockImage($sImagePath = Default) ; The Default clock background image If $sImagePath = Default Or $sImagePath = "Default" Then $sImagePath = StringTrimRight(@ScriptFullPath, 4) & ".png" If Not FileExists($sImagePath) Then ConsoleWrite("WARNING: ClockImage not found or could not be loaded initially. fallback to Default" & @CRLF) ; Set $sImagePath to Default $sImagePath = StringTrimRight(@ScriptFullPath, 4) & ".png" EndIf ; If there isn't one, make one. If Not FileExists($sImagePath) Then ConsoleWrite("WARNING: Default Image not found or could not be loaded initially. Generating new image..." & @CRLF) Local $bOk = _CreateAndSaveClockImage($iClockWidth, $sImagePath) If $bOk Then ConsoleWrite("INFO: Default Image generated successfully. Attempting to load it now." & @CRLF) Else ConsoleWrite("ERROR: Failed to generate Default Image Will go to exit." & @CRLF) Exit EndIf EndIf $hClockImage = _GDIPlus_ImageLoadFromFile($sImagePath) ; Check if loaded image is a valid pointer and file has content If IsPtr($hClockImage) And FileGetSize($sImagePath) > 0 Then ConsoleWrite("INFO: Loaded ClockImage." & @CRLF) Else ConsoleWrite("ERROR: Failed to Loaded the ClockImage. Will go to exit." & @CRLF) Exit EndIf EndFunc ;==>_GetClockImage ; Clock GUI - Initialization and Main Loop Func _CreateClock($iWidth, $iX = -1, $iY = -1) ; Tray Menu ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Local $idMove = TrayCreateItem("Move") Local $idAlarmActive = TrayCreateItem("Alarm Enable/Disable") TrayItemSetState($idAlarmActive, ($mClock.Alarm = "1" ? $TRAY_CHECKED : $TRAY_UNCHECKED)) Local $iSettings = TrayCreateMenu("Settings") Local $idSetAlarm = TrayCreateItem("Alarm Setting", $iSettings) Local $idSetColors = TrayCreateItem("Colors Setting", $iSettings) Local $idIniFile = TrayCreateItem("Ini file", $iSettings) Local $idRestart = TrayCreateItem("Restart", $iSettings) TrayCreateItem("") ; separator ----------------------- Local $idClose = TrayCreateItem("Close") TraySetClick($TRAY_CLICK_SECONDARYUP) TraySetIcon("mmcndmgr.dll", -15) TraySetToolTip("Analog Clock") TraySetState($TRAY_ICONSTATE_SHOW) ; Show the tray menu. ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Local $hDLL = DllOpen("user32.dll") ; for _IsPressed $iClockWidth = $iWidth $iClockHeight = $iWidth ; The clock GUI $hGUIClock = GUICreate("Analog Clock", $iClockWidth, $iClockHeight, $iX, $iY, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOOLWINDOW)) Local $idMouseLab = GUICtrlCreateLabel("", $iWidth / 2 - 5, $iWidth / 2 - 5, 10, 10) GUISetState(@SW_SHOW) $hImageBuffer = _GDIPlus_BitmapCreateFromScan0($iClockWidth, $iClockHeight) $hGraphicBuffer = _GDIPlus_ImageGetGraphicsContext($hImageBuffer) _GDIPlus_GraphicsSetSmoothingMode($hGraphicBuffer, $GDIP_SMOOTHINGMODE_HIGHQUALITY) ; Colors from inifile RGB to ARGB Local $sColorSeconds = "0xFF" & StringTrimLeft($mClock.ColorSeconds, 2) Local $sColorMinutes = "0xFF" & StringTrimLeft($mClock.ColorMinutes, 2) Local $sColorHours = "0xFF" & StringTrimLeft($mClock.ColorHours, 2) Local $sColorCenter = "0xFF" & StringTrimLeft($mClock.ColorCenter, 2) ; hands Width Local $iWSeconds = ($iWidth * 0.005 < 2 ? 2 : $iWidth * 0.005) Local $iWMinutes = ($iWidth * 0.015 < 4 ? 4 : $iWidth * 0.015) Local $iWHours = ($iWidth * 0.020 < 6 ? 6 : $iWidth * 0.020) ; Initialize pens and brush for drawing hands and center circle $hPenSeconds = _GDIPlus_PenCreate($sColorSeconds, $iWSeconds) ; 0xFFFF0000 $hPenMinutes = _GDIPlus_PenCreate($sColorMinutes, $iWMinutes) ; 0xFF40C880 $hPenHours = _GDIPlus_PenCreate($sColorHours, $iWHours) ; 0xFF0080C0 $hBrushCenter = _GDIPlus_BrushCreateSolid($sColorCenter) ; 0xFF000000 ; SetTimer so it doesn't freeze with the tray menu _Timer_SetTimer($hGUIClock, 250, "_RedrawClock") Local $bRestart, $aMpos, $iCnt = 0, $Tick = -1 ;******************************************** While 1 ; Check Alarm If $Tick <> @MIN Then $Tick = @MIN _CheckAlarm() _ActivityTimeout($mClock.ActivityTimeout) EndIf ; GUI Msg $idMouseLab Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_PRIMARYDOWN ; long press Left mouse button in bullet, to move the clock Local $a = GUIGetCursorInfo() If $a[4] = $idMouseLab Then While _IsPressed("01", $hDLL) ; 01 Left mouse button $iCnt += 1 If $iCnt > 60 Then $aMpos = MouseGetPos() WinMove($hGUIClock, '', $aMpos[0] - $iWidth / 2, $aMpos[1] - $iWidth / 2) ToolTip("Move it", $aMpos[0] + 30, $aMpos[1] - 10) EndIf Sleep(10) WEnd If $iCnt > 60 Then ToolTip("") $mClock.X = $aMpos[0] - $iWidth / 2 $mClock.Y = $aMpos[1] - $iWidth / 2 IniWrite($mClock.IniFile, "ClockSetting", "X", $mClock.X) IniWrite($mClock.IniFile, "ClockSetting", "Y", $mClock.Y) EndIf $iCnt = 0 EndIf EndSwitch ; Tray Msg Switch TrayGetMsg() Case $idClose ExitLoop Case $idMove ; move the clock WinActivate($hGUIClock) While 1 $aMpos = MouseGetPos() WinMove($hGUIClock, '', $aMpos[0] - $iWidth / 2, $aMpos[1] - $iWidth / 2) ToolTip("click to drop it", $aMpos[0] + 30, $aMpos[1] - 10) If _IsPressed("01", $hDLL) Then ExitLoop ; 01 Left mouse button Sleep(10) WEnd ToolTip("") $mClock.X = $aMpos[0] - $iWidth / 2 $mClock.Y = $aMpos[1] - $iWidth / 2 IniWrite($mClock.IniFile, "ClockSetting", "X", $mClock.X) IniWrite($mClock.IniFile, "ClockSetting", "Y", $mClock.Y) Case $idAlarmActive ; Alarm Enable/Disable If BitAND(TrayItemGetState($idAlarmActive), $TRAY_CHECKED) Then ; If $TRAY_CHECKED TrayItemSetState($idAlarmActive, $TRAY_UNCHECKED) IniWrite($mClock.IniFile, "ClockSetting", "Alarm", "0") $mClock.Alarm = "0" Else ; If $TRAY_UNCHECKED TrayItemSetState($idAlarmActive, $TRAY_CHECKED) IniWrite($mClock.IniFile, "ClockSetting", "Alarm", "1") $mClock.Alarm = "1" EndIf Case $idSetAlarm ; Alarm Setting _SetAlarm() Case $idSetColors ; Colors Setting _SetColors() Case $idIniFile ; Ini File (open ini file) ShellExecute($mClock.IniFile) Case $idRestart ; Restart the clock $bRestart = True ExitLoop Case $TRAY_EVENT_PRIMARYDOUBLE ; double click activate clock WinActivate($hGUIClock) EndSwitch WEnd ;******************************************** ; Clean up resources _Timer_KillAllTimers($hGUIClock) _GDIPlus_PenDispose($hPenSeconds) _GDIPlus_PenDispose($hPenMinutes) _GDIPlus_PenDispose($hPenHours) _GDIPlus_BrushDispose($hBrushCenter) _GDIPlus_GraphicsDispose($hGraphicBuffer) _GDIPlus_ImageDispose($hImageBuffer) _GDIPlus_ImageDispose($hClockImage) _GDIPlus_Shutdown() DllClose($hDLL) GUIDelete($hGUIClock) If $bRestart Then Local $Cmd = StringRight(@ScriptFullPath, 4) = ".exe" ? '"' & @ScriptFullPath & '"' : '"' & @AutoItExe & '" "' & @ScriptFullPath & '"' Exit Run($Cmd) EndIf EndFunc ;==>_CreateClock ; Helper Function to Draw a Hand Func _DrawHand($hGraphic, $hPen, $iX1, $iY1, $iLength, $fAngleDegrees) Local $fAngleRadians = _Radian($fAngleDegrees) Local $iX2 = $iX1 + ($iLength * Cos($fAngleRadians)) Local $iY2 = $iY1 + ($iLength * Sin($fAngleRadians)) _GDIPlus_GraphicsDrawLine($hGraphic, $iX1, $iY1, $iX2, $iY2, $hPen) EndFunc ;==>_DrawHand ; Redraw Clock Function (CallBack by timer) Func _RedrawClock($hWnd, $iMsg, $iIDTimer, $iTime) #forceref $hWnd, $iMsg, $iIDTimer, $iTime Local $iCurrentHour = @HOUR Local $iCurrentMinute = @MIN Local $iCurrentSecond = @SEC Local $iCenterX = $iClockWidth / 2 Local $iCenterY = $iClockHeight / 2 Local $iClockRadius = $iClockWidth / 2 _GDIPlus_GraphicsClear($hGraphicBuffer, 0x00000000) _GDIPlus_GraphicsDrawImageRect($hGraphicBuffer, $hClockImage, 0, 0, $iClockWidth, $iClockHeight) ; Calculate angles for smooth hand movement Local $iDisplayHour = $iCurrentHour If $iDisplayHour > 12 Then $iDisplayHour -= 12 Local $fAngleHours = ($iDisplayHour * 30) + ($iCurrentMinute * 0.5) - 90 _DrawHand($hGraphicBuffer, $hPenHours, $iCenterX, $iCenterY, $iClockRadius * 0.5, $fAngleHours) Local $fAngleMinutes = ($iCurrentMinute * 6) + ($iCurrentSecond * 0.1) - 90 _DrawHand($hGraphicBuffer, $hPenMinutes, $iCenterX, $iCenterY, $iClockRadius * 0.7, $fAngleMinutes) Local $fAngleSeconds = ($iCurrentSecond * 6) - 90 ; + ($iCurrentMillisecond * 0.006) ; - 90 _DrawHand($hGraphicBuffer, $hPenSeconds, $iCenterX, $iCenterY, $iClockRadius * 0.8, $fAngleSeconds) ; Draw center bullet Local $iBulletRadius = 10 _GDIPlus_GraphicsFillEllipse($hGraphicBuffer, $iCenterX - $iBulletRadius, $iCenterY - $iBulletRadius, $iBulletRadius * 2, $iBulletRadius * 2, $hBrushCenter) ; Create HBITMAP and display Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImageBuffer) If IsPtr($hHBitmap) Then _WinAPI_BitmapDisplayTransparentInGUI($hHBitmap, $hWnd) EndFunc ;==>_RedrawClock ; Custom _WinAPI_BitmapDisplayTransparentInGUI Function (by UEZ) Func _WinAPI_BitmapDisplayTransparentInGUI(ByRef $hHBitmap, ByRef $hGUI, $bReleaseGDI = True) If Not BitAND(GUIGetStyle($hGUI)[1], $WS_EX_LAYERED) Then Return SetError(1, 0, 0) Local $tSize = DllStructCreate($tagSIZE), $tSource = DllStructCreate($tagPOINT), $tBlend = DllStructCreate($tagBLENDFUNCTION) Local Const $hScrDC = _WinAPI_GetDC(0) Local Const $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC) Local Const $hOldBitmap = _WinAPI_SelectObject($hMemDC, $hHBitmap) Local $tBitmapInfo = DllStructCreate($tagBITMAP) _WinAPI_GetObject($hHBitmap, DllStructGetSize($tBitmapInfo), DllStructGetPtr($tBitmapInfo)) $tSize.X = $tBitmapInfo.bmWidth $tSize.Y = $tBitmapInfo.bmHeight $tBlend.Alpha = 0xFF $tBlend.Format = $AC_SRC_ALPHA _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, 0, DllStructGetPtr($tSize), $hMemDC, DllStructGetPtr($tSource), 0, DllStructGetPtr($tBlend), $ULW_ALPHA) _WinAPI_SelectObject($hMemDC, $hOldBitmap) _WinAPI_DeleteDC($hMemDC) _WinAPI_ReleaseDC(0, $hScrDC) If $bReleaseGDI Then _WinAPI_DeleteObject($hHBitmap) Return True EndFunc ;==>_WinAPI_BitmapDisplayTransparentInGUI ; This function draws a clock dial and saves it as a PNG. Func _CreateAndSaveClockImage($iWidth, $sFilePath) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iWidth) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hGraphics, $GDIP_SMOOTHINGMODE_HIGHQUALITY) _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINT_CLEARTYPEGRIDFIT) Local $iCenterX = $iWidth / 2 Local $iCenterY = $iWidth / 2 Local $iRadius = $iWidth / 2 ; Clear with transparent background (ARGB: A=00) _GDIPlus_GraphicsClear($hGraphics, 0x00000000) ; Colors from inifile RGB to ARGB Local $sColorOutline = "0xFF" & StringTrimLeft($mClock.ColorOutline, 2) Local $sColorTextHour = "0xFF" & StringTrimLeft($mClock.ColorTextHour, 2) Local $sColorTextMin = "0xFF" & StringTrimLeft($mClock.ColorTextMin, 2) ; Colors and Pens/Brushes Local $hPenOutline = _GDIPlus_PenCreate($sColorOutline, 5) ; 0xFFEEEEEE Local $hPenHourMark = _GDIPlus_PenCreate($sColorOutline, 5) Local $hPenMinuteMark = _GDIPlus_PenCreate($sColorOutline, 2) Local $hBrushTextMin = _GDIPlus_BrushCreateSolid($sColorTextMin) Local $hBrushTextHour = _GDIPlus_BrushCreateSolid($sColorTextHour) ; String Format for drawing and measuring text (centered) Local $hStringFormatCenter = _GDIPlus_StringFormatCreate() ; Check if string format object was successfully created If Not IsPtr($hStringFormatCenter) Or $hStringFormatCenter = 0 Then ConsoleWrite("ERROR: Failed to create GDI+ StringFormat object." & @CRLF) ; Clean up other resources before returning failure _GDIPlus_PenDispose($hPenOutline) _GDIPlus_PenDispose($hPenHourMark) _GDIPlus_PenDispose($hPenMinuteMark) _GDIPlus_BrushDispose($hBrushTextMin) _GDIPlus_BrushDispose($hBrushTextHour) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_ImageDispose($hBitmap) Return False EndIf _GDIPlus_StringFormatSetAlign($hStringFormatCenter, $GDIP_STRINGFORMAT_ALIGNMENT_CENTER) _GDIPlus_StringFormatSetLineAlign($hStringFormatCenter, $GDIP_STRINGFORMAT_LINEALIGNMENT_CENTER) ; Draw outer circle Local $iOutlinePadding = 5 _GDIPlus_GraphicsDrawEllipse($hGraphics, $iOutlinePadding, $iOutlinePadding, $iWidth - (2 * $iOutlinePadding), $iWidth - (2 * $iOutlinePadding), $hPenOutline) ; Draw hour and minute marks For $i = 0 To 59 Local $fAngleDegrees = ($i * 6) - 90 Local $fAngleRadians = _Radian($fAngleDegrees) Local $iStartX, $iStartY, $iEndX, $iEndY Local $iMarkLength If Mod($i, 5) = 0 Then ; Hour marks (every 5 minutes) $iMarkLength = $iRadius * 0.06 $iStartX = $iCenterX + (($iRadius - ($iRadius * 0.02)) * Cos($fAngleRadians)) $iStartY = $iCenterY + (($iRadius - ($iRadius * 0.02)) * Sin($fAngleRadians)) $iEndX = $iCenterX + (($iRadius - $iMarkLength - ($iRadius * 0.02)) * Cos($fAngleRadians)) $iEndY = $iCenterY + (($iRadius - $iMarkLength - ($iRadius * 0.02)) * Sin($fAngleRadians)) _GDIPlus_GraphicsDrawLine($hGraphics, $iStartX, $iStartY, $iEndX, $iEndY, $hPenHourMark) Else ; Minute marks $iMarkLength = $iRadius * 0.04 $iStartX = $iCenterX + (($iRadius - ($iRadius * 0.02)) * Cos($fAngleRadians)) $iStartY = $iCenterY + (($iRadius - ($iRadius * 0.02)) * Sin($fAngleRadians)) $iEndX = $iCenterX + (($iRadius - $iMarkLength - ($iRadius * 0.02)) * Cos($fAngleRadians)) $iEndY = $iCenterY + (($iRadius - $iMarkLength - ($iRadius * 0.02)) * Sin($fAngleRadians)) _GDIPlus_GraphicsDrawLine($hGraphics, $iStartX, $iStartY, $iEndX, $iEndY, $hPenMinuteMark) EndIf Next ; Draw numbers (Hours and Minutes) Local $iHourTextRadius = $iRadius * 0.66 ; Radius for hour numbers (adjust this to move them closer/further from center) Local $iMinuteTextRadius = $iRadius * 0.86 ; Radius for minute numbers ; Define font families Local $sFontName = "Times New Roman" Local $hFontFamily = _GDIPlus_FontFamilyCreate($sFontName) ; Critical check for font family handle If Not IsPtr($hFontFamily) Or $hFontFamily = 0 Then ConsoleWrite("ERROR: _GDIPlus_FontFamilyCreate returned an invalid handle for '" & $sFontName & "'. @error is: " & @error & @CRLF) ; Clean up current resources before returning failure _GDIPlus_PenDispose($hPenOutline) _GDIPlus_PenDispose($hPenHourMark) _GDIPlus_PenDispose($hPenMinuteMark) _GDIPlus_BrushDispose($hBrushTextMin) _GDIPlus_BrushDispose($hBrushTextHour) _GDIPlus_StringFormatDispose($hStringFormatCenter) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_ImageDispose($hBitmap) Return False EndIf For $i = 1 To 12 ; Hour Numbers (1-12) Local $sHourDigit = $i Local $fHourAngleDegrees = ($i * 30) - 90 Local $fHourAngleRadians = _Radian($fHourAngleDegrees) Local $iHourFontSize = 50 Local $hHourFont = _GDIPlus_FontCreate($hFontFamily, $iHourFontSize, 1) ; 1 = Bold typeface ; Check for font handle If Not IsPtr($hHourFont) Or $hHourFont = 0 Then ConsoleWrite("ERROR: _GDIPlus_FontCreate failed for hour font. Skipping text drawing." & @CRLF) ContinueLoop ; Skip drawing this text if font creation failed EndIf ; Calculate the approximate position for the text bounding box (large enough to contain text) Local $fApproxTextSize = $iHourFontSize * 1.5 Local $tHourLayoutRect = _GDIPlus_RectFCreate($iCenterX - $fApproxTextSize, $iCenterY - $fApproxTextSize, $fApproxTextSize * 2, $fApproxTextSize * 2) ; Measure text to get its exact dimensions Local $aHourMeasure = _GDIPlus_GraphicsMeasureString($hGraphics, $sHourDigit, $hHourFont, $tHourLayoutRect, $hStringFormatCenter) Local $fHourTextWidth = 0, $fHourTextHeight = 0 If Not @error And IsArray($aHourMeasure) And DllStructGetData($aHourMeasure[0], "Width") > 0 And DllStructGetData($aHourMeasure[0], "Height") > 0 Then $fHourTextWidth = DllStructGetData($aHourMeasure[0], "Width") $fHourTextHeight = DllStructGetData($aHourMeasure[0], "Height") Else ; Fallback: Simple estimation if measurement fails $fHourTextWidth = $iHourFontSize * 0.6 * StringLen($sHourDigit) $fHourTextHeight = $iHourFontSize * 1.0 ConsoleWrite("WARNING: Failed to measure hour text '" & $sHourDigit & "'. Fallback: Using estimation." & @CRLF) EndIf ; Calculate the FINAL position for the text, taking into account text dimensions and desired radius Local $iHourTextX = $iCenterX + ($iHourTextRadius * Cos($fHourAngleRadians)) - ($fHourTextWidth / 2) Local $iHourTextY = $iCenterY + ($iHourTextRadius * Sin($fHourAngleRadians)) - ($fHourTextHeight / 2) ; Create a layout rectangle specific for drawing the text at the calculated position Local $tDrawHourLayout = _GDIPlus_RectFCreate($iHourTextX, $iHourTextY, $fHourTextWidth, $fHourTextHeight) ; Draw the string using _GDIPlus_GraphicsDrawStringEx _GDIPlus_GraphicsDrawStringEx($hGraphics, $sHourDigit, $hHourFont, $tDrawHourLayout, $hStringFormatCenter, $hBrushTextHour) _GDIPlus_FontDispose($hHourFont) ; Minute Numbers (5, 10, ..., 60) Local $sMinuteDigit = $i * 5 If $sMinuteDigit = 60 Then $sMinuteDigit = "00" Local $fMinuteAngleDegrees = ($i * 30) - 90 Local $fMinuteAngleRadians = _Radian($fMinuteAngleDegrees) Local $iMinuteFontSize = 20 Local $hMinuteFont = _GDIPlus_FontCreate($hFontFamily, $iMinuteFontSize, 1) ; 1 = Bold typeface ; Check for font handle If Not IsPtr($hMinuteFont) Or $hMinuteFont = 0 Then ConsoleWrite("ERROR: _GDIPlus_FontCreate failed for minute font. Skipping text drawing." & @CRLF) ContinueLoop ; Skip drawing this text if font creation failed EndIf Local $fApproxMinuteTextSize = $iMinuteFontSize * 1.5 Local $tMinuteLayoutRect = _GDIPlus_RectFCreate($iCenterX - $fApproxMinuteTextSize, $iCenterY - $fApproxMinuteTextSize, $fApproxMinuteTextSize * 2, $fApproxMinuteTextSize * 2) ; Measure text Local $aMinuteMeasure = _GDIPlus_GraphicsMeasureString($hGraphics, $sMinuteDigit, $hMinuteFont, $tMinuteLayoutRect, $hStringFormatCenter) Local $fMinuteTextWidth = 0, $fMinuteTextHeight = 0 If Not @error And IsArray($aMinuteMeasure) And DllStructGetData($aMinuteMeasure[0], "Width") > 0 And DllStructGetData($aMinuteMeasure[0], "Height") > 0 Then $fMinuteTextWidth = DllStructGetData($aMinuteMeasure[0], "Width") $fMinuteTextHeight = DllStructGetData($aMinuteMeasure[0], "Height") Else ; Fallback: Simple estimation if measurement fails $fMinuteTextWidth = $iMinuteFontSize * 0.6 * StringLen($sMinuteDigit) $fMinuteTextHeight = $iMinuteFontSize * 1.0 ConsoleWrite("WARNING: Failed to measure minute text '" & $sMinuteDigit & "'. Fallback: Using estimation." & @CRLF) EndIf Local $iMinuteTextX = $iCenterX + ($iMinuteTextRadius * Cos($fMinuteAngleRadians)) - ($fMinuteTextWidth / 2) Local $iMinuteTextY = $iCenterY + ($iMinuteTextRadius * Sin($fMinuteAngleRadians)) - ($fMinuteTextHeight / 2) Local $tDrawMinuteLayout = _GDIPlus_RectFCreate($iMinuteTextX, $iMinuteTextY, $fMinuteTextWidth, $fMinuteTextHeight) ; Draw the string using _GDIPlus_GraphicsDrawStringEx _GDIPlus_GraphicsDrawStringEx($hGraphics, $sMinuteDigit, $hMinuteFont, $tDrawMinuteLayout, $hStringFormatCenter, $hBrushTextMin) _GDIPlus_FontDispose($hMinuteFont) Next _GDIPlus_FontFamilyDispose($hFontFamily) ; Dispose font family after the loop ; Save the bitmap to a PNG file Local $bSuccess = _GDIPlus_ImageSaveToFile($hBitmap, $sFilePath) ConsoleWrite("DEBUG: _GDIPlus_ImageSaveToFile $bSuccess=" & $bSuccess & ", @error=" & @error & @CRLF) ; Add check for file exist and size after saving If FileExists($sFilePath) And FileGetSize($sFilePath) > 0 Then Sleep(200) ; Give some time for file system to release the file Else ConsoleWrite("ERROR: File save verification failed for '" & $sFilePath & "'. Success: " & $bSuccess & ", Exists: " & FileExists($sFilePath) & ", Size: " & FileGetSize($sFilePath) & @CRLF) $bSuccess = False EndIf ; Clean up resources _GDIPlus_PenDispose($hPenOutline) _GDIPlus_PenDispose($hPenHourMark) _GDIPlus_PenDispose($hPenMinuteMark) _GDIPlus_BrushDispose($hBrushTextHour) _GDIPlus_BrushDispose($hBrushTextMin) _GDIPlus_StringFormatDispose($hStringFormatCenter) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_ImageDispose($hBitmap) Return $bSuccess EndFunc ;==>_CreateAndSaveClockImage ; Make, and read ini to map Func _GetClockSetting($sIniPath) If Not FileExists($sIniPath) Then ; make one Local $sTxt = "" ; Write Example data to the ini file $sTxt &= "[ClockSetting]" & @CRLF $sTxt &= "IniFile=" & $sIniPath & @CRLF $sTxt &= "Image=Default" & @CRLF $sTxt &= "Width=600" & @CRLF $sTxt &= "X=-1" & @CRLF $sTxt &= "Y=-1" & @CRLF $sTxt &= "ColorSeconds=0xFF0000" & @CRLF $sTxt &= "ColorMinutes=0x40C880" & @CRLF $sTxt &= "ColorHours=0x0080C0" & @CRLF $sTxt &= "ColorCenter=0x000000" & @CRLF $sTxt &= "ColorTextHour=0xFFFFFF" & @CRLF $sTxt &= "ColorTextMin=0xFFFFFF" & @CRLF $sTxt &= "ColorOutline=0xFFFFFF" & @CRLF $sTxt &= "Alarm=1" & @CRLF $sTxt &= "AlarmSound=C:\Windows\Media\ringout.wav" & @CRLF $sTxt &= "AlarmDays=2,3,4,5,6" & @CRLF $sTxt &= "AlarmTime=17:30" & @CRLF $sTxt &= "ActivityTimeout=3" & @CRLF FileWrite($sIniPath, $sTxt) EndIf ; Read the INI section labelled 'ClockSetting'. This will return a 2 dimensional array. Local $aArray = IniReadSection($sIniPath, "ClockSetting") Local $mMap[] If Not @error Then For $i = 1 To $aArray[0][0] $mMap[$aArray[$i][0]] = $aArray[$i][1] Next EndIf ; Default colors If $mMap.ColorSeconds = "" Then $mMap.ColorSeconds = "0xFF0000" If $mMap.ColorMinutes = "" Then $mMap.ColorMinutes = "0x40C880" If $mMap.ColorHours = "" Then $mMap.ColorHours = "0x0080C0" If $mMap.ColorCenter = "" Then $mMap.ColorCenter = "0x000000" If $mMap.ColorTextHour = "" Then $mMap.ColorTextHour = "0xFFFFFF" If $mMap.ColorTextMin = "" Then $mMap.ColorTextMin = "0xFFFFFF" If $mMap.ColorOutline = "" Then $mMap.ColorOutline = "0xFFFFFF" Return $mMap EndFunc ;==>_GetClockSetting ; Check Alarm time Func _CheckAlarm() If $mClock.Alarm <> "1" Then Return Local $iPos = StringInStr($mClock.AlarmDays, @WDAY) If Not @error And $iPos > 0 Then If $mClock.AlarmTime = @HOUR & ":" & @MIN Then ShellExecute($mClock.AlarmSound) EndIf EndFunc ;==>_CheckAlarm ; Set Alarm GUI Func _SetAlarm() Local Const $MARGIN = 10 Local $hGUIAlarm = GUICreate("Set Alarm", 300, 260, -1, -1, -1, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW)) GUICtrlCreateLabel("Select Days:", $MARGIN, $MARGIN, 100, 20) GUICtrlSetFont(-1, 9, 800) Local $a_idDays[7] Local $aDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] Local $iY = $MARGIN + 25 For $i = 0 To UBound($aDays) - 1 $a_idDays[$i] = GUICtrlCreateCheckbox($aDays[$i], 10, $iY, 90, 20) Local $iPos = StringInStr($mClock.AlarmDays, $i + 1) If Not @error And $iPos > 0 Then GUICtrlSetState(-1, $GUI_CHECKED) $iY += (20 + 2) Next GUICtrlCreateLabel("Set Time (HH:MM):", 170, $MARGIN, 150, 20) GUICtrlSetFont(-1, 9, 800) ; Bold Local $idInputTime = GUICtrlCreateInput($mClock.AlarmTime, 180, 35, 80, 20) GUICtrlSetFont(-1, 10) Local $idInfo = GUICtrlCreateLabel("", 100, 65, 190, 100) GUICtrlSetFont(-1, 10) $iY += $MARGIN GUICtrlCreateLabel("Select Sound File:", $MARGIN, $iY, 150, 20) GUICtrlSetFont(-1, 9, 800) ; Bold Local $idInputSoundFile = GUICtrlCreateInput($mClock.AlarmSound, $MARGIN, $iY + 25, 240, 20) Local $idBtnBrowse = GUICtrlCreateButton("...", 260, $iY + 25, 30, 20) Local $idBtnSetAlarm = GUICtrlCreateButton("Set Alarm", 190, 170, 100, 20 + 5) GUICtrlSetFont(-1, 10, 800) GUISetState(@SW_SHOW) While 1 Local $iMsg = GUIGetMsg() Switch $iMsg Case $GUI_EVENT_CLOSE ExitLoop Case $idBtnBrowse Local $sSoundFile = FileOpenDialog("Select Alarm Sound", @WorkingDir, "Sound Files (*.mp3;*.wav)|All Files (*.*)") If Not @error Then GUICtrlSetData($idInputSoundFile, $sSoundFile) Case $idBtnSetAlarm Local $sTime, $sSoundPath, $sDays = "", $sInfo = "" GUICtrlSetData($idInfo, "") For $i = 0 To UBound($a_idDays) - 1 If GUICtrlRead($a_idDays[$i]) = $GUI_CHECKED Then $sDays &= $i + 1 & "," Next $sDays = StringTrimRight($sDays, 1) ; remove last "," If $sDays = "" Then $sInfo &= "âš Please select at least one day." & @CRLF $sTime = GUICtrlRead($idInputTime) If Not StringRegExp($sTime, "^\d{2}:\d{2}$") Then $sInfo &= "âš Please enter time in HH:MM format (e.g., 07:30)." & @CRLF $sSoundPath = "" & GUICtrlRead($idInputSoundFile) If $sSoundPath = "" Then $sInfo &= "âš Please select an sound file." GUICtrlSetData($idInfo, $sInfo) If $sInfo <> "" Then ContinueCase ; checks if everything is valid $mClock.AlarmDays = $sDays $mClock.AlarmTime = $sTime $mClock.AlarmSound = $sSoundPath IniWrite($mClock.IniFile, "ClockSetting", "AlarmDays", $sDays) IniWrite($mClock.IniFile, "ClockSetting", "AlarmTime", $sTime) IniWrite($mClock.IniFile, "ClockSetting", "AlarmSound", $sSoundPath) ExitLoop EndSwitch WEnd GUIDelete($hGUIAlarm) EndFunc ;==>_SetAlarm ; Set Colors GUI Func _SetColors() Local $hGUIColors = GUICreate("Set Colors", 180, 250, -1, -1, -1, $WS_EX_TOOLWINDOW) GUISetFont(10) GUICtrlCreateLabel("Seconds hand", 10, 10, 101, 17, 0x0002) GUICtrlCreateLabel("Minutes hand", 10, 40, 101, 17, 0x0002) GUICtrlCreateLabel("Hours hand", 10, 70, 101, 17, 0x0002) GUICtrlCreateLabel("Center Pin", 10, 100, 101, 17, 0x0002) GUICtrlCreateLabel("Hours Didits", 10, 130, 101, 17, 0x0002) GUICtrlCreateLabel("Minutes Didits", 10, 160, 101, 17, 0x0002) GUICtrlCreateLabel("Image Outline", 10, 190, 101, 17, 0x0002) Local $aNames[8] = [7, "ColorSeconds", "ColorMinutes", "ColorHours", "ColorCenter", "ColorTextHour", "ColorTextMin", "ColorOutline"] Local $iY = 5 Local $aColors[8][3] $aColors[0][0] = 7 For $i = 1 To $aColors[0][0] $aColors[$i][0] = GUICtrlCreateButton("", 120, $iY, 50, 25, 0x8000) $aColors[$i][1] = $mClock[$aNames[$i]] GUICtrlSetBkColor(-1, $aColors[$i][1]) If $i < 5 Then GUICtrlSetTip(-1, "This will be in effect after restart the clock") If $i > 4 Then GUICtrlSetTip(-1, "This will be in effect after deleting the existing clock image") $iY += 30 Next Local $idSetColors = GUICtrlCreateButton("Set Colors", 70, $iY, 100, 25) GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif") GUISetState(@SW_SHOW) Local $nMsg, $iChooseColor While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE ExitLoop Case $aColors[1][0] To $aColors[7][0] ;ConsoleWrite("$nMsg=" & $nMsg & @CRLF) Local $id = $nMsg - 10 $iChooseColor = _ChooseColor(2, $aColors[$id][1], 2, $hGUIColors) If $iChooseColor <> -1 Then $aColors[$id][1] = $iChooseColor GUICtrlSetBkColor($aColors[$id][0], $aColors[$id][1]) EndIf Case $idSetColors For $i = 1 To $aColors[0][0] $mClock[$aNames[$i]] = $aColors[$i][1] IniWrite($mClock.IniFile, "ClockSetting", $aNames[$i], $aColors[$i][1]) Next ExitLoop EndSwitch WEnd GUIDelete($hGUIColors) EndFunc ;==>_SetColors Func _ActivityTimeout($iTimeout = 3) Local Static $iMinute, $iMouseX Local $aMpos = MouseGetPos() If $iMouseX <> $aMpos[0] Then $iMouseX = $aMpos[0] $iMinute = 0 Return EndIf $iMinute +=1 If $iMinute = $iTimeout Then $iMinute = 0 WinActivate($hGUIClock) ConsoleWrite("INFO: Activity Timeout triggered." & @CRLF) EndIf EndFunc Extra background image Please, every comment is appreciated! leave your comments and experiences here! Thank you very much1 point