Jump to content

Recommended Posts

Posted (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.

 

_Example1.png.c6f522e77f9923a2c1e0392f2e9c50ad.png

 

Example1.au3

; 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.1
; 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)


    Local $aMsg, $iSliderXLStep, $iVal
    While 1
        $aMsg = GUIGetMsg()
        Switch $aMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $id_UP
                _UC_Slider_UpdateFromValue(Default, 1)

            Case $id_DOWN
                _UC_Slider_UpdateFromValue(Default, -1)

            Case $id_UP_XL
                $iSliderXLStep = _UC_Get(Default, "SliderXLStep")
                _UC_Slider_UpdateFromValue(Default, $iSliderXLStep)

            Case $id_DOWN_XL
                $iSliderXLStep = _UC_Get(Default, "SliderXLStep")
                _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", GUICtrlRead($idVSlider))

            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)
            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

; 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.5.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

#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_SLIDER
                    _UC_Slider_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY)
                Case $UC_TYPE_BUTTON
                    _UC_Button_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)
            Switch $wParam
                Case $VK_RETURN ; (Enter)
                    Switch $iCtrlType
                        Case $UC_TYPE_TOGGLE
                            _UC_Toggle_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 $VK_SPACE ; (Space bar)
                    Switch $iCtrlType
                        Case $UC_TYPE_TOGGLE
                            _UC_Toggle_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 $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)

    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)
    _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; High Quality Antialiasing

    ; 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.Value = ($m.Value = 1 ? 0 : 1)
    _UC_Properties($idDummy, $m)
    GUICtrlSendToDummy($idDummy, $m.Value)
EndFunc   ;==>_UC_Toggle_WM_LBUTTONDOWN

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)
    _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; High Quality Antialiasing

    ; 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)

    ; 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)
    _GDIPlus_GraphicsSetSmoothingMode($hBack, 4) ; High Quality Antialiasing

    ; 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 $hWnd, $iX, $iY
    Local $m = _UC_Properties($idDummy)
    If $m.State = 0 Then Return ; If is Disabled
    If $m.State = 3 Then ; If is pressed
        _WinAPI_ReleaseCapture()
        $m.State = 2 ; Hover
        _UC_Properties($idDummy, $m)
        GUICtrlSendToDummy($idDummy, $m.Text)
    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 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)

    ; 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
    GUICtrlSendToDummy($idDummy, $m.Value)
    _UC_ToolTip("")
EndFunc   ;==>_UC_Link_WM_LBUTTONDOWN

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 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)
    _GDIPlus_GraphicsSetTextRenderingHint($hBack, 4)
    _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 by ioa747

I know that I know nothing

Posted

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 :) 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...