Listicon: Anchor the first column (Updated April 24, 2010)
Posted: Fri Mar 20, 2009 6:52 am
This library include allows you to create a ListIcon gadget that is identical in all respects to a normal listicon, except that the first column is anchored and won't move or scroll. It stays fixed. Also, it is drawn in a way that looks to the user as though it is fixed.
How it works:
The concept is fairly simple. The area containing Column 0 is removed from the clipping region of the control, so that while Column 0 is alive and well, it is never drawn. Then we take full responsibility for drawing Column 0 in the same way the gadget would do it, more or less. The main exception is that when the gadget's DC is scrolled to the left, we leave Column 0 the way it is. Simple as the idea is, it seems to take a fair whack of code to make it happen.
Update April 24/2010:
Added code to the gadget's WM_NCDESTROY proc to free all its parts when the gadget is freed. The gadget responds to FreeGadget() and HideGadget() properly now. Also, fixed a couple of minor display issues w/selected text color and focusrect display for themed/unthemed. Blends in better now. Afaik all that's left to do is gridlines.
Update March 29:
1) Made button for column 0 pressable.
2) Reworked image creation for the buttons.
In the course of making the button for column 0 pressable, I came across a problem in the way the button image was being drawn. In order to grab the image from the dc of the header or the listicon, the listicon must be scrolled all the way to the right. Otherwise button 0 is out of the clipping region. So I was scrolling to the right on a column resize to get the correct image, but what about when someone is scrolled over halfway to the left when he resizes column 0? His scroll is reset and he has to rescroll. No good.
Also, in order to make the 3 button states for pressability, I have to press the button and hover over it. When I press the button I have to draw it and then let it go, which then generates a button-press event which I can't stop. It's automatic and there is no return value for #HDN_ITEMCLICK to refuse it. So that's another problem.
As a solution, I'm getting the metrics and style from the listicon header and creating a new header of the same characteristics. I'm grabbing the 3 images, pressing and hovering etc. and once I have them I'm destroying the temporary header. This solves both of the above problems. All this takes place in the UpdateImages() procedure.
Update March 28:
1) Replaced the thread monitoring the cursor with a different approach using SetCapture_() / ReleaseCapture_(). There are no threads in this library now. Thanks to srod for helping me debug this.
2) Fixed a bug in the #WM_SETFONT / #WM_MOVE handler
3) Updated the demo prog to demonstrate multiple instances, SetGadgetFont and ResizeGadget situations.
Update March 26:
Fixed several bugs, removed completely the array storing the items. I should have realized from the start that it wasn't needed. The gadget will now behave correctly in the following situations:
1) Multiple instances in an application
2) Compiling with Tailbite.
Update March 23:
Code is mostly reworked to allow eventual mulitple gadgets in an application, the only thing left on that issue is the static array. That has to be replaced with something else. The capture problem is solved.
Update March 22, 2009:
Quite a few issues have been covered in this update. The gadget will now handle the following gracefully:
1) SetGadgetFont
2) ResizeGadget
3) #PB_Listicon_FullRowSelect
4) Resizing Column 0
5) Too-long text in column 0
Yet todo: #PB_ListIcon_Gridlines, make column 0 button pushable, multiple instances
Little test program:
How it works:
The concept is fairly simple. The area containing Column 0 is removed from the clipping region of the control, so that while Column 0 is alive and well, it is never drawn. Then we take full responsibility for drawing Column 0 in the same way the gadget would do it, more or less. The main exception is that when the gadget's DC is scrolled to the left, we leave Column 0 the way it is. Simple as the idea is, it seems to take a fair whack of code to make it happen.
Update April 24/2010:
Added code to the gadget's WM_NCDESTROY proc to free all its parts when the gadget is freed. The gadget responds to FreeGadget() and HideGadget() properly now. Also, fixed a couple of minor display issues w/selected text color and focusrect display for themed/unthemed. Blends in better now. Afaik all that's left to do is gridlines.
Update March 29:
1) Made button for column 0 pressable.
2) Reworked image creation for the buttons.
In the course of making the button for column 0 pressable, I came across a problem in the way the button image was being drawn. In order to grab the image from the dc of the header or the listicon, the listicon must be scrolled all the way to the right. Otherwise button 0 is out of the clipping region. So I was scrolling to the right on a column resize to get the correct image, but what about when someone is scrolled over halfway to the left when he resizes column 0? His scroll is reset and he has to rescroll. No good.
Also, in order to make the 3 button states for pressability, I have to press the button and hover over it. When I press the button I have to draw it and then let it go, which then generates a button-press event which I can't stop. It's automatic and there is no return value for #HDN_ITEMCLICK to refuse it. So that's another problem.
As a solution, I'm getting the metrics and style from the listicon header and creating a new header of the same characteristics. I'm grabbing the 3 images, pressing and hovering etc. and once I have them I'm destroying the temporary header. This solves both of the above problems. All this takes place in the UpdateImages() procedure.
Update March 28:
1) Replaced the thread monitoring the cursor with a different approach using SetCapture_() / ReleaseCapture_(). There are no threads in this library now. Thanks to srod for helping me debug this.
2) Fixed a bug in the #WM_SETFONT / #WM_MOVE handler
3) Updated the demo prog to demonstrate multiple instances, SetGadgetFont and ResizeGadget situations.
Update March 26:
Fixed several bugs, removed completely the array storing the items. I should have realized from the start that it wasn't needed. The gadget will now behave correctly in the following situations:
1) Multiple instances in an application
2) Compiling with Tailbite.
Update March 23:
Code is mostly reworked to allow eventual mulitple gadgets in an application, the only thing left on that issue is the static array. That has to be replaced with something else. The capture problem is solved.
Update March 22, 2009:
Quite a few issues have been covered in this update. The gadget will now handle the following gracefully:
1) SetGadgetFont
2) ResizeGadget
3) #PB_Listicon_FullRowSelect
4) Resizing Column 0
5) Too-long text in column 0
Yet todo: #PB_ListIcon_Gridlines, make column 0 button pushable, multiple instances
Code: Select all
;=========================================================================
; Library: FixedIconGadget
; Author: Lloyd Gallant (netmaestro)
; Contributors: Stephen Rodriguez (srod)
; Date: March 20, 2009
; Target Compiler: PureBasic 4.3
; Target OS: Microsoft Windows All
; License: Free, unrestricted, no warranty
;=========================================================================
;
; Command: FixedIconGadget(), identical in all respects to ListIconGadget()
;
#LVM_SUBITEMHITTEST = #LVM_FIRST + 57
Structure FIXEDICONDATA
listproc.i
buttonimgproc.i
colimgproc.i
headerproc.i
listhwnd.i
header.i
colimg_g.i
colimg.i
buttonimg_g.i
buttonimg.i
button_pressedimg.i
button_hoverimg.i
lineH.i
col_0_width.i
scroll_height.i
col_0_line_g.i
button_0_line_g.i
list_line_g.i
sizelin.i
resizing_col_0.i
themed.i
mouseinbutton.i
hdnotify.HD_NOTIFY
EndStructure
Declare headerproc(hwnd,msg,wparam,lparam)
Procedure ThemesEnabled()
dlv.DLLVERSIONINFO
dlv\cbsize=SizeOf(DLLVERSIONINFO)
lib=OpenLibrary(#PB_Any,"comctl32.dll")
If lib
CallFunction(lib,"DllGetVersion",@dlv)
DLLVersion = dlv\dwMajorVersion
CloseLibrary(lib)
EndIf
If DLLVersion = 6
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure PaintColumn_0(*fdata.FIXEDICONDATA)
If Not *fdata\themed
tcorr = 2
EndIf
With hti.LVHITTESTINFO
\pt\x = GetGadgetItemAttribute(GetDlgCtrlID_(*fdata\listhwnd),0,#PB_ListIcon_ColumnWidth)+5
\pt\y = 30
EndWith
SendMessage_(*fdata\listhwnd,#LVM_SUBITEMHITTEST,0,hti)
item = hti\iitem : If item<0 : item=0 : EndIf
StartDrawing(ImageOutput(*fdata\buttonimg))
l1 = Point(5,ImageHeight(*fdata\buttonimg)-1)
l2 = Point(5,ImageHeight(*fdata\buttonimg)-2)
l3 = Point(5,ImageHeight(*fdata\buttonimg)-3)
l4 = Point(3,3)
StopDrawing()
hdc = StartDrawing(ImageOutput(*fdata\colimg))
Box(0,0,ImageWidth(*fdata\colimg),ImageHeight(*fdata\colimg),l4)
Box(ImageWidth(*fdata\colimg)-3,0,1,ImageHeight(*fdata\colimg),l3)
Box(ImageWidth(*fdata\colimg)-2,0,1,ImageHeight(*fdata\colimg),l2)
Box(ImageWidth(*fdata\colimg)-1,0,1,ImageHeight(*fdata\colimg),l1)
DrawingFont(GetGadgetFont(GetDlgCtrlID_(*fdata\listhwnd)))
numvisible = ImageHeight(*fdata\colimg)/*fdata\lineH
cc=0
For i=item To item+numvisible
If i=GetGadgetState(GetDlgCtrlID_(*fdata\listhwnd))
exstyle = SendMessage_(*fdata\listhwnd, #LVM_GETEXTENDEDLISTVIEWSTYLE,0,0)
If exstyle & #LVS_EX_FULLROWSELECT
SetRect_(sel.RECT,0,cc**fdata\lineH+tcorr,ImageWidth(*fdata\colimg)+5,cc**fdata\lineH+*fdata\lineH+tcorr)
Else
SetRect_(sel.RECT,0,cc**fdata\lineH+tcorr,ImageWidth(*fdata\colimg)-3,cc**fdata\lineH+*fdata\lineH+tcorr)
EndIf
hBrush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
FillRect_(hdc, sel, hBrush)
DeleteObject_(hBrush)
text$ = GetGadgetItemText(GetDlgCtrlID_(*fdata\listhwnd),i,0)
While TextWidth(text$)>=ImageWidth(*fdata\colimg)-TextWidth("EE")
text$=Left(text$,Len(text$)-1)
Wend
If text$<>GetGadgetItemText(GetDlgCtrlID_(*fdata\listhwnd),i,0) : text$+".." : EndIf
DrawText(4,cc**fdata\lineH+tcorr,text$,#White,GetSysColor_(#COLOR_HIGHLIGHT))
If Not ThemesEnabled()
DrawFocusRect_(hdc, sel)
EndIf
Else
text$ = GetGadgetItemText(GetDlgCtrlID_(*fdata\listhwnd),i,0)
While TextWidth(text$)>=ImageWidth(*fdata\colimg)-TextWidth("EE")
text$=Left(text$,Len(text$)-1)
Wend
If text$<>GetGadgetItemText(GetDlgCtrlID_(*fdata\listhwnd),i,0) : text$+".." : EndIf
DrawText(4,cc**fdata\lineH+tcorr,text$,#Black,l4)
EndIf
cc+1
Next
StopDrawing()
SetGadgetState(*fdata\buttonimg_g, ImageID(*fdata\buttonimg))
SetGadgetState(*fdata\colimg_g,ImageID(*fdata\colimg))
EndProcedure
Procedure ImageProc(hwnd, msg, wparam, lparam)
*fdata.FIXEDICONDATA = GetProp_(hwnd, "fdata")
Select msg
Case #WM_NCDESTROY
RemoveProp_(hwnd, "fdata")
Case #WM_MOUSEMOVE
x = lparam&$FFFF
If x>=GadgetWidth(GetDlgCtrlID_(hwnd))-5
SetCursor_( LoadCursor_(0, #IDC_SIZEWE ))
Else
If Not *fdata\resizing_col_0
SetCursor_( LoadCursor_(0, #IDC_ARROW ))
Else
ResizeGadget(*fdata\list_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
ResizeGadget(*fdata\button_0_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
HideGadget(*fdata\list_line_g,0)
HideGadget(*fdata\button_0_line_g,0)
HideGadget(*fdata\col_0_line_g,1)
EndIf
EndIf
Case #WM_LBUTTONDOWN
SetFocus_(*fdata\listhwnd)
If lparam&$FFFF >=GadgetWidth(GetDlgCtrlID_(hwnd))-5
*fdata\resizing_col_0 = 1
SetCursor_( LoadCursor_(0, #IDC_SIZEWE ))
CallWindowProc_(*fdata\colimgproc, hwnd, msg, wparam, lparam)
SetCapture_(*fdata\listhwnd)
ProcedureReturn 0
Else
With hti.LVHITTESTINFO
\pt\x = GetGadgetItemAttribute(GetDlgCtrlID_(*fdata\listhwnd),0,#PB_ListIcon_ColumnWidth)+20
\pt\y = 24
EndWith
SendMessage_(*fdata\listhwnd,#LVM_SUBITEMHITTEST,0,hti)
firstitem = hti\iitem : If firstitem<0 : firstitem=0 : EndIf
localitem = lparam>>16 / *fdata\lineH
item = firstitem + localitem
SetFocus_(*fdata\listhwnd)
SetGadgetState(GetDlgCtrlID_(*fdata\listhwnd), item)
EndIf
Case #WM_SETCURSOR
If *fdata\resizing_col_0
SetCursor_(LoadCursor_(0, #IDC_SIZEWE))
ProcedureReturn 0
EndIf
EndSelect
ProcedureReturn CallWindowProc_(*fdata\colimgproc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure UpdateImages(*fdata.FIXEDICONDATA)
; Get column 0 text
*buffer = AllocateMemory(255)
With itm.HDITEM
\mask = #HDI_TEXT
\pszText = *buffer
\cchTextMax = 255
EndWith
SendMessage_(*fdata\header, #HDM_GETITEM, 0, @itm.HDITEM)
text$=PeekS(itm\pszText)
FreeMemory(*buffer)
; Get column 0 dimensions
SendMessage_(*fdata\header, #HDM_GETITEMRECT,0,@hr.RECT)
w = hr\right
h = hr\bottom
exstyle = GetWindowLongPtr_(*fdata\header, #GWL_EXSTYLE)
style = GetWindowLongPtr_(*fdata\header, #GWL_STYLE)
; Recreate the button on a new header
hdr = CreateWindowEx_(exstyle,"Sysheader32","",style&~#WS_VISIBLE,0,0,w,h,*fdata\listhwnd,0,GetModuleHandle_(0),0)
With itm.HDITEM
\mask = #HDI_TEXT | #HDI_WIDTH
\cxy = w
\pszText = @text$
\cchTextMax = 255
\fmt = #HDF_LEFT
EndWith
SendMessage_(hdr, #WM_SETFONT, GetGadgetFont(GetDlgCtrlID_(*fdata\listhwnd)), 1)
SendMessage_(hdr, #HDM_INSERTITEM,0,itm)
; Draw the new button in its 3 states
hdc = GetWindowDC_(hdr)
ShowWindow_(hdr, #SW_SHOW)
; normal button
UpdateWindow_(hdr)
If IsImage(*fdata\buttonimg):FreeImage(*fdata\buttonimg):EndIf
*fdata\buttonimg = CreateImage(#PB_Any,w,h)
dcout=StartDrawing(ImageOutput(*fdata\buttonimg))
BitBlt_(dcout,0,0,w,h,hdc,0,0,#SRCCOPY)
StopDrawing()
; pressed button
SendMessage_(hdr, #WM_LBUTTONDOWN, 0 ,5|5<<16)
UpdateWindow_(hdr)
If IsImage(*fdata\button_pressedimg):FreeImage(*fdata\button_pressedimg):EndIf
*fdata\button_pressedimg = CreateImage(#PB_Any,w,h)
dcout=StartDrawing(ImageOutput(*fdata\button_pressedimg))
BitBlt_(dcout,0,0,w,h,hdc,0,0,#SRCCOPY)
StopDrawing()
SendMessage_(hdr, #WM_LBUTTONUP, 0 ,5|5<<16)
; hover button
SendMessage_(hdr, #WM_MOUSEMOVE, 0 ,5|5<<16)
UpdateWindow_(hdr)
If IsImage(*fdata\button_hoverimg):FreeImage(*fdata\button_hoverimg):EndIf
*fdata\button_hoverimg = CreateImage(#PB_Any,w,h)
dcout=StartDrawing(ImageOutput(*fdata\button_hoverimg))
BitBlt_(dcout,0,0,w,h,hdc,0,0,#SRCCOPY)
StopDrawing()
ReleaseDC_(hdr, hdc)
; Finished, destroy temporary header
DestroyWindow_(hdr)
EndProcedure
Procedure ListProc(hwnd, msg, wparam, lparam)
*fdata.FIXEDICONDATA = GetProp_(hwnd, "fdata")
Select msg
Case #WM_NCDESTROY
If IsGadget(*fdata\list_line_g)
FreeGadget(*fdata\list_line_g)
EndIf
If IsGadget(*fdata\button_0_line_g)
FreeGadget(*fdata\button_0_line_g)
EndIf
If IsGadget(*fdata\col_0_line_g)
FreeGadget(*fdata\col_0_line_g)
EndIf
If IsGadget(*fdata\buttonimg_g)
FreeGadget(*fdata\buttonimg_g)
EndIf
If IsGadget(*fdata\colimg_g)
FreeGadget(*fdata\colimg_g)
EndIf
If IsImage(*fdata\colimg)
FreeImage(*fdata\colimg)
EndIf
If IsImage(*fdata\sizelin)
FreeImage(*fdata\sizelin)
EndIf
RemoveProp_(hwnd, "fdata")
Case #WM_SHOWWINDOW
If wparam
If IsGadget(*fdata\buttonimg_g)
HideGadget(*fdata\buttonimg_g, 0)
EndIf
If IsGadget(*fdata\colimg_g)
HideGadget(*fdata\colimg_g,0)
EndIf
Else
If IsGadget(*fdata\buttonimg_g)
HideGadget(*fdata\buttonimg_g, 1)
EndIf
If IsGadget(*fdata\colimg_g)
HideGadget(*fdata\colimg_g,1)
EndIf
EndIf
Case #WM_PAINT
PaintColumn_0( *fdata )
Case #WM_NOTIFY
*nmHEADER.HD_NOTIFY = lParam
Select *nmHEADER\hdr\code
Case #HDN_BEGINTRACK, #HDN_BEGINTRACKW
If *nmHEADER\iItem = 0
ProcedureReturn #True
EndIf
EndSelect
Case #WM_MOUSEMOVE
If *fdata\resizing_col_0
loc = lparam&$FFFF
Select loc
Case 10 To *fdata\col_0_width
ResizeGadget(*fdata\list_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
ResizeGadget(*fdata\button_0_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
HideGadget(*fdata\list_line_g,0)
HideGadget(*fdata\button_0_line_g,0)
HideGadget(*fdata\col_0_line_g,1)
Case *fdata\col_0_width To GadgetWidth(GetDlgCtrlID_(hwnd))-10
ResizeGadget(*fdata\col_0_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
HideGadget(*fdata\col_0_line_g,0)
HideGadget(*fdata\button_0_line_g,1)
HideGadget(*fdata\list_line_g,1)
EndSelect
EndIf
Case #WM_LBUTTONUP
If *fdata\resizing_col_0
oldwidth = *fdata\col_0_width
ReleaseCapture_()
*fdata\resizing_col_0 = #False
SetCursor_(LoadCursor_(0,#IDC_ARROW))
HideGadget(*fdata\col_0_line_g,1)
HideGadget(*fdata\list_line_g,1)
HideGadget(*fdata\button_0_line_g,1)
InvalidateRect_(hwnd,0, 1)
*fdata\col_0_width=PeekW(@lparam)
widthdiff = *fdata\col_0_width-oldwidth
oldscrollpos = GetScrollPos_(hwnd, #SB_HORZ)
If *fdata\col_0_width < 30
*fdata\col_0_width = 30
EndIf
If *fdata\col_0_width > GadgetWidth(GetDlgCtrlID_(hwnd)) - 30
*fdata\col_0_width = GadgetWidth(GetDlgCtrlID_(hwnd)) - 30
EndIf
SetGadgetItemAttribute(GetDlgCtrlID_(hwnd),0,#PB_ListIcon_ColumnWidth,*fdata\col_0_width)
SetWindowRgn_(hwnd, 0, 1)
CallWindowProc_(*fdata\listproc, hwnd, msg, wparam, lparam)
lineH = SendMessage_(hwnd,#LVM_GETITEMSPACING,#True,0)>>16
UpdateImages(*fdata)
hrgn1 = CreateRectRgn_(0,0,GadgetWidth(GetDlgCtrlID_(hwnd)),GadgetHeight(GetDlgCtrlID_(hwnd)))
hrgn2 = CreateRectRgn_(GetSystemMetrics_(#SM_CXEDGE),GetSystemMetrics_(#SM_CYEDGE),GetGadgetItemAttribute(GetDlgCtrlID_(hwnd),0,#PB_ListIcon_ColumnWidth,0) +GetSystemMetrics_(#SM_CYEDGE),GadgetHeight(GetDlgCtrlID_(hwnd))-(*fdata\scroll_height+GetSystemMetrics_(#SM_CYEDGE)))
CombineRgn_(hrgn1, hrgn1, hrgn2, #RGN_XOR)
SetWindowRgn_(hwnd, hrgn1, 1)
SendMessage_(*fdata\header, #HDM_GETITEMRECT,0,@hr.RECT)
buttonh = hr\bottom
FreeImage(*fdata\colimg)
*fdata\colimg = CreateImage(#PB_Any,*fdata\col_0_width, GadgetHeight(GetDlgCtrlID_(hwnd))-(buttonh+GetSystemMetrics_(#SM_CYEDGE)*2+*fdata\scroll_height))
ResizeGadget(*fdata\colimg_g,GadgetX(GetDlgCtrlID_(hwnd))+GetSystemMetrics_(#SM_CXEDGE),GadgetY(GetDlgCtrlID_(hwnd))+buttonh+GetSystemMetrics_(#SM_CXEDGE), #PB_Ignore,#PB_Ignore)
ResizeGadget(*fdata\buttonimg_g,GadgetX(GetDlgCtrlID_(hwnd))+GetSystemMetrics_(#SM_CXEDGE),GadgetY(GetDlgCtrlID_(hwnd))+GetSystemMetrics_(#SM_CYEDGE),*fdata\col_0_width+GetSystemMetrics_(#SM_CXEDGE),buttonh)
If newwidth > oldwidth
SetScrollPos_(hwnd, #SB_HORZ, oldscrollpos+widthdiff, 1)
EndIf
InvalidateRect_(hwnd, 0,1)
EndIf
Case #WM_SETCURSOR
If *fdata\resizing_col_0
SetCursor_(LoadCursor_(0, #IDC_SIZEWE))
ProcedureReturn 0
EndIf
Case #WM_SETFONT, #WM_MOVE
SetWindowRgn_(hwnd, 0, 1)
CallWindowProc_(*fdata\listproc, hwnd, msg, wparam, lparam)
*fdata\lineH = SendMessage_(hwnd,#LVM_GETITEMSPACING,#True,0)>>16
*fdata\header = SendMessage_(hwnd,#LVM_GETHEADER,0,0)
UpdateWindow_(hwnd)
SendMessage_(*fdata\header, #HDM_GETITEMRECT,0,@hr.RECT)
buttonw = hr\right
buttonh = hr\bottom
UpdateImages(*fdata)
hrgn1 = CreateRectRgn_(0,0,GadgetWidth(GetDlgCtrlID_(hwnd)),GadgetHeight(GetDlgCtrlID_(hwnd)))
hrgn2 = CreateRectRgn_(GetSystemMetrics_(#SM_CXEDGE),GetSystemMetrics_(#SM_CYEDGE),GetGadgetItemAttribute(GetDlgCtrlID_(hwnd),0,#PB_ListIcon_ColumnWidth,0) +GetSystemMetrics_(#SM_CYEDGE),GadgetHeight(GetDlgCtrlID_(hwnd))-(*fdata\scroll_height+GetSystemMetrics_(#SM_CYEDGE)))
CombineRgn_(hrgn1, hrgn1, hrgn2, #RGN_XOR)
SetWindowRgn_(hwnd, hrgn1, 1)
FreeImage(*fdata\colimg)
*fdata\colimg = CreateImage(#PB_Any,*fdata\col_0_width, GadgetHeight(GetDlgCtrlID_(hwnd))-(buttonh+GetSystemMetrics_(#SM_CYEDGE)*2+*fdata\scroll_height))
ResizeGadget(*fdata\colimg_g,GadgetX(GetDlgCtrlID_(hwnd))+GetSystemMetrics_(#SM_CXEDGE),GadgetY(GetDlgCtrlID_(hwnd))+buttonh+GetSystemMetrics_(#SM_CXEDGE), #PB_Ignore,#PB_Ignore)
ResizeGadget(*fdata\buttonimg_g,GadgetX(GetDlgCtrlID_(hwnd))+GetSystemMetrics_(#SM_CXEDGE),GadgetY(GetDlgCtrlID_(hwnd))+GetSystemMetrics_(#SM_CYEDGE),*fdata\col_0_width+GetSystemMetrics_(#SM_CXEDGE),buttonh)
If IsImage(*fdata\sizelin):FreeImage(*fdata\sizelin):EndIf
*fdata\sizelin = CreateImage(#PB_Any,3,GadgetHeight(GetDlgCtrlID_(hwnd)))
hdc = StartDrawing(ImageOutput(*fdata\sizelin))
Box(1,1,1,ImageHeight(*fdata\sizelin),#Gray)
SetRect_(imgrect.RECT,0,0,3,ImageHeight(*fdata\sizelin))
DrawFocusRect_(hdc,imgrect.RECT)
StopDrawing()
SetGadgetState(*fdata\col_0_line_g, ImageID(*fdata\sizelin))
SetGadgetState(*fdata\list_line_g, ImageID(*fdata\sizelin))
SetGadgetState(*fdata\button_0_line_g, ImageID(*fdata\sizelin))
InvalidateRect_(hwnd, 0,1)
EndSelect
ProcedureReturn CallWindowProc_(*fdata\listproc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure ButtonProc(hwnd, msg, wparam, lparam)
*fdata.FIXEDICONDATA = GetProp_(hwnd, "fdata")
Select msg
Case #WM_NCDESTROY
RemoveProp_(hwnd, "fdata")
Case #WM_MOUSELEAVE
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(*fdata\buttonimg))
RedrawWindow_(hwnd,0,0,#RDW_INVALIDATE|#RDW_UPDATENOW)
*fdata\mouseinbutton = #False
ProcedureReturn 0
Case #WM_LBUTTONDOWN
If lparam&$FFFF >= GadgetWidth(GetDlgCtrlID_(hwnd))-5
*fdata\resizing_col_0 = 1
SetCursor_( LoadCursor_(0, #IDC_SIZEWE ))
CallWindowProc_(*fdata\colimgproc, hwnd, msg, wparam, lparam)
SetCapture_(*fdata\listhwnd)
ProcedureReturn 0
Else
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(*fdata\button_pressedimg))
CallWindowProc_(*fdata\colimgproc, hwnd, msg, wparam, lparam)
SetCapture_(hwnd)
ProcedureReturn 0
EndIf
Case #WM_MOUSEMOVE
If Not *fdata\mouseinbutton
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(*fdata\button_hoverimg))
With tm.TRACKMOUSEEVENT
\cbSize = SizeOf(TRACKMOUSEEVENT)
\dwFlags = #TME_LEAVE
\hwndTrack = hwnd
EndWith
TrackMouseEvent_(@tm)
*fdata\mouseinbutton = #True
EndIf
If lparam&$FFFF >= GadgetWidth(GetDlgCtrlID_(hwnd))-5 And Not GetAsyncKeyState_(#VK_LBUTTON)&32768
SetCursor_( LoadCursor_(0, #IDC_SIZEWE ))
Else
If Not *fdata\resizing_col_0
SetCursor_( LoadCursor_(0, #IDC_ARROW ))
Else
ResizeGadget(*fdata\list_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
ResizeGadget(*fdata\button_0_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
HideGadget(*fdata\list_line_g,0)
HideGadget(*fdata\button_0_line_g,0)
HideGadget(*fdata\col_0_line_g,1)
EndIf
EndIf
Case #WM_LBUTTONUP
If *fdata\resizing_col_0
SendMessage_(*fdata\listhwnd, #WM_LBUTTONUP,wparam, lparam)
Else
ReleaseCapture_()
SetGadgetState(GetDlgCtrlID_(hwnd),ImageID(*fdata\buttonimg))
With *fdata\hdnotify
\iitem = 0
\hdr\hwndfrom = *fdata\header
\hdr\code = #HDN_ITEMCLICKW
EndWith
SendMessage_(*fdata\listhwnd, #WM_NOTIFY, 0, *fdata\hdnotify)
EndIf
Case #WM_SETCURSOR
If *fdata\resizing_col_0
SetCursor_(LoadCursor_(0, #IDC_SIZEWE))
ProcedureReturn 0
EndIf
EndSelect
ProcedureReturn CallWindowProc_(*fdata\buttonimgproc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure HeaderProc(hwnd, msg, wparam, lparam)
*fdata.FIXEDICONDATA = GetProp_(hwnd, "fdata")
Select msg
Case #WM_NCDESTROY
RemoveProp_(hwnd, "fdata")
Case #WM_LBUTTONUP
If *fdata\resizing_col_0
SendMessage_(*fdata\listhwnd, #WM_LBUTTONUP,wparam, lparam)
ProcedureReturn 0
EndIf
Case #WM_MOUSEMOVE
If *fdata\resizing_col_0
ResizeGadget(*fdata\col_0_line_g,lparam&$FFFF,#PB_Ignore,#PB_Ignore,#PB_Ignore)
HideGadget(*fdata\col_0_line_g,0)
HideGadget(*fdata\button_0_line_g,1)
HideGadget(*fdata\list_line_g,1)
ProcedureReturn 0
EndIf
Case #WM_SETCURSOR
If *fdata\resizing_col_0
SetCursor_(LoadCursor_(0, #IDC_SIZEWE))
ProcedureReturn 0
EndIf
GetCursorPos_(@cp.POINT)
ScreenToClient_(hwnd, cp)
SendMessage_(hwnd, #HDM_GETITEMRECT,0,@hr.RECT)
hr\right+20
If PtInRect_(hr,cp\x|cp\y<<32)
SetCursor_(LoadCursor_(0,#IDC_ARROW))
ProcedureReturn 0
EndIf
EndSelect
ProcedureReturn CallWindowProc_(*fdata\headerproc, hwnd, msg, wparam, lparam)
EndProcedure
ProcedureDLL FixedIconGadget(gadgetnumber,x,y,width,height,text$,colwidth,flags=0)
*fdata.FIXEDICONDATA = AllocateMemory(SizeOf(FIXEDICONDATA))
*fdata\themed = ThemesEnabled()
*fdata\scroll_height = GetSystemMetrics_(#SM_CYHSCROLL)
*fdata\col_0_width = colwidth
If gadgetnumber = #PB_Any
thisgadgetnumber = ListIconGadget(gadgetnumber,x,y,width,height,text$,colwidth,flags)
thisGadgetID = GadgetID(thisgadgetnumber)
retval = thisgadgetnumber
Else
thisgadgetnumber = gadgetnumber
thisGadgetID = ListIconGadget(gadgetnumber,x,y,width,height,text$,colwidth,flags)
retval = thisgadgetID
EndIf
*fdata\listhwnd = thisgadgetID
*fdata\lineH = SendMessage_(thisgadgetID,#LVM_GETITEMSPACING,#True,0)>>16
*fdata\header = SendMessage_(thisGadgetID,#LVM_GETHEADER,0,0)
SendMessage_(*fdata\header, #HDM_GETITEMRECT,0,@hr.RECT)
buttonh = hr\bottom
UpdateImages(*fdata)
hrgn1 = CreateRectRgn_(0,0,GadgetWidth(thisGadgetnumber),GadgetHeight(thisgadgetnumber))
hrgn2 = CreateRectRgn_(GetSystemMetrics_(#SM_CXEDGE),GetSystemMetrics_(#SM_CYEDGE),colwidth+GetSystemMetrics_(#SM_CYEDGE), GadgetHeight(thisgadgetnumber)-(*fdata\scroll_height+GetSystemMetrics_(#SM_CYEDGE)))
CombineRgn_(hrgn1, hrgn1, hrgn2, #RGN_XOR)
SetWindowRgn_(thisGadgetID, hrgn1, 1)
*fdata\colimg = CreateImage(#PB_Any,colwidth,GadgetHeight(thisgadgetnumber)-(buttonh+GetSystemMetrics_(#SM_CYEDGE)*2+*fdata\scroll_height),#PB_Image_DisplayFormat)
*fdata\buttonimg_g = ImageGadget(#PB_Any,GadgetX(thisgadgetnumber)+GetSystemMetrics_(#SM_CXEDGE), GadgetY(thisgadgetnumber)+GetSystemMetrics_(#SM_CYEDGE),*fdata\col_0_width+ GetSystemMetrics_(#SM_CXEDGE),buttonh,ImageID(*fdata\buttonimg))
*fdata\colimg_g = ImageGadget(#PB_Any,GadgetX(thisgadgetnumber)+GetSystemMetrics_(#SM_CXEDGE), buttonh+GadgetY(thisgadgetnumber)+GetSystemMetrics_(#SM_CYEDGE),*fdata\col_0_width,GadgetHeight(thisgadgetnumber)- (buttonh+*fdata\scroll_height+GetSystemMetrics_(#SM_CYEDGE)*2),0)
*fdata\listproc = SetWindowLong_(thisGadgetID,#GWL_WNDPROC,@ListProc())
*fdata\colimgproc = SetWindowLong_(GadgetID(*fdata\colimg_g),#GWL_WNDPROC,@ImageProc())
*fdata\headerproc = SetWindowLong_(*fdata\header,#GWL_WNDPROC,@HeaderProc())
*fdata\buttonimgproc = SetWindowLong_(GadgetID(*fdata\buttonimg_g),#GWL_WNDPROC,@ButtonProc())
SetProp_(thisgadgetid, "fdata", *fdata)
SetProp_(GadgetID(*fdata\colimg_g), "fdata", *fdata)
SetProp_(*fdata\header, "fdata", *fdata)
SetProp_(GadgetID(*fdata\buttonimg_g), "fdata", *fdata)
*fdata\sizelin = CreateImage(#PB_Any,3,GadgetHeight(thisgadgetnumber))
hdc = StartDrawing(ImageOutput(*fdata\sizelin))
Box(1,1,1,ImageHeight(*fdata\sizelin),#Gray)
SetRect_(imgrect.RECT,0,0,3,ImageHeight(*fdata\sizelin))
DrawFocusRect_(hdc,imgrect.RECT)
StopDrawing()
oldlist = UseGadgetList(thisgadgetid)
*fdata\col_0_line_g = ImageGadget(#PB_Any,*fdata\col_0_width+5,0,4,GadgetHeight(thisgadgetnumber),ImageID(*fdata\sizelin))
DisableGadget(*fdata\col_0_line_g,1)
HideGadget(*fdata\col_0_line_g,1)
UseGadgetList(GadgetID(*fdata\colimg_g))
*fdata\list_line_g = ImageGadget(#PB_Any,0,0,4,GadgetHeight(thisgadgetnumber),ImageID(*fdata\sizelin))
DisableGadget(*fdata\list_line_g,1)
HideGadget(*fdata\list_line_g,1)
UseGadgetList(GadgetID(*fdata\buttonimg_g))
*fdata\button_0_line_g = ImageGadget(#PB_Any,0,0,4,GadgetHeight(*fdata\buttonimg_g),ImageID(*fdata\sizelin))
DisableGadget(*fdata\button_0_line_g ,1)
HideGadget(*fdata\button_0_line_g ,1)
UseGadgetList(oldlist)
ProcedureReturn retval
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////////////////////////////
Code: Select all
Global old_proc
Procedure MyListProc(hwnd, msg, wparam, lparam)
Select msg
Case #WM_NOTIFY
*nmHEADER.HD_NOTIFY = lParam
Select *nmHEADER\hdr\code
Case #HDN_ITEMCLICKW
Debug "Column "+Str(*nmHEADER\iitem)+" button pressed"
EndSelect
EndSelect
ProcedureReturn CallWindowProc_(old_proc, hwnd, msg, wparam, lparam)
EndProcedure
OpenWindow(0,0,0,1024,768,"FixedIconGadget Test",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
List0 = FixedIconGadget(#PB_Any,10,10,600,300,"column 0", 140,#PB_ListIcon_FullRowSelect)
ResizeGadget(List0, 20,100,#PB_Ignore,600)
SetGadgetFont(List0, LoadFont(0, "Arial", 12) )
AddGadgetColumn(List0,1,"Column 1",100)
AddGadgetColumn(List0,2,"Column 2",100)
AddGadgetColumn(List0,3,"Column 3",100)
AddGadgetColumn(List0,4,"Column 4",100)
AddGadgetColumn(List0,5,"Column 5",100)
AddGadgetColumn(List0,6,"Column 6",100)
AddGadgetColumn(List0,7,"Column 7",100)
For i=0 To 100
AddGadgetItem(List0, -1, "Line "+Str(i)+" First gadget column 0"+Chr(10)+"Line "+Str(i)+" col 1"+Chr(10)+"Line "+Str(i)+" col 2"+Chr(10)+"Line "+Str(i)+" col 3"+Chr(10)+"Line "+Str(i)+" col 4"+Chr(10)+"Line "+Str(i)+" col 5"+Chr(10)+"Line "+Str(i)+" col 6"+Chr(10)+"Line "+Str(i)+" col 7")
Next
old_proc = SetWindowLong_(GadgetID(list0),#GWL_WNDPROC,@MyListProc())
ButtonGadget(0, 400,720,100,20,"Destroy")
Repeat
ev = WaitWindowEvent()
Select ev
Case #PB_Event_Gadget
If EventGadget()=0
FreeGadget(List0)
EndIf
EndSelect
Until ev = #PB_Event_CloseWindow