Page 1 of 1

reskinning an application (->color questions)

Posted: Thu Apr 10, 2014 4:57 pm
by broozar
hi all,

i am currently in the process of reskinning/recoloring my application. i found a handy solution for linux earlier today (http://www.purebasic.fr/english/viewtop ... 15&t=58981), now it's on to windows. as i am not a windows expert, i would be thankful for any suggestion you could give me.

the problem, in a nutshell: i want to recolor gadgets to make a grey/dark theme. setting colors through PB is supported by many of them, but not all. i am looking at 2 options:
1. recolor every gadget manually through a windows api function call ---> please share code samples if you know any, thanks!
2. override the theme on a per-application basis ---> like i did with the gtkrc file on linux. is that even possible?

let me know what you think.

cheers
felix

Re: reskinning an application (->color questions)

Posted: Fri Apr 11, 2014 12:15 am
by IdeasVacuum
For the odd gadget such as CheckBoxGadget(), there is no colour option and it does not respect the Window colour. There is an API method to fix the back colour, but you can draw your own CheckBoxGadget() on a tiny canvas and control everything. Same thing with OptionGadget, there are a few examples of 'DIY' gadgets on this forum.

To colour buttons, I suggest drawing on ButtonImageGadgets(), that is very easy and the Windows Theme does not interfere. Again, you will find examples on this forum.

If you prefer the API way, this is a code snippet published by Rashad:

Code: Select all

Procedure.i WindowCallBack(WindowId.i, Msg.i, wParam.i, lParam.i)
;----------------------------------------------------------------
Protected iReturn.i

   If Msg = #WM_CTLCOLORSTATIC

          Select GetDlgCtrlID_(lParam)   ;API call: allows choosing gadgets by their number
                  Case #MyOpt0, #MyOpt1, #MyOpt2, #MyChkBx0, #MyChkBx1, #MyChkBx2
                     ; uncomment if compiling without XP support
                     ; SetBkMode_(wParam,#TRANSPARENT)
                         SetBkColor_(wParam, RGB(0,0,0))
                       SetTextColor_(wParam, RGB(0,0,255))
                       iReturn = #False
          EndSelect
   EndIf

   ProcedureReturn iReturn

EndProcedure

Re: reskinning an application (->color questions)

Posted: Fri Apr 11, 2014 5:42 pm
by broozar
thanks! CheckBoxes, Buttons, Frames and Tabs are exactly what gives me trouble.
I would indeed prefer to do it all by API. it might take me longer, but i might learn something about windows along the way.

Please help me one more step. How do I use the callback correctly? i currently have

Code: Select all

SetWindowCallback(@WindowCallBack())
which leads to my buttons, checkboxes, frames and progress bars disappearing, and the window generally hangs (window close button does nothing, procedures that are supposed to load text from a txt file on the hard drive are not executed)

Re: reskinning an application (->color questions)

Posted: Fri Apr 11, 2014 7:01 pm
by Danilo
broozar wrote:Please help me one more step. How do I use the callback correctly? i currently have

Code: Select all

SetWindowCallback(@WindowCallBack())
which leads to my buttons, checkboxes, frames and progress bars disappearing, and the window generally hangs (window close button does nothing, procedures that are supposed to load text from a txt file on the hard drive are not executed)
Please see the help for SetWindowCallback() for an example. When returning other values than #PB_ProcessPureBasicEvents,
PureBasic does no further event handling. You need to return #PB_ProcessPureBasicEvents by default, and only return other
values (like a color, or #False/#True) to API directly, when no PB event processing is required for that message.

Re: reskinning an application (->color questions)

Posted: Fri Apr 11, 2014 10:11 pm
by broozar
thanks! i visited the help page before, but did not spot the #PB_ProcessPureBasicEvents line.
no more hangs this way, but also no coloring. May I just assume that checkboxes cannot be colored that way? I see the callback procedure firing since i added some debug calls, but the color remains unchanged.

Re: reskinning an application (->color questions)

Posted: Fri Apr 11, 2014 11:07 pm
by IdeasVacuum
It should work, it is working in one of my old apps, for Options and CheckBoxes, but I can't get it to work either. Must be something subtle that I'm overlooking. One of the forum experts will no doubt spot it immediately.
Sample code PB5.22LTS:

Code: Select all

Enumeration
#Win
#Font10
#Font14B
#MyOpt0
#MyOpt1
#MyOpt2
#MyChkBx0
#MyChkBx1
#MyChkBx2
#BtnImg
#BtnExit
EndEnumeration

LoadFont(#Font10,  "Arial", 10, #PB_Font_Bold | #PB_Font_HighQuality + 2)
LoadFont(#Font14B, "Arial Black", 14, #PB_Font_HighQuality + 2)

Global  igWinColour.i = RGB(036,036,036)
Global  igTxtColour.i = RGB(186,090,087)
;Global igBackColour.i = CreateSolidBrush_(igWinColour)

Procedure DrawBtn(iBtnID.i, sText.s, iW.i, iH.i)
;-----------------------------------------------
Protected iBtnImg.i, dX.d, dY.d, dW.d, dH.d

               CreateImage(#BtnImg, iW, iH, 24)

               If StartDrawing(ImageOutput(#BtnImg))

                             DrawingFont(FontID(#Font14B))

                             dH = TextHeight(sText)
                             dW = TextWidth(sText)
                             dX = ((iW - dW) / 2)
                             dY = ((iH - dH) / 2)

                             DrawingMode(#PB_2DDrawing_Default)
                                     Box(0,0,iW,iH,igWinColour)
                                DrawText(dX, dY, sText, igTxtColour, igWinColour)
                      SetGadgetAttribute(iBtnID, #PB_Button_Image, ImageID(#BtnImg))
                             StopDrawing()
               EndIf
EndProcedure

Procedure.i WindowCallBack(WindowId.i, iMsg.i, wParam.i, lParam.i)
;-----------------------------------------------------------------
Protected iReturn.i = #PB_ProcessPureBasicEvents

               If iMsg = #WM_CTLCOLORSTATIC

                      Select GetDlgCtrlID_(lParam)

                              ;API call: allows choosing gadgets by their number
                              ;Comment out Select to apply to all gadgets

                              Case #MyOpt0, #MyOpt1, #MyOpt2, #MyChkBx0, #MyChkBx1, #MyChkBx2
                                   ;uncomment if compiling without XP support
                                   ;SetBkMode_(wParam, #TRANSPARENT)
                                     SetBkColor_(wParam, igWinColour)
                                   SetTextColor_(wParam, igTxtColour)
                                   iReturn = #False
                      EndSelect
               EndIf

               ProcedureReturn iReturn
EndProcedure

Procedure Win()
;--------------
Protected iFlags.i = #PB_Window_Invisible | #PB_Window_SystemMenu | #PB_Window_ScreenCentered

               If OpenWindow(#Win, 0, 0, 300, 130, "Colour", iFlags)

                              SetWindowColor(#Win, igWinColour)
                               SetGadgetFont(#PB_All, FontID(#Font10))

                                OptionGadget(#MyOpt0,    20,  10, 120, 20, "Option 0")
                                OptionGadget(#MyOpt1,    20,  40, 120, 20, "Option 1")
                                OptionGadget(#MyOpt2,    20,  70, 120, 20, "Option 2")
                              CheckBoxGadget(#MyChkBx0, 150,  10, 120, 20, "Check Box 0")
                              CheckBoxGadget(#MyChkBx1, 150,  40, 120, 20, "Check Box 1")
                              CheckBoxGadget(#MyChkBx2, 150,  70, 120, 20, "Check Box 2")

                           ButtonImageGadget(#BtnExit,    0, 100, 300, 30, 0)
                                     DrawBtn(#BtnExit, "EXIT", 294, 24)

                           SetWindowCallback(@WindowCallBack(), #Win)
                                  HideWindow(#Win, #False)
               EndIf
EndProcedure

Procedure WaitForUser()
;----------------------
Protected iQuit.i = #False

               Repeat
                         Select WaitWindowEvent(1)

                               Case #PB_Event_CloseWindow: iQuit = #True
                               Case #PB_Event_Gadget

                                     Select EventGadget()

                                                 Case  #BtnExit: iQuit = #True
                                     EndSelect
                         EndSelect

                         Delay(1)

               Until iQuit = #True
EndProcedure

Win()
WaitForUser()

End

Re: reskinning an application (->color questions)

Posted: Sun Apr 13, 2014 4:59 pm
by broozar
thanks for the snippet!
IdeasVacuum wrote:it is working in one of my old apps
i tried to compile with 5.22, 5.00, as well as 4.51, no success. do you by any chance remember the version where it did still work, in case nobody comes up with a better solution?

Re: reskinning an application (->color questions)

Posted: Sun Apr 13, 2014 6:45 pm
by RASHAD

Code: Select all

Global Bkgcolor_1,Bkgcolor_2,Bkgcolor_3,Bkgcolor_4

Bkgcolor_1  = CreateSolidBrush_($88FCF9)
Bkgcolor_2  = CreateSolidBrush_($88FCA4)
Bkgcolor_3  = CreateSolidBrush_($F4FC88)
Bkgcolor_4  = CreateSolidBrush_($FB89DF)

CreateImage(0,80,22)
StartDrawing(ImageOutput(0))
    Box(0,0,80,22,#Yellow)
    DrawingMode(#PB_2DDrawing_Transparent )
    FrontColor(#Blue)
    DrawText(18,3,"TEST")
StopDrawing()

Procedure WindowProc(hwnd, uMsg, wParam, lParam) 
    Select uMSG
     Case #WM_CTLCOLORSTATIC
      Select GetProp_(lParam, "PB_ID")
         Case 1
               SetBkMode_(wParam,#TRANSPARENT	)
               SetTextColor_(wParam,#Black)
               ProcedureReturn Bkgcolor_1
           
         Case 2
                SetBkMode_(wParam,#TRANSPARENT	)
                SetTextColor_(wParam,#Red)
                ProcedureReturn Bkgcolor_2
            
          Case 3
                SetBkMode_(wParam,#TRANSPARENT	)
                SetTextColor_(wParam,#Blue)
                ProcedureReturn Bkgcolor_3
            
          Case 4
                SetBkMode_(wParam,#TRANSPARENT	)
                SetTextColor_(wParam,#Yellow)
                ProcedureReturn Bkgcolor_4
         
        EndSelect
    EndSelect    
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0,0,0,400,300,"test", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)
SetWindowColor(0,#Gray)
SetWindowCallback(@WindowProc())

CheckBoxGadget(1,10,10,120,20,"CheckBox # 1")
CheckBoxGadget(2,10,40,120,20,"CheckBox # 2")
OptionGadget(3,140,10,120,20,"Option # 1")
OptionGadget(4,140,40,120,20,"Option # 2")

For Gadget = 1 To 4
  SetWindowTheme_(GadgetID(Gadget), @null.w, @null.w)
Next

ButtonImageGadget(5,10,70,80,22,ImageID(0))

Repeat
  Select WaitWindowEvent()
      
       Case #PB_Event_CloseWindow
            Quit = 1
            
       Case #PB_Event_Gadget
          Select EventGadget()

          EndSelect
  EndSelect
Until Quit = 1

Re: reskinning an application (->color questions)

Posted: Sun Apr 13, 2014 7:40 pm
by IdeasVacuum
Hi broozar, it is working in my old app, coded with PB4.61. Tried my snippet in #PB4.61, does not work, though the debug shows that the gadget ID's are picked up correctly.

Hi Rashad - the code I used in my old app to set the back colour and text colour for option and check-box gadgets was posted by you, for me - it didn't use CreateSolidBrush though I have tried that (failed), and in any case that would not fix the text colour which is also not working. SetBkMode does not work either but as I understand it, cannot be used anyway on XP or Win7 if the User has set a fancy theme.

Edit: Just had a thought, is it pallet related? Can the colours only be chosen from a limited range?

Re: reskinning an application (->color questions)

Posted: Sun Apr 13, 2014 8:28 pm
by broozar
@RASHAD Thanks so much! Checkboxes, labels and buttons work perfectly now. 3 gadgets remain problematic, maybe you have some idea on how to solve these last issues:
1. Tabs do not seem to be affected at all, except for SetWindowTheme_, so i know i have the right gadget(s) targeted
2. Frames: labels are great, the lines around them are pretty white and wide. Any way to thin them out or recolor them?
3. StringGadgets/Inputs: like Frames, they have an ugly border. SetWindowTheme with @null diminishes the effect, but it still is not as pretty as it could be.

i also noticed the call to SetWindowTheme_ which looks very interesting. If i hypothetically made a Windows theme file, could i use this function to override the theme of my application all in one go?

cheers
felix

Re: reskinning an application (->color questions)

Posted: Sun Apr 13, 2014 10:50 pm
by RASHAD
Full color control Panel Gadget

Code: Select all

Global Bkgcolor

Bkgcolor  = CreateSolidBrush_($D5FEFD)

CreateImage(0,64,20)                           
StartDrawing(ImageOutput(0))
  DrawingMode(#PB_2DDrawing_Gradient)     
  BackColor($1EFDFD)
  FrontColor($7878FE)
  BoxedGradient(0, 0, 64, 20)               
  Box(0,0,64,20)
  DrawingMode(#PB_2DDrawing_Transparent)                         
  DrawText(4, 2, "Tab One",#Red)                     
StopDrawing()

CreateImage(1,64,20)                           
StartDrawing(ImageOutput(1))           
  Box(0,0,64,20,$BDFEBA)
  DrawingMode(#PB_2DDrawing_Transparent)                         
  DrawText(4, 2, "Tab Two",#Black)                           
StopDrawing()
                                     
Imlist = ImageList_Create_(64,20,#ILC_COLOR32,2,10)   
ImageList_Add_(Imlist,ImageID(0),0)                   
ImageList_Add_(Imlist,ImageID(1),0)                   

OpenWindow(0,0,0,400,300,"Full Control Color Panel Gadget",#PB_Window_SystemMenu| #PB_Window_ScreenCentered)
SetWindowColor(0,$FEFED1)
  PanelGadget(0,10,10,380,280)
    SendMessage_(GadgetID(0),#TCM_SETPADDING,0,1|3<<16)   
    SendMessage_(GadgetID(0),#TCM_SETIMAGELIST,0,Imlist)
    AddGadgetItem(0,0,"")
        ButtonGadget(2, 10, 15, 80, 24,"Tab 1 Button 1")
        ButtonGadget(3, 95, 15, 80, 24,"Tab 1 Button 2")
    AddGadgetItem(0,1,"")
        ButtonGadget(4, 10, 15, 80, 24,"Tab 2 Button 3")
        ButtonGadget(5, 95, 15, 80, 24,"Tab 2 Button 4")
  CloseGadgetList()

t.TC_ITEM
t\mask = #TCIF_IMAGE
t\iImage = 0
SendMessage_(GadgetID(0),#TCM_SETITEM, 0, @t)
t\iImage = 1
SendMessage_(GadgetID(0),#TCM_SETITEM, 1, @t)

;Comment for the next lines for normal background Color
SetWindowTheme_(GadgetID(0), @null.w, @null.w)
SetClassLongPtr_(GadgetID(0),#GCL_HBRBACKGROUND, Bkgcolor)

TextGadget(10,148,10,250,24,"")
SetGadgetColor(10,#PB_Gadget_BackColor,$FEFED1)
BringWindowToTop_(GadgetID(10))

Repeat
  Select WaitWindowEvent()
     
       Case #PB_Event_CloseWindow
            Quit = 1
  EndSelect
Until Quit = 1

Re: reskinning an application (->color questions)

Posted: Sun Apr 13, 2014 10:53 pm
by RASHAD
Full text & color control String Gadget
Text Val. & Hal centered (Work around :mrgreen: )

Code: Select all


CreateImage(0,300,24)
StartDrawing(ImageOutput(0))
Box(0,0,300,24,#Red)
Box(1,1,298,22,$D3FEFD)
StopDrawing()

OpenWindow(0,0,0,400,300,"", #PB_Window_SystemMenu|#PB_Window_SizeGadget| #PB_Window_ScreenCentered) 

ImageGadget(0,10,10,120,24,ImageID(0))
DisableGadget(0,1)
ContainerGadget(1, 10,10,300,24) 
    StringGadget(2,3,4,296,16,"",#PB_String_BorderLess| #ES_center) 
    SetGadgetColor(2,#PB_Gadget_BackColor,$D5FEFD)
    SetGadgetColor(2,#PB_Gadget_FrontColor,$FF3904)
CloseGadgetList()

SetClassLongPtr_(GadgetID(1),#GCL_HBRBACKGROUND, GetStockObject_(#NULL_BRUSH))

Repeat:Until WaitWindowEvent()=#WM_CLOSE 

Re: reskinning an application (->color questions)

Posted: Mon Apr 14, 2014 12:38 am
by IdeasVacuum
For the StringGadgets, why not use #PB_String_BorderLess?

Revised snippet using Rashad's code, Tested working fine on Win8:

Code: Select all

Enumeration
#Win
#Font10
#Font14B
#BtnImg
#MyOpt0
#MyOpt1
#MyOpt2
#MyChkBx0
#MyChkBx1
#MyChkBx2
#BtnExit
EndEnumeration

LoadFont(#Font10,  "Arial", 10, #PB_Font_Bold | #PB_Font_HighQuality + 2)
LoadFont(#Font14B, "Arial Black", 14, #PB_Font_HighQuality + 2)

Global  igWinColour.i = RGB(036,036,036)
Global  igTxtColour.i = RGB(186,090,087)
Global igBackColour.i = CreateSolidBrush_(igWinColour)

Procedure DrawBtn(iBtnID.i, sText.s, iW.i, iH.i)
;-----------------------------------------------
Protected iBtnImg.i, dX.d, dY.d, dW.d, dH.d

               CreateImage(#BtnImg, iW, iH, 24)

               If StartDrawing(ImageOutput(#BtnImg))

                             DrawingFont(FontID(#Font14B))

                             dH = TextHeight(sText)
                             dW = TextWidth(sText)
                             dX = ((iW - dW) / 2)
                             dY = ((iH - dH) / 2)

                             DrawingMode(#PB_2DDrawing_Default)
                                     Box(0,0,iW,iH,igWinColour)
                                DrawText(dX, dY, sText, igTxtColour, igWinColour)
                      SetGadgetAttribute(iBtnID, #PB_Button_Image, ImageID(#BtnImg))
                             StopDrawing()
               EndIf
EndProcedure

Procedure.i WindowCallBack(WindowId.i, iMsg.i, wParam.i, lParam.i)
;-----------------------------------------------------------------
Protected iReturn.i = #PB_ProcessPureBasicEvents

               If iMsg = #WM_CTLCOLORSTATIC

                      Select GetProp_(lParam, "PB_ID")

                              ;API call: allows choosing gadgets by their number
                              ;Comment out Select to apply to all gadgets

                              Case #MyOpt0, #MyOpt1, #MyOpt2, #MyChkBx0, #MyChkBx1, #MyChkBx2
                                   ;uncomment if compiling without XP support
                                      SetBkMode_(wParam, #TRANSPARENT)
                                     ;SetBkColor_(wParam,igWinColour)
                                    SetTextColor_(wParam,igTxtColour)
                                   iReturn = igBackColour
                      EndSelect
               EndIf

               ProcedureReturn iReturn
EndProcedure

Procedure Win()
;--------------
Protected iFlags.i = #PB_Window_Invisible | #PB_Window_SystemMenu | #PB_Window_ScreenCentered
Protected iGadget.i

               If OpenWindow(#Win, 0, 0, 300, 130, "Colour", iFlags)

                              SetWindowColor(#Win, igWinColour)
                               SetGadgetFont(#PB_All, FontID(#Font10))

                                OptionGadget(#MyOpt0,    20,  10, 120, 20, "Option 0")
                                OptionGadget(#MyOpt1,    20,  40, 120, 20, "Option 1")
                                OptionGadget(#MyOpt2,    20,  70, 120, 20, "Option 2")
                              CheckBoxGadget(#MyChkBx0, 150,  10, 120, 20, "Check Box 0")
                              CheckBoxGadget(#MyChkBx1, 150,  40, 120, 20, "Check Box 1")
                              CheckBoxGadget(#MyChkBx2, 150,  70, 120, 20, "Check Box 2")

                           ButtonImageGadget(#BtnExit,    0, 100, 300, 30, 0)
                                     DrawBtn(#BtnExit, "EXIT", 294, 24)

                           For iGadget = #MyOpt0 To #MyChkBx2

                                   SetWindowTheme_(GadgetID(iGadget), @null.w, @null.w)
                           Next

                           SetWindowCallback(@WindowCallBack(), #Win)
                                  HideWindow(#Win, #False)
               EndIf
EndProcedure

Procedure WaitForUser()
;----------------------
Protected iQuit.i = #False

               Repeat
                         Select WaitWindowEvent(1)

                               Case #PB_Event_CloseWindow: iQuit = #True
                               Case #PB_Event_Gadget

                                     Select EventGadget()

                                                 Case  #BtnExit: iQuit = #True
                                     EndSelect
                         EndSelect

                         Delay(1)

               Until iQuit = #True
EndProcedure

Win()
WaitForUser()

End

Re: reskinning an application (->color questions)

Posted: Sun Apr 20, 2014 10:05 pm
by broozar
sorry for being quiet for so long, i did not have a chance to check your posts until just a couple of minutes ago.

@ideas boderless puts the text in the top left corner without any padding, which looks meh. rashad's centered text is prettier.

@rashad thanks a lot for your time and effort! originally, i was hoping to get color into the thing without rewriting/custom designing gadgets. but oh well, there seems to be no way around it. however, even with your custom drawn tabs, i get a thin "white" (windows standard dialogue color) border. i will keep investigating.