Center ListIconGadget column titles?

Just starting out? Need help? Post your questions and find answers here.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Center ListIconGadget column titles?

Post by PB »

Just did a search here for the subject text but found no matches... not even
if I swapped "titles" with "text" either. :) Anybody know a way to do this?

Edit: I've been able to set the entire column to centered using Danilo's code:

Code: Select all

lvc.LV_COLUMN
lvc\mask = #LVCF_FMT
lvc\fmt = #LVCFMT_CENTER
SendMessage_(GadgetID(#ListIconGadget),#LVM_SETCOLUMN,0,@lvc) ; 0 = Column.
But this centers all the entries in the column, and not just the column title. :(
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Uhm, even when you center just the item in the header control using the code

Code: Select all

hWndheader=SendMessage_(GadgetID(1),#LVM_GETHEADER,0,0)
hditem.HD_ITEM
hditem\mask = #HDI_FORMAT
hditem\fmt = #HDF_STRING|#HDF_CENTER
SendMessage_(hWndheader, #HDM_SETITEM , 0, @hditem)
it centres the entire damn column!

The following code does the job, but strikes me as cracking a nut with a sledgehammer type approach! It simply sets the whole of column zero to have centred text (inc header and column), but then custom draws the text within individual cells in order to left justify the text etc. Of course this is complicated now by the fact that we have to manually highlight the background of selected cells etc.

An easier approach would be to custom draw the header control instead, but I happened to have the following code to hand (I ripped it from my egrids code).

Of course, there's bound to be an easy way of doing this without having to custom draw either the listicon or the header control! Where's Sparkie when you need him? :lol:

**EDIT: According to what I have found on the Powerbasic forums, not being able to center the text within the header control separately to the listicon is a basic limitation of the Windows List View control. If this is correct, then the custom drawing method outlined would seem the only way to go!

Code: Select all

#DT_END_ELLIPSIS = $8000
#CDDS_ITEM = $10000 
#CDDS_SUBITEM = $20000 
#CDDS_PREPAINT = $1 
#CDDS_ITEMPREPAINT = #CDDS_ITEM|#CDDS_PREPAINT 
#CDDS_SUBITEMPREPAINT = #CDDS_SUBITEM|#CDDS_ITEMPREPAINT 
#CDRF_DODEFAULT = $0 
#CDRF_SKIPDEFAULT = $4
#CDRF_NOTIFYITEMDRAW = $20 
#CDRF_NOTIFYSUBITEMDRAW = $20 
#CDRF_NEWFONT = $2 
#LVM_GETHEADER = #LVM_FIRST+31
#LVM_GETSUBITEMRECT = #LVM_FIRST+56 


;The following callback proc is used to custom draw the listicon.
Procedure WinCallbackproc(hWnd, uMsg, wParam, lParam) 
  Protected result, row, col, text.s,disp, brush, rc.RECT 
  Protected *pnmh.NMHDR, *LVCDHeader.NMLVCUSTOMDRAW, lptm.TEXTMETRIC,pInfo.LVHITTESTINFO
  result = #PB_ProcessPureBasicEvents 

  Select uMsg 
    Case #WM_NOTIFY 
      *pnmh.NMHDR = lParam 
      Select *pnmh\code 
        Case #NM_CUSTOMDRAW 
          *LVCDHeader.NMLVCUSTOMDRAW = lParam 
          Select *LVCDHeader\nmcd\dwDrawStage 
            Case #CDDS_PREPAINT 
              result = #CDRF_NOTIFYITEMDRAW 
            Case #CDDS_ITEMPREPAINT 
              result = #CDRF_NOTIFYSUBITEMDRAW 
            Case #CDDS_SUBITEMPREPAINT 
              result = #CDRF_SKIPDEFAULT 
              row = *LVCDHeader\nmcd\dwItemSpec 
              col = *LVCDHeader\iSubItem 
;Begin by getting the bounds of the cell rectangle.
              pInfo\iItem = row : pInfo\iSubItem = col
              rc\top = pInfo\iSubItem 
              rc\left = #LVIR_BOUNDS 
              SendMessage_(GadgetID(1), #LVM_GETSUBITEMRECT, pInfo\iItem, rc) 
              If rc\left > GadgetWidth(1) Or rc\top > GadgetHeight(1)
                ProcedureReturn result
              EndIf
              rc\right = rc\left+SendMessage_(GadgetID(1), #LVM_GETCOLUMNWIDTH, pInfo\iSubItem,0)
              GetTextMetrics_(*LVCDHeader\nmcd\hdc,@lptm)
              disp = (rc\top+rc\bottom-lptm\tmHeight)/2-rc\top;Used in vertical alignment of the text.
              disp=2*(disp/2)
              text = GetGadgetItemText(1, row, col)
;Erase cell.
              If GetGadgetItemState(1,row)
                brush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
              Else
                brush = CreateSolidBrush_(#White)
              EndIf
              FillRect_(*LVCDHeader\nmcd\hdc, rc, brush)
              DeleteObject_(brush)
;Draw text.
;Adjust positioning of text.
              rc\left+5 : rc\right-5
              rc\top=disp + rc\top
              SetTextColor_(*LVCDHeader\nmcd\hdc, #Black)
              SetBkMode_(*LVCDHeader\nmcd\hdc,#TRANSPARENT)
              DrawText_(*LVCDHeader\nmcd\hdc, @text, Len(text), @rc,#DT_END_ELLIPSIS)
            EndSelect 
      EndSelect 
  EndSelect 
  ProcedureReturn result 
EndProcedure 




If OpenWindow(0,0,0,640,300,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered,"") And CreateGadgetList(WindowID(0))
  ListIconGadget(1, WindowWidth()/4, WindowHeight()/8, WindowWidth()/2, WindowHeight()/2,"Col 0",100,#PB_ListIcon_FullRowSelect)
  SetWindowCallback(@WinCallbackproc())

  For b=1 To 10
    AddGadgetColumn(1,b,"Col " + Str(b),60)
  Next
  For b=0 To 10
    AddGadgetItem(1,-1,"Col (0, "+Str(b)+")")
  Next

;Centre the header element of column zero.
hWndheader=SendMessage_(GadgetID(1),#LVM_GETHEADER,0,0)
hditem.HD_ITEM
hditem\mask = #HDI_FORMAT
hditem\fmt = #HDF_STRING|#HDF_CENTER
SendMessage_(hWndheader, #HDM_SETITEM , 0, @hditem)

  Repeat
    EventID = WaitWindowEvent()
    Select EventID
      Case #PB_Event_Gadget
        Select EventGadgetID() 
      EndSelect
    EndSelect
  Until EventID = #PB_Event_CloseWindow
EndIf
End
Regards.
I may look like a mule, but I'm not a complete ass.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> there's bound to be an easy way of doing this

Hehe, I ended up just padding my text instead:

Code: Select all

ListIconGadget(#MyGad,0,259,352,43,"          DESC",100)
Seems a whole lot easier for now, especially as I'm using a specific font, so
it won't matter what system fonts the user has installed and/or is using. :)
Still, thanks for your reply, but as you said it's definitely way too much of a
sledgehammer approach for such a simple thing. I was hoping for something
easy like a SendMessage call... maybe Sparkie can still come to the rescue?
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Hehe, I ended up just padding my text instead:
What if the user resizes the columns? :D
I may look like a mule, but I'm not a complete ass.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

> What if the user resizes the columns? :D

I don't care. :) Although, there was some code around which supposedly
stops the columns being resized. I'm not going to bother with it, though.
The columns don't need resizing anyway -- all the data that gets displayed
is with a fixed-width font (Terminal) and all text is seen, so no need for the
user to start dragging them.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

I'm on my out the door right now so this is not fully tested, but seems to work fine on WinXP w/PB 3.94.

Code: Select all

#LVM_GETHEADER = #LVM_FIRST + 31 

Procedure CenterHeaderText(header, col) 
  hItem.HD_ITEM 
  hItem\mask = #HDI_TEXT 
  ;--> Adjust buffer size as needed for header text 
  textBuff$ = Space(32) 
  hItem\pszText = @textBuff$ 
  hItem\cchTextMax = 32 
  ;--> Get the current header item text 
  SendMessage_(header, #HDM_GETITEM, col, @hItem) 
  ;--> #HDF_CENTER will center the header text 
  hItem\mask = #HDI_TEXT | #HDI_FORMAT 
  hItem\fmt = #HDF_STRING | #HDF_CENTER 
  SendMessage_(header, #HDM_SETITEM, col, hItem) 
EndProcedure 

If OpenWindow(0, 100, 100, 400, 200, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "ListIcon Header") And CreateGadgetList(WindowID()) 
  ListIconGadget(0, 5, 5, 390, 90, "Name", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
  AddGadgetColumn(0, 1, "Address", 280) 
  AddGadgetItem(0, -1, "Harry Rannit" + Chr(10) + "12 Parliament Way, Battle Street, By the Bay") 
  AddGadgetItem(0, -1, "Ginger Brokeit" + Chr(10) + "130 PureBasic Road, BigTown, CodeCity") 
  ;--> Need the handle to the header 
  hHeader = SendMessage_(GadgetID(0),#LVM_GETHEADER,0,0) 
  ButtonGadget(1, 10, 150, 200, 20, "Center header text") 
  Repeat 
    EventID = WaitWindowEvent() 
    If EventGadgetID() = 1 And EventType() = #PB_EventType_LeftClick 
      For i = 0 To 1 
        CenterHeaderText(hHeader, i) 
      Next i 
    EndIf 
  Until EventID = #PB_Event_CloseWindow 
EndIf 
End
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

But try clicking a row!

Whenever a row is repainted, the cells are centered because the HDM_SETITEM message does seem to set the entire column's attributes.
I may look like a mule, but I'm not a complete ass.
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Thanks srod. I'll look into it later tonight when I get home. :)
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
Sparkie
PureBatMan Forever
PureBatMan Forever
Posts: 2307
Joined: Tue Feb 10, 2004 3:07 am
Location: Ohio, USA

Post by Sparkie »

Ok guys, see if this one works better than my first attempt. This may be more than you were looking for PB, but I couldn't leave it alone. :P

All header text should display centered with...

Column 0 items being aligned left
Column 1 items being aligned center
Column 2 items being aligned right

Code: Select all

; ************************************************
; Code:   Centered text in ListIconGadget Header 
; Author: Sparkie (inspired by PB and srod)
; Date:   December 31, 2005 
; OS:     Windows only 
; ************************************************ 

; ************************************************
; Constants
; ************************************************
; //////////////////////////////////
; CustomDraw drawing stage
; //////////////////////////////////
#CDDS_ITEM = $10000
#CDDS_PREPAINT = 1
#CDDS_POSTPAINT = 2
#CDDS_ITEMPOSTPAINT = #CDDS_ITEM | #CDDS_POSTPAINT
#CDDS_ITEMPREPAINT = #CDDS_ITEM | #CDDS_PREPAINT
; //////////////////////////////////
; CustomDraw return values
; //////////////////////////////////
#CDRF_DODEFAULT = 0
#CDRF_SKIPDEFAULT = 4
#CDRF_NOTIFYITEMDRAW = $20
#CDRF_NOTIFYPOSTPAINT = $10
; //////////////////////////////////
; DrawText flags
; //////////////////////////////////
#DT_END_ELLIPSIS = $8000
; //////////////////////////////////
; ListIcon messaging
; //////////////////////////////////
#LVM_GETHEADER = #LVM_FIRST + 31

; ************************************************
; Globals, Arrays
; ************************************************
; //////////////////////////////////
; Globals
; //////////////////////////////////
Global oldListIconCallback
; //////////////////////////////////
; Array of ListIcon header text
; //////////////////////////////////
;--> I use this array to fill header text within #NM_CUSTOMDRAW
Dim headerText.s(2)
headerText(0) = "Name"
headerText(1) = "Location"
headerText(2) = "Posts"

; ************************************************
; Procedures
; ************************************************
; //////////////////////////////////
; Proc for subclassed ListIconGadget
; //////////////////////////////////
Procedure SubclassedListIcon(hwnd, msg, wparam, lparam)
  result = CallWindowProc_(oldListIconCallback, hwnd, msg, wparam, lparam)
  Select msg
    Case #WM_NOTIFY
      *pnmh.NMHDR = lparam
      ;--> Get handle to ListIcon header control
      hHeader = SendMessage_(hwnd, #LVM_GETHEADER, 0, 0)
      If *pnmh\code = #NM_CUSTOMDRAW And *pnmh\hwndFrom = hHeader
        *pnmcd.NMCUSTOMDRAW = lparam
        ;--> Determine drawing stage
        Select *pnmcd\dwDrawStage
          Case #CDDS_PREPAINT
            result = #CDRF_NOTIFYITEMDRAW
          Case #CDDS_ITEMPREPAINT
            result = #CDRF_DODEFAULT | #CDRF_NOTIFYPOSTPAINT
          Case #CDDS_ITEMPOSTPAINT
            ;--> Draw centered text to header
            flags = #DT_CENTER | #DT_NOCLIP | #DT_SINGLELINE | #DT_VCENTER | #DT_END_ELLIPSIS
            SetBkMode_(*pnmcd\hdc,#TRANSPARENT)
            SetTextColor_(*pnmcd\hdc, #BLACK)
            DrawText_(*pnmcd\hdc, headerText(*pnmcd\dwItemSpec), Len(headerText(*pnmcd\dwItemSpec)), *pnmcd\rc, flags)
            result = #CDRF_DODEFAULT
        EndSelect
      EndIf
  EndSelect
  ProcedureReturn result
EndProcedure
; //////////////////////////////////
; Proc for ListIcon column alignment
; //////////////////////////////////
Procedure AlignColumn(liGad, col, align) 
  liColumn.LV_COLUMN
  liColumn\mask = #LVCF_FMT 
  liColumn\fmt = align 
  SendMessage_(liGad, #LVM_SETCOLUMN, col, liColumn) 
EndProcedure 

; ************************************************ 
; Main Window
; ************************************************
If OpenWindow(0, 100, 100, 415, 300, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "ListIcon Header Text Centered") And CreateGadgetList(WindowID())
  ;--> I'll leave the header text Null and draw them in the subclass procedure
  ListIconGadget(0, 5, 5, 405, 90, "", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
  AddGadgetColumn(0, 1, "", 200)
  AddGadgetColumn(0, 2, "", 100)
  AddGadgetItem(0, -1, "PB" + Chr(10) + "4F7a" + Chr(10) + "2396")
  AddGadgetItem(0, -1, "srod" + Chr(10) + "UK" + Chr(10) + "549")
  AddGadgetItem(0, -1, "Sparkie" + Chr(10) + "Ohio, USA" + Chr(10) + "681")
  ;--> Set column alignment
  AlignColumn(GadgetID(0), 0, #LVCFMT_LEFT)
  AlignColumn(GadgetID(0), 1, #LVCFMT_CENTER)
  AlignColumn(GadgetID(0), 2, #LVCFMT_RIGHT)
  ;--> Subclass ListIcon so we can customdraw the header text centered
  oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon())
  Repeat
    EventID = WaitWindowEvent()
  Until EventID = #PB_Event_CloseWindow
EndIf
End
What goes around comes around.

PB 5.21 LTS (x86) - Windows 8.1
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

That's nice Sparkie.

Custom drawing the header control was always going to be a little quicker.

However, whilst I understand the need for the array to store the text for the header cells (because of the quirks with custom draw), I have nevertheless tried to remove that requirement to save the bother of updating the array everytime a column is added or deleted etc.

However, this turns out to be harder than I would like.

It would seem that in order to prevent the control from painting the text itself, we need to do all custom drawing within the #CDDS_ITEMPREPAINT message. This also requires that I need to paint more than I would like, e.g. the resizing border.

The following 'nearly' does the job, although the header cells are no longer highlighted etc. (a relatively minor problem). But see what happens when you resize a column; keep an eye on the bottom right of the header control!

I've tried returning to the #CDDS_ITEMPOSTPAINT message and tried to disguise the font etc. - No success there, although this would be the best way out!

Code: Select all

; ************************************************ 
; Code:   Centered text in ListIconGadget Header 
; Author: Sparkie (inspired by PB and srod) 
; Date:   December 31, 2005 
; OS:     Windows only 
; ************************************************ 

; ************************************************ 
; Constants 
; ************************************************ 
; ////////////////////////////////// 
; CustomDraw drawing stage 
; ////////////////////////////////// 
#CDDS_ITEM = $10000 
#CDDS_PREPAINT = 1 
#CDDS_POSTPAINT = 2 
#CDDS_ITEMPOSTPAINT = #CDDS_ITEM | #CDDS_POSTPAINT 
#CDDS_ITEMPREPAINT = #CDDS_ITEM | #CDDS_PREPAINT 
; ////////////////////////////////// 
; CustomDraw return values 
; ////////////////////////////////// 
#CDRF_DODEFAULT = 0 
#CDRF_SKIPDEFAULT = 4 
#CDRF_NOTIFYITEMDRAW = $20 
#CDRF_NOTIFYPOSTPAINT = $10 
; ////////////////////////////////// 
; DrawText flags 
; ////////////////////////////////// 
#DT_END_ELLIPSIS = $8000 
; ////////////////////////////////// 
; ListIcon messaging 
; ////////////////////////////////// 
#LVM_GETHEADER = #LVM_FIRST + 31 

; ************************************************ 
; Globals, Arrays 
; ************************************************ 
; ////////////////////////////////// 
; Globals 
; ////////////////////////////////// 
Global oldListIconCallback 


;Function which returns the text from the specified header item.
Procedure.s GetHeaderText(Gadget,index) 
  Protected temp$,lvc.LV_COLUMN 
  temp$=Space(255) 
  lvc\mask = #LVCF_TEXT 
  lvc\pszText = @temp$
  lvc\cchTextMax = 255 
  SendMessage_(GadgetID(Gadget),#LVM_GETCOLUMN,index,@lvc) 
  ProcedureReturn PeekS(lvc\pszText) 
EndProcedure 

; ************************************************ 
; Procedures 
; ************************************************ 
; ////////////////////////////////// 
; Proc for subclassed ListIconGadget 
; ////////////////////////////////// 
Procedure SubclassedListIcon(hwnd, msg, wparam, lparam) 
  result = CallWindowProc_(oldListIconCallback, hwnd, msg, wparam, lparam) 
  Select msg 
    Case #WM_NOTIFY 
      *pnmh.NMHDR = lparam 
      ;--> Get handle to ListIcon header control 
      hHeader = SendMessage_(hwnd, #LVM_GETHEADER, 0, 0) 
      If *pnmh\code = #NM_CUSTOMDRAW And *pnmh\hwndFrom = hHeader 
        *pnmcd.NMCUSTOMDRAW = lparam 
        ;--> Determine drawing stage 
        Select *pnmcd\dwDrawStage 
          Case #CDDS_PREPAINT 
            result = #CDRF_NOTIFYITEMDRAW 
          Case #CDDS_ITEMPREPAINT 
            ;--> Draw centered text to header 
            flags = #DT_CENTER | #DT_NOCLIP | #DT_SINGLELINE | #DT_VCENTER | #DT_END_ELLIPSIS 
            SetBkMode_(*pnmcd\hdc,#TRANSPARENT) 
            SetTextColor_(*pnmcd\hdc, #Black) 
            text$=GetHeaderText(0,*pnmcd\dwItemSpec)
            DrawText_(*pnmcd\hdc, text$, Len(text$), *pnmcd\rc, flags) 
;Draw border line.
            pen=CreatePen_(#PS_SOLID,1,0)  
            hPenOld=SelectObject_(*pnmcd\hdc,pen);Replace old pen with new one.
            MoveToEx_(*pnmcd\hdc,*pnmcd\rc\right,*pnmcd\rc\Top+2,0)
            LineTo_(*pnmcd\hdc,*pnmcd\rc\right,*pnmcd\rc\bottom-2) 
            DeleteObject_(pen) 
            DeleteObject_(hPenOld) 
            result = #CDRF_SKIPDEFAULT

        EndSelect 
      EndIf 
  EndSelect 
  ProcedureReturn result 
EndProcedure 
; ////////////////////////////////// 
; Proc for ListIcon column alignment 
; ////////////////////////////////// 
Procedure AlignColumn(liGad, col, align) 
  liColumn.LV_COLUMN 
  liColumn\mask = #LVCF_FMT 
  liColumn\fmt = align 
  SendMessage_(liGad, #LVM_SETCOLUMN, col, liColumn) 
EndProcedure 

; ************************************************ 
; Main Window 
; ************************************************ 
If OpenWindow(0, 100, 100, 415, 300, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "ListIcon Header Text Centered") And CreateGadgetList(WindowID()) 
  ;--> I'll leave the header text Null and draw them in the subclass procedure 
  ListIconGadget(0, 5, 5, 405, 90, "Name", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
  AddGadgetColumn(0, 1, "Location", 200) 
  AddGadgetColumn(0, 2, "Posts", 100) 
  AddGadgetItem(0, -1, "PB" + Chr(10) + "4F7a" + Chr(10) + "2396") 
  AddGadgetItem(0, -1, "srod" + Chr(10) + "UK" + Chr(10) + "549") 
  AddGadgetItem(0, -1, "Sparkie" + Chr(10) + "Ohio, USA" + Chr(10) + "681") 
  ;--> Set column alignment 
  AlignColumn(GadgetID(0), 0, #LVCFMT_LEFT) 
  AlignColumn(GadgetID(0), 1, #LVCFMT_CENTER) 
  AlignColumn(GadgetID(0), 2, #LVCFMT_RIGHT) 
  ;--> Subclass ListIcon so we can customdraw the header text centered 
  oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon()) 
  Repeat 
    EventID = WaitWindowEvent() 
  Until EventID = #PB_Event_CloseWindow 
EndIf 
End 
Any ideas? I know you like a challenge as much as I! :lol:
I may look like a mule, but I'm not a complete ass.
MrMat
Enthusiast
Enthusiast
Posts: 762
Joined: Sun Sep 05, 2004 6:27 am
Location: England

Post by MrMat »

Maybe you could associate the text with the header item's lParam value so that it moves with the header.
Mat
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

MrMat wrote:Maybe you could associate the text with the header item's lParam value so that it moves with the header.
That is a stroke of genious MrMat!!!

The following could do with tidying up a bit. :D

Code: Select all

; ************************************************ 
; Code:   Centered text in ListIconGadget Header 
; Author: Sparkie (inspired by PB and srod) 
; Date:   December 31, 2005 
; OS:     Windows only 
; ************************************************ 

; ************************************************ 
; Constants 
; ************************************************ 
; ////////////////////////////////// 
; CustomDraw drawing stage 
; ////////////////////////////////// 
#CDDS_ITEM = $10000 
#CDDS_PREPAINT = 1 
#CDDS_POSTPAINT = 2 
#CDDS_ITEMPOSTPAINT = #CDDS_ITEM | #CDDS_POSTPAINT 
#CDDS_ITEMPREPAINT = #CDDS_ITEM | #CDDS_PREPAINT 
; ////////////////////////////////// 
; CustomDraw return values 
; ////////////////////////////////// 
#CDRF_DODEFAULT = 0 
#CDRF_SKIPDEFAULT = 4 
#CDRF_NOTIFYITEMDRAW = $20 
#CDRF_NOTIFYPOSTPAINT = $10 
; ////////////////////////////////// 
; DrawText flags 
; ////////////////////////////////// 
#DT_END_ELLIPSIS = $8000 
; ////////////////////////////////// 
; ListIcon messaging 
; ////////////////////////////////// 
#LVM_GETHEADER = #LVM_FIRST + 31 

; ************************************************ 
; Globals, Arrays 
; ************************************************ 
; ////////////////////////////////// 
; Globals 
; ////////////////////////////////// 
Global oldListIconCallback, hHeader
; ////////////////////////////////// 
; Array of ListIcon header text 
; ////////////////////////////////// 

; ************************************************ 
; Procedures 
; ************************************************ 
; ////////////////////////////////// 
; Proc for subclassed ListIconGadget 
; ////////////////////////////////// 
Procedure SubclassedListIcon(hwnd, msg, wparam, lparam) 
  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 And *pnmh\hwndFrom = hHeader 
        *pnmcd.NMCUSTOMDRAW = lparam 
        ;--> Determine drawing stage 
        Select *pnmcd\dwDrawStage 
          Case #CDDS_PREPAINT 
            result = #CDRF_NOTIFYITEMDRAW 
          Case #CDDS_ITEMPREPAINT 
            result = #CDRF_DODEFAULT | #CDRF_NOTIFYPOSTPAINT 
          Case #CDDS_ITEMPOSTPAINT 
            ;--> Draw centered text to header 
            flags = #DT_CENTER | #DT_NOCLIP | #DT_SINGLELINE | #DT_VCENTER | #DT_END_ELLIPSIS 
            SetBkMode_(*pnmcd\hdc,#TRANSPARENT) 
            SetTextColor_(*pnmcd\hdc, #Black) 
;Each header item has a user defined 32 bit value which we have already ensured points to the relevant column heading.
;We now need to retrieve the underlying text.
            hditem.HD_ITEM 
            hditem\mask = #HDI_LPARAM	 
            SendMessage_(hHeader, #HDM_GETITEM , *pnmcd\dwItemSpec, @hditem) 
            text$=PeekS(hditem\lparam)
            DrawText_(*pnmcd\hdc, text$, Len(text$), *pnmcd\rc, flags) 
            result = #CDRF_DODEFAULT 
        EndSelect 
      EndIf 
  EndSelect 
  ProcedureReturn result 
EndProcedure 
; ////////////////////////////////// 
; Proc for ListIcon column alignment 
; ////////////////////////////////// 
Procedure AlignColumn(liGad, col, align) 
  liColumn.LV_COLUMN 
  liColumn\mask = #LVCF_FMT 
  liColumn\fmt = align 
  SendMessage_(liGad, #LVM_SETCOLUMN, col, liColumn) 
EndProcedure 

; ************************************************ 
; Main Window 
; ************************************************ 
If OpenWindow(0, 100, 100, 415, 300, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "ListIcon Header Text Centered") And CreateGadgetList(WindowID()) 
  ;--> I'll leave the header text Null and draw them in the subclass procedure 
  ListIconGadget(0, 5, 5, 405, 90, "", 100, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection) 
  hHeader = SendMessage_(GadgetID(0), #LVM_GETHEADER, 0, 0) 
  AddGadgetColumn(0, 1, "", 200) 
  AddGadgetColumn(0, 2, "", 100) 
  AddGadgetItem(0, -1, "PB" + Chr(10) + "4F7a" + Chr(10) + "2396") 
  AddGadgetItem(0, -1, "srod" + Chr(10) + "UK" + Chr(10) + "549") 
  AddGadgetItem(0, -1, "Sparkie" + Chr(10) + "Ohio, USA" + Chr(10) + "681") 
  ;--> Set column alignment 
  AlignColumn(GadgetID(0), 0, #LVCFMT_LEFT) 
  AlignColumn(GadgetID(0), 1, #LVCFMT_CENTER) 
  AlignColumn(GadgetID(0), 2, #LVCFMT_RIGHT) 
  ;--> Subclass ListIcon so we can customdraw the header text centered 
  oldListIconCallback = SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubclassedListIcon()) 
  
;Each header item has a user defined 32 bit value which we use to point to the relevant column heading.
;This means that adding/deleting columns will not upset the column headings. 
  hditem.HD_ITEM 
  hditem\mask = #HDI_LPARAM	 
  hditem\lParam = @"Name"
  SendMessage_(hHeader, #HDM_SETITEM , 0, @hditem) 
  hditem\lParam = @"Location"
  SendMessage_(hHeader, #HDM_SETITEM , 1, @hditem) 
  hditem\lParam = @"Posts"
  SendMessage_(hHeader, #HDM_SETITEM , 2, @hditem) 
 
  Repeat 
    EventID = WaitWindowEvent() 
  Until EventID = #PB_Event_CloseWindow 
EndIf 
End 

I may look like a mule, but I'm not a complete ass.
MrMat
Enthusiast
Enthusiast
Posts: 762
Joined: Sun Sep 05, 2004 6:27 am
Location: England

Post by MrMat »

Thanks, there may be a slight problem though. It looks like AddGadgetColumn puts the column number in lParam so if PureBasic expects to use this later on then it may cause a problem.
Mat
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

I've just added a couple of columns and set the cell values using PB commands. Seems to work okay.
I may look like a mule, but I'm not a complete ass.
MrMat
Enthusiast
Enthusiast
Posts: 762
Joined: Sun Sep 05, 2004 6:27 am
Location: England

Post by MrMat »

srod wrote:I've just added a couple of columns and set the cell values using PB commands. Seems to work okay.
Sounds good then! Nice work :D
Mat
Post Reply