Page 1 of 1

ComboCheckList

Posted: Fri Jan 27, 2006 4:17 am
by localmotion34
Some said it couldnt be done...
Some said it was too hard...
Others said it was useless...
Localmotion34 was bothered by this problem...


So here it is COMBOCHECKLISTBOX. a combobox with the ability to check and uncheck items, and even use radio or pushbuttons in the combobox. the dafualt behavior is the checkbox, but you can comment out or use whatever combination of drawframecontrol you like.

HERE IS THE SECRET:

buried DEEP in the MSDN code is:

Structure comboboxinfo
cbSize.l
rcItem.RECT
rcButton.RECT
stateButton.l
hwndCombo.l
hwndEdit.l
hwndList.l
EndStructure

*combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo))
*combostruct\cbSize=SizeOf(comboboxinfo)
GetComboBoxInfo_(GadgetID(combo),*combostruct.comboboxinfo)

GETCOMBOBOXINFO returns the actual HANDLE of the combo's listbox!!!! hence you may SUBCLASS the listbox and do what you want. HMMM, think for this one i could get a bump up on the tickmarks of my name?? hmmmm........

here is the example:

Code: Select all

Enumeration
  #Window_0
EndEnumeration

Enumeration
  #Gadget_0
EndEnumeration
#DI_NORMAL = $0003

Structure combo
  State.l
  hwnd.l
  subclassed.l
EndStructure

Structure comboboxinfo
  cbSize.l
  rcItem.RECT
  rcButton.RECT
  stateButton.l
  hwndCombo.l
  hwndEdit.l
  hwndList.l
EndStructure

Procedure MakeLong1(low, high)
  ProcedureReturn low | high <<16
EndProcedure

#LB_ITEMFROMPOINT=$1A9

Procedure checkProc( hwnd, msg,wParam,lParam)
  *class.s=Space(255)
  cs=GetClassName_(hwnd,*class,Len(*class))
  If *class="ComboLBox"
    Select msg
      Case #WM_LBUTTONDOWN
        If wParam = #MK_LBUTTON
          xloc.w=lParam&$FFFF
          yloc.w = (lParam>>16)
          t = SendMessage_(hwnd, #LB_ITEMFROMPOINT, 0, MakeLong1(xloc,yloc))
          y=SendMessage_(hwnd, #LB_GETITEMRECT, t, @rct.RECT)
          rct\left=2
          rct\right=15
          If PtInRect_(rct, xloc, yloc)
            *combostruct.comboboxinfo=GetProp_(hwnd,"LBinfo")
            State=SendMessage_(*combostruct\hwndCombo, #CB_GETITEMDATA, t, 0)
            If State=0
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 1)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd )
            ElseIf State=1
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 0)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd)
            EndIf
          EndIf
        EndIf
        ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
    EndSelect
  EndIf
    ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
  EndProcedure
 
  Procedure WindowCallback(WindowID, message, wParam, lParam)
    Result = #PB_ProcessPureBasicEvents
    Select message
      Case #WM_DRAWITEM
        *DrawItem.DRAWITEMSTRUCT = lParam
        listhwnd=WindowFromDC_(*DrawItem\hdc)
        If *DrawItem\CtlType = #ODT_COMBOBOX
          SetBkMode_(*DrawItem\hdc, #TRANSPARENT) ; Text is rendered transparent
          If *DrawItem\itemState & #ODS_FOCUS
            Brush = CreateSolidBrush_($FFEEFF)
            FillRect_(*DrawItem\hdc, *DrawItem\rcItem, Brush)
            DeleteObject_(Brush)
            SetTextColor_(*DrawItem\hdc, $FF)
          Else
            FillRect_(*DrawItem\hdc, *DrawItem\rcItem, GetStockObject_(#WHITE_BRUSH))
          EndIf
          If *DrawItem\itemID <> -1
            Text$ = Space(512)
            SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT, *DrawItem\itemID, @Text$)
            TextOut_   (*DrawItem\hdc, *DrawItem\rcItem\left+2+20, *DrawItem\rcItem\top+1, Text$, Len(Text$))
            *DrawItem\rcItem\left   = 2 : *DrawItem\rcItem\right = 15                   
            *DrawItem\rcItem\top + 2
            *DrawItem\rcItem\bottom - 1
            State=SendMessage_(*DrawItem\hwndItem, #CB_GETITEMDATA, *DrawItem\itemID, 0)
            If State=0
              DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONRADIO)
              ElseIf State=1
              DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK|#DFCS_CHECKED)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH   |#DFCS_CHECKED)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONRADIO|#DFCS_CHECKED)
              EndIf
          EndIf
        EndIf
    EndSelect
    ProcedureReturn Result
  EndProcedure
 
Procedure Open_Window_0()
  If OpenWindow(#Window_0, 0, 0, 400, 100, "New window ( 0 )", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_TitleBar)
    If CreateGadgetList(WindowID(#Window_0))
      ComboBoxGadget(#Gadget_0, 60, 40, 330, 200,  #CBS_OWNERDRAWFIXED)
      *combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo))
      *combostruct\cbSize=SizeOf(comboboxinfo)
      GetComboBoxInfo_(GadgetID(#Gadget_0),*combostruct.comboboxinfo)
      SetProp_(*combostruct\hwndList,"OldProc4",SetWindowLong_(*combostruct\hwndList, #GWL_WNDPROC, @checkProc()))
      SetProp_(*combostruct\hwndList,"LBinfo",*combostruct.comboboxinfo)
    EndIf
  EndIf
EndProcedure

Open_Window_0()

SetWindowCallback(@WindowCallback())

AddGadgetItem(#Gadget_0, -1, "Test1")
AddGadgetItem(#Gadget_0, -1, "Test2")
AddGadgetItem(#Gadget_0, -1, "Test3")
 
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

End

Posted: Fri Jan 27, 2006 7:41 am
by Fangbeast
Message: #LB_ITEMFROMPOINT "Constant not found"

Might be a few others there too that aren't declared. Don't have time right now to hunt.

Posted: Fri Jan 27, 2006 8:22 am
by einander
Thanks Localmotion!

Code: Select all

#LB_ITEMFROMPOINT=$1A9

Posted: Fri Jan 27, 2006 7:57 pm
by srod
Nice bit of code there localmotion34. Always wondered what window properties could be used for. Nice.

Posted: Fri Jan 27, 2006 10:16 pm
by techjunkie
Cool! Nice work! :D

Posted: Sun Jul 26, 2009 7:19 pm
by Poshu
RAISE FROM YOUR GRAVE, OLD TOPIC!

Hum, trying to make this work, I ended up with this:

Code: Select all

Enumeration
  #Window_0
  #Gadget_0
EndEnumeration
#DI_NORMAL = $0003
#LB_ITEMFROMPOINT=$1A9

Structure comboboxinfo
  cbSize.l
  rcItem.RECT
  rcButton.RECT
  stateButton.l
  hwndCombo.l
  hwndEdit.l
  hwndList.l
EndStructure

Procedure checkProc( hwnd, msg,wParam,lParam)
  rct.RECT
  *class.s=Space(255)
  cs=GetClassName_(hwnd,*class,Len(*class))
  If *class="ComboLBox"
    Select msg
      Case #WM_LBUTTONDOWN
        If wParam = #MK_LBUTTON
          xloc.w=lParam&$FFFF
          yloc.w = lParam>>16
          ;Debug xloc
          ;Debug yloc
          rct\left=2
          rct\right=15
          ;-This is the incriminated line------------------------
          t = SendMessage_(hwnd, #LB_ITEMFROMPOINT, 0, xloc|yloc)
          ;------------------------------------------------------
          y = SendMessage_(hwnd, #LB_GETITEMRECT, #Null, @rct)
          If PtInRect_(rct, xloc | yloc)
            *combostruct.comboboxinfo=GetProp_(hwnd,"LBinfo")
            State=SendMessage_(*combostruct\hwndCombo, #CB_GETITEMDATA, t, 0)
            If State=0
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 1)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd )
            ElseIf State=1
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 0)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd)
            EndIf
          EndIf
        EndIf
        ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
    EndSelect
  EndIf
  ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
EndProcedure
 
Procedure WindowCallback(WindowID, message, wParam, lParam)
  Select message
    Case #WM_DRAWITEM
      *DrawItem.DRAWITEMSTRUCT = lParam
      listhwnd=WindowFromDC_(*DrawItem\hdc)
      If *DrawItem\CtlType = #ODT_COMBOBOX
        SetBkMode_(*DrawItem\hdc, #TRANSPARENT) ; Text is rendered transparent
        If *DrawItem\itemState & #ODS_FOCUS
          Brush = CreateSolidBrush_($FFEEFF)
          FillRect_(*DrawItem\hdc, *DrawItem\rcItem, Brush)
          DeleteObject_(Brush)
          SetTextColor_(*DrawItem\hdc, $FF)
        Else
          FillRect_(*DrawItem\hdc, *DrawItem\rcItem, GetStockObject_(#WHITE_BRUSH))
        EndIf
        ;Debug *DrawItem\itemID
        If *DrawItem\itemID <> -1
          Text$ = Space(512)
          SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT, *DrawItem\itemID, @Text$)
          TextOut_   (*DrawItem\hdc, *DrawItem\rcItem\left+2+20, *DrawItem\rcItem\top+1, Text$, Len(Text$))
          *DrawItem\rcItem\left   = 2 : *DrawItem\rcItem\right = 15                   
          *DrawItem\rcItem\top + 2
          *DrawItem\rcItem\bottom - 1
          State=SendMessage_(*DrawItem\hwndItem, #CB_GETITEMDATA, *DrawItem\itemID, #Null)
          If State=0
            DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK)
            ;DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH)
            ;DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONRADIO)
          ElseIf State=1
            DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK|#DFCS_CHECKED)
            ;DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH   |#DFCS_CHECKED)
            ;DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONRADIO|#DFCS_CHECKED)
          EndIf
        EndIf
      EndIf
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
 
OpenWindow(#Window_0, 0, 0, 400, 100, "New window ( 0 )", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_TitleBar)
ComboBoxGadget(#Gadget_0, 60, 40, 330, 20,  #CBS_OWNERDRAWFIXED)
*combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo))
*combostruct\cbSize=SizeOf(comboboxinfo)
GetComboBoxInfo_(GadgetID(#Gadget_0),*combostruct.comboboxinfo)
SetProp_(*combostruct\hwndList,"OldProc4",SetWindowLong_(*combostruct\hwndList, #GWL_WNDPROC, @checkProc()))
SetProp_(*combostruct\hwndList,"LBinfo",*combostruct.comboboxinfo)

SetWindowCallback(@WindowCallback())

AddGadgetItem(#Gadget_0, -1, "Test1")
AddGadgetItem(#Gadget_0, -1, "Test2")
AddGadgetItem(#Gadget_0, -1, "Test3")

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
    Case #PB_Event_Gadget
  EndSelect
ForEver

End
Obviously line 33 always return "0", so the only item I can check is the first one, and since I'm not familiar with Windows API, I can't get what is wrong (MSDN wasn't much of a help on this one)... Can anyone solve this please?

Posted: Sun Jul 26, 2009 8:09 pm
by Arctic Fox
Note the lines 41 and 45.

Code: Select all

Enumeration
  #Window_0
EndEnumeration

Enumeration
  #Gadget_0
EndEnumeration
#DI_NORMAL = $0003

Structure combo
  State.l
  hwnd.l
  subclassed.l
EndStructure

Structure comboboxinfo
  cbSize.l
  rcItem.RECT
  rcButton.RECT
  stateButton.l
  hwndCombo.l
  hwndEdit.l
  hwndList.l
EndStructure

Procedure MakeLong1(low, high)
  ProcedureReturn low | high <<16
EndProcedure

#LB_ITEMFROMPOINT=$1A9

Procedure checkProc( hwnd, msg,wParam,lParam)
  *class.s=Space(255)
  cs=GetClassName_(hwnd,*class,Len(*class))
  If *class="ComboLBox"
    Select msg
      Case #WM_LBUTTONDOWN
        If wParam = #MK_LBUTTON
          xloc.w=lParam&$FFFF
          yloc.w = (lParam>>16)
          t = SendMessage_(hwnd, #LB_ITEMFROMPOINT, 0, MakeLong1(xloc,yloc))
          y=SendMessage_(hwnd, #LB_GETITEMRECT, t, @rct.RECT)
          rct\left=2
          rct\right=15
          If PtInRect_(rct, yloc << 32 + xloc)
            *combostruct.comboboxinfo=GetProp_(hwnd,"LBinfo")
            State=SendMessage_(*combostruct\hwndCombo, #CB_GETITEMDATA, t, 0)
            If State=0
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 1)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd )
            ElseIf State=1
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 0)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd)
            EndIf
          EndIf
        EndIf
        ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
    EndSelect
  EndIf
    ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
  EndProcedure
 
  Procedure WindowCallback(WindowID, message, wParam, lParam)
    Result = #PB_ProcessPureBasicEvents
    Select message
      Case #WM_DRAWITEM
        *DrawItem.DRAWITEMSTRUCT = lParam
        listhwnd=WindowFromDC_(*DrawItem\hdc)
        If *DrawItem\CtlType = #ODT_COMBOBOX
          SetBkMode_(*DrawItem\hdc, #TRANSPARENT) ; Text is rendered transparent
          If *DrawItem\itemState & #ODS_FOCUS
            Brush = CreateSolidBrush_($FFEEFF)
            FillRect_(*DrawItem\hdc, *DrawItem\rcItem, Brush)
            DeleteObject_(Brush)
            SetTextColor_(*DrawItem\hdc, $FF)
          Else
            FillRect_(*DrawItem\hdc, *DrawItem\rcItem, GetStockObject_(#WHITE_BRUSH))
          EndIf
          If *DrawItem\itemID <> -1
            Text$ = Space(512)
            SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT, *DrawItem\itemID, @Text$)
            TextOut_   (*DrawItem\hdc, *DrawItem\rcItem\left+2+20, *DrawItem\rcItem\top+1, Text$, Len(Text$))
            *DrawItem\rcItem\left   = 2 : *DrawItem\rcItem\right = 15                   
            *DrawItem\rcItem\top + 2
            *DrawItem\rcItem\bottom - 1
            State=SendMessage_(*DrawItem\hwndItem, #CB_GETITEMDATA, *DrawItem\itemID, 0)
            If State=0
              DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONRADIO)
              ElseIf State=1
              DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK|#DFCS_CHECKED)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH   |#DFCS_CHECKED)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONRADIO|#DFCS_CHECKED)
              EndIf
          EndIf
        EndIf
    EndSelect
    ProcedureReturn Result
  EndProcedure
 
Procedure Open_Window_0()
  If OpenWindow(#Window_0, 0, 0, 400, 100, "New window ( 0 )", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_TitleBar)
    If CreateGadgetList(WindowID(#Window_0))
      ComboBoxGadget(#Gadget_0, 60, 40, 330, 20,  #CBS_OWNERDRAWFIXED)
      *combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo))
      *combostruct\cbSize=SizeOf(comboboxinfo)
      GetComboBoxInfo_(GadgetID(#Gadget_0),*combostruct.comboboxinfo)
      SetProp_(*combostruct\hwndList,"OldProc4",SetWindowLong_(*combostruct\hwndList, #GWL_WNDPROC, @checkProc()))
      SetProp_(*combostruct\hwndList,"LBinfo",*combostruct.comboboxinfo)
    EndIf
  EndIf
EndProcedure

Open_Window_0()

SetWindowCallback(@WindowCallback())

AddGadgetItem(#Gadget_0, -1, "Test1")
AddGadgetItem(#Gadget_0, -1, "Test2")
AddGadgetItem(#Gadget_0, -1, "Test3")
 
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

End

Posted: Sun Jul 26, 2009 8:43 pm
by Poshu
Hm... As always, I was sooooo wrong >.<;

By the way, is there any technique to make the combo gadget stand still when you check a box? It would allow user to check several boxes without opening the combo gadget again and again.

Posted: Sun Jul 26, 2009 8:49 pm
by Arctic Fox
This seems to work - but I don't know if this is the right way of doing it (you need to contact the 'experts' :wink:)

Code: Select all

Enumeration
  #Window_0
EndEnumeration

Enumeration
  #Gadget_0
EndEnumeration
#DI_NORMAL = $0003

Structure combo
  State.l
  hwnd.l
  subclassed.l
EndStructure

Structure comboboxinfo
  cbSize.l
  rcItem.RECT
  rcButton.RECT
  stateButton.l
  hwndCombo.l
  hwndEdit.l
  hwndList.l
EndStructure

Procedure MakeLong1(low, high)
  ProcedureReturn low | high <<16
EndProcedure

#LB_ITEMFROMPOINT=$1A9

Procedure checkProc( hwnd, msg,wParam,lParam)
  *class.s=Space(255)
  cs=GetClassName_(hwnd,*class,Len(*class))
  If *class="ComboLBox"
    Select msg
      Case #WM_LBUTTONDOWN
        If wParam = #MK_LBUTTON
          xloc.w=lParam&$FFFF
          yloc.w = (lParam>>16)
          t = SendMessage_(hwnd, #LB_ITEMFROMPOINT, 0, MakeLong1(xloc,yloc))
          y=SendMessage_(hwnd, #LB_GETITEMRECT, t, @rct.RECT)
          rct\left=2
          rct\right=15
          If PtInRect_(rct, yloc << 32 + xloc)
            *combostruct.comboboxinfo=GetProp_(hwnd,"LBinfo")
            State=SendMessage_(*combostruct\hwndCombo, #CB_GETITEMDATA, t, 0)
            If State=0
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 1)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd )
            ElseIf State=1
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 0)
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd)
            EndIf
          Else
            ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
          EndIf
        EndIf
        
      Default
        ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam)
    EndSelect
  EndIf
EndProcedure
 
  Procedure WindowCallback(WindowID, message, wParam, lParam)
    Result = #PB_ProcessPureBasicEvents
    Select message
      Case #WM_DRAWITEM
        *DrawItem.DRAWITEMSTRUCT = lParam
        listhwnd=WindowFromDC_(*DrawItem\hdc)
        If *DrawItem\CtlType = #ODT_COMBOBOX
          SetBkMode_(*DrawItem\hdc, #TRANSPARENT) ; Text is rendered transparent
          If *DrawItem\itemState & #ODS_FOCUS
            Brush = CreateSolidBrush_($FFEEFF)
            FillRect_(*DrawItem\hdc, *DrawItem\rcItem, Brush)
            DeleteObject_(Brush)
            SetTextColor_(*DrawItem\hdc, $FF)
          Else
            FillRect_(*DrawItem\hdc, *DrawItem\rcItem, GetStockObject_(#WHITE_BRUSH))
          EndIf
          If *DrawItem\itemID <> -1
            Text$ = Space(512)
            SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT, *DrawItem\itemID, @Text$)
            TextOut_   (*DrawItem\hdc, *DrawItem\rcItem\left+2+20, *DrawItem\rcItem\top+1, Text$, Len(Text$))
            *DrawItem\rcItem\left   = 2 : *DrawItem\rcItem\right = 15                   
            *DrawItem\rcItem\top + 2
            *DrawItem\rcItem\bottom - 1
            State=SendMessage_(*DrawItem\hwndItem, #CB_GETITEMDATA, *DrawItem\itemID, 0)
            If State=0
              DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONRADIO)
              ElseIf State=1
              DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK|#DFCS_CHECKED)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH   |#DFCS_CHECKED)
              ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONRADIO|#DFCS_CHECKED)
              EndIf
          EndIf
        EndIf
    EndSelect
    ProcedureReturn Result
  EndProcedure
 
Procedure Open_Window_0()
  If OpenWindow(#Window_0, 0, 0, 400, 100, "New window ( 0 )", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_TitleBar)
    If CreateGadgetList(WindowID(#Window_0))
      ComboBoxGadget(#Gadget_0, 60, 40, 330, 20,  #CBS_OWNERDRAWFIXED)
      *combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo))
      *combostruct\cbSize=SizeOf(comboboxinfo)
      GetComboBoxInfo_(GadgetID(#Gadget_0),*combostruct.comboboxinfo)
      SetProp_(*combostruct\hwndList,"OldProc4",SetWindowLong_(*combostruct\hwndList, #GWL_WNDPROC, @checkProc()))
      SetProp_(*combostruct\hwndList,"LBinfo",*combostruct.comboboxinfo)
    EndIf
  EndIf
EndProcedure

Open_Window_0()

SetWindowCallback(@WindowCallback())

AddGadgetItem(#Gadget_0, -1, "Test1")
AddGadgetItem(#Gadget_0, -1, "Test2")
AddGadgetItem(#Gadget_0, -1, "Test3")
 
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

End

Posted: Sun Jul 26, 2009 9:03 pm
by Poshu
It works nicely here, so it's good enough for me. Thanks a lot.

Posted: Sun Jul 26, 2009 9:53 pm
by akj
The program contains the line

Code: Select all

*combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo)) 
I would have thought this allocated heap space would need to be subsequently freed, or am I wrong?

Also, what is the advantage of using HeapAlloc_() rather than the PB intrinsic function AllocateMemory() ?

Posted: Thu Aug 13, 2009 11:13 am
by endo
very nice code! thanks a lot.

Posted: Thu Aug 13, 2009 11:39 am
by gnozal
akj wrote:The program contains the line

Code: Select all

*combostruct.comboboxinfo=HeapAlloc_(GetProcessHeap_(), 0, SizeOf(comboboxinfo)) 
I would have thought this allocated heap space would need to be subsequently freed, or am I wrong?

Also, what is the advantage of using HeapAlloc_() rather than the PB intrinsic function AllocateMemory() ?
Imho none.
Iirc, AllocateMemory is a wrapper for HeapAlloc_()

I would free the memory and remove the props in checkProc().

Code: Select all

Enumeration 
  #Window_0 
EndEnumeration 

Enumeration 
  #Gadget_0 
EndEnumeration 
#DI_NORMAL = $0003 

Structure combo 
  state.l 
  hwnd.l 
  subclassed.l 
EndStructure 

Structure comboboxinfo 
  cbSize.l 
  rcItem.RECT 
  rcButton.RECT 
  stateButton.l 
  hwndCombo.l 
  hwndEdit.l 
  hwndList.l 
EndStructure 

Procedure MakeLong1(low, high) 
  ProcedureReturn low | high <<16 
EndProcedure 

#LB_ITEMFROMPOINT=$1A9 

Procedure checkProc( hwnd, msg,wParam,lParam) 
  *class.s=Space(255) 
  cs=GetClassName_(hwnd,*class,Len(*class)) 
  If *class="ComboLBox" 
    Select msg 
      Case #WM_LBUTTONDOWN 
        If wParam = #MK_LBUTTON 
          xloc.w=lParam&$FFFF 
          yloc.w = (lParam>>16) 
          t = SendMessage_(hwnd, #LB_ITEMFROMPOINT, 0, MakeLong1(xloc,yloc)) 
          y = SendMessage_(hwnd, #LB_GETITEMRECT, t, @rct.RECT) 
          rct\left=2 
          rct\right=15 
          If PtInRect_(rct, yloc << 32 + xloc) 
            *combostruct.comboboxinfo=GetProp_(hwnd,"LBinfo") 
            state=SendMessage_(*combostruct\hwndCombo, #CB_GETITEMDATA, t, 0) 
            If state=0 
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 1) 
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd ) 
            ElseIf state=1 
              SendMessage_(*combostruct\hwndCombo, #CB_SETITEMDATA, t, 0) 
              InvalidateRect_(hwnd, rct, 0): UpdateWindow_(hwnd) 
            EndIf 
          Else 
            ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam) 
          EndIf 
        EndIf 
      Case #WM_NCDESTROY
        *combostruct=GetProp_(hwnd,"LBinfo") 
        If *combostruct
          FreeMemory(*combostruct)
        EndIf
        RemoveProp_(hwnd,"LBinfo")
        RemoveProp_(hwnd,"oldproc4")
      Default 
        ProcedureReturn CallWindowProc_(GetProp_(hwnd,"oldproc4"),hwnd,msg,wParam,lParam) 
    EndSelect 
  EndIf 
EndProcedure 
  
Procedure WindowCallback(WindowID, message, wParam, lParam) 
  Result = #PB_ProcessPureBasicEvents 
  Select message 
    Case #WM_DRAWITEM 
      *DrawItem.DRAWITEMSTRUCT = lParam 
      listhwnd=WindowFromDC_(*DrawItem\hdc) 
      If *DrawItem\CtlType = #ODT_COMBOBOX 
        SetBkMode_(*DrawItem\hdc, #TRANSPARENT) ; Text is rendered transparent 
        If *DrawItem\itemState & #ODS_FOCUS 
          Brush = CreateSolidBrush_($FFEEFF) 
          FillRect_(*DrawItem\hdc, *DrawItem\rcItem, Brush) 
          DeleteObject_(Brush) 
          SetTextColor_(*DrawItem\hdc, $FF) 
        Else 
          FillRect_(*DrawItem\hdc, *DrawItem\rcItem, GetStockObject_(#WHITE_BRUSH)) 
        EndIf 
        If *DrawItem\itemID <> -1 
          Text$ = Space(512) 
          SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT, *DrawItem\itemID, @Text$) 
          TextOut_(*DrawItem\hdc, *DrawItem\rcItem\left+2+20, *DrawItem\rcItem\top+1, Text$, Len(Text$)) 
          *DrawItem\rcItem\left   = 2 : *DrawItem\rcItem\right = 15                    
          *DrawItem\rcItem\top + 2 
          *DrawItem\rcItem\bottom - 1 
          state=SendMessage_(*DrawItem\hwndItem, #CB_GETITEMDATA, *DrawItem\itemID, 0) 
          If state=0 
            DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK) 
            ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH) 
            ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONRADIO) 
          ElseIf state=1 
            DrawFrameControl_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONCHECK|#DFCS_CHECKED) 
            ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON, #DFCS_BUTTONPUSH   |#DFCS_CHECKED) 
            ;drawframecontrol_(*DrawItem\hdc,*DrawItem\rcItem,#DFC_BUTTON,#DFCS_BUTTONRADIO|#DFCS_CHECKED) 
          EndIf 
        EndIf 
      EndIf 
  EndSelect 
  ProcedureReturn Result 
EndProcedure 
  
Procedure Open_Window_0() 
  If OpenWindow(#Window_0, 0, 0, 400, 100, "Checkbox ComboBox", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_TitleBar) 
    ComboBoxGadget(#Gadget_0, 60, 40, 330, 20,  #CBS_OWNERDRAWFIXED) 
    *combostruct.comboboxinfo=AllocateMemory(SizeOf(comboboxinfo)) 
    *combostruct\cbSize=SizeOf(comboboxinfo) 
    GetComboBoxInfo_(GadgetID(#Gadget_0),*combostruct.comboboxinfo) 
    SetProp_(*combostruct\hwndList,"OldProc4",SetWindowLong_(*combostruct\hwndList, #GWL_WNDPROC, @checkProc())) 
    SetProp_(*combostruct\hwndList,"LBinfo",*combostruct.comboboxinfo) 
  EndIf 
EndProcedure 

Open_Window_0() 

SetWindowCallback(@WindowCallback()) 

AddGadgetItem(#Gadget_0, -1, "Test1") 
AddGadgetItem(#Gadget_0, -1, "Test2") 
AddGadgetItem(#Gadget_0, -1, "Test3") 
SetGadgetState(#Gadget_0, 0)
  
Repeat 
Until WaitWindowEvent() = #PB_Event_CloseWindow 

End