ComboCheckList

Share your advanced PureBasic knowledge/code with the community.
localmotion34
Enthusiast
Enthusiast
Posts: 665
Joined: Fri Sep 12, 2003 10:40 pm
Location: Tallahassee, Florida

ComboCheckList

Post 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

Code: Select all

!.WHILE status != dwPassedOut
! Invoke AllocateDrink, dwBeerAmount
!MOV Mug, Beer
!Invoke Drink, Mug, dwBeerAmount
!.endw
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4749
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Post 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.
Amateur Radio, D-STAR/VK3HAF
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

Thanks Localmotion!

Code: Select all

#LB_ITEMFROMPOINT=$1A9
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Nice bit of code there localmotion34. Always wondered what window properties could be used for. Nice.
I may look like a mule, but I'm not a complete ass.
techjunkie
Addict
Addict
Posts: 1126
Joined: Wed Oct 15, 2003 12:40 am
Location: Sweden
Contact:

Post by techjunkie »

Cool! Nice work! :D
Image
(\__/)
(='.'=) This is Bunny. Copy and paste Bunny into your
(")_(") signature to help him gain world domination.
Poshu
Enthusiast
Enthusiast
Posts: 459
Joined: Tue Jan 25, 2005 7:01 pm
Location: Canada

Post 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?
User avatar
Arctic Fox
Enthusiast
Enthusiast
Posts: 609
Joined: Sun Dec 21, 2008 5:02 pm
Location: Aarhus, Denmark

Post 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
Poshu
Enthusiast
Enthusiast
Posts: 459
Joined: Tue Jan 25, 2005 7:01 pm
Location: Canada

Post 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.
User avatar
Arctic Fox
Enthusiast
Enthusiast
Posts: 609
Joined: Sun Dec 21, 2008 5:02 pm
Location: Aarhus, Denmark

Post 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
Poshu
Enthusiast
Enthusiast
Posts: 459
Joined: Tue Jan 25, 2005 7:01 pm
Location: Canada

Post by Poshu »

It works nicely here, so it's good enough for me. Thanks a lot.
akj
Enthusiast
Enthusiast
Posts: 665
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post 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() ?
Anthony Jordan
endo
Enthusiast
Enthusiast
Posts: 140
Joined: Fri Apr 30, 2004 10:44 pm
Location: Turkiye (istanbul)
Contact:

Post by endo »

very nice code! thanks a lot.
-= endo (registered user of purebasic since 98) =-
gnozal
PureBasic Expert
PureBasic Expert
Posts: 4229
Joined: Sat Apr 26, 2003 8:27 am
Location: Strasbourg / France
Contact:

Post 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
For free libraries and tools, visit my web site (also home of jaPBe V3 and PureFORM).
Post Reply