ioa747 Posted May 1 Posted May 1 (edited) Hi everyone, I'd like to share a project I've been working on: UC_Framework. It is a lightweight framework designed to create modern, reactive, and highly customizable GDI+ controls for AutoIt. My goal was to create a standardized, extensible way to introduce custom controls into AutoIt, moving away from static functions and towards a more "Object-Oriented" logic using AutoIt Maps Key Features: Reactive Engine: Property changes automatically trigger a redraw of the control. Extensible Architecture: The framework is designed as an "Engine." Adding a new control (e.g., a Gauge or a Custom Listview) is just a matter of defining its properties in the Map and creating its Draw function. Modern UI Elements: Includes Toggles (Round/Rect), Sliders (Horizontal/Vertical), Custom Buttons (Classic/Rounded/Pill), ,Links, labels, (more are coming). Property Management: Centralized property manager for easy control manipulation using _UC_Set and _UC_Get. Customization: Full control over colors, corner radius, fonts, and tooltips. Interactive: Built-in support for hover states, click events, and keyboard accelerators. Technical Implementation: The framework uses a Global Map (ID 1) to act as a Provider for system-wide constants, cursors, and shared resources, ensuring that your GUI remains lightweight and organized. This framework is currently in its early stages (Alpha). I am sharing it now because I want to establish a solid foundation and gather feedback on the architecture. Ideas for new controls to be integrated into the library. What's New Spoiler Version: 0.0.6 Feature Request 1552133 Version: 0.0.6.2 Feature Request 1552156 Example1.au3 expandcollapse popup; https://www.autoitscript.com/forum/topic/213667-uc_framework-universal-controls/ ;---------------------------------------------------------------------------------------- ; Title...........: Example1.au3 ; Description.....: Example of using the UC_Framework.au3 ; AutoIt Version..: 3.3.18.0 Author: ioa747 Script Version: 0.3 ; Note............: Testet in Windows 11 Pro 25H2 Date:01/05/2026 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <GUIConstantsEx.au3> #include "UC_Framework.au3" _Main() Func _Main() Local $hMainGui = GUICreate("Universal Controls GUI", 400, 250, -1, -1, BitOR($WS_CLIPCHILDREN, $GUI_SS_DEFAULT_GUI)) _UC_GUISetBkColor(0xF0F0F0, $hMainGui) Local $idLblTheme = GUICtrlCreateLabel("GUI Theme", 20, 10, 150, 17) ; === Toggles === Local $idToggleTheme = _UC_Toggle_Create($hMainGui, 20, 30, 50, 25, 0, 0xF0F0F0, 0x758184, 0xD1D1D1) Local $idToggle1 = _UC_Toggle_Create($hMainGui, 20, 80, 50, 25, 0, 0x0094FF) Local $idToggle2 = _UC_Toggle_Create($hMainGui, 20, 130, 50, 25, 1, 0xFF6A00, 0x33AA00) ; === Sliders === Local $idHLabel = GUICtrlCreateLabel("Horizontal Slider (0-100):", 20, 180) Local $idHSlider = _UC_Slider_Create($hMainGui, 20, 200, 180, 20, 0, 100, 50, 0, 0x4CD964, 0xCCCCCC, 0xFFFFFF, 4) _UC_Set(-1, "SliderXLStep", 10) ; customizable property _MapCW(_UC_Get($idHSlider), "--- $idHSlider Report ---") Local $idVLabel = _UC_Label_Create($hMainGui, "Vertical Slider (0-100):", 340, 25, 20, 150, 3, 0x000000) Local $idVSlider = _UC_Slider_Create($hMainGui, 360, 25, 20, 150, 0, 20, 20, 1, 0x0078D7) _UC_Set(-1, "ShowTooltip", 1) ; standar property _UC_Set(-1, "SliderXLStep", 5) ; customizable property ; === Buttons === Local $btnClassic = _UC_Button_Create($hMainGui, "CLASSIC RECT", 220, 20, 100, 35, 0, 0x3A71B1, 0xFFFFFF) _UC_Set(-1, "State", 0) ; standar property Local $btnModern = _UC_Button_Create($hMainGui, "ROUNDED CORNERS", 220, 70, 100, 35, 5, 0x3C975A, 0xFFFFFF) Local $btnPill = _UC_Button_Create($hMainGui, "PILL BUTTON", 220, 120, 100, 35, 30, 0xA84646, 0xFFFFFF) Local $btnRound1 = _UC_Button_Create($hMainGui, ChrW(59448), 220, 170, 35, 35, 34, 0xA14300, 0xFFFFFF) _UC_Set(-1, "Font", "Segoe Fluent Icons") _UC_Set(-1, "FontSize", 12) _UC_Set(-1, "Tooltip", "FolderOpen") _UC_Set(-1, "ShowTooltip", 1) Local $btnRound2 = _UC_Button_Create($hMainGui, "R2", 260, 170, 35, 35, 34, 0x7800AC, 0xFFFFFF) Local $btnRound3 = _UC_Button_Create($hMainGui, ChrW(59213), 300, 170, 35, 35, 34, 0xFF6A00, 0xFFFFFF) _UC_Set(-1, "Font", "Segoe Fluent Icons") _UC_Set(-1, "FontSize", 12) ; === Links === Local $Link = "https://github.com/ioa747/NetWebView2Lib" Local $idLink = _UC_Link_Create($hMainGui, "webview2autoit", $Link, 100, 30, 80, 20, 12) _UC_Set(-1, "ShowTooltip", 1) Local $id_UP = GUICtrlCreateDummy() Local $id_DOWN = GUICtrlCreateDummy() Local $id_UP_XL = GUICtrlCreateDummy() Local $id_DOWN_XL = GUICtrlCreateDummy() Local $aAccelKeys[4][2] = [["{UP}", $id_UP], ["{DOWN}", $id_DOWN], ["+{UP}", $id_UP_XL], ["+{DOWN}", $id_DOWN_XL]] GUISetAccelerators($aAccelKeys) GUISetState(@SW_SHOW) ; Map (ID 1) to act as a Provider for system-wide Variables _MapCW(_UC_Get(1), "--- System Variable ---") ; report ConsoleWrite("--- " & @CRLF) Local $aMsg, $iSliderXLStep, $iVal While 1 $aMsg = GUIGetMsg() Switch $aMsg Case $GUI_EVENT_CLOSE ExitLoop Case $id_UP _UC_Slider_UpdateFromValue(Default, 1) ; Default is the active control Case $id_DOWN _UC_Slider_UpdateFromValue(Default, -1) ; Default is the active control Case $id_UP_XL $iSliderXLStep = _UC_Get(Default, "SliderXLStep") ; Default is the active control _UC_Slider_UpdateFromValue(Default, $iSliderXLStep) Case $id_DOWN_XL $iSliderXLStep = _UC_Get(Default, "SliderXLStep") ; Default is the active control _UC_Slider_UpdateFromValue(Default, - $iSliderXLStep) Case $idToggleTheme ConsoleWrite("$idToggleTheme:" & GUICtrlRead($idToggleTheme) & @CRLF) Local $iTxtColor If GUICtrlRead($idToggleTheme) Then _UC_GUISetBkColor(0x262A2B, $hMainGui) $iTxtColor = 0xFFFFFF Else _UC_GUISetBkColor(0xF0F0F0, $hMainGui) $iTxtColor = 0x000000 EndIf GUICtrlSetColor($idLblTheme, $iTxtColor) GUICtrlSetColor($idHLabel, $iTxtColor) ; GUICtrlSetColor($idVLabel, $iTxtColor) _UC_Set($idVLabel, "Color", $iTxtColor) _UC_Refresh($hMainGui) Case $idToggle1 ConsoleWrite("$idToggle1:" & GUICtrlRead($idToggle1) & @CRLF) GUISetState((GUICtrlRead($idToggle1) ? @SW_HIDE : @SW_SHOW), _UC_Get($idToggle2, "UC_hWnd")) Case $idToggle2 ConsoleWrite("$idToggle2:" & GUICtrlRead($idToggle2) & @CRLF) _UC_Set($idHSlider, "ThumbType", GUICtrlRead($idToggle2)) Case $idHSlider $iVal = GUICtrlRead($idHSlider) GUICtrlSetData($idHLabel, "Horizontal Slider (" & $iVal & "):") ConsoleWrite("$idHSlider:" & $iVal & @CRLF) Case $idVSlider $iVal = GUICtrlRead($idVSlider) _UC_Set($idVLabel, "Text", "Vertical Slider (" & $iVal & "):") _UC_Set($btnPill, "CornerRadius", $iVal) Case $idLink ConsoleWrite("$idLink:" & GUICtrlRead($idLink) & @CRLF) Local $sText = _UC_Get($idLink, "Value") ConsoleWrite("$sText=" & $sText & @CRLF) ShellExecute($sText) Case $btnClassic ,$btnModern, $btnPill ConsoleWrite("'" & _UC_Get(Default, "Text") & "' Button Clicked!" & @CRLF) ; Default is the active control Case $btnRound1 ConsoleWrite("'" & _UC_Get($btnRound1, "Tooltip") & "' Button Clicked!" & @CRLF) _MapCW(_UC_Get($btnRound1), "--- $btnRound1 Report ---") Case $btnRound2 ConsoleWrite("'" & GUICtrlRead($btnRound2) & "' Button Clicked!" & @CRLF) Case $btnRound3 ConsoleWrite("'" & GUICtrlRead($btnRound3) & "' Button Clicked!" & @CRLF) EndSwitch WEnd _UC_Destroy($hMainGui) EndFunc ;==>_Main UC_Framework.au3 expandcollapse popup; https://www.autoitscript.com/forum/topic/213667-uc_framework-universal-controls/ ;---------------------------------------------------------------------------------------- ; Title...........: UC_Framework.au3 ; Description.....: Universal Controls framework for custom GDI+ controls (Toggles, Sliders, etc.) ; AutoIt Version..: 3.3.18.0 Author: ioa747 Script Version: 0.0.6.2 ; Note............: Testet in Windows 11 Pro 25H2 Date:15/04/2026 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include-once #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPISysWin.au3> #include <WinAPISys.au3> #include <Misc.au3> #include <WinAPIGdi.au3> #include <WindowsNotifsConstants.au3> #include <StaticConstants.au3> #include <String.au3> #include <Array.au3> #include <WinAPIvkeysConstants.au3> Global $g_UC_DebugInfo = 1 Global Enum _ $UC_TYPE_NONE, _ $UC_TYPE_TOGGLE, _ $UC_TYPE_SLIDER, _ $UC_TYPE_BUTTON, _ $UC_TYPE_LINK, _ $UC_TYPE_LABEL, _ $UC_TYPE_MAX #Region ; ~~~~~~~~~~~~~ Generic UC API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _UC_Redraw($hWnd) Local $id = _WinAPI_GetProp($hWnd, "UC_ControlID") If Not $id Then Return SetError(1, 0, 0) Local $m = _UC_Properties($id) ; get the Map Switch $m.UC_Type Case $UC_TYPE_NONE Return Case $UC_TYPE_TOGGLE _UC_Toggle_Draw($hWnd, $m) Case $UC_TYPE_SLIDER _UC_Slider_Draw($hWnd, $m) Case $UC_TYPE_BUTTON _UC_Button_Draw($hWnd, $m) Case $UC_TYPE_LINK _UC_Link_Draw($hWnd, $m) Case $UC_TYPE_LABEL _UC_Label_Draw($hWnd, $m) EndSwitch EndFunc ;==>_UC_Redraw ; #FUNCTION# ==================================================================================================================== ; Name ..........: _UC_Properties ; Description ...: Centralized Property Manager and Reactive Engine for Universal Controls. ; Syntax ........: _UC_Properties($idDummy[, $vName = Default[, $vVal = Default]]) ; Parameters ....: $idDummy - The Control ID (Dummy) assigned to the UC control. ; $vName - [Optional] Property name (String), a complete Map object, or "@Delete". ; $vVal - [Optional] The value to assign. ; If $vName is "@Delete", set $vVal to True to skip final redraw. ; If $vName is a Map, $vVal=False skips the automatic redraw. ; Return values .: Success: ; 1. GET Full Map: (Call: _UC_Properties($id)) -> Returns the entire Map object. ; 2. SET Full Map: (Call: _UC_Properties($id, $mMap)) -> Returns 1, updates memory and Redraws. ; 3. GET Value: (Call: _UC_Properties($id, "PropName")) -> Returns the specific value. ; 4. SET Value: (Call: _UC_Properties($id, "PropName", $vVal)) -> Returns 1 and Redraws. ; 5. DELETE: (Call: _UC_Properties($id, "@Delete")) -> Clears memory slot. ; Failure: ; - Returns SetError(1, 0, $mTemplate) if a requested property name does not exist. ; - Returns SetError(2, 0, 0) if $idDummy property = -1 and control does not exist. ; Author ........: ioa747 ; Remarks .......: This function implements a "Reactive Data Binding" logic. Any change to a property ; automatically triggers the _UC_Redraw() for the associated hWnd. ; ; Internal Architecture & Indexing: ; - Index [0]: Stores the total number of allocated slots (Array Size tracking). ; - Index [1]: Reserved for General Library Parameters (Global settings for the UC framework). ; - Index [2]: Reserved as a Template Map (An empty Map used to initialize new controls). ; - Index [3+]: Stores the unique Map for each individual Control ID (Dummy). ; ; Usage Scenarios: ; - Multi-Property Update: Get the Map, modify multiple keys, then Set it back to trigger one Redraw. ; - Control Initialization: The framework automatically copies the Template Map [2] when a new ; Control ID is first accessed, ensuring consistency across all controls. ; - Memory Management: Map objects are heavy. Always call with "@Delete" when a control is ; destroyed (e.g., during GUIDelete) to prevent memory leaks in long-running scripts. ; =============================================================================================================================== Func _UC_Properties($idDummy = Default, $vName = Default, $vVal = Default) Local Static $aProp[1] = [0] If $idDummy = Default Then Return $aProp If $idDummy = -1 Then If Not MapExists($aProp[1], "UC_LastCreatedID") Then Return SetError(2, 0, 0) $idDummy = $aProp[1].UC_LastCreatedID EndIf ; Dynamic Resize If $idDummy > $aProp[0] Then Local $iNewSize = $idDummy + 10 ReDim $aProp[$iNewSize] $aProp[0] = UBound($aProp) - 1 ; Initialize Template (if it doesn't already exist) If Not IsMap($aProp[2]) Then Local $mMap[] ; in Autoit allways controls start from 3 $aProp[1] = $mMap ; General Properties $aProp[2] = $mMap ; Template Empty Map EndIf EndIf ; Map Selection (or Template) Local $m = (IsMap($aProp[$idDummy]) ? $aProp[$idDummy] : $aProp[2]) Select Case $vName = Default Return $aProp[$idDummy] ; GET MAP Case IsMap($vName) $aProp[$idDummy] = $vName ; SET MAP If $vVal = Default And MapExists($vName, "UC_hWnd") Then _UC_Redraw($vName.UC_hWnd) Return 1 Case Else If $vVal = Default Then ; GET Val If MapExists($m, $vName) Then Return $m[$vName] Else Return SetError(1, 0, $m) EndIf Else ; SET Val If $vName = "@Delete" Then $aProp[$idDummy] = "" If $vVal = Default Then _UC_Redraw($m.UC_hWnd) Return 1 EndIf $m[$vName] = $vVal $aProp[$idDummy] = $m _UC_Redraw($m.UC_hWnd) Return 1 EndIf EndSelect EndFunc ;==>_UC_Properties Func _UC_Get($idCtrl = Default, $sProp = Default) If $idCtrl = Default Then $idCtrl = _UC_Properties(1, "UC_ActiveControlID") If Not $idCtrl Then Return SetError(1, 0, 0) If $sProp = Default Then Return $idCtrl EndIf Return _UC_Properties($idCtrl, $sProp) EndFunc ;==>_UC_Get Func _UC_Set($idCtrl = Default, $sProp = Default, $vValue = Default) If $idCtrl = Default Then $idCtrl = _UC_Properties(1, "UC_ActiveControlID") If Not $idCtrl Then Return SetError(1, 0, 0) If $sProp = Default Then Return $idCtrl EndIf Return _UC_Properties($idCtrl, $sProp, $vValue) EndFunc ;==>_UC_Set Func _UC_Destroy($hParent = Default, $idDummy = Default) Local $m, $aAll = _UC_Properties(Default) ; $hParent=Default => Bulk Delete All If $hParent = Default Then For $i = 3 To $aAll[0] $m = $aAll[$i] If IsMap($m) Then If MapExists($m, "UC_hWnd") Then _WinAPI_RemoveProp($m.UC_hWnd, "UC_ControlID") GUIDelete($m.UC_hWnd) EndIf _UC_Properties($i, "@Delete", True) EndIf Next Return 1 Else ; $idDummy=Default => Bulk delete All from $hParent UC_hParent If $idDummy = Default Then For $i = 3 To $aAll[0] $m = $aAll[$i] If IsMap($m) Then If MapExists($m, "UC_hWnd") Then If $m.UC_hParent = $hParent Then _WinAPI_RemoveProp($m.UC_hWnd, "UC_ControlID") GUIDelete($m.UC_hWnd) _UC_Properties($i, "@Delete", True) EndIf EndIf EndIf Next Return 1 Else ; Individual deletion $m = $aAll[$idDummy] If MapExists($m, "UC_hWnd") Then _WinAPI_RemoveProp($m.UC_hWnd, "UC_ControlID") GUIDelete($m.UC_hWnd) EndIf Return _UC_Properties($idDummy, "@Delete", True) EndIf EndIf EndFunc ;==>_UC_Destroy Func _UC_Refresh($hWnd) Return _WinAPI_RedrawWindow($hWnd, 0, 0, BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_ALLCHILDREN)) EndFunc ;==>_UC_Refresh Func _UC_GUISetBkColor($iBkColor, $hWnd) GUISetBkColor($iBkColor, $hWnd) _WinAPI_SetProp($hWnd, "UC_GUIBkColor", $iBkColor) EndFunc ;==>_UC_GUISetBkColor Func _UC_GetContrastColor($iBkColor) ;, $iPrecent = 20) 🚧 ; Extract RGB components Local $iR = BitAND(BitShift($iBkColor, 16), 0xFF) Local $iG = BitAND(BitShift($iBkColor, 8), 0xFF) Local $iB = BitAND($iBkColor, 0xFF) ; Calculate perceived brightness Local $iLuminance = (0.299 * $iR) + (0.587 * $iG) + (0.114 * $iB) ; Calculate Hover and Pressed colors (Logic: BGR for WinAPI) ;~ Local $iBGR = _WinAPI_SwitchColor($iBkColor) ; If background is bright, return a semi-transparent dark stroke ; If background is dark, return a semi-transparent light stroke If $iLuminance > 128 Then Return 0x80000000 ; Semi-transparent Black ;~ Return _WinAPI_SwitchColor(_WinAPI_ColorAdjustLuma($iBGR, - $iPrecent)) ; 20% Darker Else Return 0x80FFFFFF ; Semi-transparent White ;~ Return _WinAPI_SwitchColor(_WinAPI_ColorAdjustLuma($iBGR, $iPrecent)) ; 20% Lighter EndIf EndFunc ;==>_UC_GetContrastColor Func _UC_SetCursor($idCtrl, $iCursorID = 0) Local $hWnd = _UC_Get($idCtrl, "UC_hWnd") Return GUISetCursor($iCursorID, 0, $hWnd) EndFunc ;==>_UC_SetCursor Func _UC_ToolTip($sText, $iX = -1, $iY = -1, $hParent = 0) Local Static $hToolTipGUI = 0, $idLabel = 0, $idFrame = 0 Local $m = _UC_Properties(1) ; Retrieve global properties/settings context ; Initialization (Run once) If $hToolTipGUI = 0 Then ; Create popup window with ToolWindow style to hide from taskbar $hToolTipGUI = GUICreate("UC_ToolTip", 100, 20, -1, -1, $WS_POPUP, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST, $WS_EX_TRANSPARENT), $hParent) $m.UC_ToolTip_hWnd = $hToolTipGUI ; Default Style Settings Local $iBk = 0xFFF8D4 ; Classic tooltip yellow $m.UC_ToolTip_BkColor = $iBk $m.UC_ToolTip_TxtColor = ($iBk < 0x888888 ? 0xFFFFFF : 0x000000) $m.UC_ToolTip_Transparency = 220 $m.UC_ToolTip_FontName = "Segoe UI" $m.UC_ToolTip_FontSize = 9 $m.UC_ToolTip_FontWeight = 400 $m.UC_ToolTip_FontAttribute = 0 ; Create GUI Controls $idFrame = GUICtrlCreateLabel("", 0, 0, 100, 20, $SS_BLACKFRAME) GUICtrlSetState(-1, $GUI_DISABLE) $idLabel = GUICtrlCreateLabel("", 5, 2, 90, 16) GUICtrlSetColor(-1, $m.UC_ToolTip_TxtColor) GUICtrlSetFont(-1, $m.UC_ToolTip_FontSize, $m.UC_ToolTip_FontWeight, $m.UC_ToolTip_FontAttribute, $m.UC_ToolTip_FontName) GUISetBkColor($m.UC_ToolTip_BkColor, $hToolTipGUI) WinSetTrans($hToolTipGUI, "", $m.UC_ToolTip_Transparency) EndIf ; Handle Hide State If $sText == "" Then If BitAND(WinGetState($hToolTipGUI), 2) Then GUISetState(@SW_HIDE, $hToolTipGUI) $m.UC_ToolTip_Text = "" _UC_Properties(1, $m, False) ; update the map Return EndIf ; Optimization: Skip update if text is unchanged (only update position) If $m.UC_ToolTip_Text = $sText Then If $iX = -1 Then Local $aPos = MouseGetPos() WinMove($hToolTipGUI, "", $aPos[0] + 15, $aPos[1] + 15) EndIf Return EndIf $m.UC_ToolTip_Text = $sText ; Update stored text _UC_Properties(1, $m, False) ; update the map ; Dynamic Sizing Logic Local $aTextSize = _UC_GetTextSize($sText, $m.UC_ToolTip_FontName, $m.UC_ToolTip_FontSize) Local $iWidth = $aTextSize[0] + 10 ; Add horizontal padding Local $iHeight = $aTextSize[1] + 4 ; Add vertical padding If $iWidth < 40 Then $iWidth = 40 ; Enforce minimum width ; Positioning If $iX = -1 Then Local $aMousePos = MouseGetPos() $iX = $aMousePos[0] + 15 $iY = $aMousePos[1] + 15 EndIf If $iX + $iWidth > @DesktopWidth Then $iX = @DesktopWidth - $iWidth If $iY + $iHeight > @DesktopHeight Then $iY = @DesktopHeight - $iHeight ; Apply Changes and Display WinMove($hToolTipGUI, "", $iX, $iY, $iWidth, $iHeight) GUICtrlSetPos($idFrame, 0, 0, $iWidth, $iHeight) GUICtrlSetPos($idLabel, 5, 2, $iWidth - 10, $iHeight - 4) GUICtrlSetData($idLabel, $sText) ; Show without stealing focus If Not BitAND(WinGetState($hToolTipGUI), 2) Then GUISetState(@SW_SHOWNOACTIVATE, $hToolTipGUI) EndFunc ;==>_UC_ToolTip Func _UC_GetTextSize($sString, $sFont = "Segoe UI", $fFontSize = 9, $iFontStyle = 0) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND(_WinAPI_GetDesktopWindow()) Local $hFamily = _GDIPlus_FontFamilyCreate($sFont) Local $hFont = _GDIPlus_FontCreate($hFamily, $fFontSize, $iFontStyle) Local $hFormat = _GDIPlus_StringFormatCreate() Local $tLayout = _GDIPlus_RectFCreate(0, 0, 0, 0) ; aInfo[0] contains the $tagGDIPRECTF with the calculated dimensions Local $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $sString, $hFont, $tLayout, $hFormat) Local $aSize[2] If Not @error Then $aSize[0] = Ceiling(DllStructGetData($aInfo[0], "Width")) $aSize[1] = Ceiling(DllStructGetData($aInfo[0], "Height")) Else $aSize[0] = 0 $aSize[1] = 0 EndIf ; Cleanup resources _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_GraphicsDispose($hGraphics) Return $aSize EndFunc ;==>_UC_GetTextSize Func _UC_IsMouseOver($hWnd) Local $tPoint = _WinAPI_GetMousePos() Return (_WinAPI_WindowFromPoint($tPoint) = $hWnd) EndFunc #EndRegion ; ~~~~~~~~~~~~~ Generic UC API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ Framework Internal Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func __UC_Framework_Init($hParent) Static $bInitialized = False If $bInitialized Then Return _GDIPlus_Startup() GUIRegisterMsg($WM_ERASEBKGND, "__UC_Main_MsgHandler") GUIRegisterMsg($WM_PAINT, "__UC_Main_MsgHandler") GUIRegisterMsg($WM_LBUTTONDOWN, "__UC_Main_MsgHandler") GUIRegisterMsg($WM_MOUSEMOVE, "__UC_Main_MsgHandler") GUIRegisterMsg($WM_LBUTTONUP, "__UC_Main_MsgHandler") GUIRegisterMsg($WM_SETFOCUS, "__UC_Main_MsgHandler") GUIRegisterMsg($WM_KEYDOWN, "__UC_Main_MsgHandler") OnAutoItExitRegister("__UC_Framework_Shutdown") _UC_ToolTip("", -1, -1, $hParent) Local $aCursorType = StringSplit("Hand|AppStarting|Arrow|Cross|Help|IBeam|Icon|No|" & _ "Size|SizeAll|SizeNESW|SizeNS|SizeNWSE|SizeWE|UpArrow|Wait|None", "|", 2) For $i = 0 To UBound($aCursorType) - 1 _UC_Properties(1, "Cursor_" & $aCursorType[$i], $i) Next $bInitialized = True EndFunc ;==>__UC_Framework_Init Func __UC_Main_MsgHandler($hWnd, $iMsg, $wParam, $lParam) #forceref $wParam Local Static $hLastChild = 0, $hToolTipGUI = _UC_Properties(1, "UC_ToolTip_hWnd") If $hToolTipGUI = $hWnd Then Return $GUI_RUNDEFMSG ; First we check if the previous control needs "Reset" ; This must be done regardless of whether $hWnd is a UC control or not. If $hLastChild And $hLastChild <> $hWnd Then Local $idLast = _WinAPI_GetProp($hLastChild, "UC_ControlID") If $idLast Then Local $mLast = _UC_Properties($idLast) ; Only if it is not already Normal or Disabled If $mLast.State <> 1 Then _UC_ToolTip("") If $mLast.State <> 0 Then $mLast.State = 1 _UC_Properties($idLast, $mLast) EndIf EndIf EndIf $hLastChild = 0 EndIf ; Now we check the current window Local $idDummy = _WinAPI_GetProp($hWnd, "UC_ControlID") If Not $idDummy Then Return $GUI_RUNDEFMSG ; If we got here, we are in UC Control. Local $iCtrlType = _UC_Properties($idDummy, "UC_Type") Local $iX = BitAND($lParam, 0xFFFF) Local $iY = BitShift($lParam, 16) Switch $iMsg Case $WM_PAINT _UC_Redraw($hWnd) Local $tPAINTSTRUCT = DllStructCreate($tagPAINTSTRUCT) _WinAPI_BeginPaint($hWnd, $tPAINTSTRUCT) _WinAPI_EndPaint($hWnd, $tPAINTSTRUCT) Return 0 Case $WM_ERASEBKGND Return 1 Case $WM_LBUTTONDOWN Switch $iCtrlType Case $UC_TYPE_TOGGLE _UC_Toggle_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_SLIDER _UC_Slider_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_BUTTON _UC_Button_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_LINK _UC_Link_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) EndSwitch Return 0 Case $WM_LBUTTONUP Switch $iCtrlType Case $UC_TYPE_TOGGLE _UC_Toggle_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_SLIDER _UC_Slider_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_BUTTON _UC_Button_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_LINK _UC_Link_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) EndSwitch Return 0 Case $WM_MOUSEMOVE Switch $iCtrlType Case $UC_TYPE_TOGGLE _UC_Toggle_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_SLIDER _UC_Slider_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_BUTTON _UC_Button_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_LINK _UC_Link_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) EndSwitch $hLastChild = $hWnd _UC_Properties(1, "UC_ActiveControlID", Int($idDummy)) _UC_Properties(1, "UC_ActiveControlType", Int($iCtrlType)) Return 0 Case $WM_SETFOCUS Switch $iCtrlType Case $UC_TYPE_TOGGLE _UC_Toggle_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_SLIDER _UC_Slider_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_BUTTON _UC_Button_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) Case $UC_TYPE_LINK _UC_Link_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) EndSwitch ;ConsoleWrite( "$hWnd:" & $hWnd & ", XY:" & $iX & ", " & $iY & @CRLF) $hLastChild = $hWnd _UC_Properties(1, "UC_ActiveControlID", Int($idDummy)) _UC_Properties(1, "UC_ActiveControlType", Int($iCtrlType)) Return 0 Case $WM_KEYDOWN ; $wParam contains the key code (Virtual Key Code) ; ConsoleWrite("$wParam=" & $wParam & @CRLF) Switch $wParam Case $VK_SPACE ; (Space bar) Switch $iCtrlType Case $UC_TYPE_TOGGLE _UC_Toggle_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Sleep(50) _UC_Toggle_WM_LBUTTONUP($idDummy, $hWnd, -1, -1) Case $UC_TYPE_BUTTON _UC_Button_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Sleep(50) _UC_Button_WM_LBUTTONUP($idDummy, $hWnd, -1, -1) Case $UC_TYPE_LINK _UC_Link_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Sleep(50) _UC_Link_WM_LBUTTONUP($idDummy, $hWnd, -1, -1) EndSwitch Return 0 Case $VK_ADD ;, $VK_RIGHT, $VK_UP Switch $iCtrlType Case $UC_TYPE_SLIDER _UC_Slider_UpdateFromValue($idDummy, 1) EndSwitch Return 0 Case $VK_SUBTRACT ;, $VK_LEFT, $VK_DOWN Switch $iCtrlType Case $UC_TYPE_SLIDER _UC_Slider_UpdateFromValue($idDummy, -1) EndSwitch Return 0 ;~ Case Else ;~ ConsoleWrite("Case Else: $wParam=" & $wParam & @CRLF) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>__UC_Main_MsgHandler Func __UC_ParentColor($hWnd) Local $hParent = _WinAPI_GetParent($hWnd) Local $iCol = _WinAPI_GetProp($hParent, "UC_GUIBkColor") Return ($iCol ? $iCol : _WinAPI_GetSysColor($COLOR_BTNFACE)) ; $COLOR_BTNFACE as Default EndFunc ;==>__UC_ParentColor Func __UC_Framework_Shutdown() _UC_Destroy() _GDIPlus_Shutdown() EndFunc ;==>__UC_Framework_Shutdown Func __DW($sString, $iErrorNoLineNo = 1, $iLine = @ScriptLineNumber, $iError = @error, $iExtended = @extended) If Not $g_UC_DebugInfo Then Return SetError($iError, $iExtended, 0) Local $iReturn If $iErrorNoLineNo = 1 Then If $iError Then $iReturn = ConsoleWrite("@@(" & $iLine & ") :: @error:" & $iError & ", @extended:" & $iExtended & ", " & $sString) Else $iReturn = ConsoleWrite("+>(" & $iLine & ") :: " & $sString) EndIf Else $iReturn = ConsoleWrite($sString) EndIf ; Remarks: The @error and @extended are not set on return leaving them as they were before calling. Return SetError($iError, $iExtended, $iReturn) EndFunc ;==>__DW #EndRegion ; ~~~~~~~~~~~~~ Framework Internal Functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ Helper Functions for Map Management ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _Map2D(Const ByRef $mMap) Local $aMapKeys = MapKeys($mMap) Local $aMap2D[UBound($aMapKeys)][2] For $i = 0 To UBound($aMapKeys) - 1 $aMap2D[$i][0] = $aMapKeys[$i] $aMap2D[$i][1] = $mMap[$aMapKeys[$i]] Next Return $aMap2D EndFunc ;==>_Map2D Func _ClearMap(ByRef $mMap) Local $m[] $mMap = $m EndFunc ;==>_ClearMap Func _MapCW(ByRef $m, $sTitle = "--- Map info ---") ; ConsoleWrite map ConsoleWrite($sTitle & @CRLF) Local $aObject = _Map2D($m) Local $iMaxKeyLen = 0 Local $sKey For $i = 0 To UBound($aObject) - 1 $sKey = $aObject[$i][0] If StringLen($sKey) > $iMaxKeyLen Then $iMaxKeyLen = StringLen($sKey) EndIf Next For $i = 0 To UBound($aObject) - 1 $sKey = $aObject[$i][0] Local $vValue = $aObject[$i][1] Local $sPadding = _StringRepeat(" ", $iMaxKeyLen - StringLen($sKey) + 1) Local $sDim, $sLabel = "" Local $iDimension If IsMap($vValue) Then $sLabel = "= {Map[" & UBound($vValue) & "]}" ConsoleWrite($sKey & $sPadding & $sLabel & @CRLF) ElseIf IsArray($vValue) Then $iDimension = UBound($vValue, $UBOUND_DIMENSIONS) ; The dimension of the array e.g. 1/2/3 dimensional. $sDim = "" For $d = 1 To $iDimension $sDim &= "[" & UBound($vValue, $d) & "]" Next $sLabel = "= {Array" & $sDim & "}" ConsoleWrite($sKey & $sPadding & $sLabel & @CRLF) Else ConsoleWrite($sKey & $sPadding & "= " & $vValue & @CRLF) EndIf Next EndFunc ;==>_MapCW #EndRegion ; ~~~~~~~~~~~~~ Helper Functions for Map Management ~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ Helper Functions for Window Properties (WinAPI) ~~~~~~~~~~~~~~~ Func _WinAPI_SetProp($hWnd, $sName, $iVal) Local $aRet = DllCall("user32.dll", "bool", "SetPropW", "hwnd", $hWnd, "wstr", $sName, "handle", $iVal) Return $aRet[0] EndFunc ;==>_WinAPI_SetProp Func _WinAPI_GetProp($hWnd, $sName) Local $aRet = DllCall("user32.dll", "handle", "GetPropW", "hwnd", $hWnd, "wstr", $sName) Return $aRet[0] EndFunc ;==>_WinAPI_GetProp Func _WinAPI_RemoveProp($hWnd, $sName) Local $aRet = DllCall("user32.dll", "ptr", "RemovePropW", "hwnd", $hWnd, "wstr", $sName) Return $aRet[0] EndFunc ;==>_WinAPI_RemoveProp #EndRegion ; ~~~~~~~~~~~~~ Helper Functions for Window Properties (WinAPI) ~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ UC Toggle API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _UC_Toggle_Create($hParent, $iX, $iY, $iW, $iH, $iType = 0, $hOnCol = 0x4CD964, $hOffCol = 0xD1D1D1, $hBtnCol = 0xFFFFFF) GUISwitch($hParent) Local $idDummy = GUICtrlCreateDummy() Local $hChild = GUICreate("UC_Control_" & $idDummy, $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS, $WS_TABSTOP), $WS_EX_TRANSPARENT, $hParent) __UC_Framework_Init($hParent) GUISetCursor(_UC_Get(1, "Cursor_Hand"), $GUI_CURSOR_OVERRIDE, $hChild) Local $m[] ; Universal Properties $m.UC_Type = $UC_TYPE_TOGGLE $m.UC_ControlID = $idDummy $m.UC_hWnd = $hChild $m.UC_hParent = $hParent ; Specific properties for the toggle control $m.State = 1 ; Initially enabled (State 0=Disabled, 1=Normal, 2=Hover, 3=Pressed) $m.Type = $iType ; Type of toggle (0=ROUNDED, 1=RECTANGLE) $m.Value = 0 ; Initial value (0=off, 1=on) $m.OnColor = $hOnCol ; Color when the toggle is on $m.OffColor = $hOffCol ; Color when the toggle is off $m.BtnColor = $hBtnCol ; Color of the Thumb button _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy) _UC_Properties($idDummy, $m) _UC_Properties(1, "UC_LastCreatedID", $idDummy) GUISwitch($hParent) Return $idDummy EndFunc ;==>_UC_Toggle_Create Func _UC_Toggle_Draw($hWnd, ByRef $m) Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd) Local $aSize = WinGetClientSize($hWnd) Local $iW = $aSize[0], $iH = $aSize[1] ;~ GUISetCursor(_UC_Get(1, ($m.State == 0 ? "Cursor_Arrow" : "Cursor_Hand")), $GUI_CURSOR_OVERRIDE, $hWnd) ;~ ; State-based color selection ;~ Switch $m.State ;~ Case 0 ; Disabled ;~ $hDrawCol = $m.DisableColor ;~ $hTextCol = $m.DisableTxtColor ;~ Case 2 ; Hover ;~ $hDrawCol = $m.HoverColor ;~ Case 3 ; Pressed ;~ $hDrawCol = $m.PressColor ;~ Case Else ; Normal (1) ;~ $hDrawCol = $m.BtnColor ;~ EndSwitch ; Buffer Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics) Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap) ; Settings for Sharpening _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; HighQuality Antialiasing _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4) ; HighQuality (Half-pixel offset) ; _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5) ; AntiAliasGridFit (Crisp Text) ; Clear background with parent color _GDIPlus_GraphicsClear($hBack, $hBGColor) Local $hColor = "0xFF" & Hex($m.Value ? $m.OnColor : $m.OffColor, 6) Local $hBrushBg = _GDIPlus_BrushCreateSolid($hColor) Local $hBrushBtn = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.BtnColor, 6)) Local $hPenHotTrack = _GDIPlus_PenCreate("0x80" & Hex($m.BtnColor, 6), 4) ; HotTrack If $m.Type = 0 Then ; ROUND Local $hPath = _GDIPlus_PathCreate() _GDIPlus_PathAddArc($hPath, 0, 0, $iH, $iH, 180, 90) _GDIPlus_PathAddArc($hPath, $iW - $iH, 0, $iH, $iH, 270, 90) _GDIPlus_PathAddArc($hPath, $iW - $iH, 0, $iH, $iH, 0, 90) _GDIPlus_PathAddArc($hPath, 0, 0, $iH, $iH, 90, 90) _GDIPlus_PathCloseFigure($hPath) _GDIPlus_GraphicsFillPath($hBack, $hPath, $hBrushBg) _GDIPlus_PathDispose($hPath) Local $iXPos = $m.Value ? ($iW - $iH + 2) : 2 _GDIPlus_GraphicsFillEllipse($hBack, $iXPos, 2, $iH - 4, $iH - 4, $hBrushBtn) If $m.State = 2 Then _GDIPlus_GraphicsDrawEllipse($hBack, $iXPos, 2, $iH - 4, $iH - 4, $hPenHotTrack) Else ; RECT _GDIPlus_GraphicsFillRect($hBack, 0, 0, $iW, $iH, $hBrushBg) Local $iSqW = ($iW / 3) - 4 Local $iSqX = $m.Value ? ($iW - $iSqW - 2) : 2 _GDIPlus_GraphicsFillRect($hBack, $iSqX, 2, $iSqW, $iH - 4, $hBrushBtn) If $m.State = 2 Then _GDIPlus_GraphicsDrawRect($hBack, $iSqX, 2, $iSqW, $iH - 4, $hPenHotTrack) EndIf ; Double Buffering: Copy backbuffer to screen _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $iW, $iH) _GDIPlus_PenDispose($hPenHotTrack) _GDIPlus_BrushDispose($hBrushBg) _GDIPlus_BrushDispose($hBrushBtn) _GDIPlus_GraphicsDispose($hBack) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_GraphicsDispose($hGraphics) EndFunc ;==>_UC_Toggle_Draw Func _UC_Toggle_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled $m.State = 3 ; is pressed _UC_Properties($idDummy, $m) _WinAPI_SetCapture($hWnd) EndFunc ;==>_UC_Toggle_WM_LBUTTONDOWN Func _UC_Toggle_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) #forceref $idDummy, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 3 Then ; If is pressed _WinAPI_ReleaseCapture() ; Area control If _UC_IsMouseOver($hWnd) Or ($iX = -1 And $iY = -1) Then $m.State = 2 ; Hover $m.Value = ($m.Value = 1 ? 0 : 1) _UC_Properties($idDummy, $m) GUICtrlSendToDummy($idDummy, $m.Value) ; Execution! Else $m.State = 1 ; Normal (Cancel execution) _UC_Properties($idDummy, $m) EndIf EndIf EndFunc ;==>_UC_Button_WM_LBUTTONUP Func _UC_Toggle_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled If $m.State = 1 Then ; If is normal $m.State = 2 ; Hover _UC_Properties($idDummy, $m) EndIf EndFunc ;==>_UC_Toggle_WM_MOUSEMOVE #EndRegion ; ~~~~~~~~~~~~~ UC Toggle API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ UC Slider API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _UC_Slider_Create($hParent, $iX, $iY, $iW, $iH, $iMin = 0, $iMax = 100, $iValue = 0, $iType = 0, _ $hCol = 0x4CD964, $hTrackCol = 0xD1D1D1, $hThumbCol = 0xFFFFFF, $iTrackSize = 4) GUISwitch($hParent) Local $idDummy = GUICtrlCreateDummy() Local $hChild = GUICreate("UC_Control_" & $idDummy, $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS, $WS_TABSTOP), $WS_EX_TRANSPARENT, $hParent) __UC_Framework_Init($hParent) GUISetCursor(_UC_Get(1, "Cursor_Hand"), $GUI_CURSOR_OVERRIDE, $hChild) Local $m[], $iShowTooltip = 0, $iThumbType = 0 ; Universal Properties $m.UC_Type = $UC_TYPE_SLIDER $m.UC_ControlID = $idDummy $m.UC_hWnd = $hChild $m.UC_hParent = $hParent ; Toggle Specific Properties $m.State = 1 ; 0=Disable ; 1=Normal ; 2=Hover ; 3=Pressed $m.IsDragging = 0 ; Is now Dragging $m.DragOffset = 0 ; DragOffset property $m.Min = $iMin ; Min Value $m.Max = $iMax ; Max Value $m.Value = $iValue ; curent Value $m.Type = $iType ; 0=Horizontal; 1=Vertical $m.ThumbType = $iThumbType ; 0=Round; 1=Rectangular $m.ShowTooltip = $iShowTooltip ; show Tooltip while dragging $m.Color = $hCol ; Color $m.TrackColor = $hTrackCol ; TrackColor $m.ThumbColor = $hThumbCol ; ThumbColor $m.TrackSize = $iTrackSize ; Size of Color line _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy) _UC_Properties($idDummy, $m) _UC_Properties(1, "UC_LastCreatedID", $idDummy) GUISwitch($hParent) Return $idDummy EndFunc ;==>_UC_Slider_Create Func _UC_Slider_Draw($hWnd, ByRef $m) Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd) Local $aSize = WinGetClientSize($hWnd) Local $iW = $aSize[0], $iH = $aSize[1] ;~ GUISetCursor(_UC_Get(1, ($m.State == 0 ? "Cursor_Arrow" : "Cursor_Hand")), $GUI_CURSOR_OVERRIDE, $hWnd) ; Buffer Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics) Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap) ; Settings for Sharpening _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; HighQuality Antialiasing _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4) ; HighQuality (Half-pixel offset) ; _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5) ; AntiAliasGridFit (Crisp Text) ; Clear background with parent color _GDIPlus_GraphicsClear($hBack, $hBGColor) ; Percentage calculation (Float) Local $iRange = $m.Max - $m.Min If $iRange <= 0 Then $iRange = 1 Local $fPercent = ($m.Value - $m.Min) / $iRange ; Paints & Pens Local $hBrushTrack = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.TrackColor, 6)) Local $hBrushFill = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.Color, 6)) Local $hBrushThumb = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.ThumbColor, 6)) Local $hPenThumbBorder = _GDIPlus_PenCreate(0xFF888888, 1) Local $hPenHotTrack = _GDIPlus_PenCreate("0x80" & Hex($m.ThumbColor, 6), 4) ; HotTrack Local $iThumbSizeH, $iThumbSizeW If $m.Type = 0 Then ; HORIZONTAL If $m.ThumbType = 0 Then ; Round Thumb $iThumbSizeH = $iH - 4 $iThumbSizeW = $iThumbSizeH Else ; Rectangular Thumb $iThumbSizeH = $iH - 4 $iThumbSizeW = $iThumbSizeH / 2 EndIf Local $iXPos = (($iW - $iThumbSizeW - 1) * $fPercent) Local $iTrackY = ($iH - $m.TrackSize) / 2 _GDIPlus_GraphicsFillRect($hBack, ($iThumbSizeW / 4), $iTrackY, $iW - ($iThumbSizeW / 2), $m.TrackSize, $hBrushTrack) _GDIPlus_GraphicsFillRect($hBack, ($iThumbSizeW / 4), $iTrackY, $iXPos + ($iThumbSizeW / 2), $m.TrackSize, $hBrushFill) If $m.ThumbType = 0 Then ; Round Thumb _GDIPlus_GraphicsFillEllipse($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $hBrushThumb) _GDIPlus_GraphicsDrawEllipse($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $hPenThumbBorder) If $m.State = 2 Then _GDIPlus_GraphicsDrawEllipse($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $hPenHotTrack) Else ; Rectangular Thumb _GDIPlus_GraphicsFillRect($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $hBrushThumb) _GDIPlus_GraphicsDrawRect($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $hPenThumbBorder) If $m.State = 2 Then _GDIPlus_GraphicsDrawRect($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $hPenHotTrack) EndIf Else ; VERTICAL If $m.ThumbType = 0 Then ; Round Thumb $iThumbSizeH = $iW - 4 $iThumbSizeW = $iThumbSizeH Else ; Rectangular Thumb $iThumbSizeW = $iW - 4 $iThumbSizeH = $iThumbSizeW / 2 EndIf Local $iYPos = ($iH - $iThumbSizeH - 1) - (($iH - $iThumbSizeH - 2) * $fPercent) Local $iTrackX = ($iW - $m.TrackSize) / 2 _GDIPlus_GraphicsFillRect($hBack, $iTrackX, ($iThumbSizeH / 4), $m.TrackSize, $iH - ($iThumbSizeH / 2), $hBrushTrack) _GDIPlus_GraphicsFillRect($hBack, $iTrackX, $iYPos + ($iThumbSizeH / 4), $m.TrackSize, $iH - $iYPos - ($iThumbSizeH / 2), $hBrushFill) If $m.ThumbType = 0 Then ; Round Thumb _GDIPlus_GraphicsFillEllipse($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $hBrushThumb) _GDIPlus_GraphicsDrawEllipse($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $hPenThumbBorder) If $m.State = 2 Then _GDIPlus_GraphicsDrawEllipse($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $hPenHotTrack) Else ; Rectangular Thumb _GDIPlus_GraphicsFillRect($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $hBrushThumb) _GDIPlus_GraphicsDrawRect($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $hPenThumbBorder) If $m.State = 2 Then _GDIPlus_GraphicsDrawRect($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $hPenHotTrack) EndIf EndIf ; Double Buffering: Copy backbuffer to screen _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $iW, $iH) ; Clean up _GDIPlus_PenDispose($hPenHotTrack) _GDIPlus_PenDispose($hPenThumbBorder) _GDIPlus_BrushDispose($hBrushTrack) _GDIPlus_BrushDispose($hBrushFill) _GDIPlus_BrushDispose($hBrushThumb) _GDIPlus_GraphicsDispose($hBack) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_GraphicsDispose($hGraphics) EndFunc ;==>_UC_Slider_Draw Func _UC_Slider_UpdateFromMouse($hWnd, ByRef $m, $iX, $iY) Local $aSize = WinGetClientSize($hWnd) ; Fix for negative values (when mouse moves left/up) ; Windows sends 16-bit signed values in lParam If $iX > 32767 Then $iX -= 65536 If $iY > 32767 Then $iY -= 65536 ; Calculate the offset to center the thumb on the mouse position Local $iThumbSize, $iAvailableTrack, $fPercent = 0 If $m.Type = 0 Then ; HORIZONTAL ; The thumb starts at 0 and reaches the GUI width minus its own width $iThumbSize = $aSize[1] ; In horizontal, the thumb's width is the height of the GUI $iAvailableTrack = $aSize[0] - $iThumbSize $fPercent = ($iX - ($iThumbSize / 2)) / $iAvailableTrack Else ; VERTICAL $iThumbSize = $aSize[0] ; In vertical, the thumb's height is the width of the GUI $iAvailableTrack = $aSize[1] - $iThumbSize ; For vertical, by default 0 is below, so: $fPercent = ($aSize[1] - $iY - ($iThumbSize / 2)) / $iAvailableTrack EndIf ; LIMITATION If $fPercent < 0 Then $fPercent = 0 If $fPercent > 1 Then $fPercent = 1 Local $iNewVal = Int($m.Min + ($fPercent * ($m.Max - $m.Min))) If $iNewVal <> $m.Value Then $m.Value = $iNewVal _UC_Properties($m.UC_ControlID, $m) GUICtrlSendToDummy($m.UC_ControlID, $iNewVal) If $m.ShowTooltip Then _UC_ToolTip($iNewVal) EndIf EndFunc ;==>_UC_Slider_UpdateFromMouse Func _UC_Slider_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled $m.IsDragging = 1 $m.State = 3 ; Pressed If $m.ShowTooltip Then _UC_ToolTip(String($m.Value)) _UC_Properties($idDummy, $m, False) ; *** False to avoid _UC_Redraw _WinAPI_SetCapture($hWnd) _UC_Slider_UpdateFromMouse($hWnd, $m, $iX, $iY) EndFunc ;==>_UC_Slider_WM_LBUTTONDOWN Func _UC_Slider_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled $m.State = 2 ; Hover If $m.IsDragging Then $m.IsDragging = 0 _UC_Properties($idDummy, $m) _WinAPI_ReleaseCapture() _UC_ToolTip("") EndIf EndFunc ;==>_UC_Slider_WM_LBUTTONUP Func _UC_Slider_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled If $m.IsDragging Then _UC_Slider_UpdateFromMouse($hWnd, $m, $iX, $iY) Else If $m.State <> 0 And $m.State <> 2 And $m.State <> 3 Then $m.State = 2 ; Hover _UC_Properties($idDummy, $m) EndIf EndIf EndFunc ;==>_UC_Slider_WM_MOUSEMOVE Func _UC_Slider_UpdateFromValue($idDummy = Default, $iValue = 1) If $idDummy = Default Then $idDummy = _UC_Properties(1, "UC_ActiveControlID") If Not $idDummy Then Return SetError(1, 0, 0) Local $m = _UC_Properties($idDummy) If Not ($m.UC_Type = $UC_TYPE_SLIDER) Then Return SetError(2, 0, 0) Local $iNewValue $iNewValue = $m.Value + $iValue $iNewValue = ($iNewValue > $m.Max ? $m.Max : $iNewValue) $iNewValue = ($iNewValue < $m.Min ? $m.Min : $iNewValue) $m.Value = $iNewValue _UC_Properties($idDummy, $m) GUICtrlSendToDummy($idDummy, $iNewValue) EndFunc ;==>_UC_Slider_UpdateFromValue #EndRegion ; ~~~~~~~~~~~~~ UC Slider API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ UC Button API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _UC_Button_Create($hParent, $sText, $iX, $iY, $iW, $iH, $iCorner = 0, $hBtnCol = 0xFFFFFF, $hTxtCol = 0x000000) GUISwitch($hParent) Local $idDummy = GUICtrlCreateDummy() Local $hChild = GUICreate("", $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS, $WS_TABSTOP), $WS_EX_TRANSPARENT, $hParent) ; Store the button text in the Dummy control GUICtrlSetData($idDummy, $sText) __UC_Framework_Init($hParent) GUISetCursor(_UC_Get(1, "Cursor_Hand"), $GUI_CURSOR_OVERRIDE, $hChild) ; Calculate Hover and Pressed colors (Logic: BGR for WinAPI) Local $iBGR = _WinAPI_SwitchColor($hBtnCol) Local $iHov = _WinAPI_SwitchColor(_WinAPI_ColorAdjustLuma($iBGR, 20)) ; 20% Lighter Local $iPre = _WinAPI_SwitchColor(_WinAPI_ColorAdjustLuma($iBGR, -10)) ; 10% Darker Local $m[] ; Universal Properties $m.UC_Type = $UC_TYPE_BUTTON $m.UC_ControlID = $idDummy $m.UC_hWnd = $hChild $m.UC_hParent = $hParent ; Toggle Specific Properties $m.State = 1 ; 0=Disable ; 1=Normal ; 2=Hover ; 3=Pressed $m.CornerRadius = $iCorner $m.BtnColor = $hBtnCol $m.HoverColor = $iHov $m.PressColor = $iPre $m.TextColor = $hTxtCol $m.DisableColor = 0xCCCCCC $m.DisableTxtColor = 0x888888 $m.Text = $sText $m.Font = "Segoe UI" $m.FontSize = 9 $m.FontStyle = 0 ; 0=Normal ; 1=Bold ; 2=Italic ; 4=Underline; 8=Strikethrough $m.FontHorAlg = 1 ; Horizontal aligned ; 0=left ; 1=Center ; 2=right $m.FontVerAlg = 1 ; Vertical aligned ; 0=left ; 1=Center ; 2=right $m.ShowTooltip = 0 $m.Tooltip = "" _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy) _UC_Properties($idDummy, $m) _UC_Properties(1, "UC_LastCreatedID", $idDummy) GUISwitch($hParent) Return $idDummy EndFunc ;==>_UC_Button_Create Func _UC_Button_Draw($hWnd, ByRef $m) Local $aSize = WinGetClientSize($hWnd) Local $iW = $aSize[0], $iH = $aSize[1] If $iW <= 0 Or $iH <= 0 Then Return Local $iR = $m.CornerRadius Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6) Local $hDrawCol, $hTextCol = $m.TextColor ;~ GUISetCursor(_UC_Get(1, ($m.State == 0 ? "Cursor_Arrow" : "Cursor_Hand")), $GUI_CURSOR_OVERRIDE, $hWnd) ; State-based color selection Switch $m.State Case 0 ; Disabled $hDrawCol = $m.DisableColor $hTextCol = $m.DisableTxtColor Case 2 ; Hover $hDrawCol = $m.HoverColor Case 3 ; Pressed $hDrawCol = $m.PressColor Case Else ; Normal (1) $hDrawCol = $m.BtnColor EndSwitch ; Initialize GDI+ Context Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd) Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics) Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap) ; Settings for Sharpening _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; HighQuality Antialiasing _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4) ; HighQuality (Half-pixel offset) _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5) ; AntiAliasGridFit (Crisp Text) ; Clear background with parent color _GDIPlus_GraphicsClear($hBack, $hBGColor) ; Draw Button Shape Local $hBrushBg = _GDIPlus_BrushCreateSolid("0xFF" & Hex($hDrawCol, 6)) ; Apply "Golden Rule" for Pill Shape: Radius cannot exceed Height / 2 Local $iMaxR = $iH / 2 If $iR > $iMaxR Then $iR = $iMaxR If $iR > 0 Then Local $id = $iR * 2 Local $hPath = _GDIPlus_PathCreate() _GDIPlus_PathAddArc($hPath, 0, 0, $id, $id, 180, 90) _GDIPlus_PathAddArc($hPath, $iW - $id - 1, 0, $id, $id, 270, 90) _GDIPlus_PathAddArc($hPath, $iW - $id - 1, $iH - $id - 1, $id, $id, 0, 90) _GDIPlus_PathAddArc($hPath, 0, $iH - $id - 1, $id, $id, 90, 90) _GDIPlus_PathCloseFigure($hPath) _GDIPlus_GraphicsFillPath($hBack, $hPath, $hBrushBg) _GDIPlus_PathDispose($hPath) Else _GDIPlus_GraphicsFillRect($hBack, 0, 0, $iW, $iH, $hBrushBg) EndIf ; Draw Text (Self-contained font creation to prevent memory leaks) Local $hFamily = _GDIPlus_FontFamilyCreate($m.Font) Local $hFont = _GDIPlus_FontCreate($hFamily, $m.FontSize, $m.FontStyle) Local $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, $m.FontHorAlg) ; Horizontal aligned _GDIPlus_StringFormatSetLineAlign($hFormat, $m.FontVerAlg) ; Vertical aligned Local $hBrushTxt = _GDIPlus_BrushCreateSolid("0xFF" & Hex($hTextCol, 6)) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH) _GDIPlus_GraphicsDrawStringEx($hBack, $m.Text, $hFont, $tLayout, $hFormat, $hBrushTxt) ; Double Buffering: Copy backbuffer to screen _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) ; Cleanup Section: Dispose all local GDI+ objects _GDIPlus_BrushDispose($hBrushBg) _GDIPlus_BrushDispose($hBrushTxt) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_GraphicsDispose($hBack) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_GraphicsDispose($hGraphics) EndFunc ;==>_UC_Button_Draw Func _UC_Button_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled $m.State = 3 ; Pressed _UC_Properties($idDummy, $m) _WinAPI_SetCapture($hWnd) EndFunc ;==>_UC_Button_WM_LBUTTONDOWN Func _UC_Button_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) #forceref $idDummy, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 3 Then ; If is pressed _WinAPI_ReleaseCapture() ; Area control If _UC_IsMouseOver($hWnd) Or ($iX = -1 And $iY = -1) Then $m.State = 2 ; Hover _UC_Properties($idDummy, $m) GUICtrlSendToDummy($idDummy, $m.Text) ; Execution! Else $m.State = 1 ; Normal (Cancel execution) _UC_Properties($idDummy, $m) EndIf EndIf EndFunc ;==>_UC_Button_WM_LBUTTONUP Func _UC_Button_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled If $m.State = 1 Then ; If is normal $m.State = 2 ; Hover _UC_Properties($idDummy, $m) If $m.ShowTooltip And _UC_IsMouseOver($hWnd) Then _UC_ToolTip($m.Tooltip) EndIf EndFunc ;==>_UC_Button_WM_MOUSEMOVE #EndRegion ; ~~~~~~~~~~~~~ UC Button API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ UC Link API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _UC_Link_Create($hParent, $sText, $sURL, $iX, $iY, $iW, $iH, $iFontSize = 9, $hColor = 0x0094FF, $hHoverColor = 0xFF0000) GUISwitch($hParent) Local $idDummy = GUICtrlCreateDummy() Local $hChild = GUICreate("", $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS, $WS_TABSTOP), $WS_EX_TRANSPARENT, $hParent) __UC_Framework_Init($hParent) GUISetCursor(_UC_Get(1, "Cursor_Hand"), $GUI_CURSOR_OVERRIDE, $hChild) Local $m[] $m.UC_Type = $UC_TYPE_LINK $m.UC_ControlID = $idDummy $m.UC_hWnd = $hChild $m.UC_hParent = $hParent ; Link Specific $m.Text = $sText ; text to display $m.Value = $sURL ; link (local or remote) $m.State = 1 ; 0=Disable ; 1=Normal ; 2=Hover ; 3=Pressed $m.Color = $hColor ; Text Color $m.HoverColor = $hHoverColor ; hover Color $m.DisableTxtColor = 0x888888 ; Disabled Text Color $m.Font = "Segoe UI" $m.FontSize = $iFontSize $m.ShowTooltip = 0 _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy) _UC_Properties($idDummy, $m) _UC_Properties(1, "UC_LastCreatedID", $idDummy) GUISwitch($hParent) Return $idDummy EndFunc ;==>_UC_Link_Create Func _UC_Link_Draw($hWnd, ByRef $m) Local $aSize = WinGetClientSize($hWnd) Local $iW = $aSize[0], $iH = $aSize[1] Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6) ;~ GUISetCursor(_UC_Get(1, ($m.State == 0 ? "Cursor_Arrow" : "Cursor_Hand")), $GUI_CURSOR_OVERRIDE, $hWnd) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd) Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics) Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap) ; Settings for Sharpening _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; HighQuality Antialiasing _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4) ; HighQuality (Half-pixel offset) _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5) ; AntiAliasGridFit (Crisp Text) ; Clear background with parent color _GDIPlus_GraphicsClear($hBack, $hBGColor) ; Color and style selection based on State Local $iDrawCol Local $iStyle ; 0=Normal, 1=Bold, 2=Italic, 4=Underline, 8=Strikethrough Switch $m.State Case 0 ; Disabled $iDrawCol = $m.DisableColor $iStyle = 2 Case 1 ; Normal $iDrawCol = $m.Color $iStyle = 0 Case 2 ; Hover $iDrawCol = $m.HoverColor $iStyle = 4 Case Else ; Normal (1) $iDrawCol = $m.Color $iStyle = 0 EndSwitch Local $hBrushTxt = _GDIPlus_BrushCreateSolid("0xFF" & Hex($iDrawCol, 6)) Local $hFamily = _GDIPlus_FontFamilyCreate($m.Font) Local $hFont = _GDIPlus_FontCreate($hFamily, $m.FontSize, $iStyle) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH) Local $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_GraphicsDrawStringEx($hBack, $m.Text, $hFont, $tLayout, $hFormat, $hBrushTxt) _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) ; Cleanup _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_BrushDispose($hBrushTxt) _GDIPlus_GraphicsDispose($hBack) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_GraphicsDispose($hGraphics) EndFunc ;==>_UC_Link_Draw Func _UC_Link_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled $m.State = 3 ; is pressed _UC_Properties($idDummy, $m) _WinAPI_SetCapture($hWnd) _UC_ToolTip("") EndFunc ;==>_UC_Link_WM_LBUTTONDOWN Func _UC_Link_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY) #forceref $idDummy, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 3 Then ; If is pressed _WinAPI_ReleaseCapture() ; Area control If _UC_IsMouseOver($hWnd) Or ($iX = -1 And $iY = -1) Then $m.State = 2 ; Hover _UC_Properties($idDummy, $m) GUICtrlSendToDummy($idDummy, $m.Value) ; Execution! Else $m.State = 1 ; Normal (Cancel execution) _UC_Properties($idDummy, $m) EndIf EndIf EndFunc ;==>_UC_Button_WM_LBUTTONUP Func _UC_Link_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled If $m.State = 1 Then ; If is normal $m.State = 2 ; Hover _UC_Properties($idDummy, $m) If $m.ShowTooltip And _UC_IsMouseOver($hWnd) Then _UC_ToolTip($m.Value) EndIf EndFunc ;==>_UC_Link_WM_MOUSEMOVE #EndRegion ; ~~~~~~~~~~~~~ UC Link API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #Region ; ~~~~~~~~~~~~~ UC Label API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Func _UC_Label_Create($hParent, $sText, $iX, $iY, $iW, $iH, $iRotationIdx = 0, $hColor = 0xFFFFFF, $hBkColor = -2) GUISwitch($hParent) Local $idDummy = GUICtrlCreateDummy() Local $hChild = GUICreate("", $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS), $WS_EX_TRANSPARENT, $hParent) If $iRotationIdx > 3 Or $iRotationIdx < 0 Then $iRotationIdx = 0 __UC_Framework_Init($hParent) ;~ GUISetCursor(_UC_Get(1, "Cursor_Hand"), $GUI_CURSOR_OVERRIDE, $hChild) Local $m[] $m.UC_Type = $UC_TYPE_LABEL $m.UC_ControlID = $idDummy $m.UC_hWnd = $hChild $m.UC_hParent = $hParent ; Properties $m.Text = $sText $m.RotationIdx = $iRotationIdx ; 0=0, 1=90, 2=180, 3=270 $m.Color = $hColor ; Text Color $m.Color_Bk = $hBkColor ; -2 = Transparent (Parent Color) ; $GUI_BKCOLOR_TRANSPARENT $m.Color_Hover = $hColor ; Default: same as color $m.Font = "Segoe UI" ; font name $m.FontSize = 9 ; Initial Size $m.FontStyle = 0 ; 0=Normal, 1=Bold, etc. $m.Padding = 4 ; Internal safety margin $m.State = 1 ; 0=Disable ; 1=Normal ; 2=Hover ; 3=Pressed _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy) _UC_Properties($idDummy, $m) _UC_Properties(1, "UC_LastCreatedID", $idDummy) GUISwitch($hParent) Return $idDummy EndFunc ;==>_UC_Label_Create Func _UC_Label_Draw($hWnd, ByRef $m) Local $aClientSize = WinGetClientSize($hWnd) Local $iW = $aClientSize[0], $iH = $aClientSize[1] ; GUISetCursor(_UC_Get(1, ($m.State == 0 ? "Cursor_Arrow" : "Cursor_Hand")), $GUI_CURSOR_OVERRIDE, $hWnd) Local $hBGColor = "0xFF" & Hex(($m.Color_Bk == -2 ? __UC_ParentColor($hWnd) : $m.Color_Bk), 6) Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd) Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics) Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap) ; Settings for Sharpening _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; HighQuality Antialiasing _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4) ; HighQuality (Half-pixel offset) _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5) ; AntiAliasGridFit (Crisp Text) _GDIPlus_GraphicsClear($hBack, $hBGColor) ; --- CLAMPING LOGIC --- Local $fFitSize = $m.FontSize Local $aSize Local $aAngles = [0, 90, 180, 270] Local $iAngle = $aAngles[$m.RotationIdx] While 1 $aSize = _UC_GetTextSize($m.Text, $m.Font, $fFitSize, $m.FontStyle) Local $iTargetDim = ($iAngle = 90 Or $iAngle = 270) ? $iH : $iW If $aSize[0] > ($iTargetDim - $m.Padding) And $fFitSize > 4 Then $fFitSize -= 0.5 Else ExitLoop EndIf WEnd $m.FontSize = $fFitSize ; --- STYLING --- Local $iDrawCol = ($m.State = 2 ? $m.Color_Hover : $m.Color) Local $hBrushTxt = _GDIPlus_BrushCreateSolid("0xFF" & Hex($iDrawCol, 6)) Local $hFamily = _GDIPlus_FontFamilyCreate($m.Font) Local $hFont = _GDIPlus_FontCreate($hFamily, $m.FontSize, $m.FontStyle) Local $hFormat = _GDIPlus_StringFormatCreate(0x1000) _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) ; --- ROTATION & TRANSLATION --- _GDIPlus_GraphicsTranslateTransform($hBack, $iW / 2, $iH / 2) _GDIPlus_GraphicsRotateTransform($hBack, $iAngle) ; We use large values to avoid clipping. Local $iDim = ($iW > $iH ? $iW : $iH) * 2 Local $tLayout = _GDIPlus_RectFCreate(-$iDim / 2, -$iDim / 2, $iDim, $iDim) _GDIPlus_GraphicsDrawStringEx($hBack, $m.Text, $hFont, $tLayout, $hFormat, $hBrushTxt) _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0) ; Cleanup _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_BrushDispose($hBrushTxt) _GDIPlus_GraphicsDispose($hBack) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_GraphicsDispose($hGraphics) EndFunc ;==>_UC_Label_Draw Func _UC_Label_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY) #forceref $hWnd, $iX, $iY Local $m = _UC_Properties($idDummy) If $m.State = 0 Then Return ; If is Disabled If $m.State = 1 Then ; If is normal $m.State = 2 _UC_Properties($idDummy, $m) EndIf EndFunc ;==>_UC_Label_WM_MOUSEMOVE #EndRegion ; ~~~~~~~~~~~~~ UC Label API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Please, every comment is appreciated! leave your comments and experiences here! Thank you very much Edited Sunday at 12:30 PM by ioa747 Version (0.0.6.2) WildByDesign, pixelsearch, argumentum and 1 other 2 2 I know that I know nothing
argumentum Posted May 1 Posted May 1 Requests: 1) When you click a button, if you slide the cursor away from the control, don't execute. 2) The toggles, to act as the buttons do, that act on the release of the mouse. 3) if, because this is a GDI GUI, tab around the controls. This is a very nice looking thing 🤩 Thanks for sharing WildByDesign and ioa747 1 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
ioa747 Posted Saturday at 07:48 AM Author Posted Saturday at 07:48 AM 11 hours ago, argumentum said: Requests: 1) When you click a button, if you slide the cursor away from the control, don't execute. ✔️ 2) The toggles, to act as the buttons do, that act on the release of the mouse. ✔️ 3) if, because this is a GDI GUI, tab around the controls. ✔️ This is a very nice looking thing 🤩 Thank you very much 😍 I updated the first post Version (0.0.6) argumentum 1 I know that I know nothing
WildByDesign Posted Saturday at 12:25 PM Posted Saturday at 12:25 PM This is really special. I can envision a lot of potential for this framework. Especially for the fact that you have designed it in such a way that it can be extended upon with more controls and customization. And we have some real GDI+ geniuses in this forum should they decide to partake in this. The controls really are lightweight, fast and responsive. I have only one minor concern: I feel like the rounded corners and edges in general are a bit fuzzy. If they can be sharpened, I think that it would be an important improvement.
WildByDesign Posted Saturday at 12:42 PM Posted Saturday at 12:42 PM If someone designs a new control (for example, ListView or TreeView) for the framework, would that control work with the existing standard UDF (eg. _GUICtrlListView_*) functions?
argumentum Posted Saturday at 02:35 PM Posted Saturday at 02:35 PM if you take the GUI and press alt-space then arrow down, will go to move, then press enter, and that's the idea when tabbing around. Should adding the accelerator ( for when you press enter on a highlighted control ) be left to the UDF or the user? ( in regards of having the control execute. ) 🤔 and !, thanks for the update Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
ioa747 Posted Sunday at 12:27 AM Author Posted Sunday at 12:27 AM (edited) 12 hours ago, WildByDesign said: I feel like the rounded corners and edges in general are a bit fuzzy. If they can be sharpened, I think that it would be an important improvement. I added the properties to all the controls, I hope this improve the situation ; Settings for Sharpening _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; HighQuality Antialiasing _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4) ; HighQuality (Half-pixel offset) _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5) ; AntiAliasGridFit (Crisp Text) 12 hours ago, WildByDesign said: If someone designs a new control (for example, ListView or TreeView) for the framework, would that control work with the existing standard UDF (eg. _GUICtrlListView_*) functions? That’s a very insightful question. Initially, the short answer is no, standard UDFs (like _GUICtrlListView_*) won't work directly because when you design a new control from scratch, you are primarily working with its structural elements (e.g., a ListView would consist of a data array and a GDI+ rendered area). To achieve full compatibility, a wrapper would be needed, but that often means losing the full creative freedom of GDI+ design. However, there is a more advanced way I’m handling this in the UC_Framework: Since every control in this framework is hosted in its own dedicated child window ($hChild = GUICreate(...)), it acts as a container. This allows for a Hybrid Design: GDI+ Controls: Purely custom-drawn for maximum flexibility and "sharpened" aesthetics (using the modes we discussed). Native Composition: You can actually 'nest' a native Windows control inside a UC_Control container. For a complex control like a ListView, we can use GDI+ to draw a beautiful, modern frame and then host a native ListView inside it. This way, you get the best of both worlds: the visual superiority of the framework and the functional compatibility with standard UDFs. So, while a pure GDI+ control won't 'speak' the native UDF language, the framework's architecture is open enough to allow 'Hybrid Controls' that do! 10 hours ago, argumentum said: Should adding the accelerator ( for when you press enter on a highlighted control ) Regarding the accelerators, I’ve decided that the UDF should handle this logic to keep things simple for the user. For now, I have implemented the Spacebar as the primary keyboard trigger. I chose Space over Enter because, in the Windows API, the Enter key requires extra message handling (like $WM_GETDLGCODE) and window separation to prevent it from being 'stolen' by the system—which is a lot of extra overhead for the core framework at this stage. However, implementing even the Spacebar was tricky due to the 'Mouse Safety' feature I recently added (where sliding the cursor away cancels the click). To make keyboard triggers work without a mouse present, I introduced a special coordinate exception: ; Logic to allow Keyboard Triggers while maintaining Mouse Safety ; If coordinates are -1, -1, we bypass the 'MouseOver' check If _UC_IsMouseOver($hWnd) Or ($iX = -1 And $iY = -1) Then ; ... execution logic ... EndIf ; How the Spacebar trigger is handled internally: Case $UC_TYPE_BUTTON _UC_Button_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY) Sleep(50) _UC_Button_WM_LBUTTONUP($idDummy, $hWnd, -1, -1) ; Using -1, -1 to force execution I updated the first post Version (0.0.6.2) Edited Sunday at 01:14 AM by ioa747 argumentum and WildByDesign 2 I know that I know nothing
WildByDesign Posted Sunday at 01:12 PM Posted Sunday at 01:12 PM (edited) 12 hours ago, ioa747 said: I added the properties to all the controls, I hope this improve the situation Yes, absolutely. Especially once I added DPI scaling to my testing example. The difference between the previous release and this updated release is fantastic. Much sharper. Thank you for the quick update and also your very well detailed reply. I appreciate it. 12 hours ago, ioa747 said: Initially, the short answer is no, standard UDFs (like _GUICtrlListView_*) won't work directly because when you design a new control from scratch, you are primarily working with its structural elements (e.g., a ListView would consist of a data array and a GDI+ rendered area). To achieve full compatibility, a wrapper would be needed, but that often means losing the full creative freedom of GDI+ design. Thank you for clarifying. Also, I would think that if a developer does come along and adds a beautiful ListView control entirely custom in GDI+, they could also potentially create functions that are similar to UDF _GUICtrlListView_* functions but that are more specific to their custom GDI+ ListView. The sky is the limit. By the way, you are so incredibly well organized with the way that you respond with details, the way that you document everything and so much more. You are clear and concise with everything (all aspects) and that it is very helpful to learn from and understand. 12 hours ago, ioa747 said: For a complex control like a ListView, we can use GDI+ to draw a beautiful, modern frame and then host a native ListView inside it. This way, you get the best of both worlds: the visual superiority of the framework and the functional compatibility with standard UDFs. This is a very interesting possibility as well. So there are many different possibilities with this UC Framework which makes it very flexible. Edited Sunday at 01:14 PM by WildByDesign ioa747 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now