Object Theme Library (for Dark or Light Theme)

Share your advanced PureBasic knowledge/code with the community.
User avatar
jacdelad
Addict
Addict
Posts: 1477
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: Object Theme Library (for Dark or Light Theme)

Post by jacdelad »

Found the culprit: Line 798 in ObjectTheme.pbi. It's a SendMessage_() call within the Callback-function. Don't know if this is even allowed, maybe it's just a timing-thing. Both demos work, if I comment it out.
Also: The ComboBox with image doesn't change color for me. Looks like it works for you.
And finally: Windows 10, x64.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

Cool that you found it 8)
But I don't really understand why! it should be possible to send a message (even in a callback) to change the theme depending on whether the Gadget is enabled or disabled.
This is what I tried to do for the checkbox, option and TrackBar, to see the disabled state, grayed out. By changing the theme when the message WM_ENABLE is received.
I'll take another look to see how I could do it differently, thanks for the feedback :)
User avatar
jacdelad
Addict
Addict
Posts: 1477
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: Object Theme Library (for Dark or Light Theme)

Post by jacdelad »

I'm not sure, but maybe this creates an endless recursion or something like that.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

I've removed my SetWindowTheme tweak and also the StaticProc callback, which is no longer needed.
it's simpler and better this way.
Thanks :) it's uploaded on Github v1.2
novablue
Enthusiast
Enthusiast
Posts: 165
Joined: Sun Nov 27, 2016 6:38 am

Re: Object Theme Library (for Dark or Light Theme)

Post by novablue »

Very nice! I would like to ask if you could put as much of your code as possible into a module for better code separation?
User avatar
jacdelad
Addict
Addict
Posts: 1477
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: Object Theme Library (for Dark or Light Theme)

Post by jacdelad »

I downloaded version 1.2, but it crashes again, this time at line 836, another SendMessage_() within the callback procedure.
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

Very strange, I don't know why you have this, as for the previous one, I don't reproduce despite the number of tries made.
There should be no worries, endless recursion...by using SendMessage_(lParam, #EM_SETSEL, -1, 0) in the Window Callback. There's no reason and it's been working like that for a while now in ObjectColor with no return!
And here, it is useful to deselect the ComboBox editable string if it is not the active Gadget. Otherwise, the text would be selected after each use of SetObjectTheme()
Does anyone else reproduce or have any idea why jacdelad has this error that I don't have ?
Last edited by ChrisR on Thu Nov 23, 2023 12:32 pm, edited 1 time in total.
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

novablue wrote: Wed Nov 22, 2023 8:05 pm Very nice! I would like to ask if you could put as much of your code as possible into a module for better code separation?
I'm not always a fan of modules but here it's appropriate, it works by itself, without the need for postevent()...
I've updated it as a module, on Github in version 1.3 now.
UseModule ObjectTheme is mandatory to call macros directly (e.g. ButtonGadget) without having to change existing code and use ObjectTheme::ButtonGadget.
User avatar
Kuron
Addict
Addict
Posts: 1626
Joined: Sat Oct 17, 2009 10:51 pm
Location: Pacific Northwest

Re: Object Theme Library (for Dark or Light Theme)

Post by Kuron »

novablue wrote: Wed Nov 22, 2023 8:05 pm Very nice! I would like to ask if you could put as much of your code as possible into a module for better code separation?
I would ask that he DOESN'T.
Best wishes to the PB community. Thank you for the memories. ♥️
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

It shouldn't be too hard to maintain the 2 versions, standard and module, they are very close.
The 2 versions are on GitHub, the module version at the root and the standard version in the Non-Module_Version folder.

I'm a bit annoyed by jacdelad bugs that I don't understand at all, so thanks for the feedback to know how it goes for you?
In case of crash, it would be good to have Callstack infos
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Object Theme Library (for Dark or Light Theme)

Post by Little John »

ChrisR wrote: Thu Nov 23, 2023 12:12 pm Does anyone else reproduce or have any idea why jacdelad has this error that I don't have ?
I don't encounter any issues with this library here (on Windows 11). For me, version 1.3 works as well as version 1.0 did.
User avatar
jacdelad
Addict
Addict
Posts: 1477
Joined: Wed Feb 03, 2021 12:46 pm
Location: Planet Riesa
Contact:

Re: Object Theme Library (for Dark or Light Theme)

Post by jacdelad »

It's even getting stranger for me: I put a Debug right before said SendMessage_() and it always works about a hundred times or so before crashing at also said position.

I tried using #WM_GETTEXT and #WM_SETTEXT. It doesn't crash, but rendering doesn't work anymore...
PureBasic 6.04/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/130TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

Little John wrote: Thu Nov 23, 2023 7:33 pm
ChrisR wrote: Thu Nov 23, 2023 12:12 pm Does anyone else reproduce or have any idea why jacdelad has this error that I don't have ?
I don't encounter any issues with this library here (on Windows 11). For me, version 1.3 works as well as version 1.0 did.
Thanks for your confirmation Little John.
Just for further testing, I added this snippet to ObjectTheme_Demo.pb, to change theme every 10s and with 10 call to SendMessage_(lParam, #EM_SETSEL, -1, 0) each time.
And I let it running all night, with no problems, no bugs and no memory leaks.
So it's up to jacdelad!

Code: Select all

Procedure Thread(Value)
  PostEvent(#PB_Event_Gadget, #Window_1, #ApplyTheme_1, #PB_EventType_LeftClick)
  Delay(Value)
  CreateThread(@Thread(),10000)
EndProcedure
........
Open_Window_1()
Open_Window_2()

CreateThread(@Thread(), 10000)
dcr3
Enthusiast
Enthusiast
Posts: 165
Joined: Fri Aug 04, 2017 11:03 pm

Re: Object Theme Library (for Dark or Light Theme)

Post by dcr3 »

First time trying it, I haven't tried previous versions. So I can't comment on it.

On this version 1.3, It crashes on the 64bit, on the 32bit there is a stack overflow at line 1030.
User avatar
ChrisR
Addict
Addict
Posts: 1150
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: Object Theme Library (for Dark or Light Theme)

Post by ChrisR »

Gulp!
If you're compiling in x64, what does the OnError window say when it crashes?
In x86, can you please send the Debug\Callstack infos, screenshot or info with lines and procedure.

There's a bit of work behind it and I wouldn't want to put it in the trash.
It seems to work well for me and Little John but not for you and jacdelad. What's wrong!!!

Does it also crash with this summary code?
And possibly, does ObjectColor crash as well?

Code: Select all

EnableExplicit

Enumeration Window
  #Window
EndEnumeration

Enumeration Gadgets
  #String
  #Combo
  #Btn_Change_Color
EndEnumeration

Global BaseColor.l    = $2A0408
Global BrushBaseColor = CreateSolidBrush_(BaseColor)
Global NewColor.l     = $04082A
Global BrushNewColor  = CreateSolidBrush_(NewColor)
Global BrushHighLight = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))

Procedure SetComboDarkMode(IDGadget)
  Protected ChildGadget, Buffer.s = Space(64)

  If GetClassName_(IDGadget, @Buffer, 64)
    If Buffer = "ComboBox"
      SetWindowTheme_(IDGadget, "DarkMode_CFD", "Combobox")
    EndIf
  EndIf
  ChildGadget = GetWindow_(IDGadget, #GW_CHILD)
  If ChildGadget
    Buffer = Space(64)
    If GetClassName_(ChildGadget, @Buffer, 64)
      If Buffer = "ComboBox"
        SetWindowTheme_(ChildGadget, "DarkMode_CFD", "Combobox")
      EndIf 
    EndIf
  EndIf
EndProcedure

Procedure WinCallback(hWnd, uMsg, wParam, lParam)
  Protected Result = #PB_ProcessPureBasicEvents
  Protected Gadget, ParentGadget, Buffer.s, Text.s
  Protected *DrawItem.DRAWITEMSTRUCT
  
  Select uMsg
    Case #WM_CLOSE
      PostEvent(#PB_Event_Gadget, GetDlgCtrlID_(hWnd), 0, #PB_Event_CloseWindow)
      
    Case #WM_NCDESTROY
      DeleteObject_(BrushBaseColor)
      DeleteObject_(BrushNewColor)
      DeleteObject_(BrushHighLight)
      
    Case #WM_CTLCOLOREDIT
      ParentGadget = GetParent_(lParam)
      Buffer = Space(64)
      If GetClassName_(ParentGadget, @Buffer, 64)
        If Buffer = "ComboBox"
          Gadget = GetDlgCtrlID_(ParentGadget)
          If Gadget <> GetActiveGadget()
            ; TRY by commenting the SendMessage below, the text in the ComboBox edit part is selected, as long as it has not been deselected
            SendMessage_(lParam, #EM_SETSEL, -1, 0)   ; Deselect the ComboBox editable string if not the active Gadget
          EndIf
          SetTextColor_(wParam, #White)
          SetBkMode_(wParam, #TRANSPARENT)
          If GetWindowColor(#Window) = BaseColor
            ProcedureReturn BrushBaseColor
          Else
            ProcedureReturn BrushNewColor
          EndIf
        EndIf
      EndIf
      
    Case #WM_DRAWITEM
      *DrawItem.DRAWITEMSTRUCT = lParam
      If *DrawItem\CtlType = #ODT_COMBOBOX And IsGadget(wParam) And *DrawItem\itemID <> -1
        If *DrawItem\itemstate & #ODS_SELECTED
          FillRect_(*DrawItem\hDC, *DrawItem\rcitem, BrushHighLight)
        Else
          If GetWindowColor(#Window) = BaseColor
            FillRect_(*DrawItem\hDC, *DrawItem\rcitem, BrushBaseColor)
          Else
            FillRect_(*DrawItem\hDC, *DrawItem\rcitem, BrushNewColor)
          EndIf
        EndIf
        
        SetBkMode_(*DrawItem\hDC, #TRANSPARENT)
        SetTextColor_(*DrawItem\hDC, #White)
        Text = GetGadgetItemText(*DrawItem\CtlID, *DrawItem\itemID)
        *DrawItem\rcItem\left + DesktopScaledX(4)
        DrawText_(*DrawItem\hDC, Text, Len(Text), *DrawItem\rcItem, #DT_LEFT | #DT_SINGLELINE | #DT_VCENTER)
      EndIf
      
  EndSelect
  
  ProcedureReturn Result
EndProcedure

Procedure Open_Window(X = 0, Y = 0, Width = 220, Height = 175)
  Protected I
  If OpenWindow(#Window, X, Y, Width, Height, "CTLCOLOREDIT", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    SetWindowColor(#Window, BaseColor)
    StringGadget(#String, 20, 20, 180, 24, "String")
    SetGadgetColor(#String, #PB_Gadget_FrontColor, #White)
    SetGadgetColor(#String, #PB_Gadget_BackColor, BaseColor)
    ComboBoxGadget(#Combo, 20, 65, 180, 28, #PB_ComboBox_Editable | #CBS_HASSTRINGS | #CBS_OWNERDRAWFIXED)
    SendMessage_(GadgetID(#Combo), #CB_SETMINVISIBLE, 5, 0)
    For I = 1 To 10 : AddGadgetItem(#Combo, -1, "Combo Element " + Str(I)) : Next
    SetGadgetState(#Combo, 0)
    ButtonGadget(#Btn_Change_Color, 20, 115, 180, 40, "Change_Color")
    
    SetComboDarkMode(GadgetID(#Combo))
    SetWindowCallback(@WinCallback(), #Window)
    ProcedureReturn #True
  EndIf
EndProcedure

If Open_Window()
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Btn_Change_Color
            If GetWindowColor(#Window) = BaseColor
              SetWindowColor(#Window, NewColor)
              SetGadgetColor(#String, #PB_Gadget_BackColor, NewColor)
            Else
              SetWindowColor(#Window, BaseColor)
              SetGadgetColor(#String, #PB_Gadget_BackColor, BaseColor)
            EndIf
        EndSelect
    EndSelect
  ForEver
EndIf
Post Reply