Page 1 of 1

Button in List View

Posted: Fri Oct 07, 2011 11:51 pm
by michaeled314
In my application I want to create a button in one column of the list icon gadget (Win API treats it like a list view when in report mode)... It is an image button. However, I am not able to do this, even with research... Can anybody help... I am in detailed view (report style set)... Any Win API suggestions

- Michael

Re: Button in List View

Posted: Sat Oct 08, 2011 2:18 pm
by netmaestro
This task, while certainly doable, is not exactly trivial. You must solve for the case where columns are moved or resized and it is advisable to employ a method of controlling the line height of your ListIcon to accomodate image sizes. At the "standard" height, by the time you get button edges in there, there's only a handful of pixels left for your image height. Height is managed here with ownerdraw. Also, resizing of the column containing the button should be disallowed.

Disclaimer: Fair warning, this code is venturing into unsupported Purebasic territory; Overlapping gadgets are not supported at all in Purebasic. This code works fine on 4.60 RC1 but there is no guarantee that the team won't change the way ListIcon events and/or drawing get handled in the future and throw a monkey wrench into this.

Code: Select all


Procedure MainWindowCallBack(hwnd, msg, wparam, lparam) 
  result = #PB_ProcessPureBasicEvents 
  
  Select msg 
    Case #WM_DRAWITEM 
      *lpdis.DRAWITEMSTRUCT = lparam 
      Dim itemrect.RECT(3) 
      For i = 1 To 3 
        FillMemory(@itemrect(i),SizeOf(RECT)) 
        itemrect(i)\top = i 
        SendMessage_(*lpdis\hwndItem, #LVM_GETSUBITEMRECT, *lpdis\itemid, @itemrect(i)) 
        text$ = GetGadgetItemText(GetDlgCtrlID_(*lpdis\hwndItem), *lpdis\itemid, i) 
        SelectObject_(*lpdis\hDC, GetStockObject_(#NULL_PEN)) 
        WhiteBrush = CreateSolidBrush_(#White) 
        SelectObject_(*lpdis\hDC, WhiteBrush) 
        Rectangle_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, itemrect(i)\right, itemrect(i)\bottom) 
        TextOut_(*lpdis\hDC, itemrect(i)\left+4, itemrect(i)\top+4, text$, Len(text$)) 
        DeleteObject_(WhiteBrush) 
      Next 
      
    Case #WM_MEASUREITEM 
      *lpmis.MEASUREITEMSTRUCT = lparam 
      *lpmis\itemheight = 20 
      
  EndSelect 
  
  ProcedureReturn result 
  
EndProcedure 

Procedure Reposition_Buttons()
  Static firstcall = #True
  Static topline=0
  
  If firstcall
    header = SendMessage_(GadgetID(0), #LVM_GETHEADER,0,0)
    SendMessage_(header, #HDM_GETITEMRECT, 0, @hr.RECT)
    topline   = hr\bottom
    firstcall = #False
  EndIf
  
  For i=1 To 3
    FillMemory(itemrect.RECT, SizeOf(RECT))
    itemrect\top = 3
    itemrect\left = #LVIR_BOUNDS
    SendMessage_(GadgetID(0), #LVM_GETSUBITEMRECT, i-1, @itemrect.RECT) 
    If itemrect\top >= topline
      ResizeGadget(i, itemrect\left+1, itemrect\top+1, #PB_Ignore, #PB_Ignore)
      HideGadget(i,0)
    Else
      HideGadget(i,1)
    EndIf
  Next
EndProcedure

Procedure SubClass_LV(hwnd, msg, wparam, lparam) 
  
  oldproc = GetProp_(hwnd, "oldproc")
  
  Select msg
    Case #WM_NCDESTROY
      RemoveProp_(hwnd, "oldproc")
      
    Case #WM_HSCROLL, #WM_VSCROLL
      Reposition_Buttons()
      
    Case #WM_NOTIFY 
      *nmHEADER.HD_NOTIFY = lParam 
      Select *nmHEADER\hdr\code 
        Case #HDN_ITEMCHANGINGA, #HDN_ITEMCHANGINGW
          If *nmHEADER\iItem=3
            SetCursor_(LoadCursor_(0, #IDC_NO))
            ProcedureReturn #True
          EndIf
          Reposition_Buttons()
      EndSelect
      
  EndSelect 
  
  ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)  
  
EndProcedure 

OpenWindow(0,0,0,320,240,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
SetWindowCallback(@MainWindowCallBack()) 

ListIconGadget(0,0,0,320,240,"",0,#LVS_OWNERDRAWFIXED|#PB_ListIcon_GridLines) 
SetWindowLong_(GadgetID(0),#GWL_STYLE,GetWindowLong_(GadgetID(0),#GWL_STYLE)|#WS_CLIPCHILDREN)
SetProp_(GadgetID(0), "oldproc", SetWindowLong_(GadgetID(0), #GWL_WNDPROC, @SubClass_LV()))

AddGadgetColumn(0,1,"Column 1",100) 
AddGadgetColumn(0,2,"Column 2",100) 
AddGadgetColumn(0,3,"Column 3",90) 
AddGadgetItem(0, -1, Chr(10) + "Line 0 Col 1" + Chr(10) +  "Line 0  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 1 Col 1" + Chr(10) +  "Line 1  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 2 Col 1" + Chr(10) +  "Line 2  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 3 Col 1" + Chr(10) +  "Line 3  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 4 Col 1" + Chr(10) +  "Line 4  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 5 Col 1" + Chr(10) +  "Line 5  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 6 Col 1" + Chr(10) +  "Line 6  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 7 Col 1" + Chr(10) +  "Line 7  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 8 Col 1" + Chr(10) +  "Line 8  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 9 Col 1" + Chr(10) +  "Line 9  Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 10 Col 1" + Chr(10) + "Line 10 Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 11 Col 1" + Chr(10) + "Line 11 Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 12 Col 1" + Chr(10) + "Line 12 Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 13 Col 1" + Chr(10) + "Line 13 Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 14 Col 1" + Chr(10) + "Line 14 Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 15 Col 1" + Chr(10) + "Line 15 Col 2" + Chr(10) ) 
AddGadgetItem(0, -1, Chr(10) + "Line 16 Col 1" + Chr(10) + "Line 16 Col 2" + Chr(10) ) 

CreateImage(0, 80,12)
StartDrawing(ImageOutput(0))
  Box(0,0,80,16,#Red)
StopDrawing()

UseGadgetList(GadgetID(0))
For i=1 To 3
  FillMemory(itemrect.RECT, SizeOf(RECT))
  itemrect\top = 3
  itemrect\left = #LVIR_BOUNDS
  SendMessage_(GadgetID(0),#LVM_GETSUBITEMRECT, i-1, @itemrect) 
  ResizeImage(0, itemrect\right-itemrect\left, itemrect\bottom-itemrect\top)
  ContainerGadget(i, itemrect\left+1, itemrect\top+1, itemrect\right-itemrect\left-2, itemrect\bottom-itemrect\top-2) 
  ButtonImageGadget(i+3, 0,0, itemrect\right-itemrect\left-2, itemrect\bottom-itemrect\top-2, ImageID(0))
  CloseGadgetList()
Next
UseGadgetList(WindowID(0))

Repeat 
  EventID = WaitWindowEvent() 
  Select EventID 
    Case #PB_Event_Gadget 
      Select GadgetType(EventGadget())
        Case #PB_GadgetType_ButtonImage
          Debug "Button "+Str(EventGadget())+" pressed"
      EndSelect 
  EndSelect 
Until EventID = #WM_CLOSE 

Re: Button in List View

Posted: Sat Oct 08, 2011 3:01 pm
by srod
Nice. I'd probably hide the buttons when vertical scrolling though else the header gets in the way. :)

Re: Button in List View

Posted: Sat Oct 08, 2011 3:26 pm
by netmaestro
Thanks srod! There is always something I didn't think of. Very great to have you here again backstopping me :mrgreen:

Code edited with the fix.

Re: Button in List View

Posted: Sat Oct 08, 2011 8:14 pm
by srod
:D

Re: Button in List View

Posted: Sat Oct 08, 2011 10:48 pm
by Psych
Nice code indeed.

I did notice the list doesnt update properly on scroll track, drag the slider down 1 and the list moves but the buttons remain. Shouldnt take too much to sort that out though.

This is also a solution to putting progressbars in columns too :)

Re: Button in List View

Posted: Sat Oct 08, 2011 10:53 pm
by netmaestro
This is because of line-by-line scrolling, nothing will change it.

Re: Button in List View

Posted: Mon Oct 10, 2011 1:16 am
by michaeled314
Thanks for the code

As you can see in the Tips and Tricks section, I like to make my list icon report view columns non resizable
This makes it much easier


- Michael

Re: Button in List View

Posted: Mon Oct 10, 2011 6:33 am
by electrochrisso
8) NM, So it is best to use your code for fixed sized grid stuff then. :?: