Updated version with few bugs fixed (drawing, PgUp/PgDn, multiple CB support).
Code: Select all
Structure MyCB
oldProc.i
prevItm.i
lastKey.i
EndStructure
wc.WNDCLASSEX\cbSize = SizeOf(WNDCLASSEX)
GetClassInfoEx_(GetModuleHandle_(0), @"ComboBox", @wc)
Global *TmpCB.MyCB, *Text=AllocateMemory(128), CBCB = wc\lpfnWndProc
Procedure ComboProc(hWnd, uMsg, wParam, lParam)
*TmpCB = GetProp_(hWnd, "MyCB")
If *TmpCB
oldProc = *TmpCB\oldProc
Else
oldProc = CBCB;#WM_DELETEITEM
EndIf
Select uMsg
Case #WM_KEYDOWN
*TmpCB\lastKey = wParam
Case #WM_NCDESTROY
RemoveProp_(hWnd, "MyCB")
FreeMemory(*TmpCB)
EndSelect
ProcedureReturn CallWindowProc_(oldProc, hWnd, uMsg, wParam, lParam)
EndProcedure
Procedure WinCallback(hWnd, uMsg, wParam, lParam)
Select uMsg
Case #WM_DRAWITEM
*lpdis.DRAWITEMSTRUCT = lParam
SetBkMode_(*lpdis\hDC, #TRANSPARENT)
If *lpdis\CtlType = #ODT_COMBOBOX
If *lpdis\itemState & #ODS_SELECTED
If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETITEMDATA, *lpdis\itemID, 0) And *lpdis\itemID > -1
*lpdis\CtlType = GetSysColorBrush_(#COLOR_BTNFACE)
Else
*lpdis\CtlType = GetSysColorBrush_(#COLOR_HIGHLIGHT)
EndIf
Else
*lpdis\CtlType = GetSysColorBrush_(#COLOR_WINDOW)
EndIf
FillRect_(*lpdis\hDC, *lpdis\rcItem, *lpdis\CtlType)
*lpdis\rcItem\left+4
If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETLBTEXT, *lpdis\itemID, *Text) > -1
If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETITEMDATA, *lpdis\itemID, 0);SendMessage_()
SetTextColor_(*lpdis\hDC, #Gray);GetSysColor_(#COLOR_GRAYTEXT)
EndIf
DrawText_(*lpdis\hDC, *Text, -1, *lpdis\rcItem, #DT_NOCLIP|#DT_VCENTER|#DT_SINGLELINE)
SetTextColor_(*lpdis\hDC, GetSysColor_(#COLOR_WINDOWTEXT))
EndIf
EndIf
Case #WM_COMMAND
*TmpCB = GetProp_(lParam, "MyCB"); it should be checked if pointer isn't NULL (too lazy for that)
Select (wParam>>16) & $FFFF;HIWORD
Case #CBN_SELCHANGE
Var = CallWindowProc_(CBCB, lParam, #CB_GETCURSEL, 0, 0);SendMessage_()
If Var <> *TmpCB\prevItm
If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, Var, 0);SendMessage_()
If *TmpCB\lastKey = 38 Or *TmpCB\lastKey = 37;Up
For i=Var-1 To 0 Step -1
If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
*TmpCB\prevItm = i : Break
EndIf
Next
ElseIf *TmpCB\lastKey = 40 Or *TmpCB\lastKey = 39;Down
For i=Var+1 To CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1
If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
*TmpCB\prevItm = i : Break
EndIf
Next
ElseIf *TmpCB\lastKey = 33;PgUp
For i=0 To CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1
If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
*TmpCB\prevItm = i : Break
EndIf
Next
ElseIf *TmpCB\lastKey = 34;PgDn
For i=CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1 To 0 Step -1
If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
*TmpCB\prevItm = i : Break
EndIf
Next
EndIf
CallWindowProc_(CBCB, lParam, #CB_SETCURSEL, *TmpCB\prevItm, 0);SendMessage_()
Else
*TmpCB\prevItm = Var
EndIf
EndIf
Case #CBN_DROPDOWN
*TmpCB\lastKey = 0
EndSelect
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
Procedure MakeMyCB(ID)
*TmpCB = AllocateMemory(SizeOf(MyCB))
*TmpCB\prevItm = SendMessage_(GadgetID(ID), #CB_GETCURSEL, 0, 0)
*TmpCB\oldProc = SetWindowLongPtr_(GadgetID(ID), #GWL_WNDPROC, @ComboProc())
SetProp_(GadgetID(ID), "MyCB", *TmpCB)
EndProcedure
OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(1, 10, 40, 250, 21, #CBS_OWNERDRAWFIXED|#CBS_HASSTRINGS)
ComboBoxGadget(2, 10, 70, 250, 21, #CBS_OWNERDRAWFIXED|#CBS_HASSTRINGS)
For i = 1 To 10
AddGadgetItem(1, -1, "ComboBox A Item " + Str(i))
AddGadgetItem(2, -1, "ComboBox B Item " + Str(i))
Next
MakeMyCB(1)
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 3, #True);DISABLE ITEM
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 4, #True);DISABLE ITEM
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 9, #True);DISABLE ITEM
MakeMyCB(2)
SendMessage_(GadgetID(2), #CB_SETITEMDATA, 2, #True);DISABLE ITEM
SendMessage_(GadgetID(2), #CB_SETITEMDATA, 6, #True);DISABLE ITEM
SendMessage_(GadgetID(2), #CB_SETITEMDATA, 7, #True);DISABLE ITEM
SetWindowCallback(@WinCallback(), 0)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver