A very simple SetGadgetColorEx() function [Windows]

Share your advanced PureBasic knowledge/code with the community.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

A very simple SetGadgetColorEx() function [Windows]

Post by Zapman »

This library extends the SetGadgetColor() PureBasic native function to all of the PureBasic gadgets.

Simply add

Code: Select all

XIncludeFile "SetGadgetColorEx.pbi"
into your code, and then you can use SetGadgetColor() for buttons, Panels, Combos, StringGadgets, ExplorerComboGadget etc.

You can also call 'ApplyColorsToAllGadgets()' to attribute a couple of colors to all of the gadgets figuring into a particular window.

[Edit 03 feb. 2025] : the code below has been improved. It is now faster and works better with ListView and ComboBox gadgets.
The ApplyColorThemes.pbi library which appears in one of the posts below has also been updated.
[Edit 05 feb. 2025] : Combox and editable Combox are now flawless, as their lists.
[Edit 08 feb. 2025] : The FrameGadget reacts to its creation flags (#PB_Frame_Single, #PB_Frame_Double, #PB_Frame_Flat or #PB_Frame_Container). Drawing a big contener is far faster.
[Edit 12 feb. 2025] : The PanelGadget's arrows (look at the up-right arrows of the following picture) are now colorized. The library functions have be simplified and optimized for all gadgets having child windows. Adding of a 'ApplyColorsToAllGadgets()' function.
[Edit 19 feb. 2025] : All gadgets are now fully colorized by the library.
[Edit 25 feb. 2025] : ExplorerCombo, Calendar and Date gadgets had problems with some versions of Windows. That is fixed.

To be sure to get the last version, visit https://www.editions-humanis.com/downlo ... ads_EN.htm.

Image

Due to the size limitation of the forum, the code below has very few comments. Download the full version from https://www.editions-humanis.com/downlo ... ads_EN.htm.

Code: Select all

;
; ****************************************************************************************
;
;                                   SetGadgetColorEx()
;                                      Windows only
;                              Zapman - March 2025 - 4 Forum
;
;            This file should be saved under the name "SetGadgetColorEx.pbi".
;
; ****************************************************************************************
;
;-   1--- FIRST PART: MISCELLANEOUS FUNCTIONS (possibly reusable for other needs) ---
;
CompilerIf Not(Defined(DwmSetWindowAttribute, #PB_Prototype))
  Prototype.i DwmSetWindowAttribute(hWnd.i, dwAttribute.i, pvAttribute.i, cbAttribute.i)
CompilerEndIf
;
CompilerIf Not(Defined(IsDarkModeEnabled, #PB_Procedure))
  Procedure IsDarkModeEnabled()
    ;
    Protected key = 0
    Protected darkModeEnabled = 0
    ;
    If RegOpenKeyEx_(#HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", 0, #KEY_READ, @key) = #ERROR_SUCCESS
      Protected value = 1
      Protected valueSize = SizeOf(value)
      If RegQueryValueEx_(key, "AppsUseLightTheme", 0, #Null, @value, @valueSize) = #ERROR_SUCCESS
        darkModeEnabled = Abs(value - 1) ; 0 = dark, 1 = light
      EndIf
      RegCloseKey_(key)
    EndIf
    ;
    ProcedureReturn darkModeEnabled
  EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(ApplyDarkModeToWindow, #PB_Procedure))
  Procedure ApplyDarkModeToWindow(Window = 0)
    ;
    Protected hWnd = WindowID(Window)
    ;
    If hWnd And OSVersion() >= #PB_OS_Windows_10
      Protected hDwmapi = OpenLibrary(#PB_Any, "dwmapi.dll")
      ;
      If hDwmapi
        Protected DwmSetWindowAttribute_.DwmSetWindowAttribute = GetFunction(hDwmapi, "DwmSetWindowAttribute")
        ; Enable dark mode if possible
        If DwmSetWindowAttribute_
          Protected darkModeEnabled = IsDarkModeEnabled()
          If darkModeEnabled
            #DWMWA_USE_IMMERSIVE_DARK_MODE = 20
            DwmSetWindowAttribute_(hWnd, #DWMWA_USE_IMMERSIVE_DARK_MODE, @darkModeEnabled, SizeOf(darkModeEnabled))
            SetWindowColor(Window, $202020)
            ;
            If IsWindowVisible_(hWnd)
              HideWindow(Window, #True)
              HideWindow(Window, #False)
            EndIf
          EndIf
        EndIf
        ;
        CloseLibrary(hDwmapi)
      EndIf
    EndIf
  EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(GetProperty, #PB_Procedure))
  ;
  Procedure GP_EnumPropsProc(hWnd, lpszString, hData, lParam)
    If lpszString > 65536
      If PeekS(lpszString) = PeekS(lParam)
        PokeS(lParam, "*")
        ProcedureReturn #False
      EndIf
    EndIf
    ProcedureReturn #True
  EndProcedure
  ;
  Procedure GetProperty(hWnd, propName$)
    ;
    If propName$
      Protected TString$ = propName$
      EnumPropsEx_(hWnd, @GP_EnumPropsProc(), @TString$)
      If TString$ = "*"
        ProcedureReturn GetProp_(hWnd, propName$)
      Else
        ProcedureReturn -1
      EndIf
    Else
      ProcedureReturn -1
    EndIf
  EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(GetGadgetParentWindow, #PB_Procedure))
  Procedure GetGadgetParentWindow(Gadget)
    ;
    ; This function is by 'mk-soft', english forum.
    ;
    Protected ID, r1
    ;
    If IsGadget(Gadget)
      CompilerSelect #PB_Compiler_OS
        CompilerCase #PB_OS_MacOS
          Protected *Gadget.sdkGadget = IsGadget(Gadget)
          If *Gadget
            ID = WindowID(*Gadget\Window)
            r1 = PB_Window_GetID(ID)
          Else
            r1 = -1
          EndIf
        CompilerCase #PB_OS_Linux
          ID = gtk_widget_get_toplevel_(GadgetID(Gadget))
          If ID
            r1 = g_object_get_data_(ID, "pb_id")
          Else
            r1 = -1
          EndIf
        CompilerCase #PB_OS_Windows           
          ID = GetAncestor_(GadgetID(Gadget), #GA_ROOT)
          r1 = GetProp_(ID, "PB_WINDOWID")
          If r1 > 0
            r1 - 1
          Else
            r1 = -1
          EndIf
      CompilerEndSelect
    Else
      r1 = -1
    EndIf
    ProcedureReturn r1
  EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(MixColors, #PB_Procedure))
  Procedure MixColors(Color1, Color2, Ratio.f)
    If Ratio > 1 : Ratio = 1 : EndIf
    Protected Red = Red(Color1) * Ratio + Red(Color2) * (1 - Ratio)
    Protected Green = Green(Color1) * Ratio + Green(Color2) * (1 - Ratio)
    Protected Blue = Blue(Color1) * Ratio + Blue(Color2) * (1 - Ratio)
    ProcedureReturn RGB(Red, Green, Blue)
  EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(ShiftColorComponent, #PB_Procedure))
  Procedure ShiftColorComponent(CComponent, Shift)
    CComponent + Shift
    If CComponent < 0 : CComponent = 0 : EndIf
    If CComponent > 256 : CComponent = 256 : EndIf
    ProcedureReturn CComponent
  EndProcedure
CompilerEndIf
;
;
; ****************************************************************************************
;-              2--- SECOND PART: SPECIALIZED FUNCTIONS FOR THIS LIBRARY ---
;
EnumerationBinary EdgesStyle
  #SGCE_NoEdges = 0
  #SGCE_HoverSensitive = 1
  #SGCE_Flat
  #SGCE_Single
  #SGCE_Double
  #SGCE_WithTitle
EndEnumeration
;
Structure SGCE_GadgetsInfosStruct
  ID.i
  Handle.i
  FrontColor.i
  BackColor.i
  EdgesColor.l
  HighlightedEdgesColor.l
  EdgesStyle.i
  Enabled.i
  MainWindow.i
EndStructure
;
#SGCE_StandardColors = -1
;
NewList SGCE_GadgetsInfos.SGCE_GadgetsInfosStruct()
;
Procedure SGCE_IsCustomColorGadget(GadgetID)
  ;
  Protected CustomColor = 1
  ;
  Select GadgetType(GadgetID)
    Case #PB_GadgetType_Button, #PB_GadgetType_CheckBox, #PB_GadgetType_Option, #PB_GadgetType_Panel
      CustomColor = 1
    Case #PB_GadgetType_ComboBox, #PB_GadgetType_ExplorerCombo, #PB_GadgetType_Frame, #PB_GadgetType_Container
      CustomColor = 1
    Case #PB_GadgetType_Calendar, #PB_GadgetType_Date, #PB_GadgetType_ListIcon
      CustomColor = 1
    Case #PB_GadgetType_ExplorerList
      CustomColor = 1
      ;
    Case #PB_GadgetType_Editor, #PB_GadgetType_String, #PB_GadgetType_ListView, #PB_GadgetType_ButtonImage
      CustomColor = -1
    Case #PB_GadgetType_Spin, #PB_GadgetType_Image, #PB_GadgetType_ExplorerTree, #PB_GadgetType_Tree
      CustomColor = -1
    Case #PB_GadgetType_MDI, #PB_GadgetType_ScrollArea
      CustomColor = -1
      ;
    Case #PB_GadgetType_Canvas, #PB_GadgetType_HyperLink, #PB_GadgetType_Text, #PB_GadgetType_ProgressBar
      CustomColor = 0
  EndSelect
  ProcedureReturn CustomColor
EndProcedure
;
CompilerIf Not(Defined(RGBAColor, #PB_Structure))
  Structure RGBAColor
    red.a
    green.a
    blue.a
    alpha.a
  EndStructure
CompilerEndIf
;
Procedure SGCE_PartialReplaceColors(StartX, StartY, EndX, EndY, Width, *BitmapAddress, maxlum, LowContrast.f, *backColor.RGBAColor, *FrontColor.RGBAColor, DoBlowOut = 1)
  ;
  Structure tagRGBQUAD
    blue.a
    green.a
    red.a
    alpha.a
  EndStructure
  ;
  Protected y, x, *pixelColor.tagRGBQUAD, PixelDarkness.f, PixelLuminosity.f
  Protected BlowOut.f, CrushBlacks.f, mColor.l, mConvColor.l
  ;
  For y = StartY To EndY - 1
    Protected yXWidth = y * Width
    For x = StartX To EndX - 1
      *pixelColor = *BitmapAddress + (yXWidth + x) * 4
      If mColor = PeekL(*pixelColor)
        PokeL(*pixelColor, mConvColor)
      Else
        mColor = PeekL(*pixelColor)
        ;
        PixelLuminosity = (*pixelColor\red + *pixelColor\green + *pixelColor\blue) / maxlum
        ;
        If DoBlowOut And PixelLuminosity > 0.7
          Protected Emphasys.f = 3.7
          BlowOut = (PixelLuminosity + 1) * (PixelLuminosity + 1) / Emphasys
          If BlowOut > 1 : BlowOut = 1 : EndIf
          PixelLuminosity = PixelLuminosity * (1 - LowContrast) + BlowOut * LowContrast

        EndIf
        If DoBlowOut = 2 And PixelLuminosity < 0.99
          PixelLuminosity * 0.95
        EndIf
        If PixelLuminosity < 0.3
          CrushBlacks = PixelLuminosity * PixelLuminosity * PixelLuminosity
          PixelLuminosity = PixelLuminosity * (1 - LowContrast) + CrushBlacks * LowContrast
        EndIf
        ;
        If PixelLuminosity > 1 : PixelLuminosity = 1 : EndIf
        PixelDarkness = 1 - PixelLuminosity
        ;
        *pixelColor\red   * PixelDarkness + *backColor\red   * PixelLuminosity
        *pixelColor\green * PixelDarkness + *backColor\green * PixelLuminosity
        *pixelColor\blue  * PixelDarkness + *backColor\blue  * PixelLuminosity
        ;
        *pixelColor\red   * PixelLuminosity + *FrontColor\red   * PixelDarkness
        *pixelColor\green * PixelLuminosity + *FrontColor\green * PixelDarkness
        *pixelColor\blue  * PixelLuminosity + *FrontColor\blue  * PixelDarkness
        mConvColor = PeekL(*pixelColor)
      EndIf
      ;
    Next
  Next
EndProcedure
;
Procedure SGCE_CreateBitmapWithAddress(hDCSrce, Width, Height, *backColor.RGBAColor, *FrontColor.RGBAColor, *memDC.Integer, *BitmapAddress.Integer, *oldBitmap.Integer, *maxlum.Integer, *LowContrast.float)
  ;
  ; Initialize a BITMAPINFO structure:
  Protected bmi.BITMAPINFO
  bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth = Width
  bmi\bmiHeader\biHeight = Height
  bmi\bmiHeader\biPlanes = 1
  bmi\bmiHeader\biBitCount = 32     ; 32 bits par pixel (RGBA).
  bmi\bmiHeader\biCompression = #BI_RGB
  ;
  *maxlum\i = Red(GetSysColor_(#COLOR_BTNFACE)) + Green(GetSysColor_(#COLOR_BTNFACE)) + Blue(GetSysColor_(#COLOR_BTNFACE))
  *LowContrast\f = (*backColor\red + *backColor\green + *backColor\blue - *FrontColor\red - *FrontColor\green - *FrontColor\blue) / *maxlum\i
  *LowContrast\f = Abs(1 - Abs(*LowContrast\f))
  ;
  Protected hBitmap = CreateDIBSection_(hDCSrce, bmi, #DIB_RGB_COLORS, *BitmapAddress, 0, 0)
  ;
  *memDC\i = CreateCompatibleDC_(hDCSrce)
  ;
  *oldBitmap\i = SelectObject_(*memDC\i, hBitmap)
  BitBlt_(*memDC\i, 0, 0, Width, Height, hDCSrce, 0, 0, #SRCCOPY)
  ProcedureReturn hBitmap
EndProcedure
;
Procedure SGCE_RepaintEdges(*GadgetsInfos.SGCE_GadgetsInfosStruct, Highlight = #False, hDCType = 1)
  ;
  Protected gRect.Rect, pt.point, ps.PAINTSTRUCT
  Protected hdc, hOldPen, hOldBrush, hBrush, hPen
  Protected gHandle = *GadgetsInfos\Handle
  Protected EdgeShift, EdgeWidth, EdgesColor, PaintBackground
  ;
  If *GadgetsInfos\EdgesStyle & #SGCE_Double
    EdgeWidth = 2
  ElseIf *GadgetsInfos\EdgesStyle & #SGCE_Single Or *GadgetsInfos\EdgesStyle & #SGCE_Flat Or *GadgetsInfos\EdgesStyle & #SGCE_WithTitle
    EdgeWidth = 1
  Else
    EdgeWidth = 0
  EndIf
  ;
  If Highlight
    EdgesColor = *GadgetsInfos\HighlightedEdgesColor
    If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Date
      PaintBackground = #True
    Else
      PaintBackground = #False
    EndIf
  Else
    If *GadgetsInfos\EdgesStyle & #SGCE_Flat
      EdgesColor = *GadgetsInfos\FrontColor
    Else
      EdgesColor = *GadgetsInfos\EdgesColor
    EndIf
    ;
    If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Container
      PaintBackground = #True
    ElseIf GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Frame And GetWindow_(GadgetID(*GadgetsInfos\ID), #GW_CHILD)
      PaintBackground = #True
    EndIf
  EndIf
  ;
  If EdgeWidth Or PaintBackground
    If Abs(hDCType) > 2
      hdc = hDCType
      GetClientRect_(gHandle, @gRect)
      If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Frame
        gRect\top + DesktopScaledX(10) - 3
      EndIf
    ElseIf hDCType = -1
      hDC = BeginPaint_(gHandle, ps)
      GetClientRect_(gHandle, @gRect)
      gRect\right + 2 * EdgeWidth : gRect\bottom + 2 * EdgeWidth
    ElseIf hDCType > 0
      hdc =  GetDC_(GetParent_(gHandle))
      GetWindowRect_(gHandle, @gRect)
      pt\x = gRect\left : pt\y = gRect\top
      ScreenToClient_(GetParent_(gHandle), @pt)
      gRect\right - gRect\left + pt\x : gRect\bottom - gRect\top + pt\y
      gRect\left = pt\x : gRect\top = pt\y
    Else ; hDCType = 0
      hdc =  GetDC_(gHandle)
      GetWindowRect_(gHandle, @gRect)
      gRect\right - gRect\left : gRect\bottom - gRect\top
      gRect\left = 0 : gRect\top = 0
      ;
    EndIf
    ;
    If EdgeWidth
      hPen = CreatePen_(#PS_SOLID, EdgeWidth, EdgesColor)
    Else
      hPen = CreatePen_(#PS_SOLID, EdgeWidth, *GadgetsInfos\BackColor)
    EndIf
    If PaintBackground
      hBrush = CreateSolidBrush_(*GadgetsInfos\BackColor)
    Else
      hBrush = GetStockObject_(#NULL_BRUSH)
    EndIf
    hOldPen = SelectObject_(hDC, hPen)
    hOldBrush = SelectObject_(hDC, hBrush)
    ;
    Rectangle_(hdc, gRect\left - EdgeShift + EdgeWidth/2, gRect\top - EdgeShift + EdgeWidth/2, gRect\right - EdgeShift, gRect\bottom - EdgeShift)
    If PaintBackground = 0 And EdgeWidth = 1
      ; Erase the inner white frame:
      DeleteObject_(hPen)
      hPen = CreatePen_(#PS_SOLID, 1, *GadgetsInfos\BackColor)
      SelectObject_(hDC, hPen)
      Rectangle_(hdc, gRect\left - EdgeShift + 1, gRect\top - EdgeShift + 1, gRect\right - EdgeShift - 1, gRect\bottom - EdgeShift - 1)
    EndIf
    SelectObject_(hDC, hOldPen)
    SelectObject_(hDC, hOldBrush)
    DeleteObject_(hBrush)
    DeleteObject_(hPen)
    If Abs(hDCType) <= 2 And hDCType <> -1
      DeleteDC_(hdc)
    EndIf
  ElseIf hDCType = -1
    BeginPaint_(gHandle, ps)
  EndIf
  If hDCType = -1
    EndPaint_(gHandle, ps)
  EndIf
EndProcedure
;
Define SGCE_KillCalendarAnimation
Procedure SGCE_DrawAndReplaceColors(gHandle, lParam, OldCBProc, BackColor, FrontColor, GType)
  ;
  Protected ps.PAINTSTRUCT, gRect.Rect, ActualTheme
  Protected hBitmap, oldBitmap, memDC, maxlum, LowContrast.f
  Protected *BitmapAddress, CenterRect.Rect, hBrush, hDC
  Shared SGCE_KillCalendarAnimation
  ;
  If GType = #PB_GadgetType_Date Or GType = #PB_GadgetType_Calendar
    If SGCE_KillCalendarAnimation
      ActualTheme = GetWindowTheme_(gHandle)
      If ActualTheme <> 0
        SetProp_(gHandle, "SGCE_OldTheme", ActualTheme)
        SetWindowTheme_(gHandle, "", "")
        SendMessage_(gHandle, #MCM_SETCOLOR, #MCSC_BACKGROUND,  BackColor)
      EndIf
      SGCE_KillCalendarAnimation = #False
    EndIf
    ;
    ActualTheme = GetWindowTheme_(gHandle)
    If ActualTheme = 0 And GetProp_(gHandle, "SGCE_OldTheme")
      SetWindowTheme_(gHandle, @"Explorer", #Null)
    EndIf
  EndIf
    ;
  GetClientRect_(gHandle, @gRect)
  ;
  hdc = BeginPaint_(gHandle, ps)
  ;
  Protected width = gRect\right - gRect\left
  Protected Height = gRect\bottom - gRect\top
  ;
  hBitmap = SGCE_CreateBitmapWithAddress(hDC, Width, Height, @BackColor, @FrontColor, @memDC, @*BitmapAddress, @oldBitmap, @maxlum, @LowContrast)
  ;
  CallWindowProc_(OldCBProc, gHandle, #WM_PAINT, memDC, lParam)
  ;
  ; Change image colors:
  ;
  If GType = #PB_GadgetType_Panel
    SelectClipRgn_(memDC, 0)
    ;
    Protected hSlice = DesktopScaledX(3), vSlice = DesktopScaledY(3), upSlice = DesktopScaledY(26)
    ;
    If hSlice > Width : hSlice = Width : EndIf
    If vSlice > Height : vSlice = Height : EndIf
    If vSlice + upSlice > Height : upSlice = Height - vSlice : EndIf
    SGCE_PartialReplaceColors(0, 0, Width, hSlice, Width, *BitmapAddress, maxlum, LowContrast, @BackColor, @FrontColor, 2)
    SGCE_PartialReplaceColors(0, Height - upSlice, Width, Height, Width, *BitmapAddress, maxlum, LowContrast, @BackColor, @FrontColor, 2)
    SGCE_PartialReplaceColors(0, vslice, hSlice, Height - upSlice, Width, *BitmapAddress, maxlum, LowContrast, @BackColor, @FrontColor, 2)
    SGCE_PartialReplaceColors(Width - hSlice, vslice, Width, Height - upSlice, Width, *BitmapAddress, maxlum, LowContrast, @BackColor, @FrontColor, 2)
    ;
    If Width > hSlice * 2 And Height > (vSlice + upSlice)
      hBrush = CreateSolidBrush_(PeekL(@BackColor))
      CenterRect\left = hSlice : CenterRect\right = Width - hSlice
      CenterRect\top = upSlice : CenterRect\bottom = Height - vSlice
      FillRect_(memDC, CenterRect, hBrush)
      DeleteObject_(hBrush)
    EndIf
    ;
  Else
    SGCE_PartialReplaceColors(0, 0, Width, Height, Width, *BitmapAddress, maxlum, LowContrast, @BackColor, @FrontColor)
  EndIf
  ;
  ;
  BitBlt_(hdc, gRect\left, gRect\top, width, Height, memDC, 0, 0, #SRCCOPY)
  ;
  SelectObject_(memDC, oldBitmap)
  DeleteObject_(hBitmap)
  DeleteDC_(memDC)
  ;           
  EndPaint_(gHandle, ps)
EndProcedure
;
Procedure SGCE_ChildrenCallback(CTRLhandle, uMsg, wParam, lParam)
  ;
  Protected SGCE_OldCallBack = GetProp_(CTRLhandle, "SGCE_OldCallBack")
  Protected *GadgetsInfos.SGCE_GadgetsInfosStruct = GetWindowLongPtr_(CTRLhandle, #GWL_USERDATA)
  ;
  If uMsg = #WM_PAINT
    SGCE_DrawAndReplaceColors(CTRLhandle, lParam, SGCE_OldCallBack, *GadgetsInfos\BackColor, *GadgetsInfos\FrontColor, GadgetType(*GadgetsInfos\ID))
    ProcedureReturn 1
  EndIf
  ;
  ProcedureReturn CallWindowProc_(SGCE_OldCallBack, CTRLhandle, uMsg, wParam, lParam)
EndProcedure
;
Procedure SGCE_DropDownCallback(gHandle, uMsg, wParam, lParam)
  ;
  Protected SGCE_OldCallBack = GetProp_(gHandle, "SGCE_OldCallBack")
  Protected ps.PAINTSTRUCT
  Protected *GadgetsInfos.SGCE_GadgetsInfosStruct = GetWindowLongPtr_(gHandle, #GWL_USERDATA)
  ;
  If uMsg = #WM_PAINT
    BeginPaint_(gHandle, ps)
    EndPaint_(gHandle, ps)
    ;
    SGCE_RepaintEdges(*GadgetsInfos, #True, 0)
    ProcedureReturn 0
  EndIf
  ;
  ProcedureReturn CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lParam)
EndProcedure
;
Procedure SGCE_DrawContainerGadget(*GadgetsInfos.SGCE_GadgetsInfosStruct)
  ;
  ;
  Protected ps.PAINTSTRUCT
  Protected gHandle = *GadgetsInfos\Handle
  ;
  BeginPaint_(gHandle, ps)
  EndPaint_(gHandle, ps)
  ;
  SGCE_RepaintEdges(*GadgetsInfos)
EndProcedure
;
Procedure SGCE_DrawFrameGadget(*GadgetsInfos.SGCE_GadgetsInfosStruct)
  ;
  ;
  Protected gRect.Rect, Size.SIZE, ps.PAINTSTRUCT
  Protected gHandle = *GadgetsInfos\Handle, hBrush
  ;
  If *GadgetsInfos\EdgesStyle & #SGCE_WithTitle = 0
    SGCE_RepaintEdges(*GadgetsInfos, #False, -1)
  Else
    ;
    Protected hDC = BeginPaint_(gHandle, ps)
    SGCE_RepaintEdges(*GadgetsInfos, #False, hDC)
    ;
    Protected Text$ = GetGadgetText(*GadgetsInfos\ID)
    Protected hFont = SendMessage_(gHandle, #WM_GETFONT, 0, 0)
    SelectObject_(hDC, hFont)
    ;
    If Text$
      GetClientRect_(gHandle, @gRect.Rect)
      gRect\Left + DesktopScaledX(4)
      gRect\top + DesktopScaledX(10) - 3
      gRect\bottom = gRect\top + 1
      GetTextExtentPoint32_(hDC, Text$, Len(Text$), @Size) ; Get the text width
      gRect\Right = gRect\Left + Size\cx + DesktopScaledX(6)
      hBrush = CreateSolidBrush_(*GadgetsInfos\BackColor)
      FillRect_(hdc, gRect, hBrush)
      DeleteObject_(hBrush)
      ;
      gRect\top - DesktopScaledX(15) + 7
      gRect\bottom + 30
      SetTextColor_(hDC, *GadgetsInfos\FrontColor)
      SetBkMode_(hDC, #TRANSPARENT)
      DrawText_(hDC, Text$, Len(Text$), @gRect.Rect, #DT_CENTER | #DT_SINGLELINE)
    EndIf
    ;
    EndPaint_(gHandle, ps)
  EndIf
  ProcedureReturn 1
  ;
EndProcedure
;
Procedure SGCE_DrawExplorerComboItem(SGCE_OldCallBack, gHandle, uMsg, wParam, lparam, *GadgetsInfos.SGCE_GadgetsInfosStruct)
  ;
  Protected bitmapInfo.BITMAP
  Protected *dis.DRAWITEMSTRUCT = lParam
  Protected hDC = *dis\hDC
  Protected disWidth = *dis\rcItem\right - *dis\rcItem\left
  Protected disHeight = *dis\rcItem\bottom - *dis\rcItem\top
  ; 
  Protected hBitmapSrc = GetCurrentObject_(hDC, #OBJ_BITMAP)
  GetObject_(hBitmapSrc, SizeOf(BITMAP), @bitmapInfo.BITMAP)
  Protected Width = bitmapInfo\bmWidth
  Protected Height = bitmapInfo\bmHeight
  ;
  Protected hBitmap, oldBitmap, memDC, maxlum, LowContrast.f
  Protected *BitmapAddress
  ;
  hBitmap = SGCE_CreateBitmapWithAddress(hDC, Width, Height, @*GadgetsInfos\BackColor, @*GadgetsInfos\FrontColor, @memDC, @*BitmapAddress, @oldBitmap, @maxlum, @LowContrast)
  ;         
  SelectObject_(memDC, GetCurrentObject_(hDC, #OBJ_FONT))
  ;
  *dis\hDC = memDC
  CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lparam)
  *dis\hDC = hDC
  ;
  If *dis\itemAction <> #ODA_FOCUS
    SGCE_PartialReplaceColors(0, 0, Width, Height, Width, *BitmapAddress, maxlum, LowContrast, @*GadgetsInfos\BackColor, @*GadgetsInfos\FrontColor, 0)
  EndIf
  ;
  If *dis\itemAction = #ODA_DRAWENTIRE And *dis\rcItem\top < SendMessage_(gHandle, #CB_GETITEMHEIGHT, 0, 0)
    SelectClipRgn_(hDC, 0)
    BitBlt_(hDC, 0, 0, Width, Height, memDC, 0, 0, #SRCCOPY)
  Else
    BitBlt_(hDC, *dis\rcItem\left, *dis\rcItem\top, disWidth, disHeight, memDC, *dis\rcItem\left, *dis\rcItem\top, #SRCCOPY)
  EndIf
  ;
  SelectObject_(memDC, oldBitmap)
  DeleteObject_(hBitmap)
  DeleteDC_(memDC)
  ;
EndProcedure
;
Procedure SGCE_InstallCallbackAndData(hWnd, *procAddr, *GadgetsInfos, ClassName$ = "")
  If ClassName$
    Protected WclassName$ = Space(256)
    GetClassName_(hWnd, @WclassName$, 255)
    If LCase(WclassName$) <> LCase(ClassName$)
      ProcedureReturn #False
    EndIf
  EndIf
  Protected SGCE_OldCallBack = GetProp_(hWnd, "SGCE_OldCallBack")
  If SGCE_OldCallBack = 0
    SGCE_OldCallBack = SetWindowLongPtr_(hWnd, #GWL_WNDPROC, *procAddr)
    SetProp_(hWnd, "SGCE_OldCallBack"   , SGCE_OldCallBack)
    SetProp_(hWnd, "SGCE_ActualCallBack", *procAddr)
    If *GadgetsInfos
      SetWindowLongPtr_(hWnd, #GWL_USERDATA, *GadgetsInfos)
    EndIf
    ProcedureReturn #True
  EndIf
EndProcedure
;
Procedure SGCE_UnUnstallCallback(hWnd, ClassName$ = "")
  If hWnd
    If ClassName$
      Protected WclassName$ = Space(256)
      GetClassName_(hWnd, @WclassName$, 255)
      If LCase(WclassName$) <> LCase(ClassName$)
        ProcedureReturn #False
      EndIf
    EndIf
    Protected SGCE_OldCallBack    = GetProp_(hWnd, "SGCE_OldCallBack")
    Protected SGCE_ActualCallBack = GetProp_(hWnd, "SGCE_ActualCallBack")
    If SGCE_OldCallBack And GetWindowLongPtr_(hWnd, #GWL_WNDPROC) = SGCE_ActualCallBack
      SetWindowLongPtr_(hWnd, #GWL_WNDPROC, SGCE_OldCallBack)
      RemoveProp_(hWnd, "SGCE_OldCallBack")
      RemoveProp_(hWnd, "SGCE_ActualCallBack")
      ProcedureReturn #True
    EndIf
  EndIf
EndProcedure
;
Procedure SGCE_EnumThreadAndInstallCallback(hWnd, *GadgetsInfos.SGCE_GadgetsInfosStruct)
  ;
  Protected hCal, gRect.Rect
  Protected className$ = Space(256)
  ;
  GetClassName_(hWnd, @className$, 255)
  If LCase(className$) = "dropdown"
    If SGCE_InstallCallbackAndData(hWnd, @SGCE_DropDownCallback(), *GadgetsInfos)
      hCal = GetWindow_(hWnd, #GW_CHILD)
      SGCE_InstallCallbackAndData(hCal, @SGCE_ChildrenCallback(), *GadgetsInfos)
      ;
      SendMessage_(hCal, #MCM_GETMINREQRECT, 0, @gRect.Rect)
      SetWindowPos_(hWnd, 0, 0, 0, gRect\right - gRect\left, gRect\bottom - gRect\top + 6, #SWP_NOMOVE | #SWP_NOZORDER)
      ;
      *GadgetsInfos\Handle = hWnd
    EndIf
  EndIf
  ProcedureReturn #True
EndProcedure
;
Procedure SGCE_RedrawChildWindows(hWnd, lParam)
  If GetProperty(hWnd, "PB_ID") <> -1
    InvalidateRect_(hWnd, 0, #True)
  EndIf
  ProcedureReturn #True
EndProcedure
;
Procedure SGCE_ChangeColorsCallback(gHandle, uMsg, wParam, lParam)
  ;
  Protected hCTRLWnd, BackColor, BackLuminosity, Shift
  Protected *GadgetsInfos.SGCE_GadgetsInfosStruct = GetWindowLongPtr_(gHandle, #GWL_USERDATA)
  Protected SGCE_OldCallBack = GetProp_(gHandle, "SGCE_OldCallBack")
  Static    LastHoveredGadget
  Shared    SGCE_KillCalendarAnimation
  ;
  Select uMsg
    Case #WM_CAPTURECHANGED
      If IsGadget(*GadgetsInfos\ID) And (GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Date)
        EnumThreadWindows_(GetCurrentThreadId_(), @SGCE_EnumThreadAndInstallCallback(), *GadgetsInfos)
      EndIf
      ;
    Case #WM_NOTIFY
      If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Date
        Protected *nmhdr.NMHDR = lParam
        If *nmhdr\code = #NM_RELEASEDCAPTURE
          SGCE_KillCalendarAnimation = #True
        EndIf
      EndIf
      ;
    Case #WM_LBUTTONUP
      If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Calendar
        SGCE_KillCalendarAnimation = #True
      EndIf
      ;
    Case 4097
      If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Date Or GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Calendar
        SGCE_KillCalendarAnimation = #True
      EndIf
      ;
    Case #WM_DRAWITEM
      If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_ExplorerCombo
        SGCE_DrawExplorerComboItem(SGCE_OldCallBack, gHandle, uMsg, wParam, lparam, *GadgetsInfos)
        ;        
        ProcedureReturn 0
      EndIf
      ;
    Case #WM_SETTEXT, #WM_ENABLE
      InvalidateRect_(gHandle, 0, #True)
      ;
    Case #WM_MOUSEMOVE, #WM_NCMOUSEMOVE
      CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lParam)
      If LastHoveredGadget <> gHandle
        If *GadgetsInfos\EdgesStyle & #SGCE_HoverSensitive
          SGCE_RepaintEdges(*GadgetsInfos, #True)
          LastHoveredGadget = gHandle
          ;
          Protected tme.TRACKMOUSEEVENT
          tme\cbSize = SizeOf(TRACKMOUSEEVENT)
          tme\hwndTrack = gHandle
          tme\dwFlags = #TME_LEAVE
          If uMsg = #WM_NCMOUSEMOVE
            tme\dwFlags | #TME_NONCLIENT
          EndIf
          TrackMouseEvent_(@tme)
        EndIf
      EndIf
      ;
    Case #WM_MOUSELEAVE, #WM_NCMOUSELEAVE
      If LastHoveredGadget
        LastHoveredGadget = 0
        If *GadgetsInfos\EdgesStyle & #SGCE_HoverSensitive
          SGCE_RepaintEdges(*GadgetsInfos, #False)
        EndIf
      EndIf
      ;
    Case #WM_CTLCOLORLISTBOX, #WM_CTLCOLOREDIT
      SetBkColor_(wParam, *GadgetsInfos\BackColor)
      SetTextColor_(wParam, *GadgetsInfos\FrontColor)
      ProcedureReturn CreateSolidBrush_(*GadgetsInfos\BackColor)
      ;
    Case #WM_NCPAINT
      CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lParam) ; <-- needed by some gadgets (as listview) to repaint scrollbars.
      ;
      If SGCE_IsCustomColorGadget(*GadgetsInfos\ID) = -1
        If LastHoveredGadget = gHandle
          SGCE_RepaintEdges(*GadgetsInfos, #True)
        Else
          SGCE_RepaintEdges(*GadgetsInfos, #False)
        EndIf
      EndIf
      ProcedureReturn 0
      ;
    Case #WM_PAINT
      ;
      If GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Spin
        hCTRLWnd = GetWindow_(gHandle, #GW_HWNDNEXT) ; For SpinGadget
        SGCE_InstallCallbackAndData(hCTRLWnd, @SGCE_ChildrenCallback(), *GadgetsInfos, #UPDOWN_CLASS)
        InvalidateRect_(hCTRLWnd, 0, #True)
        ;
        ProcedureReturn CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lParam)
        ;
      ElseIf SGCE_IsCustomColorGadget(*GadgetsInfos\ID) = -1
        ProcedureReturn CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lParam)
        ;
      ElseIf GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Frame
        SGCE_DrawFrameGadget(*GadgetsInfos)
        ProcedureReturn 0
        ;
      ElseIf GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_Container
        SGCE_DrawContainerGadget(*GadgetsInfos)
        EnumChildWindows_(gHandle, @SGCE_RedrawChildWindows(), 0)
        ProcedureReturn 0
        ;
      Else
        BackColor = *GadgetsInfos\BackColor
        If (GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_ListIcon Or GadgetType(*GadgetsInfos\ID) = #PB_GadgetType_ExplorerList) And FindWindowEx_(gHandle, 0, #WC_HEADER, #Null) = 0
          BackLuminosity = Red(BackColor)*0.299 + Green(BackColor)*0.587 + Blue(BackColor)*0.114
          Shift = 15
          If BackLuminosity > 128 : Shift * -1 : EndIf
          BackColor = RGB(ShiftColorComponent(Red(BackColor), Shift), ShiftColorComponent(Green(BackColor), Shift), ShiftColorComponent(Blue(BackColor), Shift))
        EndIf
        ;
        SGCE_DrawAndReplaceColors(gHandle, lParam, SGCE_OldCallBack, BackColor, *GadgetsInfos\FrontColor, GadgetType(*GadgetsInfos\ID))
        ;
        If *GadgetsInfos\Enabled <> IsWindowEnabled_(gHandle)
          *GadgetsInfos\Enabled = IsWindowEnabled_(gHandle)
          InvalidateRect_(gHandle, 0, #True)
        EndIf
        ;
        If *GadgetsInfos\EdgesStyle & #SGCE_HoverSensitive
          SGCE_RepaintEdges(*GadgetsInfos, LastHoveredGadget)
        EndIf
        ;
      EndIf
      ;
      hCTRLWnd = FindWindowEx_(gHandle, 0, #UPDOWN_CLASS, #Null) ; For PanelGadget
      If hCTRLWnd
        SGCE_InstallCallbackAndData(hCTRLWnd, @SGCE_ChildrenCallback(), *GadgetsInfos)
        InvalidateRect_(hCTRLWnd, 0, #True)
      EndIf
      ;
      hCTRLWnd = FindWindowEx_(gHandle, 0, #WC_HEADER, #Null) ; For ListIcon and ExplorerList gadgets
      If hCTRLWnd
        SGCE_InstallCallbackAndData(hCTRLWnd, @SGCE_ChangeColorsCallback(), *GadgetsInfos)
        InvalidateRect_(hCTRLWnd, 0, #True)
      EndIf 
      ;
      ProcedureReturn 0
      ;
  EndSelect
  ;
  ProcedureReturn CallWindowProc_(SGCE_OldCallBack, gHandle, uMsg, wParam, lParam)
  ;
EndProcedure
;
Procedure SGCE_MainWindowCallbackCleaner(hWnd, uMsg, wParam, lParam)
  ;
  Shared SGCE_GadgetsInfos()
  Protected *pnmh.NMHDR
  ;
  If uMsg = #WM_DESTROY
    ForEach SGCE_GadgetsInfos()
      If Not (IsGadget(SGCE_GadgetsInfos()\ID)) Or WindowID(SGCE_GadgetsInfos()\MainWindow) = hWnd
        DeleteElement(SGCE_GadgetsInfos())
      EndIf
    Next
  EndIf
  ;
  ; Normal callback:
  Protected SGCE_OldCallBack = GetProp_(hWnd, "SGCE_OldCallBack")
  ProcedureReturn CallWindowProc_(SGCE_OldCallBack, hWnd, uMsg, wParam, lParam)
  ;
EndProcedure
;
; ****************************************************************************************
;
;-                 3--- THIRD PART: MAIN FUNCTIONS OF THIS LIBRARY ---
;
; ****************************************************************************************
;
Procedure GetGadgetColorEx(GadgetID, ColorType)
  ;
  ;
  Shared SGCE_GadgetsInfos()
  Protected Result = GetGadgetColor(GadgetID, ColorType)
  ;
  If IsGadget(GadgetID) And SGCE_IsCustomColorGadget(GadgetID) And ListSize(SGCE_GadgetsInfos())
    ;
    Protected *ActualElement = @SGCE_GadgetsInfos()
    ;
    ForEach SGCE_GadgetsInfos()
      If SGCE_GadgetsInfos()\Handle = GadgetID(GadgetID)
        If ColorType = #PB_Gadget_BackColor
          Result = SGCE_GadgetsInfos()\BackColor
        ElseIf ColorType = #PB_Gadget_FrontColor
          Result = SGCE_GadgetsInfos()\FrontColor
        EndIf
        Break
      EndIf
    Next
    ;
    ChangeCurrentElement(SGCE_GadgetsInfos(), *ActualElement)
    ;
  EndIf
  ProcedureReturn Result
EndProcedure
;
Procedure SetGadgetColorEx(GadgetID, ColorType, Color = 0, ThisColorOnly = 0)
  ;
  ; Extended SetGadgetColor function for all gadgets.
  ;
  ; If parameter 'ColorType' is set to '#SGCE_StandardColors',
  ; standard colors are restored for the gadget.
  ;
  ; The 'Color' parameter can be an RGB() value or can be '#PB_Default'.
  ; The 'ColorType' parameter can be #PB_Gadget_BackColor or #PB_Gadget_FrontColor.
  ;
  ; If 'ThisColorOnly' is set to zero and if #PB_Gadget_FrontColor is not allready set,
  ; the FrontColor will be adjusted in opposition from the BackColor.
  ;
  ; If 'ThisColorOnly' is set to zero and if #PB_Gadget_BackColor is not allready set,
  ; the BackColor with be set to the same color as the window or contener background color.
  ;
  ; If 'ThisColorOnly' is set to 1, only the color specified by ColorType
  ; (#PB_Gadget_BackColor or #PB_Gadget_FrontColor) is adjusted.
  ;
  ;
  Shared SGCE_GadgetsInfos()
  ;
  Protected BackLuminosity, ParentWindow, Found, hCTRLWnd, hWnd, gRect.Rect
  Protected FrontColor, hParent, ApplyDarkMode, Red, Green, Blue
  ;
  If IsGadget(GadgetID)
    ;
    ParentWindow = GetGadgetParentWindow(GadgetID)
    If IsWindow(ParentWindow)
      SGCE_InstallCallbackAndData(WindowID(ParentWindow), @SGCE_MainWindowCallbackCleaner(), 0)
    EndIf
    ;
    Found = 0
    If ListSize(SGCE_GadgetsInfos())
      ForEach SGCE_GadgetsInfos()
        If SGCE_GadgetsInfos()\ID = GadgetID
          Found = 1
          Break
        EndIf
      Next
    EndIf
    ;
    SetStandardColor: 
    If ColorType = #SGCE_StandardColors
      If Found
        ;
        ForEach SGCE_GadgetsInfos()
          If SGCE_GadgetsInfos()\ID = GadgetID
            hCTRLWnd = FindWindowEx_(GadgetID(GadgetID), 0, #UPDOWN_CLASS, #Null) ; For PanelGadget
            SGCE_UnUnstallCallback(hCTRLWnd)
            ;
            hCTRLWnd = FindWindowEx_(GadgetID(GadgetID), 0, #WC_HEADER, #Null)    ; For ListIcon and ExplorerList
            SGCE_UnUnstallCallback(hCTRLWnd)
            ;
            hCTRLWnd = GetWindow_(GadgetID(GadgetID), #GW_HWNDNEXT)               ; For SpinGadget
            SGCE_UnUnstallCallback(hCTRLWnd, #UPDOWN_CLASS)
            ;
            SGCE_UnUnstallCallback(GadgetID(GadgetID))
            ;
            DeleteElement(SGCE_GadgetsInfos())
          EndIf
        Next
        ;
        If IsWindowVisible_(GadgetID(GadgetID))
          HideGadget(GadgetID, #True)
          HideGadget(GadgetID, #False)
        EndIf
      EndIf
      SetGadgetColor(GadgetID, #PB_Gadget_FrontColor, #PB_Default)
      SetGadgetColor(GadgetID, #PB_Gadget_BackColor,  #PB_Default)
      ;
      ProcedureReturn
      ;
    EndIf
    ;
    If Found = 0
      Found = 1
      AddElement(SGCE_GadgetsInfos())
      SGCE_GadgetsInfos()\ID = GadgetID
      SGCE_GadgetsInfos()\Handle = GadgetID(GadgetID)
      SGCE_GadgetsInfos()\FrontColor = #PB_Default
      SGCE_GadgetsInfos()\BackColor = #PB_Default
      SGCE_GadgetsInfos()\Enabled = IsWindowEnabled_(GadgetID(GadgetID))
      SGCE_GadgetsInfos()\MainWindow = ParentWindow
      SGCE_GadgetsInfos()\EdgesStyle = 0
    EndIf
    ;
    If ColorType = #PB_Gadget_BackColor
      ;
      SGCE_GadgetsInfos()\BackColor = Color
      ;
      ;
      If ThisColorOnly = 0 And SGCE_GadgetsInfos()\FrontColor = #PB_Default And Color <> #PB_Default
        BackLuminosity = Red(Color)*0.299 + Green(Color)*0.587 + Blue(Color)*0.114
        If BackLuminosity < 128 And BackLuminosity >80
          FrontColor = #White
        ElseIf BackLuminosity > 128
          FrontColor = 0
        Else
          FrontColor = RGB(220, 220, 220)
        EndIf
        SGCE_GadgetsInfos()\FrontColor = FrontColor
      EndIf
      ;
    ElseIf ColorType = #PB_Gadget_FrontColor
      ;
      SGCE_GadgetsInfos()\FrontColor = Color
      ;
      If ThisColorOnly = 0 And SGCE_GadgetsInfos()\BackColor = #PB_Default And Color <> #PB_Default
        ;
        hParent = GetAncestor_(GadgetID(GadgetID), #GA_PARENT) ; Get the parent window/gadget handle
        ;
        If hParent
          If IsWindow(ParentWindow) And hParent = WindowID(ParentWindow)
            SGCE_GadgetsInfos()\BackColor = GetWindowColor(ParentWindow)
          Else
            Protected ParentPBID = GetProp_(hParent, "PB_ID")
            If IsGadget(ParentPBID)
              SGCE_GadgetsInfos()\BackColor = GetGadgetColorEx(ParentPBID, #PB_Gadget_BackColor)
            EndIf
          EndIf
        EndIf
      EndIf
    EndIf
    ;
    ApplyDarkMode = 0
    Select GadgetType(GadgetID)
      Case #PB_GadgetType_ScrollArea, #PB_GadgetType_ScrollBar, #PB_GadgetType_Editor, #PB_GadgetType_ListIcon, #PB_GadgetType_ListView
        ApplyDarkMode = 1
      Case #PB_GadgetType_ListView, #PB_GadgetType_ComboBox, #PB_GadgetType_ExplorerCombo, #PB_GadgetType_ExplorerList
        ApplyDarkMode = 1
      Case #PB_GadgetType_ExplorerTree, #PB_GadgetType_Container, #PB_GadgetType_Web, #PB_GadgetType_WebView, #PB_GadgetType_Scintilla
        ApplyDarkMode = 1
      Case #PB_GadgetType_Tree, #PB_GadgetType_MDI
        ApplyDarkMode = 1
    EndSelect
    ;
    If SGCE_GadgetsInfos()\FrontColor = #PB_Default
      Protected RealFrontColor = GetSysColor_(#COLOR_WINDOWTEXT)
    Else
      RealFrontColor = SGCE_GadgetsInfos()\FrontColor
    EndIf
    If SGCE_GadgetsInfos()\BackColor = #PB_Default
      Protected RealBackColor = GetSysColor_(#COLOR_BTNFACE)
    Else
      RealBackColor = SGCE_GadgetsInfos()\BackColor
    EndIf
    ;
    If ApplyDarkMode
      If Red(RealBackColor)*0.299 + Green(RealBackColor)*0.587 + Blue(RealBackColor)*0.114 > 128
        SetWindowTheme_(GadgetID(GadgetID), @"Explorer", #Null)
      Else
        SetWindowTheme_(GadgetID(GadgetID), @"DarkMode_Explorer", #Null)
      EndIf
    EndIf
    ;
    If (SGCE_GadgetsInfos()\FrontColor = #PB_Default Or SGCE_GadgetsInfos()\FrontColor = GetSysColor_(#COLOR_WINDOWTEXT)) And (SGCE_GadgetsInfos()\BackColor = #PB_Default Or SGCE_GadgetsInfos()\BackColor = GetSysColor_(#COLOR_BTNFACE))
      ColorType = #SGCE_StandardColors
      Goto SetStandardColor
    EndIf
    ;
    ;
    Protected CustomColor = SGCE_IsCustomColorGadget(GadgetID)
    ;
    If CustomColor
      ;
      SGCE_GadgetsInfos()\FrontColor = RealFrontColor
      SGCE_GadgetsInfos()\BackColor = RealBackColor
      ;
      If CustomColor = -1 Or GadgetType(GadgetID) = #PB_GadgetType_ListIcon Or GadgetType(GadgetID) = #PB_GadgetType_Calendar Or GadgetType(GadgetID) = #PB_GadgetType_ExplorerList
        If GetWindowLongPtr_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_CLIENTEDGE Or GetWindowLongPtr_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_WINDOWEDGE Or GetWindowLongPtr_(GadgetID(GadgetID), #GWL_STYLE) & #WS_BORDER Or GadgetType(GadgetID) = #PB_GadgetType_Editor
          SGCE_GadgetsInfos()\EdgesStyle = #SGCE_HoverSensitive | #SGCE_Single
        EndIf
        If GadgetType(GadgetID) = #PB_GadgetType_ScrollArea
          If GetWindowLong_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_STATICEDGE
            SGCE_GadgetsInfos()\EdgesStyle = #SGCE_HoverSensitive | #SGCE_Single
          ElseIf GetWindowLong_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_WINDOWEDGE
            SGCE_GadgetsInfos()\EdgesStyle = #SGCE_HoverSensitive | #SGCE_Double
          ElseIf GetWindowLong_(GadgetID(GadgetID), #GWL_STYLE) & #WS_BORDER
            SGCE_GadgetsInfos()\EdgesStyle = #SGCE_HoverSensitive | #SGCE_Flat
          EndIf
        EndIf
        If GadgetType(GadgetID) = #PB_GadgetType_Calendar
          SendMessage_(GadgetID(GadgetID), #MCM_GETMINREQRECT, 0, @gRect.Rect)
          SetWindowPos_(GadgetID(GadgetID), 0, 0, 0, gRect\right - gRect\left - 2, gRect\bottom - gRect\top - 2, #SWP_NOMOVE | #SWP_NOZORDER)
        EndIf
        ;
      ElseIf GadgetType(GadgetID) = #PB_GadgetType_Date
        SGCE_GadgetsInfos()\EdgesStyle = #SGCE_Single
        ;
      ElseIf GadgetType(GadgetID) = #PB_GadgetType_Frame
        If GetWindowLong_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_CLIENTEDGE
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_Double
        ElseIf GetWindowLong_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_STATICEDGE
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_Single
        ElseIf Not(GetWindowLong_(GadgetID(GadgetID), #GWL_STYLE) & #SS_ETCHEDFRAME)
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_Flat
        Else
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_WithTitle
        EndIf
        ;
      ElseIf GadgetType(GadgetID) = #PB_GadgetType_Container
        If GetWindowLong_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_CLIENTEDGE
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_Double
        ElseIf GetWindowLong_(GadgetID(GadgetID), #GWL_EXSTYLE) & #WS_EX_STATICEDGE
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_Single
        ElseIf GetWindowLong_(GadgetID(GadgetID), #GWL_STYLE) & $800000
          SGCE_GadgetsInfos()\EdgesStyle | #SGCE_Flat
        EndIf
      EndIf
      SGCE_GadgetsInfos()\EdgesColor =  MixColors(SGCE_GadgetsInfos()\FrontColor, SGCE_GadgetsInfos()\BackColor, 0.25)
      SGCE_GadgetsInfos()\HighlightedEdgesColor = MixColors(SGCE_GadgetsInfos()\FrontColor, SGCE_GadgetsInfos()\BackColor, 0.6)
      ;
      SGCE_InstallCallbackAndData(GadgetID(GadgetID), @SGCE_ChangeColorsCallback(), @SGCE_GadgetsInfos())
      ;
    EndIf
    If CustomColor <> 1
      If ColorType = #PB_Gadget_FrontColor
        SetGadgetColor(GadgetID, #PB_Gadget_FrontColor, SGCE_GadgetsInfos()\FrontColor)
      ElseIf ColorType = #PB_Gadget_BackColor
        SetGadgetColor(GadgetID, #PB_Gadget_BackColor, SGCE_GadgetsInfos()\BackColor)
      Else
        SetGadgetColor(GadgetID, ColorType, Color)
      EndIf
    EndIf
  EndIf
EndProcedure
;
Structure SGCE_ColorForEnum
  ColorType.i
  Color.i
EndStructure
;
Procedure SGCE_EnumGadgetsAndSetColor(hGadget, *ColorForEnum.SGCE_ColorForEnum)
  ;
  Protected GadgetPBID = GetProperty(hGadget, "PB_ID")
  If GadgetPBID >= 0
    SetGadgetColorEx(GadgetPBID, *ColorForEnum\ColorType, *ColorForEnum\Color)
  EndIf
  ProcedureReturn #True
EndProcedure
;
Procedure ApplyColorsToAllGadgets(WindowNum, FrontColor, BackColor)
  ;
  ;
  Protected ColorForEnum.SGCE_ColorForEnum
  ;
  SetWindowColor(WindowNum, BackColor)
  ;
  Protected hWnd = WindowID(WindowNum)
  ;
  ColorForEnum\Color = BackColor
  ColorForEnum\ColorType = #PB_Gadget_BackColor
  EnumChildWindows_(hWnd, @SGCE_EnumGadgetsAndSetColor(), @ColorForEnum)
  ColorForEnum\Color = FrontColor
  ColorForEnum\ColorType = #PB_Gadget_FrontColor
  EnumChildWindows_(hWnd, @SGCE_EnumGadgetsAndSetColor(), @ColorForEnum)
  ;
EndProcedure
;
;
Macro GetGadgetColor(a, b)
	GetGadgetColorEx(a, b)
EndMacro

Macro SetGadgetColor(a, b, c)
	SetGadgetColorEx(a, b, c)
EndMacro
;
;
; ****************************************************************************************
;
;-                         4--- FORTH PART: DEMO PROCEDURE ---
;
; ****************************************************************************************
;
;
CompilerIf #PB_Compiler_IsMainFile
  ; The following won't run when this file is used as 'Included'.
  ;
  Macro ColorizeGadgets()
    ApplyColorsToAllGadgets(#SGCE_DemoWindow, FrontColor, BackColor)
    ;
    ; Then customize colors for some gadgets:
    ;
    ; Lighten the background of the frame contener and its buttons:
    If BackColor = -1
      LightenBackground = $D0D0D0
    Else
      If Red(BackColor)*0.299 + Green(BackColor)*0.587 + Blue(BackColor)*0.114 > 128
        LightenBackground = RGB(Red(BackColor) - 20, Green(BackColor) - 20, Blue(BackColor) - 20)
      Else
        LightenBackground = RGB(Red(BackColor) + 20, Green(BackColor) + 20, Blue(BackColor) + 20)
      EndIf
      SetGadgetColor(#SGCE_Frame, #PB_Gadget_BackColor, LightenBackground)
      SetGadgetColor(#SGCE_Option1, #PB_Gadget_BackColor, LightenBackground)
      SetGadgetColor(#SGCE_Option2, #PB_Gadget_BackColor, LightenBackground)
      ; Set fantasy colors for OptionGadgets:
      SetGadgetColor(#SGCE_Option1, #PB_Gadget_FrontColor, RGB($FF, $50, $FF))
      If Red(BackColor)*0.299 + Green(BackColor)*0.587 + Blue(BackColor)*0.114 > 128
        SetGadgetColor(#SGCE_Option2, #PB_Gadget_FrontColor, $008080)
      Else
        SetGadgetColor(#SGCE_Option2, #PB_Gadget_FrontColor, $00FFE0)
      EndIf
    EndIf
    ;
    ; Lighten the background of the right contener:
    SetGadgetColor(#SGCE_Contener, #PB_Gadget_BackColor, LightenBackground)
    ;
    ; Clear the colors of #SGCE_StandardButton (it will have default colors):
    SetGadgetColor(#SGCE_StandardButton, #PB_Gadget_BackColor, StandardBack)
    SetGadgetColor(#SGCE_StandardButton, #PB_Gadget_FrontColor, StandardFront)
    ; Set the colors of #LightBlueButton:
    SetGadgetColor(#SGCE_LightBlueButton, #PB_Gadget_BackColor, LightBlueBack)
    SetGadgetColor(#SGCE_LightBlueButton, #PB_Gadget_FrontColor, LightBlueFront)
    ; Set the colors of #SGCE_MatrixButton:
    SetGadgetColor(#SGCE_MatrixButton, #PB_Gadget_BackColor, MatrixBack)
    SetGadgetColor(#SGCE_MatrixButton, #PB_Gadget_FrontColor, MatrixFront)
    ; Set the colors of #SGCE_DarkGreyButton:
    SetGadgetColor(#SGCE_DarkGreyButton, #PB_Gadget_BackColor, DarkGreyBack)
    SetGadgetColor(#SGCE_DarkGreyButton, #PB_Gadget_FrontColor, DarkGreyFront)
    ;
  EndMacro
  ;
  Procedure MulticolorDemoWindow()
    ;
    Protected LightenBackground
    ;
    Enumeration WindowAndGadgetNum
      #SGCE_DemoWindow
      #SGCE_Frame
      #SGCE_Option1
      #SGCE_Option2
      #SGCE_CheckBox
      #SGCE_Button1
      #SGCE_Text
      #SGCE_String
      #SGCE_Editor
      #SGCE_ListView
      #SGCE_Panel
      #SGCE_Contener
      #SGCE_StandardButton
      #SGCE_LightBlueButton
      #SGCE_MatrixButton
      #SGCE_DarkGreyButton
      #SGCE_ListIcon
      #SGCE_Combo
      #SGCE_ComboEdit
      #SGCE_ExplorerCombo
      #SGCE_Date
      #SGCE_Calendar
      #SGCE_ExplorerList
      #SGCE_ExplorerTree
      #SGCE_Tree
      #SGCE_Spin
      #SGCE_MDI
      #SGCE_ChildWindow
      #SGCE_BQuit
    EndEnumeration
    ;
    ; To have a faster and cleaner color drawing, first create the window
    ; with the #PB_Window_Invisible attribute and make it visible just
    ; before the WindowEvent loop.
    ; (This is not mandatory)
    If OpenWindow(#SGCE_DemoWindow, 100, 100, 540, 310, "SetGadgetColorEx Demo", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_Invisible)
    ApplyDarkModeToWindow(#SGCE_DemoWindow)
    ;
    ;
    FrameGadget(#SGCE_Frame, 10, 10, 120, 65, "FrameGadget",  #PB_Frame_Container)
    ;
      OptionGadget(#SGCE_Option1, 15, 15, 70, 25, "Option #1")
      SetGadgetState(#SGCE_Option1, 1)
      OptionGadget(#SGCE_Option2, 15, 35, 70, 25, "Option #2")
    CloseGadgetList()
    ;
    CheckBoxGadget(#SGCE_CheckBox, 10, 90, 120, 25, "CheckBoxGadget")
    SetGadgetState(#SGCE_CheckBox, 1)
    ButtonGadget(#SGCE_Button1, 20, 120, 100, 25, "Desabled Button")
    DisableGadget(#SGCE_Button1, #True)
    ;
    TextGadget(#PB_Any, 10, 160, 120, 25, "StringGadget")
    StringGadget(#SGCE_String, 10, 180, 120, 25, "StringGadget")
    ;
    TextGadget(#PB_Any, 10, 230, 120, 20, "EditorGadget")
    EditorGadget(#SGCE_Editor, 10, 250, 120, 50)
    SetGadgetText(#SGCE_Editor, "EditorGadget with a long text.")
    ;
    PanelWidth = 247
    PanelGadget(#SGCE_Panel, 140, 10, PanelWidth, WindowHeight(#SGCE_DemoWindow) - 19)
    ;
    AddGadgetItem(#SGCE_Panel, -1, "Combos")
      TextGadget(#PB_Any, 6, 20, PanelWidth - 20, 20, "ComboBoxGadget")
      ComboBoxGadget(#SGCE_Combo, 6, 40, PanelWidth - 20, 22)
      For ct = 1 To 5 : AddGadgetItem(#SGCE_Combo, -1, "ComboBox standard " + Str(ct)) : Next
      SetGadgetState(#SGCE_Combo, 0)
      ;
      TextGadget(#PB_Any, 6, 80, PanelWidth - 20, 20, "ComboBoxGadget - Editable")
      ComboBoxGadget(#SGCE_ComboEdit, 6, 100, PanelWidth - 20, 22, #PB_ComboBox_Editable)
      For ct = 1 To 5 : AddGadgetItem(#SGCE_ComboEdit, -1, "ComboBox Editable " + Str(ct)) : Next
      SetGadgetState(#SGCE_ComboEdit, 0)
      ;
      TextGadget(#PB_Any, 6, 160, PanelWidth - 20, 20, "ExplorerComboGadget")
      ExplorerComboGadget(#SGCE_ExplorerCombo, 6, 180, PanelWidth - 20, 22, "C:")
      ;
    AddGadgetItem(#SGCE_Panel, -1, "Lists")
      TextGadget(#PB_Any, 6, 10, PanelWidth - 20, 20, "ListIconGadget")
      ListIconGadget(#SGCE_ListIcon, 6, 30, PanelWidth - 20, 80, "ListIcon", 70)
      AddGadgetColumn(#SGCE_ListIcon, 1, "Column 2", 100)
      For ct = 1 To 10 : AddGadgetItem(#SGCE_ListIcon, -1, "Element " + Str(ct) + #LF$ + "Column 2 Element " + Str(ct))
      Next
      TextGadget(#PB_Any, 6, 130, PanelWidth - 20, 20, "ExplorerListGadget")
      ExplorerListGadget(#SGCE_ExplorerList, 6, 150, PanelWidth - 20, 100, "C:")
      ;
      AddGadgetItem(#SGCE_Panel, -1, "ListView")
      TextGadget(#PB_Any, 6, 30, PanelWidth - 20, 20, "ListViewGadget")
      ListViewGadget(#SGCE_ListView, 6, 50, PanelWidth - 20, 140)
      ;
      For ct = 1 To 20
        AddGadgetItem(#SGCE_ListView, ct - 1, "ListView Gadget " + Str(ct))
      Next
      ;
    AddGadgetItem(#SGCE_Panel, -1, "Date")
      TextGadget(#PB_Any, 6, 10, PanelWidth - 20, 20, "DateGadget")
      DateGadget(#SGCE_Date, 6, 30, PanelWidth - 20, 22)
      TextGadget(#PB_Any, 6, 70, PanelWidth - 20, 20, "CalendarGadget")
      CalendarGadget(#SGCE_Calendar, 6, 90, PanelWidth , 164)
    AddGadgetItem(#SGCE_Panel, -1, "Trees")
      TextGadget(#PB_Any, 6, 10, PanelWidth - 20, 20, "ExplorerTreeGadget")
      ExplorerTreeGadget(#SGCE_ExplorerTree, 6, 30, PanelWidth - 20, 95, "C:")
      TextGadget(#PB_Any, 6, 135, PanelWidth - 20, 20, "TreeGadget")
      TreeGadget(#SGCE_Tree, 6, 155, PanelWidth - 20, 100)
      For a = 0 To 10
        AddGadgetItem(#SGCE_Tree, -1, "Normal "+Str(a), 0, 0)
        AddGadgetItem(#SGCE_Tree, -1, "Node "+Str(a), 0, 0)
        AddGadgetItem(#SGCE_Tree, -1, "SubElement 1", 0, 1)
        AddGadgetItem(#SGCE_Tree, -1, "SubElement 2", 0, 1)
        AddGadgetItem(#SGCE_Tree, -1, "SubElement 3", 0, 1)
        AddGadgetItem(#SGCE_Tree, -1, "SubElement 4", 0, 1)
        AddGadgetItem(#SGCE_Tree, -1, "File "+Str(a), 0, 0)
      Next
    AddGadgetItem(#SGCE_Panel, -1, "Others")
      TextGadget(#PB_Any, 6, 10, PanelWidth - 20, 20, "SpinGadget")
      SpinGadget(#SGCE_Spin, 6, 30, PanelWidth - 20, 22, 0, 5, #PB_Spin_Numeric)
      SetGadgetText(#SGCE_Spin, "1")
      HyperLinkGadget(#PB_Any, 6, 70, PanelWidth - 20, 20, "HyperLinkGadget", $FFA020)
      
      TextGadget(#PB_Any, 6, 110, PanelWidth - 20, 20, "ScrollAreaGadget")
      ScrollAreaGadget(#PB_Any, 6, 130, PanelWidth - 20, 50, 220, 60)
      CloseGadgetList()
      ;
    CloseGadgetList()
    ;
    ContainerWidth = 130
    TextGadget(#PB_Any, WindowWidth(#SGCE_DemoWindow) - ContainerWidth - 10, 12, ContainerWidth, 70, "<-- Browse the panels to see how each gadget looks like when colorized.", #PB_Text_Center)
    ;
    TextGadget(#PB_Any, WindowWidth(#SGCE_DemoWindow) - ContainerWidth - 10, 100, ContainerWidth, 20, "Choose your color:", #PB_Text_Center)
    ContainerGadget(#SGCE_Contener, WindowWidth(#SGCE_DemoWindow) - ContainerWidth - 10, 120, ContainerWidth, 130)
      ;
      ButtonGadget(#SGCE_StandardButton,  10, 10,  ContainerWidth - 20, 22, "Standard")
      ButtonGadget(#SGCE_LightBlueButton, 10, 40,  ContainerWidth - 20, 22, "Light blue")
      ButtonGadget(#SGCE_MatrixButton,    10, 70,  ContainerWidth - 20, 22, "Matrix")
      ButtonGadget(#SGCE_DarkGreyButton,  10, 100, ContainerWidth - 20, 22, "Dark grey")
      CloseGadgetList()
      ;
    DisableGadget(#SGCE_MatrixButton, #True)
    ;     
    ButtonGadget(#SGCE_BQuit, WindowWidth(#SGCE_DemoWindow) - ContainerWidth - 10, WindowHeight(#SGCE_DemoWindow) - 35, 130, 25, "Exit")
    ;
    ;
    ; If you want to, you can attribute colors to your gadgets one by one.
    ; But if you want to achieve something like a color theme, which changes the colors
    ; of all the gadgets in your window (to get a dark mode, for example), there are two
    ; ways to do it:
    ;
    ; • You can include the 'ApplyColorThemes.pb' library in your project.
    ;   This library is available on the Zapman website:
    ;   https://www.editions-humanis.com/downloads/PureBasic/ZapmanDowloads_EN.htm
    ;   It allows the users to create, modify or simply choose an existing colors theme
    ;   and to apply it to the current program.
    ;
    ; • If you just need a quick method to apply a couple of colors to all of your gadgets,
    ;   you can simply call ApplyColorsToAllGadgets() as it is done by ColorizeGadgets() below.
    ;
    StandardBack   = #PB_Default
    StandardFront  = #PB_Default
    LightBlueBack  = $FFFFE0
    LightBlueFront = $A04000
    MatrixBack     = $282800
    MatrixFront    = $A0FF5A
    DarkGreyBack   = $202020
    DarkGreyFront  = $E0E0E0
    ;
    BackColor  = MatrixBack ; Matrix default setting
    FrontColor = MatrixFront; Matrix default setting
    ;
    ColorizeGadgets()
    ;
    ; If the window has been created with the #PB_Window_Invisible attribute,
    ; this is the moment to make it visible.
    HideWindow(#SGCE_DemoWindow, #False)
    ;
    Repeat
      Event = WaitWindowEvent()
      
      If Event = #PB_Event_Gadget
  
        Select EventGadget()
          Case #SGCE_CheckBox
            If GetGadgetState(#SGCE_CheckBox)
              DisableGadget(#SGCE_Button1, #True)
              SetGadgetText(#SGCE_Button1, "Desabled Button")
            Else
              DisableGadget(#SGCE_Button1, #False)
              SetGadgetText(#SGCE_Button1, "Enabled Button")
            EndIf
          Case #SGCE_StandardButton, #SGCE_LightBlueButton, #SGCE_MatrixButton, #SGCE_DarkGreyButton
            BackColor  = GetGadgetColor(EventGadget(), #PB_Gadget_BackColor)
            FrontColor = GetGadgetColor(EventGadget(), #PB_Gadget_FrontColor)
            ;
            DisableGadget(#SGCE_StandardButton, #False)
            DisableGadget(#SGCE_LightBlueButton, #False)
            DisableGadget(#SGCE_MatrixButton, #False)
            DisableGadget(#SGCE_DarkGreyButton, #False)
            ;
            DisableGadget(EventGadget(), #True)
            
            ColorizeGadgets()
            ;
          Case #SGCE_BQuit
            Break
        EndSelect
        ;
      ElseIf Event = #PB_Event_CloseWindow
        Break
      EndIf
    ForEver
    CloseWindow(#SGCE_DemoWindow)
  EndIf
  EndProcedure
  ;
  MulticolorDemoWindow()
  ;
CompilerEndIf
Last edited by Zapman on Thu Mar 13, 2025 2:12 pm, edited 48 times in total.
Denis
Enthusiast
Enthusiast
Posts: 778
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Re: A very simple SetGadgetColorEx() function

Post by Denis »

Excellent code Zapman.
It's perfect under Windows 11 Professional version 24H2. :wink:
A+
Denis
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

Jacobus, from french forum, has noticed a bug (colors not modified) when a gadget was desabled. I also noticed a problem while changing the text of a gadget.
Code above has been corrected to fix that.
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: A very simple SetGadgetColorEx() function

Post by ChrisR »

Superb, nice code in the Callback, ReplaceColors
I like the colored Glyphs for checboxes, OptionGadget.

Not everything is colored for ListIcon, ComboBox, I haven't tested with other Gadgets.

Code: Select all

ListIconGadget(#ListIcon, 140, 260, 200, 90, "ListIcon", 120)
AddGadgetColumn(#ListIcon, 1, "Column 2", 240)
SetWindowTheme_(GadgetID(#ListIcon), "DarkMode_Explorer", #Null)
For ct = 1 To 5 : AddGadgetItem(#ListIcon, -1, "ListIcon Element " + Str(ct) +Chr(10)+ "Column 2 Element " + Str(ct)) : Next
SetGadgetColorEx(#ListIcon, #PB_Gadget_FrontColor, RGB($C0,$FF,$0))

ComboBoxGadget(#Combo, 350, 260, 200, 28)
For ct = 1 To 5 : AddGadgetItem(#Combo, -1, "Combo Element " + Str(ct)) : Next
SetGadgetState(#Combo, 0)
SetWindowTheme_(GadgetID(#Combo), "DarkMode_Explorer", #Null)
SetGadgetColorEx(#Combo, #PB_Gadget_FrontColor, RGB($FF,$FF,$0))

ComboBoxGadget(#ComboEdit, 350, 300, 200, 28, #PB_ComboBox_Editable)
For ct = 1 To 5 : AddGadgetItem(#ComboEdit, -1, "Combo Editable Element " + Str(ct)) : Next
SetGadgetState(#ComboEdit, 0)
SetWindowTheme_(GadgetID(#ComboEdit), "DarkMode_Explorer", #Null)
SetGadgetColorEx(#ComboEdit, #PB_Gadget_FrontColor, RGB($FF,$FF,$0))
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: A very simple SetGadgetColorEx() function

Post by ChrisR »

Zapman wrote: Tue Oct 29, 2024 8:08 pm Of course, there’s ObjectTheme.pbi by ChrisR (viewtopic.php?t=82890&hilit=dark+theme), which allows you to choose a sophisticated theme for windows. However, it’s rather heavy, and the design displayed resembles that of older Windows versions.
The initialization is a bit heavy to load the map with gadget colors but not much and it's fast enough afterwards when drawing in callbacks.

hmm, I don't really agree with "resembles that of older Windows version", the goal is to achieve a certain color harmony through a theme between the various controls and windows, not to change the color of each controls.

And a design like the one below is rather modern, it's quite similar to the CheckOut Bootstrap example in dark mode (with modern web technology)

Image
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

Thanks a lot for the test and for your comments, ChrisR. I'm honored, given your amazing level of programming.

I didn't intend to compare your code with mine, that would be ridiculous.
If I described your code as 'heavy', it's only because of its size. Its performance is impeccable.
And you're right, apart from the design of the checkbox and the optiongadgets, the other gadgets have a modern look. I removed this unfair comment from my first post.

My code proposal undoubtedly contains other defects than those you have already noted (certain parts of certain gadgets are not colored).
In all honesty, I don't think I have the skills to fix them, at least not without spending weeks on them and I have other projects going on.
But, as I said, this code has the advantage of lightness and simplicity and we must take it for what it is: a sort of 'patch' which allows us to simply respond to some common needs.

Thank you again for your comments.
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: A very simple SetGadgetColorEx() function

Post by ChrisR »

"given your amazing level of programming"
I wouldn't say that at all, I can handle some stuff but sometimes I feel small, really small when I see the level of some experts around, really, I still have so much to learn :wink:
SetGadgetColorEx() function would probably require a little extra work for some Gadgets but it is really good as it is and I really love the colored glyph for checkbox and option Gadgets. Nice Work :)
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

I obviously looked at the code of ObjectTheme.pb to see if I could draw inspiration from it, when I had the basic idea for my approach. I was amazed by your mastery and the incredible work behind your solution. I guess there's a few months of work on that. It's beautiful!

Before this code, i tried another way for option and ckeckbox, using simple caracters like ◉, ○ and ✓ (drawn in a square box) and it has also a very simple and good looking.

Code: Select all

     If GadgetType = #PB_GadgetType_CheckBox Or GadgetType = #PB_GadgetType_Option
        ;
        If GadgetType = #PB_GadgetType_CheckBox
          If hoverFlag = gHandle And OutOfArea = 0
            Set_hdcBrushColor(hdc, AdjustColorLuminosity(BackColor, LumDiff*1.5))
          EndIf
          Set_hdcPenColor  (hdc, TextColor)
          Vmiddle = gadgetRect\top+(gadgetRect\bottom-gadgetRect\top)/2
          Rectangle_(hdc, gadgetRect\left, Vmiddle - 6, gadgetRect\left + 13, Vmiddle + 7)
          gadgetRect\Left + 2
          If GetGadgetState(GadgetsColors()\GadgetID)
            DrawText_(hdc, "✓", -1, gadgetRect, #DT_LEFT | #DT_VCENTER | #DT_SINGLELINE)
          EndIf
        ElseIf GadgetType = #PB_GadgetType_Option
          If hoverFlag = gHandle And OutOfArea = 0
            SetTextColor_(hdc, AdjustColorLuminosity(TextColor, LumDiff))
          EndIf
          Set_hdcFont (hdc, "Segoe UI", 20)
          If GetGadgetState(GadgetsColors()\GadgetID)
            DrawText_(hdc, "◉", -1, gadgetRect, #DT_LEFT | #DT_VCENTER | #DT_SINGLELINE)
          Else
            DrawText_(hdc, "○", -1, gadgetRect, #DT_LEFT | #DT_VCENTER | #DT_SINGLELINE)
          EndIf
          Set_hdcFont (hdc, "Segoe UI", 16)
          gadgetRect\Left + 2
        EndIf
        gadgetRect\Left + 14
        DrawText_(hdc, GadgetTitle$, -1, gadgetRect, #DT_LEFT | #DT_VCENTER | #DT_SINGLELINE)
      ElseIf GadgetType = #PB_GadgetType_Button
        DrawText_(hdc, GadgetTitle$, -1, gadgetRect, #DT_CENTER | #DT_VCENTER | #DT_SINGLELINE)
      ElseIf GadgetType = #PB_GadgetType_Panel
        DrawText_(hdc, GadgetTitle$, -1, gadgetRect, #DT_LEFT | #DT_SINGLELINE)
      EndIf
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: A very simple SetGadgetColorEx() function

Post by ChrisR »

It's nice too with ◉, ○ and ✓ drawn
Otherwise, I tried to understand a little more the ReplaceColors() procedure
I didn't understand all but it's pretty impressive and it works pretty well

But I've noticed that for some Gadgets (e.g. CheckBox), there may be a slight change in background color.
Image

I think due to maxlum = 255 + 255 + 255 vs maxlum = 240 + 240 + 240 (GetSysColor_(#COLOR_3DFACE), according to Gadget type
It doesn't look too bad, adding:

Code: Select all

TColor = GetPixel_(memDC, 1, 1) ; With GetPixel_(memDC, 0, 0), the ComboBox Border is not drawn. GetSysColor_(#COLOR_3DFACE), GetSysColor_(#COLOR_WINDOW),...
; Parcourir et modifier les pixels pour modifier les couleurs :
For y = 0 To height - 1
  For x = 0 To width - 1
    ; Calculer l'adresse du pixel actuel en 32 bits (BGRA)
    *pixelColor = *pixels + (y * width + x) * 4
    
    If *pixelColor\red = Red(TColor) And *pixelColor\green = Green(TColor) And *pixelColor\blue = Blue(TColor)
      *pixelColor\red   = *backColor\red  
      *pixelColor\green = *backColor\green
      *pixelColor\blue  = *backColor\blue
    ElseIf *pixelColor\red = 0 And *pixelColor\green = 0 And *pixelColor\blue = 0
      *pixelColor\red   = *foreColor\red  
      *pixelColor\green = *foreColor\green
      *pixelColor\blue  = *foreColor\blue
    Else
      .....
Edit: About ObjectTheme, so that you don't misjudge my skills. I would like to point out that many things in the CallBack are codes taken from here and there on the Forum, that I have gathered together. I wouldn't have been able to do it otherwise.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

If you set the window back color to white and don't call SetgadgetColorEx() for any gadget, you get this:
Image
Which demonstrates that 'natural' back color for Checkbox and Options is not white, but light gray.
So, when SetgadgetColorEx() replace the original colors by BackColor and ForeColor, if BackColor is black, you won't get a pure black for the back color of these two gadgets. If you set Backcolor to black and ForeColor to white, you want to invert original colors, then the original light gray becomes a very dark gray, but not black (I hope to be understandable).

So, my choice to replace colors has its limits: this example shows that it is not possible to get a pure black background for Checkbox and OptionGadget by my method. But it has some advantages: a sort of logic is respected and if the original design is good, the final look is probably also good.

By many additions like the one you propose, it's of course possible to break this logic and to get some customized result for some customized colors (as the background color). But you take the risk to get some strange effects for some particular choices of BackColor or ForeColor. you also take the risk to have some strange effects arround the texts, because antialiasing generates a range of grays arround the original black text color.

But I'm very happy to see that you took time to play with my toy :) I've not time at the moment to digg more arround the goal to set a pure black background to these two types of gadget, but I'll come back later.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

Hi ChrisR!

I come back with a proposition to apply your idea as logically as possible into the original algo.
* The original algo replaces white by BackColor and black by ForeColor.
* What you propose is to measure color of point located at (1,1) and to apply BackColor to this specific color. By this way, even if the original background of the gadget is not white, the BackColor will paint it using pure color.

In my point of view, the best way to do something like that with less risk of strange results (we must assume that Windows design will perhaps evoluate along time), is to measure luminosity of point located at (1,1) and to use this luminosity as 'white' reference, instead of taking pure white (255,255,255) as the reference.

Here is the adapted code of the ReplaceColors() procedure:

Code: Select all

Procedure ReplaceColors(hdc, width, height, *backColor.pixelColor, *foreColor.pixelColor)
  ;
  Structure tagRGBQUAD
    ; Fields are 'a' type and not 'b' type,
    ; because 'a' is unsigned and 'b' is signed.
    blue.a
    green.a
    red.a
    alpha.a
  EndStructure

  ;
  Protected *pixels, y, x, LowContrast.f
  Protected *pixelColor.tagRGBQUAD, PixelLuminosity.f, PixelDarkness.f
  Protected BlowOut.f, CrushBlacks.f
  ;
  ; Initialize a BITMAPINFO structure:
  Protected bmi.BITMAPINFO
  bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth = width
  bmi\bmiHeader\biHeight = height
  bmi\bmiHeader\biPlanes = 1
  bmi\bmiHeader\biBitCount = 32     ; 32 bits per pixel (RGBA).
  bmi\bmiHeader\biCompression = #BI_RGB
  ;
  ; Calculate the maximum brightness of a pixel:
  
  Protected maxlum = 245 + 245 + 245
  ; LowContrast is calculated to be 1 when the contrast between the asked background color (BackColor)
  ; and the asked drawing color (ForeColor) is zero, and to be zero when this contrast is maximal:
  LowContrast = (*backColor\red + *backColor\green + *backColor\blue - *foreColor\red - *foreColor\green - *foreColor\blue) / maxlum
  LowContrast = Abs(1 - Abs(LowContrast))
  ;
  ; Create a DIBSection and retrieve the pointer to the pixels:
  Protected hBitmap = CreateDIBSection_(hdc, bmi, #DIB_RGB_COLORS, @*pixels, 0, 0)
  ;
  ; Create a compatible memory context and copy the pixels to it:
  Protected memDC = CreateCompatibleDC_(hdc)
  ;
  Protected oldBitmap = SelectObject_(memDC, hBitmap)
  BitBlt_(memDC, 0, 0, width, height, hdc, 0, 0, #SRCCOPY)
  ;
  Color = GetPixel_(memDC, 1, 1); Up-Left color of the gadget background.
  maxLum = Red(Color) + Green(Color) + Blue(Color) ; Compute luminosity of the background.
  If maxLum = 0 : maxLum = 1 : EndIf ; Be sure to not divide by zero later.

  ; Iterate and modify the pixels to change the colors:
  For y = 0 To height - 1
    For x = 0 To width - 1
      ; Calculate the address of the current pixel in 32 bits (BGRA)
      *pixelColor = *pixels + (y * width + x) * 4

      PixelLuminosity = (*pixelColor\red + *pixelColor\green + *pixelColor\blue) / maxLum
      ;
      ; The following correction is intended to improve text readability when
      ; the contrast between the background color (*backColor) and the stroke color (*foreColor)
      ; is medium or low.
      ;
      ; BlowOut brings high luminosities closer to white.
      ; (In photography, this is called "blowing out" the whites).
      If PixelLuminosity > 0.7
        BlowOut = (PixelLuminosity + 1) * (PixelLuminosity + 1) / 2.5
        If BlowOut > 1 : BlowOut = 1 : EndIf
        ; The lower the contrast between the background and stroke color,
        ; the more the BlowOut correction is applied.
        PixelLuminosity = PixelLuminosity * (1 - LowContrast) + BlowOut * LowContrast
      ElseIf PixelLuminosity < 0.3
        ; CrushBlacks darkens the dark tones.
        ; (In photography, this is called "crushing" the blacks).
        CrushBlacks = PixelLuminosity * PixelLuminosity * PixelLuminosity
        ; The lower the contrast between the background and stroke color,
        ; the more the CrushBlacks correction is applied.
        PixelLuminosity = PixelLuminosity * (1 - LowContrast) + CrushBlacks * LowContrast
      EndIf
      ;
      If PixelLuminosity > 1 : PixelLuminosity = 1 : EndIf
      PixelDarkness = 1 - PixelLuminosity
      ;
      ; The principle of color modification is as follows:
      ; - The lighter the pixel, the less its color is retained and the more it is replaced by *backColor:
      *pixelColor\red   * PixelDarkness + *backColor\red   * PixelLuminosity
      *pixelColor\green * PixelDarkness + *backColor\green * PixelLuminosity
      *pixelColor\blue  * PixelDarkness + *backColor\blue  * PixelLuminosity
      ;
      ; - The darker the pixel, the less its color is retained and the more it is replaced by *foreColor:
      *pixelColor\red   * PixelLuminosity + *foreColor\red   * PixelDarkness
      *pixelColor\green * PixelLuminosity + *foreColor\green * PixelDarkness
      *pixelColor\blue  * PixelLuminosity + *foreColor\blue  * PixelDarkness
      ;
    Next
  Next
  ;
  ; Copy the modified bitmap into the original HDC
  BitBlt_(hdc, 0, 0, width, height, memDC, 0, 0, #SRCCOPY)
  ;
  ; Release resources
  SelectObject_(memDC, oldBitmap)
  DeleteObject_(hBitmap)
  DeleteDC_(memDC)
EndProcedure
Compared to the original code, there are only four lines added. A first group of three lines is added before the loop:

Code: Select all

  Color = GetPixel_(memDC, 1, 1); Up-Left color of the gadget bakcground.
  maxLum = Red(Color) + Green(Color) + Blue(Color) ; Compute luminosity of the background.
  If maxLum = 0 : maxLum = 1 : EndIf ; Be sure to not divide by zero later.
And another line is added just before computing PixelDarkness:

Code: Select all

      If PixelLuminosity > 1 : PixelLuminosity = 1 : EndIf
to be sure that exceptionnal pixels which have a higher luminosity than background's won't appear strange colored.

I've also translated all commentaries in english.

The result is very similar to the one you've illustrated above (a pure black is applied to the option gadgets).

Thanks for your interrest and please pardon my occasionally hasardous english.
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

The first post has been updated with a new version of this library.
  • ChrisR's remarks and suggestions were taken into account to improve the background color of the gadgets.
  • More comments have been added to the code
  • Memory is now cleaned when a window using SetGadgetColorEx() is closed.
  • Some other minor bugs have been fixed
  • A complete set of functions have been added to manage color themes for your applications. It's available in the 'ApplyColorThemes.pb' additionnal file
Image
Image

Here is the code: for ApplyColorThemes.pb (it needs the "ZapmanColorRequester.pb" library downloadable here: https://www.editions-humanis.com/downlo ... uester.zip)

Code: Select all

;
; **************************************************************************
;
;                             ApplyColorThemes
;                               Windows only
;                            Zapman - Dec 2024
;
;      This file should be saved under the name "ApplyColorThemes.pbi".
;
;    This library offers a set of functions to implemente a color-themes
;           support (as a dark mode theme) into your applications.
;
;  • The EditThemesColors() function allows you to set a couple of colors for
;    background and foreground and give a name to this set.
;  • The SetGadgetsColorsFromTheme() will apply this theme to a list of gadgets.
;  • GetColorThemesFromPreferences() and SetColorThemesToPreferences() allows
;    you to record and restore a set of themes to and from a .prefs file.
;  • ThemesDemoWindow() shows an example of use for this set of functions.
;
; **************************************************************************
; NOTICE: This library is NOT stand alone.
; "SetGadgetColorEx.pbi" and "ZapmanColorRequester.pbi" are needed as included files.
;
;
; ******************************************************************
;
;-        1--- First PART: FUNCTIONS FOR SETTING THEMES ---
;
XIncludeFile "SetGadgetColorEx.pbi"
XIncludeFile "ZapmanColorRequester.pbi"
;
Structure InterfaceColorsStruct
  PresetName.s
  Editable.b
  BackgroundColor.l
  TextColor.l
  DefaultBackgroundColor.l
  DefaultTextColor.l
EndStructure
;
Global NewList InterfaceColorPresets.InterfaceColorsStruct()
;
Procedure TC_GetColorFromType(ColorType$, *currentColor.InterfaceColorsStruct)
  If ColorType$ = "BackgroundColor"
    ProcedureReturn *currentColor\BackgroundColor
  ElseIf ColorType$ = "TextColor"
    ProcedureReturn *currentColor\TextColor
  EndIf
EndProcedure
;
Procedure TC_GetRealColorFromType(ColorType$, *currentColor.InterfaceColorsStruct)
  ; 
  Protected Color = TC_GetColorFromType(ColorType$, *currentColor)
  ;
  ProcedureReturn GetRealColorFromType(ColorType$, Color)
EndProcedure
;
Procedure TC_SetColorFromType(ColorType$, Color, *currentColor.InterfaceColorsStruct)
  ;
  If ColorType$ = "BackgroundColor"
    *currentColor\BackgroundColor = Color
  ElseIf ColorType$ = "TextColor"
    *currentColor\TextColor = Color
  EndIf
EndProcedure
;
Procedure TC_DisableResetGadget(*currentColor.InterfaceColorsStruct, BDefault)
  ;
  Protected TC_DisableColorGadgets
  ;
  If *currentColor\Editable And (*currentColor\DefaultBackgroundColor <> -2)  And (*currentColor\DefaultBackgroundColor <> *currentColor\BackgroundColor Or *currentColor\DefaultTextColor <> *currentColor\TextColor)
    TC_DisableColorGadgets = #False
  Else
    TC_DisableColorGadgets = #True
  EndIf
  ;
  DisableGadget(BDefault, TC_DisableColorGadgets)
  ;
EndProcedure
;
Procedure TC_DisableColorGadgets(*currentColor.InterfaceColorsStruct, *ECGadgets.EditColorGadgetsStruct, BDefault)
  ;
  Protected TC_DisableColorGadgets
  ;
  TC_DisableResetGadget(*currentColor.InterfaceColorsStruct, BDefault)
    ;
  If *currentColor\Editable
    TC_DisableColorGadgets = #False
  Else
    TC_DisableColorGadgets = #True
  EndIf
  DisableGadget(*ECGadgets\Red_Input, TC_DisableColorGadgets)
  DisableGadget(*ECGadgets\Green_Input, TC_DisableColorGadgets)
  DisableGadget(*ECGadgets\Blue_Input, TC_DisableColorGadgets)
  DisableGadget(*ECGadgets\Hue_Input, TC_DisableColorGadgets)
  DisableGadget(*ECGadgets\Sat_Input, TC_DisableColorGadgets)
  DisableGadget(*ECGadgets\Lum_Input, TC_DisableColorGadgets)
  DisableGadget(*ECGadgets\HexColor_Input, TC_DisableColorGadgets)
  ;
EndProcedure
;
Procedure TC_EnableDisableComboReadOnly(TempPresetsEditable, gadgetPreset, BDel)
  ;
  ; Enable/disable edition for ComboGadget, regarding the 'TempPresets()\Editable' field:
  ;
  Structure COMBOBOXINFO 
    cbSize.l
    rcItem.rect
    rcButton.rect
    stateButton.l
    hwndCombo.l
    hwndItem.l
    hwndList.l
  EndStructure
  Protected cbi.comboboxinfo\cbSize = SizeOf(COMBOBOXINFO)
  ;
  GetComboBoxInfo_(GadgetID(gadgetPreset), @cbi)
  If TempPresetsEditable
    SendMessage_(cbi\hwndItem, #EM_SETREADONLY, 0, 0)
    DisableGadget(BDel, #False)
  Else
    SendMessage_(cbi\hwndItem, #EM_SETREADONLY, 1, 0)
    DisableGadget(BDel, #True)
  EndIf
EndProcedure
;
Procedure SetThemesColors()
  ClearList(InterfaceColorPresets())
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Standard"
  InterfaceColorPresets()\Editable = #False
  InterfaceColorPresets()\BackgroundColor = #PB_Default
  InterfaceColorPresets()\TextColor = #PB_Default
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Lemon"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = RGB(239, 255, 234)
  InterfaceColorPresets()\TextColor = RGB(0, 50, 0)
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Light gray"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = RGB(230, 231, 232)
  InterfaceColorPresets()\TextColor = RGB(47, 47, 49)
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Dark gray"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = RGB(30, 45, 45)
  InterfaceColorPresets()\TextColor = RGB(240, 240, 240)
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Brown sugar"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = RGB(61, 45, 45)
  InterfaceColorPresets()\TextColor = RGB(240, 240, 200)
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Matrix"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = RGB(0, 40, 40)
  InterfaceColorPresets()\TextColor = RGB(90, 255, 160)
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Rapsody"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = RGB(0, 10, 50)
  InterfaceColorPresets()\TextColor = RGB(160, 255, 210)
  AddElement(InterfaceColorPresets())
  InterfaceColorPresets()\PresetName = "Raspberry"
  InterfaceColorPresets()\Editable = #True
  InterfaceColorPresets()\BackgroundColor = $7E00A8
  InterfaceColorPresets()\TextColor = $CDFFCC
  ForEach InterfaceColorPresets()
    InterfaceColorPresets()\DefaultBackgroundColor = InterfaceColorPresets()\BackgroundColor
    InterfaceColorPresets()\DefaultTextColor = InterfaceColorPresets()\TextColor
  Next
  SelectElement(InterfaceColorPresets(), 0)
EndProcedure
;
Procedure SetGadgetsColorsFromTheme(MainWindow, *currentColor.InterfaceColorsStruct, GadgetList$, Colortype$ = "")
  ;
  ; Set colors (background and text colors) to a list of gadgets.
  ; GadgetList$ must be formated as this:
  ; "GadgetNumber1,GadgetNumber2,GadgetNumber3,GadgetNumber4,..."
  ;
  ; If the parameter 'Colortype$' is empty, both BackgroundColor and TextColor will be
  ; applied to the gadgets.
  ; If the parameter 'Colortype$' contains "BackgroundColor" or "TextColor",
  ; only the corresponding color will applied to the gadgets.
  ;
  ; Canvas type gadgets that are included in the 'GadgetList$' list will be entirely repainted
  ; with an intermediate color between *currentColor\BackgroundColor and *currentColor\TextColor.
  ; You should therefore only include in this list the canvases used as separation lines in your
  ; window.
  ;
  Protected PosInGadgetList = 0, Gadget
  ;
  If Colortype$ = "" Or Colortype$ = "BackgroundColor"
    SetWindowColor(MainWindow, *currentColor\BackgroundColor)
  EndIf
  ;
  Repeat
    PosInGadgetList + 1
    Gadget = Val(StringField(GadgetList$, PosInGadgetList, ","))
    If IsGadget(Gadget)
      If GadgetType(Gadget) = #PB_GadgetType_Canvas
        RepaintCanvasSeparator(Gadget, CalculateBorderColor(*currentColor\TextColor, *currentColor\BackgroundColor))
      Else
        If Colortype$ = "" Or Colortype$ = "BackgroundColor"
          SetGadgetColorEx(Gadget, #PB_Gadget_BackColor, *currentColor\BackgroundColor)
        EndIf
        If Colortype$ = "" Or Colortype$ = "TextColor"
          SetGadgetColorEx(Gadget, #PB_Gadget_FrontColor, *currentColor\TextColor)
        EndIf
      EndIf
    EndIf
  Until StringField(GadgetList$, PosInGadgetList, ",") = ""
EndProcedure
;
Procedure SetFontAndGadgetsColors(MainWindow, *currentColor.InterfaceColorsStruct, GadgetList$, Colortype$ = "")
  ;
  Protected PosInGadgetList = 0, Gadget
  ;
  SetGadgetsColorsFromTheme(MainWindow, *currentColor, GadgetList$, Colortype$)
  ;
  Global PBBAllGadgetsFont
  If PBBAllGadgetsFont = 0
    PBBAllGadgetsFont = FontID(LoadFont(#PB_Any, "Segoe UI", 9))
  EndIf
  ;
  Repeat
    PosInGadgetList + 1
    Gadget = Val(StringField(GadgetList$, PosInGadgetList, ","))
    If IsGadget(Gadget)
      SetGadgetFont(Gadget, PBBAllGadgetsFont)
    EndIf
  Until StringField(GadgetList$, PosInGadgetList, ",") = ""
  ;
EndProcedure
;
Procedure EditThemesColors(ParentWindow= -1)
  ;
  Shared ECGadgets.EditColorGadgetsStruct
  ;
  ; Window and gadget numbers:
  Protected gadgetPreset, BWidth, BAdd, BDel
  Protected OptionText, OptionBackground, TxPreset, BDefault
  ; Other variables:
  Protected WWidth, WMargins, VPos, GadgetList$, Index
  Protected *TempPresetsAdr, mIndex, GetOut
  ;
  Protected WHeight, WParam, OX, OY, Frame1, MarginCircular, *GadgetAdress
  Protected Event, EventType, EventGadget, EventMenu, mColor
  ;
  If ListSize(InterfaceColorPresets()) < 1
    ; Create an InterfaceColorPresets() if none exists:
    SetThemesColors()
  EndIf
  ;
  Protected NewList TempPresets.InterfaceColorsStruct()
  ClearList(TempPresets())
  CopyList(InterfaceColorPresets(), TempPresets())
  ;
  WWidth = 480
  WHeight = 350
  WMargins = 15
  WParam = #PB_Window_SystemMenu | #PB_Window_Invisible
  Protected ParentWindowID = ComputeWinOrigins(@OX, @OY, WWidth, WHeight, ParentWindow)
  ;
  ECGadgets\EditColorWindow = OpenWindow(#PB_Any, OX, OY, WWidth, WHeight, GetTextFromCatalog("ThemeColors"), WParam, ParentWindowID)
  ;
  If ECGadgets\EditColorWindow
    ApplyDarkModeToWindow(ECGadgets\EditColorWindow)
    StickyWindow(ECGadgets\EditColorWindow, 1)
    ;
    VPos = WMargins
    ;
    TxPreset = TextGadget(#PB_Any, WMargins, VPos + 2, 100, 20, GetTextFromCatalog("Presets"))
    GadgetList$ + Str(TxPreset) + ","
    gadgetPreset = ComboBoxGadget(#PB_Any, WMargins + 105, VPos, 180, 22, #PB_ComboBox_Editable)
    ForEach TempPresets()
      AddGadgetItem(gadgetPreset, -1, TempPresets()\PresetName)
    Next
    SelectElement(TempPresets(), ListIndex(InterfaceColorPresets()))
    SetGadgetState(gadgetPreset, ListIndex(TempPresets()))
    GadgetList$ + Str(gadgetPreset) + ","
    BWidth = 22
    BAdd = ButtonGadget(#PB_Any, WWidth - WMargins - 2 * BWidth - 5, VPos, BWidth, 22, "+")
    GadgetList$ + Str(BAdd) + ","
    BDel = ButtonGadget(#PB_Any, WWidth - WMargins - BWidth, VPos, BWidth, 22, "-")
    GadgetList$ + Str(BDel) + ","
        ;
    VPos + 35
    Frame1 = CanvasGadget(#PB_Any, WMargins, VPos, WWidth - 2 * WMargins, 1)
    GadgetList$ + Str(Frame1) + ","
    ;
    BWidth = 140
    VPos + 5
    OptionBackground = OptionGadget(#PB_Any, 100, VPos, BWidth, 25, GetTextFromCatalog("BackgroundColor"))
    GadgetList$ + Str(OptionBackground) + ","
    ;
    ; Select OptionBackground by default:
    SetGadgetState(OptionBackground, 1)
    ECGadgets\Color = TempPresets()\BackgroundColor
    ECGadgets\SGC_ColorType$ = "BackgroundColor"
    ;
    OptionText = OptionGadget(#PB_Any, WWidth - BWidth - 20, VPos, BWidth, 25, GetTextFromCatalog("TextColor"))
    GadgetList$ + Str(OptionText) + ","
    ;
    ECGadgets\MarginTop = VPos + 35
    MarginCircular = 15
    ECGadgets\MarginButtonsBottom = MarginCircular
    ECGadgets\MarginButtonsTop = 0
    ECGadgets\MarginInterBlocks = 31
    ECGadgets\MarginLeft = MarginCircular
    ECGadgets\MarginRight = MarginCircular
    ECGadgets\HexFieldVPos = -2      ; Position of the 'Hexa value' fields (-1 is at the bottom-left of the window, -2 is at Interblocks-right).
    ECGadgets\HorizGadgetsMargin = 5 ; Vertical margins between gadgets.
    ;
    ECGadgets\BackColor = GetRealColorFromType("BackgroundColor", TempPresets()\BackgroundColor)    ; Background color for all canvas cursors.
    ECGadgets\TextColor = GetRealColorFromType("TextColor", TempPresets()\TextColor)                ; Color used to calculate gadgets borders color.                                        ; Color for gadgets borders.
    ;
    ; Initialyse ZapmanColorRequester gadgets:
    ZCR_CreateGadgets()
    ;
    ZCR_SetText()
    ZCR_SetFieldsSizeAndMargins()
    ZCR_CreateTargetAndCursors()
    ZCR_ResizeGadgets()
    ;
    ; Add ZapmanColorRequester gadgets to the gadgetlist$
    *GadgetAdress = @ECGadgets\Red_Legend
    Repeat
      GadgetList$ + Str(PeekI(*GadgetAdress)) + ","
      *GadgetAdress + SizeOf(Integer)
    Until *GadgetAdress > @ECGadgets\BCancel

    ;
    VPos  = ECGadgets\InterBlocksVerticalPos + 5
    BDefault = ButtonGadget(#PB_Any, WMargins, VPos, 170, 21, GetTextFromCatalog("ResetToDefaultColor"))
    GadgetList$ + Str(BDefault) + ","
    ;
    TC_EnableDisableComboReadOnly(TempPresets()\Editable, gadgetPreset, BDel)
    ;
    TC_DisableColorGadgets(TempPresets(), ECGadgets, BDefault)
    ;
    #ZCR_Escape_Cmd = 1
    #ZCR_Enter = 2
    AddKeyboardShortcut(ECGadgets\EditColorWindow, #PB_Shortcut_Escape, #ZCR_Escape_Cmd)
    AddKeyboardShortcut(ECGadgets\EditColorWindow, #PB_Shortcut_Return, #ZCR_Enter)
    ;
    ; Initialize cursor's positions for trackbars and gadget's colors:
    ZCR_SetGadgetsFromColor(ECGadgets)
    ;
    SetFontAndGadgetsColors(ECGadgets\EditColorWindow, TempPresets(), GadgetList$)
    ;
    ; The window was invisible until now, because we created it with #PB_Window_Invisible.
    ; We make it visible now.
    HideWindow(ECGadgets\EditColorWindow, #False)
    ;
    SetActiveGadget(gadgetPreset)
    ;
    Repeat
      Event = WaitWindowEvent(10)
      If Event
        EventType   = EventType()
        EventGadget = EventGadget()
        EventMenu   = EventMenu()
        ;
        ; Manage trackbars and input events:
        If TempPresets()\Editable
          mColor = ECGadgets\Color 
          GetOut = ZCR_Events(Event, EventGadget, EventType)
          If mColor <> ECGadgets\Color
            If ECGadgets\SGC_ColorType$ = "TextColor"
              TempPresets()\TextColor = ECGadgets\Color
            Else
              TempPresets()\BackgroundColor = ECGadgets\Color
            EndIf
            SetGadgetsColorsFromTheme(ECGadgets\EditColorWindow, TempPresets(), GadgetList$, ECGadgets\SGC_ColorType$)
            TC_DisableResetGadget(TempPresets(), BDefault)
          EndIf
        EndIf
        ;
        Select Event
          Case #PB_Event_Menu
            If EventMenu = #ZCR_Escape_Cmd
              GetOut = -1
            ElseIf EventMenu = #ZCR_Enter
              GetOut = 1
            EndIf
          Case #PB_Event_Gadget
            Select EventGadget

              Case gadgetPreset
                If GetGadgetState(gadgetPreset) = -1
                  TempPresets()\PresetName = GetGadgetText(gadgetPreset)
                  SetGadgetItemText(gadgetPreset, ListIndex(TempPresets()), GetGadgetText(gadgetPreset))
                Else
                  SelectElement(TempPresets(), GetGadgetState(gadgetPreset))
                  ;
                  ; Enable/disable edition regarding the 'TempPresets()\Editable' field:
                  TC_EnableDisableComboReadOnly(TempPresets()\Editable, gadgetPreset, BDel)
                  ;
                  TC_DisableColorGadgets(TempPresets(), ECGadgets, BDefault)
                  SetGadgetsColorsFromTheme(ECGadgets\EditColorWindow, TempPresets(), GadgetList$)
                  ECGadgets\Color = TC_GetRealColorFromType(ECGadgets\SGC_ColorType$, TempPresets())
                  ECGadgets\BackColor = TempPresets()\BackgroundColor
                  ECGadgets\TextColor = TempPresets()\TextColor
                  ZCR_SetGadgetsFromColor(ECGadgets)
                EndIf
              Case BAdd
                Index = ListIndex(TempPresets())
                *TempPresetsAdr = @TempPresets()
                mIndex = Index
                ;
                ; Look for where the new preset can be inserted (or added to the end of the list):
                While mIndex + 1 < ListSize(TempPresets()) And TempPresets()\Editable = 0
                  mIndex + 1
                  SelectElement(TempPresets(), mIndex)
                Wend
                If mIndex = Index Or TempPresets()\Editable = 0
                  mIndex + 1
                EndIf
                ;
                ; Insert or add an element to the list:
                If mIndex < ListSize(TempPresets())
                  SelectElement(TempPresets(), mIndex)
                  InsertElement(TempPresets())
                Else
                  AddElement(TempPresets())
                EndIf
                ;
                ; Copy the last selected element to the new one:
                CopyStructure(*TempPresetsAdr, @TempPresets(), InterfaceColorsStruct)
                TempPresets()\PresetName + " (copy)"
                TempPresets()\Editable = #True
                TempPresets()\DefaultTextColor = -2
                TempPresets()\DefaultBackgroundColor = -2
                ; Update the ComboGadget:
                AddGadgetItem(gadgetPreset, mIndex, TempPresets()\PresetName)
                SetGadgetState(gadgetPreset, mIndex)
                TC_EnableDisableComboReadOnly(TempPresets()\Editable, gadgetPreset, BDel)
                TC_DisableColorGadgets(TempPresets(), ECGadgets, BDefault)
                ;
              Case BDel
                Index = ListIndex(TempPresets())
                DeleteElement(TempPresets())
                RemoveGadgetItem(gadgetPreset, Index)
                SetGadgetState(gadgetPreset, Index - 1)
                SelectElement(TempPresets(), Index - 1)
                ;
                TC_EnableDisableComboReadOnly(TempPresets()\Editable, gadgetPreset, BDel)
                ;
                TC_DisableColorGadgets(TempPresets(), ECGadgets, BDefault)
                SetGadgetsColorsFromTheme(ECGadgets\EditColorWindow, TempPresets(), GadgetList$)
                ECGadgets\Color = TC_GetRealColorFromType(ECGadgets\SGC_ColorType$, TempPresets())
                ECGadgets\BackColor = TempPresets()\BackgroundColor
                ECGadgets\TextColor = TempPresets()\TextColor
                ZCR_SetGadgetsFromColor(ECGadgets)
              Case OptionBackground, OptionText
                If EventGadget = OptionBackground
                  ECGadgets\SGC_ColorType$ = "BackgroundColor"
                Else
                  ECGadgets\SGC_ColorType$ = "TextColor"
                EndIf
                SetGadgetsColorsFromTheme(ECGadgets\EditColorWindow, TempPresets(), GadgetList$, ECGadgets\SGC_ColorType$)
                ECGadgets\Color = TC_GetRealColorFromType(ECGadgets\SGC_ColorType$, TempPresets())
                ZCR_SetGadgetsFromColor(ECGadgets)
              Case BDefault
                If ECGadgets\SGC_ColorType$ = "BackgroundColor"
                  TC_SetColorFromType(ECGadgets\SGC_ColorType$, TempPresets()\DefaultBackgroundColor, TempPresets())
                Else
                  TC_SetColorFromType(ECGadgets\SGC_ColorType$, TempPresets()\DefaultTextColor, TempPresets())
                EndIf
                SetGadgetsColorsFromTheme(ECGadgets\EditColorWindow, TempPresets(), GadgetList$, ECGadgets\SGC_ColorType$)
                ECGadgets\Color = TC_GetRealColorFromType(ECGadgets\SGC_ColorType$, TempPresets())
                ECGadgets\BackColor = TempPresets()\BackgroundColor
                ECGadgets\TextColor = TempPresets()\TextColor
                TC_DisableResetGadget(TempPresets(), BDefault)
                ZCR_SetGadgetsFromColor(ECGadgets)
                ;
              Case ECGadgets\BOk ; OK button
                GetOut = 1
              Case ECGadgets\BCancel ; Cancel button
                GetOut = -1
            EndSelect
            ;
        EndSelect
      EndIf
    Until Event = #PB_Event_CloseWindow Or GetOut
    ;
    If GetOut = 1
      ClearList(InterfaceColorPresets())
      CopyList(TempPresets(), InterfaceColorPresets())
      ForEach InterfaceColorPresets()
        If InterfaceColorPresets()\DefaultTextColor = -2
          InterfaceColorPresets()\DefaultTextColor = InterfaceColorPresets()\TextColor
        EndIf
        If InterfaceColorPresets()\DefaultBackgroundColor = -2
          InterfaceColorPresets()\DefaultBackgroundColor = InterfaceColorPresets()\BackgroundColor
        EndIf
      Next
      SelectElement(InterfaceColorPresets(), ListIndex(TempPresets()))
    EndIf
  EndIf
  CloseWindow(ECGadgets\EditColorWindow)
EndProcedure
;
Procedure GetColorThemesFromPreferences(MyPreferenceFile$)
  ;
  Protected Found, PrefString$, ColorTheme
  ;
  If ListSize(InterfaceColorPresets()) < 1
    If OpenPreferences(MyPreferenceFile$)
      Found = 0
      ClearList(InterfaceColorPresets())
      ExaminePreferenceKeys()
      While NextPreferenceKey()
        If Left(PreferenceKeyName(), Len("ColorPresets")) = "ColorPresets"
          Found = 1
          PrefString$ = PreferenceKeyValue()
          AddElement(InterfaceColorPresets())
          InterfaceColorPresets()\PresetName      = StringField(PrefString$, 1, ",")
          InterfaceColorPresets()\Editable        = Val(StringField(PrefString$, 2, ","))
          InterfaceColorPresets()\BackgroundColor = Val(StringField(PrefString$, 3, ","))
          InterfaceColorPresets()\TextColor       = Val(StringField(PrefString$, 4, ","))
          InterfaceColorPresets()\DefaultBackgroundColor = Val(StringField(PrefString$, 5, ","))
          InterfaceColorPresets()\DefaultTextColor       = Val(StringField(PrefString$, 6, ","))
        EndIf
      Wend
      ColorTheme = ReadPreferenceInteger("ColorTheme", 0)
      ClosePreferences()
    EndIf
    If Found = 0
      ; There is not theme in the preference file or the preference file doen't exist.
      ; Create some prerecorded themes:
      SetThemesColors()
    EndIf
    If ListSize(InterfaceColorPresets())
      SelectElement(InterfaceColorPresets(), ColorTheme)
    EndIf
  Else
    ColorTheme = ListIndex(InterfaceColorPresets())
  EndIf
  ProcedureReturn ColorTheme
EndProcedure
;
Procedure SetColorThemesToPreferences(MyPreferenceFile$, DefaultTheme)
  ;
  Protected PrefString$, index
  ;
  If MyPreferenceFile$ And ListSize(InterfaceColorPresets()) > 0
    If OpenPreferences(MyPreferenceFile$) = 0
      CreatePreferences(MyPreferenceFile$)
      ClosePreferences()
    EndIf
    ;
    If OpenPreferences(MyPreferenceFile$)
      ;
      ; Erase old values:
      ExaminePreferenceKeys()
      While NextPreferenceKey()
        If Left(PreferenceKeyName(), Len("ColorPresets")) = "ColorPresets"
          RemovePreferenceKey(PreferenceKeyName())
        EndIf
      Wend
      ;
      ; Save actual values:
      index = 0
      ForEach InterfaceColorPresets()
        PrefString$ = ReplaceString(InterfaceColorPresets()\PresetName, ",", "-") + ","
        PrefString$ + Str(InterfaceColorPresets()\Editable) + ","
        PrefString$ + Str(InterfaceColorPresets()\BackgroundColor) + ","
        PrefString$ + Str(InterfaceColorPresets()\TextColor) + ","
        PrefString$ + Str(InterfaceColorPresets()\DefaultBackgroundColor) + ","
        PrefString$ + Str(InterfaceColorPresets()\DefaultTextColor) + ","
        index + 1
        WritePreferenceString("ColorPresets" + Str(index), PrefString$)
      Next
      WritePreferenceInteger("ColorTheme", DefaultTheme)
      ClosePreferences()
      SelectElement(InterfaceColorPresets(), DefaultTheme)
    EndIf
  EndIf
EndProcedure
;
;
;
; *************************************************************************************
;
;-                      2--- SECOND PART: DEMO PROCEDURE ---
;
; *************************************************************************************
;
Procedure ThemesDemoWindow()
  ;
  Protected PresentationText$, VPos, ct, GadgetList$, MyPreferenceFile$, ColorTheme, Event
  ;
  If OpenWindow(0, 100, 100, 450, 360, "Themes DemoWindow", #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_Invisible)
    ApplyDarkModeToWindow(0)
    ;
    Enumeration GadgetNum
      #TFrame
      #TOption1
      #TOption2
      #TCheckBox
      #TButton1
      #TText
      #TString
      #TEditor
      #TListView
      #SepLine1
      #TBSeeOtherExample
      #SepLine2
      #TTChooseTheme
      #TCBChooseTheme
      #TBEditThemes
      #TBQuit
    EndEnumeration
    ;
    PresentationText$ = "This window shows the result that SeGadgetColorEx can achieve when used to set display themes."
    PresentationText$ + #CR$ + #CR$ + "Note that some gadgets are not fully colorized by SetGadgetColorEx. However, as you can see "
    PresentationText$ + "on the left side of this text, it works for most of them."
    PresentationText$ + #CR$ + #CR$ + "The ''Exit'' button is colored red, regardless of the display theme chosen, showing that you can combine "
    PresentationText$ + "the use of themes and independent colors for certain gadgets."
    PresentationText$ + #CR$ + #CR$ + "Use the ''Choose a theme'' combobox to change the theme, and the ''Edit themes'' button to modify them."
    ; Creating two option buttons
    FrameGadget(#TFrame, 10, 10, 120, 70, "Options")
    
    OptionGadget(#TOption1, 15, 25, 100, 25, "Button #1")
    OptionGadget(#TOption2, 15, 45, 100, 25, "Button #2")
    ;
    CheckBoxGadget(#TCheckBox, 10, 90, 100, 25, "Desable")
    SetGadgetState(#TCheckBox, 1)
    ButtonGadget(#TButton1, 10, 120, 100, 25, "Desabled Button")
    DisableGadget(#TButton1, #True)
    ;
    TextGadget(#TText, 10, 150, 100, 25, "Simple text")
    ;
    StringGadget(#TString, 10, 170, 100, 25, "StringGadget")
    ;
    EditorGadget(#TEditor, 140, 10, 300, 240, #PB_Editor_WordWrap)
    SetGadgetText(#TEditor, PresentationText$)
    ;
    ; CanvasGadget is used to create an horizontal line separator
    ; in the window.
    CanvasGadget(#SepLine1, 10, 265, WindowWidth(0) - 20, 1)
    ;
    ButtonGadget(#TBSeeOtherExample, (WindowWidth(0) - 300) / 2, 275, 300, 25, "See another example with multicolor gadgets")
    ;
    ; CanvasGadget is used to create an horizontal line separator
    ; in the window.
    CanvasGadget(#SepLine2, 10, 310, WindowWidth(0) - 20, 1)
    ;
    VPos = WindowHeight(0) - 33
    TextGadget(#TTChooseTheme, 10, VPos, 100, 25, "Choose the theme:")
    ComboBoxGadget(#TCBChooseTheme, 120, VPos - 3, 100, 22)
    ;
    ; Initialize some presets for the themes:
    MyPreferenceFile$ = GetTemporaryDirectory() + "MyPrefs.txt" ; <--- Change this line to use another pref file address.
    ColorTheme = GetColorThemesFromPreferences(MyPreferenceFile$)
    ;
    ForEach InterfaceColorPresets()
      AddGadgetItem(#TCBChooseTheme, -1, InterfaceColorPresets()\PresetName)
    Next
    SelectElement(InterfaceColorPresets(), ColorTheme)
    SetGadgetState(#TCBChooseTheme, ColorTheme)
    ;
    ButtonGadget(#TBEditThemes, 230, VPos - 4, 100, 25, "Edit themes")
    ;       
    ButtonGadget(#TBQuit, WindowWidth(0) - 100, VPos - 4, 90, 25, "Exit")
    ;
    ; Set a gadget list to indicate which gadgets must be colorized:
    For ct = #TFrame To #TBQuit
      GadgetList$ + Str(ct) + ","
    Next
    ;
    SetGadgetsColorsFromTheme(0, @InterfaceColorPresets(), GadgetList$)
    ;
    ; Manage #TBQuit button color separately:
    SetGadgetColorEx(#TBQuit, #PB_Gadget_FrontColor, RGB(255, 20, 20))
    ;
    ; The window was invisible until now, because we created it with #PB_Window_Invisible.
    ; We make it visible now.
    HideWindow(0, #False)
    ;       
    Repeat
      Event = WaitWindowEvent()
      
      If Event = #PB_Event_Gadget

        Select EventGadget()
          Case #TBSeeOtherExample
            DisableWindow(0, #True)
            MulticolorDemoWindow()
            DisableWindow(0, #False)
            SetForegroundWindow_(WindowID(0))
          Case #TCBChooseTheme
            If GetGadgetState(#TCBChooseTheme) > -1
              SelectElement(InterfaceColorPresets(), GetGadgetState(#TCBChooseTheme))
              ;
              SetGadgetsColorsFromTheme(0, @InterfaceColorPresets(), GadgetList$)
              ; Manage #TBQuit button color separately:
              SetGadgetColorEx(#TBQuit, #PB_Gadget_FrontColor, RGB(255, 20, 20))
            EndIf
          Case #TBEditThemes
            DisableWindow(0, #True)
            EditThemesColors(0)
            DisableWindow(0, #False)
            ClearGadgetItems(#TCBChooseTheme)
            ColorTheme = ListIndex(InterfaceColorPresets())
            ForEach InterfaceColorPresets()
              AddGadgetItem(#TCBChooseTheme, -1, InterfaceColorPresets()\PresetName)
            Next
            SelectElement(InterfaceColorPresets(), ColorTheme)
            SetGadgetState(#TCBChooseTheme, ColorTheme)
            ;
            SetGadgetsColorsFromTheme(0, @InterfaceColorPresets(), GadgetList$)
            ; Manage #TBQuit button color separately:
            SetGadgetColorEx(#TBQuit, #PB_Gadget_FrontColor, RGB(255, 20, 20))
            ;
            SetForegroundWindow_(WindowID(0))
          Case #TCheckBox
            If GetGadgetState(#TCheckBox)
              DisableGadget(#TButton1, #True)
              SetGadgetText(#TButton1, "Desabled Button")
            Else
              DisableGadget(#TButton1, #False)
              SetGadgetText(#TButton1, "Enabled Button")
            EndIf
      
          Case #TBQuit
            Break
        EndSelect
        ;
      ElseIf Event = #PB_Event_CloseWindow
        Break
      EndIf
    ForEver
    ;
    ; You will certainly want to save the presets in a 'pref' file in order to allow
    ; the user to reuse some set he has modified.
    ; Before calling 'ClearList' to clean memory, you can do so:
    ;
    MyPreferenceFile$ = GetTemporaryDirectory() + "MyPrefs.txt" ; <--- Change this line to use another pref file address.
    SetColorThemesToPreferences(MyPreferenceFile$, GetGadgetState(#TCBChooseTheme))
    ;
    ; Then, free memory if you have not another window to colorize.
    ClearList(InterfaceColorPresets())
    ;
    CloseWindow(0)
  EndIf
EndProcedure
;
CompilerIf #PB_Compiler_IsMainFile
  ; The following won't run when this file is used as 'Included'.
  ;
  ThemesDemoWindow()

CompilerEndIf
Last edited by Zapman on Mon Feb 03, 2025 11:55 am, edited 4 times in total.
dcr3
Enthusiast
Enthusiast
Posts: 181
Joined: Fri Aug 04, 2017 11:03 pm

Re: A very simple SetGadgetColorEx() function

Post by dcr3 »

Very nice and compact. 8)

I like the new additions. To be able to set and save themes.

To make it complete.You should try to add colour to the other gadgets. :wink:
Fred
Administrator
Administrator
Posts: 18153
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: A very simple SetGadgetColorEx() function

Post by Fred »

Looks cool, thanks for sharing !
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: A very simple SetGadgetColorEx() function

Post by Zapman »

dcr3 wrote: Mon Nov 25, 2024 9:45 pmVery nice and compact. 8) / To make it complete.You should try to add colour to the other gadgets. :wink:
Thank you very much, dcr3. The compact aspect is the point.

ChrisR has done a huge work to offer a very complete themes management library. (viewtopic.php?t=82890&hilit=dark+theme)
This code does'nt attempt to compete with his beautifull 'ObjectTheme.pbi'.

It's an alternative, lite but partial solution, following another way for doing the job, mainly to respond to the "dark theme" need for small applications.
Last edited by Zapman on Tue Nov 26, 2024 11:44 am, edited 1 time in total.
Post Reply