Colouring ListIconGadget headers

Just starting out? Need help? Post your questions and find answers here.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Colouring ListIconGadget headers

Post by Fangbeast »

I found the following code in the forum to subclass a listicongadget so that I can colour the heading area but after I managed to modify it to colour 3 gadgets, it appeared that I was doing something wrong ans any gadgets after 3 wouldn't colour.

Code: Select all

; Subclass ListIcon so we can customdraw the header text and colour the header area
;============================================================================================================================

Procedure SubclassedListIcon(hwnd, msg, wparam, lparam)
  Protected hdi.hd_item
  result = CallWindowProc_(form\oldListIconCallback, hwnd, msg, wparam, lparam)
  Select msg
    Case #WM_NOTIFY
      *pnmh.NMHDR = lparam    ;--> Get handle to ListIcon header control
      If *pnmh\code = #NM_CUSTOMDRAW
        *pnmcd.NMCUSTOMDRAW = lparam ;--> Determine drawing stage
        Select *pnmcd\dwDrawStage
          Case #CDDS_PREPAINT
            result = #CDRF_NOTIFYITEMDRAW
          Case #CDDS_ITEMPREPAINT ; Get header text.
            text$ = Space(100)
            hdi\mask = #HDI_TEXT
            hdi\psztext = @text$
            hdi\cchtextmax = Len(text$)
            SendMessage_(form\hHeader, #HDM_GETITEM, *pnmcd\dwItemSpec, hdi) ; Check button state.
            If *pnmcd\uItemState & #CDIS_SELECTED
              DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH | #DFCS_PUSHED)  ; Offset text because of the selected button.
              InflateRect_(*pnmcd\rc, -1, -1)
            Else
              DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH)
            EndIf ; Draw background. ; Here we alternate red text on blue background.
            InflateRect_(*pnmcd\rc, -1, -1)
            SetBkMode_(*pnmcd\hdc, #TRANSPARENT)
            ;If *pnmcd\dwItemSpec & 1
              FillRect_(*pnmcd\hdc, *pnmcd\rc, form\brush)
              SetTextColor_(*pnmcd\hdc, $000000)
            ;Else
            ;  FillRect_(*pnmcd\hdc, *pnmcd\rc, Colour)
            ;  SetTextColor_(*pnmcd\hdc, $000000)
            ;EndIf
            DrawText_(*pnmcd\hdc, @text$, Len(text$), *pnmcd\rc, #DT_CENTER | #DT_VCENTER | #DT_END_ELLIPSIS)
            result = #CDRF_SKIPDEFAULT
        EndSelect
      EndIf
  EndSelect
  ProcedureReturn result
EndProcedure
These are the two lines to invoke the colouring of a single gadget and I was wondering if there is a simple way to use a linked list to subclass and colour as many gadget headings that I want without resorting to a library with features I don't need?

Code: Select all

;------------------------------------------------------------------------------------------------
  ; Sublcass ListIconGadget to allow header to be painted
  ;------------------------------------------------------------------------------------------------
  form\hHeader = SendMessage_(GadgetID(#Gadget_ebackup_items), #LVM_GETHEADER, 0, 0) ; Subclass ListIcon so we can customdraw the header text
  form\oldListIconCallback = SetWindowLong_(GadgetID(#Gadget_ebackup_items), #GWL_WNDPROC, @SubclassedListIcon())
Give me 30 years and I' might get betetr with the API but I doubt it :D :D :D :D :D
Amateur Radio, D-STAR/VK3HAF
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

fangles, I reckon the problem is your 'form' structure variable which I presume is global.

The thing is, that the code you're using was written for PB 3.94. With PB 4, we can easily get the header text and so there is no need to store the handle of the header control etc. In fact, we never needed to store it anyhow ... but that's another story! :)

The following is very rough and ready (but is all I have time for!) with the colouring routine being simplified over the version you're currently using:

Code: Select all

;Coloured header control.
;By srod.
;Purebasic 4.
;Windows.


#LVM_GETHEADER = #LVM_FIRST + 31 

; Globals 
Global oldListIconCallback, redbrush, bluebrush 
redbrush=CreateSolidBrush_(#Yellow)
bluebrush=CreateSolidBrush_(#Yellow)


; Proc for subclassed ListIconGadget 
Procedure SubclassedListIcon(hwnd, msg, wparam, lparam) 
  Protected hdi.hd_item
  result = CallWindowProc_(oldListIconCallback, hwnd, msg, wparam, lparam) 
  Select msg 
    Case #WM_NOTIFY 
      *pnmh.NMHDR = lparam 
      ;--> Get handle to ListIcon header control 
        If *pnmh\code = #NM_CUSTOMDRAW
        *pnmcd.NMCUSTOMDRAW = lparam 
        ;--> Determine drawing stage 
        Select *pnmcd\dwDrawStage 
          Case #CDDS_PREPAINT 
            result = #CDRF_NOTIFYITEMDRAW 
          Case #CDDS_ITEMPREPAINT 
;Get header text.
            text$=GetGadgetItemText(GetDlgCtrlID_(hWnd),-1,*pnmcd\dwItemSpec)
 ;Check button state.
            If *pnmcd\uItemState & #CDIS_SELECTED
              DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH|#DFCS_PUSHED)
;Offset text because of the selected button.
              InflateRect_(*pnmcd\rc,-1,-1)
            Else
              DrawFrameControl_(*pnmcd\hdc, *pnmcd\rc, #DFC_BUTTON, #DFCS_BUTTONPUSH)
            EndIf
;Draw background.
            *pnmcd\rc\bottom-2 : *pnmcd\rc\right-2
            SetBkMode_(*pnmcd\hdc,#TRANSPARENT) 
            If *pnmcd\dwItemSpec&1
              FillRect_(*pnmcd\hdc, *pnmcd\rc, redbrush)
              SetTextColor_(*pnmcd\hdc, #Blue) 
            Else
              FillRect_(*pnmcd\hdc, *pnmcd\rc, bluebrush)
              SetTextColor_(*pnmcd\hdc, #Red) 
            EndIf
            *pnmcd\rc\top+2
            InflateRect_(*pnmcd\rc,-5,0)
            If *pnmcd\rc\right>*pnmcd\rc\left
              DrawText_(*pnmcd\hdc, @text$, Len(text$), *pnmcd\rc, #DT_CENTER|#DT_VCENTER|#DT_END_ELLIPSIS)
            EndIf
            result = #CDRF_SKIPDEFAULT
        EndSelect 
      EndIf 
  EndSelect 
  ProcedureReturn result 
EndProcedure 


; ************************************************ 
; Main Window 
; ************************************************ 
If OpenWindow(0, 100, 100, 415, 400, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  ListIconGadget(0, 5, 5, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
  ListIconGadget(1, 5, 90, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
  ListIconGadget(2, 5, 175, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
  ListIconGadget(3, 5, 250, 405, 80, "col 0", 50, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
;Subclass ListIcon so we can customdraw the header text 
  oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon()) 
  oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon()) 
  oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon()) 
  oldListIconCallback = SetWindowLong_(GadgetID(3), #GWL_WNDPROC, @SubclassedListIcon()) 

;Add 10 more columns.
  For j = 0 To 3
    For i = 1 To 10
      AddGadgetColumn(j, i, "col "+Str(i), 50) 
    Next  
  next
;Add some data
  For b=0 To 99; Add 100 rows.
    AddGadgetItem(0,-1,"")
  Next
  For i = 0 To 99
    For j = 0 To 50
      SetGadgetItemText(0,i,Str(i+j),j)
    Next j
  Next i            

  Repeat 
    EventID = WaitWindowEvent() 
  Until EventID = #PB_Event_CloseWindow 

  DeleteObject_(redbrush)
  DeleteObject_(bluebrush)
  
EndIf 
End 
I see no need for linked lists etc. If you really need to store info on each listicon then consider using a Window's property to store a pointer to whatever data you need to store.
I may look like a mule, but I'm not a complete ass.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Thank you

Post by Fangbeast »

I can see that I am going to have to sell my children to pay you. I still don't know bugger alla bout manipulating the api which is why I can't figure these things out myself. Normal pb code I can bugger up and hopefully fix but this stuff???

Thanks for that.. Hope things are going okay for you.
Amateur Radio, D-STAR/VK3HAF
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Colouring ListIconGadget headers

Post by Fangbeast »

Really old post but as this question is related, I'll put it here.

The above code works fine if I do this for every code in the main openwindow statement

oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())

(oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())

oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())

However, if I do this inside a PROCEDURE that opens another window on top of the main one, my program will either crash at the opening of that window when encountering that statement or when I exit that window.

I can reproduce it at will. Simply commenting out that statement fixes my problem immediately.
Amateur Radio, D-STAR/VK3HAF
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Colouring ListIconGadget headers

Post by MachineCode »

In one of the PureBasic blog posts, they said to change all SetWindowLong_() to SetWindowLongPtr_() now. Try that. And the same for GetWindowLong_() to GetWindowLongPtr_().
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Colouring ListIconGadget headers

Post by Fangbeast »

Thanks for that MachineCode, fingers crossed.

**EDIT** Just did it in 8 places in my program, tested, works like a charm. I'll go read the blog post, not that i'll understand it but I'll read it:):)

Thanks again.
Amateur Radio, D-STAR/VK3HAF
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Colouring ListIconGadget headers

Post by srod »

If you are using PB x64 (or writing code to compile on both x86 and x64) then yes you want to be using SetWindowLongPtr_() etc. fangles.
I may look like a mule, but I'm not a complete ass.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Colouring ListIconGadget headers

Post by Fangbeast »

srod wrote:If you are using PB x64 (or writing code to compile on both x86 and x64) then yes you want to be using SetWindowLongPtr_() etc. fangles.
No, I'm not. Could not shell out the buckaroonies for the x64 version of win7, especially when I could not get x64 versions of all my needed hardware drivers so I never bothered.

Just used PSPad text editor to do a search and replace on ALL my code and no more problems.

So glad it was an easy fix, too many other dramas going on around here :):):)
Amateur Radio, D-STAR/VK3HAF
User avatar
idle
Always Here
Always Here
Posts: 5096
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Colouring ListIconGadget headers

Post by idle »

Fangbeast wrote:Really old post but as this question is related, I'll put it here.

The above code works fine if I do this for every code in the main openwindow statement

oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())

(oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())

oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())

However, if I do this inside a PROCEDURE that opens another window on top of the main one, my program will either crash at the opening of that window when encountering that statement or when I exit that window.

I can reproduce it at will. Simply commenting out that statement fixes my problem immediately.
I don't think you can't use it like that, not with multiple windows since the address stored in OldListIconCallBack
will always refer to the last opened windows procedure resulting in an IMA in your callback
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Colouring ListIconGadget headers

Post by Fangbeast »

idle wrote:
Fangbeast wrote:Really old post but as this question is related, I'll put it here.

The above code works fine if I do this for every code in the main openwindow statement

oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())

(oldListIconCallback = SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @SubclassedListIcon())

oldListIconCallback = SetWindowLong_(GadgetID(2), #GWL_WNDPROC, @SubclassedListIcon())

However, if I do this inside a PROCEDURE that opens another window on top of the main one, my program will either crash at the opening of that window when encountering that statement or when I exit that window.

I can reproduce it at will. Simply commenting out that statement fixes my problem immediately.
I don't think you can't use it like that, not with multiple windows since the address stored in OldListIconCallBack
will always refer to the last opened windows procedure resulting in an IMA in your callback
Seems to work at the moment. Since I changed Get/SetWindowLong to Get/SetWindowLongPtr, it's no longer crashing, which it was before, all the time.

So much to do, I need a holiday!
Amateur Radio, D-STAR/VK3HAF
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Colouring ListIconGadget headers

Post by srod »

If you are not using PB x64 then SetWindowLongPtr_() will make no difference.
I may look like a mule, but I'm not a complete ass.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Colouring ListIconGadget headers

Post by Fangbeast »

srod wrote:If you are not using PB x64 then SetWindowLongPtr_() will make no difference.
Well, it made a difference here, apparently. Whether that's due to something else is decidedly unclear to me. Once I had changed from Get/SetWindowLong to Get/SetWindowLongPtr, no more crashes at all.

If that change is not the reason, I don't know why. As you well know, API isn't my forte.
Amateur Radio, D-STAR/VK3HAF
Post Reply