I want to have an editable listicongadget. One column in that listicongadget needs to contain a combobox dropdown gadget. I took the 2008 code from Srod and modified this a bit to suits my needs (see code snippet). This part works perfectly as far as direct editing is concerned.
Then I tried to implement comboboxes into this code. I used the 2005 code from Srod.
http://www.purebasic.fr/english/viewtop ... n+listicon
The problem is that this code is too old for the current PureBasic version as a couple of the commands don't work anymore. Also I don't have much (very little) experience in API programming so I really don't know what things to change and where.
Maybe someone could point me in the right direction?
John
Code: Select all
#HDI_ORDER                  = $80
#EC_RIGHTMARGIN             = 2
Structure _LIEdit
  listOldProc.i
  editHwnd.i
  item.i
  subitem.i
  x.i
  y.i
  cx.i
  cy.i
EndStructure
;Returns zero if an error.
Procedure.i SetListIconEditable(listID)
	Protected result, parenthWnd, *mem._LIEdit, hWnd, dlv.DLLVERSIONINFO, func, lib
	;Check that listID references a valid listicon.
	If IsGadget(listID) And GadgetType(listID)=#PB_GadgetType_ListIcon
		hWnd = GadgetID(listID)
		;Is the listicon already registered?
		If GetProp_(hWnd, "_LIEdit")=0 ;No!
			;Allocate enough memory for a _LIEdit structure.
			*mem=AllocateMemory(SizeOf(_LIEdit))
			If *mem
				SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE)&~#LVS_EDITLABELS)
				;Set the fields of the _LIEedit structure.
				*mem\listOldProc = SetWindowLong_(hWnd, #GWL_WNDPROC, @_LIEListProc())
				;Store a pointer to this structure in a window property ofthe listicon.          
				SetProp_(hWnd, "_LIEdit", *mem)
				;Subclass the parent window if not already through another listicon.
				parenthWnd=GetParent_(hWnd)
				If GetProp_(parenthWnd, "_LIEditOldProc")=0 ;No!
					SetProp_(parenthWnd, "_LIEditOldProc", SetWindowLong_(parenthWnd, #GWL_WNDPROC, @_LIEwinProc()))
				EndIf
				result=1
			EndIf
		EndIf
	EndIf
	ProcedureReturn result
EndProcedure
;Sets the specified cell to be edited.
Procedure EditCell(listID, item, subitem)
	Protected hWnd, *liedit._LIEdit, numrows, numcols
	;Check that listID references a valid listicon.
	If IsGadget(listID) And GadgetType(listID)=#PB_GadgetType_ListIcon
		;Check that the listicon is registered as editable.
		hWnd = GadgetID(listID)
		*liedit = GetProp_(hWnd, "_LIEdit")
		If *liedit
			;Check parameters are in range.
			numrows = CountGadgetItems(listID)
			numcols = SendMessage_(SendMessage_(hWnd,#LVM_GETHEADER,0,0), #HDM_GETITEMCOUNT,0,0)
			If item>=0 And item < numrows And subitem>0 And subitem < numcols
				*liedit\item = item
				*liedit\subitem = subitem
				SetActiveGadget(listID)
				_LIEEditCell(*liedit, hWnd)
			EndIf
		EndIf
	EndIf
EndProcedure
Procedure _LIEEditCell(*liedit._LIEdit, hWnd)
	Protected rc.RECT, clientrc.RECT, numCols, headerWnd
	Protected Dim cols.l(0), i, blnFoundZeroColumn
	Protected hdi.HDITEM
	;Scroll the listicon if the clicked cell is not entirely visible
	;*****IF YOU WISH TO RESTRICT WHICH CELLS CAN BE EDITED, THEN PERFORM THE NECESSARY CHECKS HERE
	;*****ON THE VALUES OF *liedit\item and *liedit\subitem (WHICH INDICATE WHICH CELL IS ABOUT
	;*****TO BE EDITED) AND RUN THE FOLLOWING LINES FOR THOSE CELLS WHICH ARE TO BE EDITED.
	rc\top = *liedit\subitem
	rc\left = #LVIR_BOUNDS
	SendMessage_(hWnd, #LVM_GETSUBITEMRECT, *liedit\item, rc)
	GetClientRect_(hWnd, clientrc)
	If rc\left < 0 Or (rc\right-rc\left)>=clientrc\right
		SendMessage_(hWnd, #LVM_SCROLL,rc\left,0) 
	Else
		If rc\right > clientrc\right
			SendMessage_(hWnd, #LVM_SCROLL,rc\right-clientrc\right,0) 
		EndIf
	EndIf
	SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE)|#LVS_EDITLABELS)
	SendMessage_(hWnd, #LVM_EDITLABEL, *liedit\item, 0)
EndProcedure
;New Procedure to implement ComboBox functionality
Procedure _LIEComboCell(*liedit._LIEdit, hWnd)
	; need some help with this part
EndProcedure
;Window proc of the ListIcon parent window.
Procedure.i _LIEwinProc(hWnd, uMsg, wParam, lParam)
	Protected result, oldwinproc, *nmh. NMHDR, listhWnd, edithWnd, *liedit._LIEdit, *lvd.LV_DISPINFO, rc.RECT
	Protected hdi.HDITEM, headerWnd
	Static celltext$
	;Retrieve the address of the old proc.
	oldwinproc = GetProp_(hWnd, "_LIEditOldProc")
	Select uMsg
		Case #WM_NOTIFY
			*nmh=lParam
			Select *nmh\code
				Case #LVN_BEGINLABELEDIT
					listhWnd = *nmh\hwndFrom
					;Retrieve the address of the LIEdit structure.
					*liedit = GetProp_(listhWnd, "_LIEdit")
					If *liedit ;Good to go!
						*liedit\editHwnd=0
						;Get the handle of the edit control used to edit the label.
						edithWnd = SendMessage_(listhWnd, #LVM_GETEDITCONTROL,0,0)
						;Subclass the edit control.
						SetProp_(edithWnd, "_LIEditOldProc", SetWindowLong_(edithWnd, #GWL_WNDPROC, @_LIEeditProc()))
						;Set text.
						celltext$=GetGadgetItemText(*nmh\idFrom, *liedit\item, *liedit\subitem)
						SendMessage_(edithWnd, #WM_SETTEXT, 0, celltext$)
						SetGadgetItemText(*nmh\idFrom, *liedit\item, "",*liedit\subitem)
						;Get bounding rectangle.
						rc\top = *liedit\subitem
						rc\left = #LVIR_BOUNDS 
						SendMessage_(listhWnd, #LVM_GETSUBITEMRECT, *liedit\item, rc) 
						*liedit\x=rc\left
						*liedit\y=rc\top
						*liedit\cx=SendMessage_(listhWnd, #LVM_GETCOLUMNWIDTH, *liedit\subitem,0)
						*liedit\cy=rc\bottom-rc\top
					EndIf
				Case #LVN_ENDLABELEDIT
					listhWnd = *nmh\hwndFrom
					;Retrieve the address of the LIEdit structure.
					*liedit = GetProp_(listhWnd, "_LIEdit")
					If *liedit ;Good to go!
						*lvd = lParam
						If *lvd\item\pszText
							SetGadgetItemText(*nmh\idFrom, *liedit\item, PeekS(*lvd\item\pszText), *liedit\subitem)
						Else              
							SetGadgetItemText(*nmh\idFrom, *liedit\item, celltext$, *liedit\subitem)
						EndIf
						SetWindowLong_(listhWnd, #GWL_STYLE, GetWindowLong_(listhWnd, #GWL_STYLE)&~#LVS_EDITLABELS)
						headerWnd = SendMessage_(listhWnd,#LVM_GETHEADER,0,0)
						SendMessage_(headerWnd, #HDM_SETITEM, 0, hdi) 
					EndIf
						; Insert new blank line
						If *liedit\item=CountGadgetItems(*nmh\idFrom)-1
							If Trim(GetGadgetItemText(*nmh\idFrom, *liedit\item, 1))+Trim(GetGadgetItemText(*nmh\idFrom, *liedit\item, 2))+Trim(GetGadgetItemText(*nmh\idFrom, *liedit\item, 3))<>""
								AddGadgetItem(*nmh\idFrom, -1, "")
							EndIf
						EndIf
				Default
					result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
			EndSelect
		Case #WM_NCDESTROY
			result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
			RemoveProp_(hWnd, "_LIEditOldProc")
		Default
			result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
	EndSelect
	ProcedureReturn result
EndProcedure
;Window proc of the ListIcon.
Procedure.i _LIEListProc(hWnd, uMsg, wParam, lParam)
	Protected result, *liedit._LIEdit, PInfo.LVHITTESTINFO, *nmHEADER.HD_NOTIFY
	;Retrieve the address of the LIEdit structure.
	*liedit = GetProp_(hWnd, "_LIEdit")
	Select uMsg
		Case #WM_NOTIFY
			*nmHEADER = lParam 
			Select *nmHEADER\hdr\code
					;Case #HDN_BEGINTRACK, #HDN_BEGINTRACKW ;Prevent column 0 from being resized.
					;  If *nmHEADER\iItem=0
					;    result=1
					;  EndIf
				Case #HDN_ENDTRACK, #HDN_ENDTRACKW
					InvalidateRect_(hWnd,0,1)
				Default
					result=CallWindowProc_(*liedit\listOldProc, hWnd, uMsg, wParam, lParam)
			EndSelect
		Case #WM_LBUTTONDBLCLK
			;Identify the clicked item
			PInfo\pt\x = lParam&$ffff 
			PInfo\pt\y = (lParam>>16)&$ffff 
			SendMessage_(hwnd, #LVM_SUBITEMHITTEST, 0, PInfo) 
			If PInfo\iItem <> -1 ;A valid cell was clicked.
				*liedit\item = PInfo\iItem
				*liedit\subitem = PInfo\iSubItem
				If PInfo\iSubItem=2 ; column 2 should be combobox
					_LIEComboCell(*liedit, hWnd)
				Else
					_LIEEditCell(*liedit, hWnd) ; all other columns can be edited directly
				EndIf
			EndIf
		Case #WM_NCDESTROY
			result=CallWindowProc_(*liedit\listOldProc, hWnd, uMsg, wParam, lParam)
			RemoveProp_(hWnd, "_LIEdit")
			FreeMemory(*liedit)
		Default
			result=CallWindowProc_(*liedit\listOldProc, hWnd, uMsg, wParam, lParam)
	EndSelect
	ProcedureReturn result
EndProcedure
;Window proc of the edit control.
Procedure.i _LIEeditProc(hWnd, uMsg, wParam, lParam)
	Protected result, oldwinproc, *liedit._LIEdit, *wpos.WINDOWPOS
	;Retrieve the address of the old proc.
	oldwinproc = GetProp_(hWnd, "_LIEditOldProc")
	;Retrieve the address of the LIEdit structure.
	*liedit = GetProp_(GetParent_(hWnd), "_LIEdit")
	Select uMsg
		Case #WM_ERASEBKGND
			;A hack in order to clear the default selection of characters.
			result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
			If *liedit\editHwnd=0
				*liedit\editHwnd = hWnd
				;Set margins.
				SendMessage_(hWnd, #EM_SETMARGINS, #EC_LEFTMARGIN|#EC_RIGHTMARGIN, 4)
				SendMessage_(hWnd, #EM_SETSEL, -1,0)
			EndIf
		Case #WM_WINDOWPOSCHANGING
			*wpos=lParam
			*wpos\cx=*liedit\cx ;Comment this line to get an edit control which grows with the text.
			*wpos\x=*liedit\x
			*wpos\cy=*liedit\cy
			*wpos\y=*liedit\y
			result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
		Case #WM_NCDESTROY
			result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
			RemoveProp_(hWnd, "_LIEditOldProc")
		Default
			result=CallWindowProc_(oldwinproc, hWnd, uMsg, wParam, lParam)
	EndSelect
	ProcedureReturn result
EndProcedure


