UC_Framework - Universal Controls

 

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.

 

 

        _AutoIt3_B6zik.gif           

  
1272.png  1272.png.2afd1588c237217b88328d753518873

 

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.0.8.0
; 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", 520, 450, -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 (50):", 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)

    ; === Progressbar ===
    Local $idProgress = _UC_ProgressBar_Create($hMainGui, 20, 240, 350, 24, 0, 100, 50)
    _UC_Set(-1, "ShowPercent", True)

    ; === Radial Progressbar ===
    Local $idRadial = _UC_RadialProgress_Create($hMainGui, 400, 40, 100)
    _UC_Set(-1, "RingThickness", 12)
    _UC_Set(-1, "FontSize", 16)
    _UC_Set(-1, "Value", 50)

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

    ; === Image ===
    Local $iWidth, $sImage = @ScriptDir & "\1272.png"
    Local $idImage1 = _UC_Image_Create($hMainGui, $sImage, 10, 300, 0.6)
    $iWidth = _UC_Get(-1, "Width")
    Local $idImage2 = _UC_Image_Create($hMainGui, $sImage, 10 + $iWidth, 300, 0.4)
    $iWidth += _UC_Get(-1, "Width")
    Local $idImage3 = _UC_Image_Create($hMainGui, $sImage, 10 + $iWidth, 300, 0.2)
    _UC_Set(-1, "SetFocus", 1)

    ; === Timer ===
    _UC_Timer_Set($idImage3, 100, "_CallBackTimerFunction")
    _UC_Timer_Set($btnRound2, 500, "_CallBackTimerFlash")


    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()
    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 & "):")
                _UC_Set($idProgress, "Value", $iVal)
                _UC_Set($idRadial, "Value", $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)
                _UC_Timer_Set($idImage3, 100, "_CallBackTimerFunction")
            Case $btnRound3
                ConsoleWrite("'" & GUICtrlRead($btnRound3) & "' Button Clicked!" & @CRLF)
            Case $idImage1, $idImage2, $idImage3
                ConsoleWrite("'" & _UC_Get(Default, "Filename") & "'  Scale:" & _UC_Get(Default, "Scale") & @CRLF)  ; Default is the active control
        EndSwitch

    WEnd

    _UC_Destroy($hMainGui)

EndFunc   ;==>_Main

Func _CallBackTimerFunction(ByRef $mt)
    _MapCW($mt, ">>> _CallBackTimerFunction=" & $mt.id & " .Fired=" & $mt.Fired & " <<<")
    If Not MapExists($mt, "Custom") Then $mt.Custom = 3
    $mt.Custom -= 0.2
    Local $UC = _UC_Properties($mt.ControlID)
    WinMove($UC.UC_hWnd, "", Default, Default, $UC.Width * $mt.Custom, $UC.Height * $mt.Custom)
    If $mt.Custom < 0.9 Then _UC_Timer_Kill($mt.id)
EndFunc   ;==>_CallBackTimerFunction

Func _CallBackTimerFlash(ByRef $mt)
    Local $iFlash = Mod($mt.Fired, 2)
    Local $UC = _UC_Properties($mt.ControlID)
    $UC.BtnColor = ($iFlash ? 0xB200FF : 0x7800AC)
    _UC_Properties($mt.ControlID, $UC)

EndFunc   ;==>_CallBackTimerFlash

 

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.8.0
; 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>
#include <Timers.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_IMAGE, _
        $UC_TYPE_PROGRESSBAR, _
        $UC_TYPE_RADIALPROGRESS, _
        $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)
        Case $UC_TYPE_RADIALPROGRESS
            _UC_RadialProgress_Draw($hWnd, $m)
        Case $UC_TYPE_PROGRESSBAR
            _UC_ProgressBar_Draw($hWnd, $m)
        Case $UC_TYPE_IMAGE
            _UC_Image_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], $mMap[]

    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
            ; in Autoit allways controls start from 3
            $aProp[1] = $mMap ; General Properties
            $aProp[2] = $mMap ; Timers  Map
        EndIf

    EndIf

    ; Map Selection (or Template)
    Local $m = (IsMap($aProp[$idDummy]) ? $aProp[$idDummy] : $mMap)

    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
                _UC_Timer_Remove($idDummy)
                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
                    _UC_Timer_Remove($idDummy)
                    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 IsMap($m) Then
                _UC_Timer_Remove($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
    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   ;==>_UC_IsMouseOver

#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_LBUTTONDBLCLK, "__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)
                Case $UC_TYPE_IMAGE
                    _UC_Image_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
            EndSwitch
            Return 0

        Case $WM_LBUTTONDBLCLK
            Switch $iCtrlType
                Case $UC_TYPE_TOGGLE
                    _UC_Toggle_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
                Case $UC_TYPE_SLIDER
                    _UC_Slider_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
                Case $UC_TYPE_BUTTON
                    _UC_Button_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
                Case $UC_TYPE_LINK
                    _UC_Link_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
                Case $UC_TYPE_IMAGE
                    _UC_Image_WM_LBUTTONDBLCLK($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)
                Case $UC_TYPE_IMAGE
                    _UC_Image_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)
                Case $UC_TYPE_IMAGE
                    _UC_Image_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)
                Case $UC_TYPE_IMAGE
                    _UC_Image_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
            Return 0
    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

; #FUNCTION# ====================================================================================================================
; Name...........: __UC_DrawRoundedRect
; Description....: Internal helper for drawing and/or filling rounded rectangles.
; Parameters.....: $hBrush - Handle to a brush to fill the rect. Set to 0 to skip filling.
;                  $hPen   - Handle to a pen to draw the border. Set to 0 to skip border.
; ===============================================================================================================================
Func __UC_DrawRoundedRect($hGraphics, $iX, $iY, $iW, $iH, $iR, $hBrush = 0, $hPen = 0)

    ; If we have neither Brush nor Pen, there is no point in continuing
    If $hBrush = 0 And $hPen = 0 Then Return

    ; Case for simple rectangle (Radius = 0)
    If $iR <= 0 Then
        If $hBrush <> 0 Then _GDIPlus_GraphicsFillRect($hGraphics, $iX, $iY, $iW, $iH, $hBrush)
        If $hPen <> 0 Then _GDIPlus_GraphicsDrawRect($hGraphics, $iX, $iY, $iW, $iH, $hPen)
        Return
    EndIf

    ; Creating the Path
    Local $id = $iR * 2
    Local $hPath = _GDIPlus_PathCreate()

    _GDIPlus_PathAddArc($hPath, $iX, $iY, $id, $id, 180, 90)
    _GDIPlus_PathAddArc($hPath, $iX + $iW - $id, $iY, $id, $id, 270, 90)
    _GDIPlus_PathAddArc($hPath, $iX + $iW - $id, $iY + $iH - $id, $id, $id, 0, 90)
    _GDIPlus_PathAddArc($hPath, $iX, $iY + $iH - $id, $id, $id, 90, 90)
    _GDIPlus_PathCloseFigure($hPath)

    ; First the filling (so as not to cover the outline)
    If $hBrush <> 0 Then _GDIPlus_GraphicsFillPath($hGraphics, $hPath, $hBrush)

    ; After the outline
    If $hPen <> 0 Then _GDIPlus_GraphicsDrawPath($hGraphics, $hPath, $hPen)

    _GDIPlus_PathDispose($hPath)
EndFunc   ;==>__UC_DrawRoundedRect

#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 Timers API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Func _UC_Timer_Set($idCtrl, $iElapse = 250, $sUserFunc = "", $iTimerID = -1)
    Local $UC = _UC_Properties($idCtrl)
    Local $hParent = $UC.UC_hParent
    Local $id = _Timer_SetTimer($hParent, $iElapse, "__UC_Timer_Internal_Handler", $iTimerID)
    If Not $id Then Return SetError(1, 0, 0)

    ; Timer Data
    Local $mt[], $mMap[]

    $mt.id = $id
    $mt.elapse = $iElapse
    $mt.UserFunc = $sUserFunc
    $mt.hwnd = $hParent
    $mt.ControlID = $idCtrl
    $mt.Fired = 0
    $mt.RetVal = ""
    $mt.LastError = 0

    Local $mTimers = (MapExists($UC, "Timers") ? $UC.Timers : $mMap)
    $mTimers[String($mt.id)] = $mt
    $UC.Timers = $mTimers

    _UC_Properties(2, String($mt.id), $idCtrl)
    _UC_Properties($idCtrl, $UC, False)

    Return $id
EndFunc   ;==>_UC_Timer_Set

Func __UC_Timer_Internal_Handler($hWnd, $iMsg, $iIDTimer, $iTime) ; central Timer callback
    #forceref $hWnd, $iMsg, $iTime
    Local $m = _UC_TimerMap($iIDTimer)
    If @error Then Return SetError(1, 0, "") ; It's not our timer.
    $m.RetVal = ""
    $m.LastError = 0

    If $m.UserFunc <> "" Then
        $m.Fired += 1
        $m.RetVal = Call($m.UserFunc, $m)
        If @error = 0xDEAD And @extended = 0xBEEF Then $m.LastError = 2 ; *** function does not exist or invalid number of parameters.
        If MapExists(_UC_Properties(2), String($iIDTimer)) Then _UC_TimerMap($iIDTimer, $m)
        Return 0
    EndIf

EndFunc   ;==>__UC_Timer_Internal_Handler

Func _UC_Timer_Kill($iTimerID)
    Local $m = _UC_TimerMap($iTimerID)
    If Not @error Then
        Local $Result = _Timer_KillTimer($m.hwnd, $m.id)
        _UC_TimerMap($iTimerID, "@Delete")
        Local $mTimerIndex = _UC_Properties(2)
        Local $sKey = String($m.id)
        If IsMap($mTimerIndex) And MapExists($mTimerIndex, $sKey) Then MapRemove($mTimerIndex, $sKey)
        _UC_Properties(2, $mTimerIndex)
        Return $Result
    EndIf
    Return False
EndFunc   ;==>_UC_Timer_Kill

Func _UC_Timer_Remove($idCtrl)
    Local $mUC = _UC_Properties($idCtrl)
    If MapExists($mUC, "Timers") Then
        Local $aTimers = _Map2D($mUC.Timers)
        For $i = 0 To UBound($aTimers) - 1
            _UC_Timer_Kill($aTimers[$i][0])
        Next
    EndIf
EndFunc   ;==>_UC_Timer_Remove

Func _UC_TimerMap($iIDTimer, $mTimer = 0)
    Local $sKey, $idCtrl, $mTimers
    $sKey = String($iIDTimer)
    $idCtrl = _UC_Properties(2, $sKey)
    If Not @error Then
        Local $mUC = _UC_Properties($idCtrl)
        If IsMap($mUC) Then
            $mTimers = $mUC.Timers
            If $mTimer = 0 Then ; Get map
                If IsMap($mTimers) And MapExists($mTimers, $sKey) Then Return $mTimers[$sKey]
            Else ; .............. Set map
                If IsMap($mTimers) And IsMap($mTimer) Then
                    $mTimers[$sKey] = $mTimer
                EndIf

                If IsMap($mTimers) And MapExists($mTimers, $sKey) And $mTimer = "@Delete" Then ; Delete map
                    MapRemove($mTimers, $sKey)
                EndIf

                $mUC.Timers = $mTimers
                Return _UC_Properties($idCtrl, $mUC, False)

            EndIf
        EndIf
    EndIf
    Return SetError(1, 0, 0)
EndFunc   ;==>_UC_TimerMap
#EndRegion ; ~~~~~~~~~~~~~ UC Timers API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#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]

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

    ; Clear background
    _GDIPlus_GraphicsClear($hBack, $hBGColor)

    ; Resources
    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 semi-transparent

    Local $iR, $iXPos, $iBtnW

    If $m.Type = 0 Then ; ROUND TYPE
        $iR = $iH / 2 ; Fully rounded corners (Pill shape)

        ; Draw Toggle Background
        __UC_DrawRoundedRect($hBack, 0, 0, $iW - 1, $iH - 1, $iR, $hBrushBg, 0)

        ; Calculate Slider Button Position
        $iXPos = $m.Value ? ($iW - $iH + 2) : 2
        $iBtnW = $iH - 5 ; Circle diameter

        ; Draw Slider Button
        __UC_DrawRoundedRect($hBack, $iXPos, 2, $iBtnW, $iBtnW, $iBtnW / 2, $hBrushBtn, ($m.State = 2 ? $hPenHotTrack : 0))

    Else ; RECT TYPE
        $iR = 0 ; Sharp corners

        ; Draw Toggle Background
        __UC_DrawRoundedRect($hBack, 0, 0, $iW, $iH, $iR, $hBrushBg, 0)

        ; Calculate Slider Button Position
        Local $iSqW = ($iW / 3) - 4
        Local $iSqX = $m.Value ? ($iW - $iSqW - 2) : 2

        ; Draw Slider Button
        __UC_DrawRoundedRect($hBack, $iSqX, 2, $iSqW, $iH - 4, $iR, $hBrushBtn, ($m.State = 2 ? $hPenHotTrack : 0))
    EndIf

    ; Present to Screen
    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $iW, $iH)

    ; Cleanup
    _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_Toggle_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

Func _UC_Toggle_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY

    ; For now, a double click on a button should behave exactly like a fast single click.
    ; So we just forward the parameters straight to the Down handler.
    Return _UC_Toggle_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
EndFunc   ;==>_UC_Toggle_WM_LBUTTONDBLCLK
#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]

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

    ; Clear background
    _GDIPlus_GraphicsClear($hBack, $hBGColor)

    ; Percentage calculation
    Local $iRange = $m.Max - $m.Min
    If $iRange <= 0 Then $iRange = 1
    Local $fPercent = ($m.Value - $m.Min) / $iRange

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

    Local $iThumbSizeW, $iThumbSizeH, $iR, $iTrackR

    If $m.Type = 0 Then ; HORIZONTAL

        ; Define Thumb Dimensions
        $iThumbSizeH = $iH - 4
        $iThumbSizeW = ($m.ThumbType = 0 ? $iThumbSizeH : $iThumbSizeH / 2)
        $iR = ($m.ThumbType = 0 ? $iThumbSizeW / 2 : 0) ; Round or Rect Thumb
        $iTrackR = $m.TrackSize / 2 ; Rounded track ends

        Local $iXPos = (($iW - $iThumbSizeW - 1) * $fPercent)
        Local $iTrackY = ($iH - $m.TrackSize) / 2

        ; Draw Track Background
        __UC_DrawRoundedRect($hBack, ($iThumbSizeW / 4), $iTrackY, $iW - ($iThumbSizeW / 2), $m.TrackSize, $iTrackR, $hBrushTrack, 0)

        ; Draw Track Fill
        __UC_DrawRoundedRect($hBack, ($iThumbSizeW / 4), $iTrackY, $iXPos + ($iThumbSizeW / 2), $m.TrackSize, $iTrackR, $hBrushFill, 0)

        ; Draw Thumb (With HotTrack Pen if hovered)
        __UC_DrawRoundedRect($hBack, $iXPos, 2, $iThumbSizeW, $iThumbSizeH, $iR, $hBrushThumb, ($m.State = 2 ? $hPenHotTrack : $hPenThumbBorder))

    Else ; VERTICAL

        ; Define Thumb Dimensions
        $iThumbSizeW = $iW - 4
        $iThumbSizeH = ($m.ThumbType = 0 ? $iThumbSizeW : $iThumbSizeW / 2)
        $iR = ($m.ThumbType = 0 ? $iThumbSizeH / 2 : 0) ; Round or Rect Thumb
        $iTrackR = $m.TrackSize / 2

        Local $iYPos = ($iH - $iThumbSizeH - 1) - (($iH - $iThumbSizeH - 2) * $fPercent)
        Local $iTrackX = ($iW - $m.TrackSize) / 2

        ; Draw Track Background
        __UC_DrawRoundedRect($hBack, $iTrackX, ($iThumbSizeH / 4), $m.TrackSize, $iH - ($iThumbSizeH / 2), $iTrackR, $hBrushTrack, 0)

        ; Draw Track Fill
        __UC_DrawRoundedRect($hBack, $iTrackX, $iYPos + ($iThumbSizeH / 4), $m.TrackSize, $iH - $iYPos - ($iThumbSizeH / 2), $iTrackR, $hBrushFill, 0)

        ; Draw Thumb (With HotTrack Pen if hovered)
        __UC_DrawRoundedRect($hBack, 2, $iYPos, $iThumbSizeW, $iThumbSizeH, $iR, $hBrushThumb, ($m.State = 2 ? $hPenHotTrack : $hPenThumbBorder))

    EndIf

    ; Present to Screen
    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $iW, $iH)

    ; Cleanup
    _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

Func _UC_Slider_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY

    ; For now, a double click on a button should behave exactly like a fast single click.
    ; So we just forward the parameters straight to the Down handler.
    Return _UC_Slider_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
EndFunc   ;==>_UC_Slider_WM_LBUTTONDBLCLK
#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

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

    ; Clear background with parent color
    _GDIPlus_GraphicsClear($hBack, $hBGColor)

    ; Create Background Brush
    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

    ; Draw Button Shape
    ; We pass 0 for the Pen because the button currently uses only Fill
    __UC_DrawRoundedRect($hBack, 0, 0, $iW - 1, $iH - 1, $iR, $hBrushBg, 0)

    ; Draw Text
    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 alignment
    _GDIPlus_StringFormatSetLineAlign($hFormat, $m.FontVerAlg) ; Vertical alignment

    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)

    ; Present to Screen (Double Buffering)
    _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)

    ; Cleanup Section
    _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

Func _UC_Button_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY

    ; For now, a double click on a button should behave exactly like a fast single click.
    ; So we just forward the parameters straight to the Down handler.
    Return _UC_Button_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
EndFunc   ;==>_UC_Button_WM_LBUTTONDBLCLK
#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) ; TextRenderingHintClearTypeGridFit

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

    ; Present to Screen
    _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_Link_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

Func _UC_Link_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY

    ; For now, a double click on a button should behave exactly like a fast single click.
    ; So we just forward the parameters straight to the Down handler.
    Return _UC_Link_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
EndFunc   ;==>_UC_Link_WM_LBUTTONDBLCLK
#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) ; TextRenderingHintClearTypeGridFit

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

    ; Present to Screen
    _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_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
    Return
    #forceref $idDummy, $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_Label_WM_LBUTTONDOWN

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

Func _UC_Label_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY

    ; For now, a double click on a button should behave exactly like a fast single click.
    ; So we just forward the parameters straight to the Down handler.
    Return _UC_Label_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
EndFunc   ;==>_UC_Label_WM_LBUTTONDBLCLK
#EndRegion ; ~~~~~~~~~~~~~ UC Label  API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Region ; ~~~~~~~~~~~~~ UC Image API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Func _UC_Image_Create($hParent, $sFilename, $iX, $iY, $fScale = 1.0)
    GUISwitch($hParent)
    Local $idDummy = GUICtrlCreateDummy()

    Local $hImage = _GDIPlus_ImageLoadFromFile($sFilename)
    Local $iW = Int(_GDIPlus_ImageGetWidth($hImage) * $fScale)
    Local $iH = Int(_GDIPlus_ImageGetHeight($hImage) * $fScale)

    Local $hChild = GUICreate("UC_Control_" & $idDummy, $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS), $WS_EX_TRANSPARENT, $hParent)

    __UC_Framework_Init($hParent)

    Local $m[]
    $m.UC_Type = $UC_TYPE_IMAGE
    $m.UC_ControlID = $idDummy
    $m.UC_hWnd = $hChild
    $m.UC_hParent = $hParent

    $m.State = 1                ; 1=Normal, 2=Hover, 3=Pressed
    $m.Filename = $sFilename
    $m.Scale = $fScale
    $m.Image = $hImage
    $m.Width = $iW
    $m.Height = $iH
    $m.Resampling = 7           ; HighQualityBicubic
    $m.ShowTooltip = 0
    $m.Tooltip = ""
    $m.SetFocus = 0

    _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy)
    _UC_Properties($idDummy, $m)
    _UC_Properties(1, "UC_LastCreatedID", $idDummy)

    GUISwitch($hParent)
    Return $idDummy
EndFunc   ;==>_UC_Image_Create

Func _UC_Image_Draw($hWnd, ByRef $m)
    Local $aSize = WinGetClientSize($hWnd)
    Local $iW = $aSize[0], $iH = $aSize[1]
    If $iW <= 0 Or $iH <= 0 Then Return

    Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd)
    Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    _GDIPlus_GraphicsSetInterpolationMode($hBack, $m.Resampling)
    _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4)

    Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6)
    _GDIPlus_GraphicsClear($hBack, $hBGColor)

    If $m.Image <> 0 Then
        _GDIPlus_GraphicsDrawImageRect($hBack, $m.Image, 0, 0, $iW, $iH)
    EndIf

    ; Visual feedback for Hover/Pressed (Optional)
    If $m.State = 3 And $m.SetFocus Then ; Pressed: Slight darkening
        Local $hBrushOver = _GDIPlus_BrushCreateSolid(0x30000000)
        _GDIPlus_GraphicsFillRect($hBack, 0, 0, $iW, $iH, $hBrushOver)
        _GDIPlus_BrushDispose($hBrushOver)
    EndIf

    _GDIPlus_GraphicsDrawImage($hGraphics, $hBitmap, 0, 0)

    _GDIPlus_GraphicsDispose($hBack)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
EndFunc   ;==>_UC_Image_Draw

Func _UC_Image_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY
    Local $m = _UC_Properties($idDummy)
    If $m.State = 0 Then Return
    $m.State = 3 ; Pressed
    _UC_Properties($idDummy, $m) ; ReDraw to show feedback
    _WinAPI_SetCapture($hWnd)
EndFunc   ;==>_UC_Image_WM_LBUTTONDOWN

Func _UC_Image_WM_LBUTTONUP($idDummy, $hWnd, $iX, $iY)
    Local $m = _UC_Properties($idDummy)
    If $m.State = 3 Then
        _WinAPI_ReleaseCapture()
        If _UC_IsMouseOver($hWnd) Or ($iX = -1 And $iY = -1) Then
            $m.State = 2 ; Hover
            _UC_Properties($idDummy, $m)
            GUICtrlSendToDummy($idDummy, $m.UC_ControlID)
        Else
            $m.State = 1 ; Normal
            _UC_Properties($idDummy, $m, True)
        EndIf
    EndIf
EndFunc   ;==>_UC_Image_WM_LBUTTONUP

Func _UC_Image_WM_MOUSEMOVE($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY
    Local $m = _UC_Properties($idDummy)
    If $m.State = 0 Or $m.State = 3 Then Return
    If $m.State = 1 Then
        $m.State = 2 ; Hover
        _UC_Properties($idDummy, $m) ; ReDraw for hover effect
        If $m.ShowTooltip Then _UC_ToolTip($m.Tooltip)
    EndIf
EndFunc   ;==>_UC_Image_WM_MOUSEMOVE

Func _UC_Image_WM_LBUTTONDBLCLK($idDummy, $hWnd, $iX, $iY)
    #forceref $hWnd, $iX, $iY

    ; For now, a double click on a button should behave exactly like a fast single click.
    ; So we just forward the parameters straight to the Down handler.
    Return _UC_Image_WM_LBUTTONDOWN($idDummy, $hWnd, $iX, $iY)
EndFunc   ;==>_UC_Image_WM_LBUTTONDBLCLK
#EndRegion ; ~~~~~~~~~~~~~ UC Image API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#Region ; ~~~~~~~~~~~~~ UC ProgressBar API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; #FUNCTION# ====================================================================================================================
; Name...........: _UC_ProgressBar_Create
; Description....: Creates a custom GDI+ ProgressBar control.
; Syntax.........: _UC_ProgressBar_Create($hParent, $iX, $iY, $iW, $iH [, ...])
; Author.........: Polar
; ===============================================================================================================================
Func _UC_ProgressBar_Create($hParent, $iX, $iY, $iW, $iH, $iMin = 0, $iMax = 100, $iValue = 0, _
        $iType = 0, $iCornerRadius = 0, $hFillColor = 0x4CD964, $hTrackColor = 0xD1D1D1, $hBorderColor = 0xA0A0A0)

    GUISwitch($hParent)
    Local $idDummy = GUICtrlCreateDummy()
    Local $hChild = GUICreate("", $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS), $WS_EX_TRANSPARENT, $hParent)

    __UC_Framework_Init($hParent)

    Local $m[]

    ; Universal Properties
    $m.UC_Type = $UC_TYPE_PROGRESSBAR
    $m.UC_ControlID = $idDummy
    $m.UC_hWnd = $hChild
    $m.UC_hParent = $hParent

    ; ProgressBar Properties
    $m.State = 1
    $m.Min = $iMin
    $m.Max = $iMax
    $m.Value = $iValue
    $m.Type = $iType ; 0=Horizontal | 1=Vertical
    $m.CornerRadius = $iCornerRadius

    $m.FillColor = $hFillColor
    $m.TrackColor = $hTrackColor
    $m.BorderColor = $hBorderColor
    $m.ShowPercent = False
    $m.TextColor = 0x000000

    $m.Font = "Segoe UI"
    $m.FontSize = 9
    $m.FontStyle = 1

    _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy)
    _UC_Properties($idDummy, $m)
    _UC_Properties(1, "UC_LastCreatedID", $idDummy)
    GUISwitch($hParent)
    Return $idDummy
EndFunc   ;==>_UC_ProgressBar_Create

Func _UC_ProgressBar_Draw($hWnd, ByRef $m)
    Local $aSize = WinGetClientSize($hWnd)
    Local $iW = $aSize[0]
    Local $iH = $aSize[1]

    If $iW <= 0 Or $iH <= 0 Then Return

    Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6)

    ; Clamp value
    If $m.Value < $m.Min Then $m.Value = $m.Min
    If $m.Value > $m.Max Then $m.Value = $m.Max

    ; Calculate Percentage
    Local $iRange = ($m.Max - $m.Min)
    If $iRange <= 0 Then $iRange = 1
    Local $fPercent = ($m.Value - $m.Min) / $iRange

    ; GDI+ Initialization
    Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd)
    Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    ; Set High Quality Rendering
    _GDIPlus_GraphicsSetSmoothingMode($hBack, 4)
    _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4)
    _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5)

    ; Clear Background
    _GDIPlus_GraphicsClear($hBack, $hBGColor)

    ; Create Resources
    Local $hBrushTrack = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.TrackColor, 6))
    Local $hBrushFill = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.FillColor, 6))
    Local $hBrushText = _GDIPlus_BrushCreateSolid("0xFF" & Hex($m.TextColor, 6))
    Local $hPenBorder = _GDIPlus_PenCreate("0xFF" & Hex($m.BorderColor, 6), 1)

    ; Radius Calculation
    Local $iR = $m.CornerRadius
    Local $iMaxR = (($iH < $iW) ? $iH : $iW) / 2
    If $iR > $iMaxR Then $iR = $iMaxR

    ; Draw Track (Background of the Progress Bar)
    __UC_DrawRoundedRect($hBack, 0, 0, $iW - 1, $iH - 1, $iR, $hBrushTrack, $hPenBorder)

    ; Draw Fill (The actual progress)
    Local $iFillX, $iFillY, $iFillW, $iFillH

    If $m.Type = 0 Then ; Horizontal
        $iFillW = Int(($iW - 2) * $fPercent)
        If $iFillW > 0 Then
            ; Fill only, no border for the inner bar
            __UC_DrawRoundedRect($hBack, 1, 1, $iFillW, $iH - 3, $iR, $hBrushFill, 0)
        EndIf
    Else ; Vertical
        $iFillH = Int(($iH - 2) * $fPercent)
        If $iFillH > 0 Then
            $iFillX = 1
            $iFillY = $iH - $iFillH - 1
            ; Fill only, no border for the inner bar
            __UC_DrawRoundedRect($hBack, $iFillX, $iFillY, $iW - 3, $iFillH, $iR, $hBrushFill, 0)
        EndIf
    EndIf

    ; Draw Percent Text (Optional)
    If $m.ShowPercent Then
        Local $iPercent = Int($fPercent * 100)
        Local $hFamily = _GDIPlus_FontFamilyCreate($m.Font)
        Local $hFont = _GDIPlus_FontCreate($hFamily, $m.FontSize, $m.FontStyle)
        Local $hFormat = _GDIPlus_StringFormatCreate()

        _GDIPlus_StringFormatSetAlign($hFormat, 1) ; Center
        _GDIPlus_StringFormatSetLineAlign($hFormat, 1) ; Center

        Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH)
        _GDIPlus_GraphicsDrawStringEx($hBack, $iPercent & "%", $hFont, $tLayout, $hFormat, $hBrushText)

        ; Text Resources Cleanup
        _GDIPlus_StringFormatDispose($hFormat)
        _GDIPlus_FontDispose($hFont)
        _GDIPlus_FontFamilyDispose($hFamily)
    EndIf

    ; Present to Screen
    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $iW, $iH)

    ; Final Cleanup
    _GDIPlus_PenDispose($hPenBorder)
    _GDIPlus_BrushDispose($hBrushTrack)
    _GDIPlus_BrushDispose($hBrushFill)
    _GDIPlus_BrushDispose($hBrushText)
    _GDIPlus_GraphicsDispose($hBack)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
EndFunc   ;==>_UC_ProgressBar_Draw
#EndRegion ; ~~~~~~~~~~~~~ UC ProgressBar API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Region ; ~~~~~~~~~~~~~ UC Radial Progress API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Func _UC_RadialProgress_Create( _
        $hParent, _
        $iX, _
        $iY, _
        $iSize, _
        $iMin = 0, _
        $iMax = 100, _
        $iValue = 0, _
        $hProgressColor = 0x0078D7, _
        $hTrackColor = 0x404040)

    GUISwitch($hParent)

    Local $idDummy = GUICtrlCreateDummy()

    Local $hChild = GUICreate( _
            "", _
            $iSize, _
            $iSize, _
            $iX, _
            $iY, _
            BitOR($WS_CHILD, $WS_VISIBLE, $WS_CLIPSIBLINGS), _
            $WS_EX_TRANSPARENT, _
            $hParent)

    __UC_Framework_Init($hParent)

    Local $m[]

    ; Universal
    $m.UC_Type = $UC_TYPE_RADIALPROGRESS
    $m.UC_ControlID = $idDummy
    $m.UC_hWnd = $hChild
    $m.UC_hParent = $hParent

    ; Values
    $m.Min = $iMin
    $m.Max = $iMax
    $m.Value = $iValue

    ; Appearance
    $m.ProgressColor = $hProgressColor
    $m.TrackColor = $hTrackColor

    ; Ring
    $m.RingThickness = 10
    $m.StartAngle = -90
    $m.RoundCap = 1

    ; Text
    $m.ShowPercent = 1
    $m.TextColor = 0xFFFFFF
    $m.Font = "Segoe UI"
    $m.FontSize = 18
    $m.FontStyle = 1

    ; Optional glow
    $m.Glow = 0

    ; Background center
    $m.CenterColor = 0x202020

    _WinAPI_SetProp($hChild, "UC_ControlID", $idDummy)

    _UC_Properties($idDummy, $m)
    _UC_Properties(1, "UC_LastCreatedID", $idDummy)

    GUISwitch($hParent)

    Return $idDummy

EndFunc   ;==>_UC_RadialProgress_Create

Func _UC_RadialProgress_Draw($hWnd, ByRef $m)

    Local $aSize = WinGetClientSize($hWnd)

    Local $iW = $aSize[0]
    Local $iH = $aSize[1]

    If $iW <= 0 Or $iH <= 0 Then Return

    Local $hBGColor = "0xFF" & Hex(__UC_ParentColor($hWnd), 6)

    Local $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hWnd)

    Local $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGraphics)
    Local $hBack = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    ; Quality
    _GDIPlus_GraphicsSetSmoothingMode($hBack, 4)
    _GDIPlus_GraphicsSetPixelOffsetMode($hBack, 4)
    _GDIPlus_GraphicsSetTextRenderingHint($hBack, 5)

    ; Clear
    _GDIPlus_GraphicsClear($hBack, $hBGColor)

    ; Percent
    Local $iRange = $m.Max - $m.Min
    If $iRange <= 0 Then $iRange = 1

    Local $fPercent = ($m.Value - $m.Min) / $iRange

    If $fPercent < 0 Then $fPercent = 0
    If $fPercent > 1 Then $fPercent = 1

    Local $fSweep = 360 * $fPercent

    ; Geometry
    Local $iThickness = $m.RingThickness

    Local $iPad = Ceiling($iThickness / 2) + 2

    Local $iArcW = $iW - ($iPad * 2)
    Local $iArcH = $iH - ($iPad * 2)

    ; Pens
    Local $hTrackPen = _GDIPlus_PenCreate( _
            "0xFF" & Hex($m.TrackColor, 6), _
            $iThickness)

    Local $hProgPen = _GDIPlus_PenCreate( _
            "0xFF" & Hex($m.ProgressColor, 6), _
            $iThickness)

    ; Round caps
    If $m.RoundCap Then
        _GDIPlus_PenSetStartCap($hProgPen, 2)
        _GDIPlus_PenSetEndCap($hProgPen, 2)
    EndIf

    ; Track
    _GDIPlus_GraphicsDrawArc( _
            $hBack, _
            $iPad, _
            $iPad, _
            $iArcW, _
            $iArcH, _
            0, _
            360, _
            $hTrackPen)

    ; Glow
    If $m.Glow Then

        Local $hGlowPen = _GDIPlus_PenCreate( _
                "0x40" & Hex($m.ProgressColor, 6), _
                $iThickness + 8)

        If $m.RoundCap Then
            _GDIPlus_PenSetStartCap($hGlowPen, 2)
            _GDIPlus_PenSetEndCap($hGlowPen, 2)
        EndIf

        _GDIPlus_GraphicsDrawArc( _
                $hBack, _
                $iPad, _
                $iPad, _
                $iArcW, _
                $iArcH, _
                $m.StartAngle, _
                $fSweep, _
                $hGlowPen)

        _GDIPlus_PenDispose($hGlowPen)

    EndIf

    ; Progress arc
    _GDIPlus_GraphicsDrawArc( _
            $hBack, _
            $iPad, _
            $iPad, _
            $iArcW, _
            $iArcH, _
            $m.StartAngle, _
            $fSweep, _
            $hProgPen)

    ; Center fill
    If $m.CenterColor <> -1 Then

        Local $hCenterBrush = _GDIPlus_BrushCreateSolid( _
                "0xFF" & Hex($m.CenterColor, 6))

        Local $iCenter = $iThickness + 4

        _GDIPlus_GraphicsFillEllipse( _
                $hBack, _
                $iCenter, _
                $iCenter, _
                $iW - ($iCenter * 2), _
                $iH - ($iCenter * 2), _
                $hCenterBrush)

        _GDIPlus_BrushDispose($hCenterBrush)

    EndIf

    ; Percentage text
    If $m.ShowPercent Then

        Local $sText = Int($fPercent * 100) & "%"

        Local $hFamily = _GDIPlus_FontFamilyCreate($m.Font)

        Local $hFont = _GDIPlus_FontCreate( _
                $hFamily, _
                $m.FontSize, _
                $m.FontStyle)

        Local $hBrushTxt = _GDIPlus_BrushCreateSolid( _
                "0xFF" & Hex($m.TextColor, 6))

        Local $hFormat = _GDIPlus_StringFormatCreate()

        _GDIPlus_StringFormatSetAlign($hFormat, 1)
        _GDIPlus_StringFormatSetLineAlign($hFormat, 1)

        Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iW, $iH)

        _GDIPlus_GraphicsDrawStringEx( _
                $hBack, _
                $sText, _
                $hFont, _
                $tLayout, _
                $hFormat, _
                $hBrushTxt)

        _GDIPlus_StringFormatDispose($hFormat)
        _GDIPlus_BrushDispose($hBrushTxt)
        _GDIPlus_FontDispose($hFont)
        _GDIPlus_FontFamilyDispose($hFamily)

    EndIf

    ; Present
    _GDIPlus_GraphicsDrawImageRect( _
            $hGraphics, _
            $hBitmap, _
            0, _
            0, _
            $iW, _
            $iH)

    ; Cleanup
    _GDIPlus_PenDispose($hTrackPen)
    _GDIPlus_PenDispose($hProgPen)

    _GDIPlus_GraphicsDispose($hBack)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)

EndFunc   ;==>_UC_RadialProgress_Draw
#EndRegion ; ~~~~~~~~~~~~~ UC Radial Progress API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 

Please, every comment is appreciated!
leave your comments and experiences here!
Thank you very much  :)

 

Edited by ioa747
Version (0.0.8.0)

Comments

Popular posts from this blog