Page 1 of 1

ComboBox api wrapper...

Posted: Fri Apr 02, 2010 5:28 pm
by srod
Hi,

Purebasic 4.5 brings an upgrade to ComboBox gadgets in that, under windows, PB has replaced the older ComboBox control class with the newer ComboBoxEx control classes. This allows for easy use of image lists etc. (See the PB help manual for an example).

However, this does have one disadvantage, namely that you cannot (at least I have been unable to do so) use owner-drawn methods with these new controls. (For me, a consequence of this is that my EsGRID control has collapsed... albeit temporarily! :wink: )

I have therefore created this small wrapper around the Windows ComboBox control class, mimicking, as far as is possible, the operation of PB's gadget library etc. Indeed, Freak kindly made his original C code available so that I could mimick PB's original wrapper right down to the last comment. The good thing being that we are guaranteed to have a control which is absolutely compatible with the original PB ComboboxGadget right down to the borders and styles etc. (Just what I need for EsGRID's salvation!)

My thanks to Freak/Fred for making this code available and allowing me to make this posting.

Main code...

Code: Select all

CompilerIf Defined(INCLUDE_APICOMBO, #PB_Constant)=0
#INCLUDE_APICOMBO=1
;/////////////////////////////////////////////////////////////////////////////////
;***API Combo controls***  - Version 1.1.
;=======================
;   Thanks to Timo (Freak) for his permission to translate (from C) his original Windows wrapper around the ComboBox api.
;
;   Created with Purebasic 4.5 for Windows.
;
;   Platforms:  Windows.
;/////////////////////////////////////////////////////////////////////////////////

;/////////////////////////////////////////////////////////////////////////////////
;With Purebasic 4.5 the ComboBox gadget has been upgraded to a Windows ComboBoxEx control which, whilst offering images etc.
;does not allow us to use ownerdrawn techniques etc.
;This api wrapper, therefore, offers easy access to standard ComboBox controls which can be ownerdrawn and so on. We follow the original
;Purebasic ComboBoxGadget (prior to PB 4.5) as close as possible and indeed this code is a direct translation of Freak/Fred's original
;C code.
;/////////////////////////////////////////////////////////////////////////////////

;/////////////////////////////////////////////////////////////////////////////////
;NOTES :
;
;   i)    Create a combo control with the APIComboGadget() function.
;         Use the 'styles' parameter to set some styles (e.g. #CBS_OWNERDRAWFIXED) which will be in addition to those set internally.
;
;   ii)   The #GWL_USERDATA attribute is used internally. Do not use it!
;/////////////////////////////////////////////////////////////////////////////////

EnableExplicit


Procedure.i APIComboGadget(hWndParent, x, y, width, height, styles=0, blnEditable=#False)
  Protected hWnd, hEdit, rc.RECT, bordersHeight
  If hWndParent
    styles | #WS_CHILD | #WS_VISIBLE | #WS_BORDER | #CBS_HASSTRINGS | #WS_GROUP | #WS_VSCROLL | #CBS_AUTOHSCROLL
    If blnEditable
      styles | #CBS_DROPDOWN
    Else
      styles | #CBS_DROPDOWNLIST|#WS_TABSTOP
    EndIf
    hWnd = CreateWindowEx_(#WS_EX_CLIENTEDGE, @"ComboBox", 0, styles, x, y, width, 350, hWndParent, -1, GetModuleHandle_(0), 0) 
    If hWnd
      If blnEditable
        ;Add the tabstop to the edit control.
          hEdit = GetWindow_(hWnd, #GW_CHILD)
          SetWindowLongPtr_(hEdit, #GWL_STYLE, GetWindowLongPtr_(hEdit, #GWL_STYLE) | #WS_TABSTOP)
      EndIf
      ;Set the real height by taking the selection item's border into account.
        SendMessage_(hWnd, #WM_SETFONT, GetStockObject_(#DEFAULT_GUI_FONT), 0)
        SendMessage_(hWnd, #CB_SETITEMHEIGHT, -1, 15)
        GetWindowRect_(hWnd, rc)
        bordersHeight = rc\bottom - rc\top - 15  
        SendMessage_(hWnd, #CB_SETITEMHEIGHT, -1, height-bordersHeight)
      ;Record the height.
        SetWindowLongPtr_(hWnd, #GWL_USERDATA, bordersHeight)
    EndIf
  EndIf
  ProcedureReturn hWnd
EndProcedure


Procedure APICombo_AddGadgetItem(hWndCombo, position, text$)
  If position >= -1
    SendMessage_(hWndCombo, #CB_INSERTSTRING, position, @text$)
  EndIf
EndProcedure


Procedure APICombo_ClearGadgetItems(hWndCombo)
  SendMessage_(hWndCombo, #CB_RESETCONTENT, 0, 0)
EndProcedure  


Procedure.i APICombo_CountGadgetItems(hWndCombo)
  ProcedureReturn SendMessage_(hWndCombo, #CB_GETCOUNT, 0, 0)
EndProcedure

  
Procedure APICombo_DisableGadget(hWndCombo, state)
  If state
    state = 0
  Else
    state = 1
  EndIf
  EnableWindow_(hWndCombo, state)
EndProcedure


Procedure APICombo_FreeGadget(hWndCombo)
  DestroyWindow_(hWndCombo)
EndProcedure


Procedure.i APICombo_GadgetHeight(hWndCombo)
  Protected result, wp.WINDOWPLACEMENT
  wp\Length = SizeOf(WINDOWPLACEMENT)
  If GetWindowPlacement_(hWndCombo, wp)
    result = wp\rcNormalPosition\bottom - wp\rcNormalPosition\top
  EndIf
  ProcedureReturn result
EndProcedure


Procedure.i APICombo_GadgetWidth(hWndCombo)
  Protected result, wp.WINDOWPLACEMENT
  wp\Length = SizeOf(WINDOWPLACEMENT)
  If GetWindowPlacement_(hWndCombo, wp)
    result = wp\rcNormalPosition\right - wp\rcNormalPosition\left
  EndIf
  ProcedureReturn result
EndProcedure


Procedure.i APICombo_GadgetX(hWndCombo)
  Protected result, wp.WINDOWPLACEMENT
  wp\Length = SizeOf(WINDOWPLACEMENT)
  If GetWindowPlacement_(hWndCombo, wp)
    result = wp\rcNormalPosition\left
  EndIf
  ProcedureReturn result
EndProcedure


Procedure.i APICombo_GadgetY(hWndCombo)
  Protected result, wp.WINDOWPLACEMENT
  wp\Length = SizeOf(WINDOWPLACEMENT)
  If GetWindowPlacement_(hWndCombo, wp)
    result = wp\rcNormalPosition\top
  EndIf
  ProcedureReturn result
EndProcedure


Procedure.i APICombo_GetGadgetItemData(hWndCombo, item)
  ProcedureReturn SendMessage_(hWndCombo, #CB_GETITEMDATA, item, 0)
EndProcedure


Procedure.s APICombo_GetGadgetItemText(hWndCombo, item)
  Protected length, text$
  length = SendMessage_(hWndCombo, #CB_GETLBTEXTLEN, item, 0)
  If length > 0
    text$ = Space(length)
    SendMessage_(hWndCombo, #CB_GETLBTEXT, item, @text$)
  EndIf
  ProcedureReturn text$
EndProcedure


Procedure.i APICombo_GetGadgetState(hWndCombo)
  ProcedureReturn SendMessage_(hWndCombo, #CB_GETCURSEL, 0, 0)
EndProcedure


Procedure.s APICombo_GetGadgetText(hWndCombo)
  Protected length, text$
  length = GetWindowTextLength_(hWndCombo)
  If length > 0
    text$ = space(length)
    GetWindowText_(hWndCombo, @text$, 100) 
  EndIf
  ProcedureReturn text$
EndProcedure


Procedure APICombo_HideGadget(hWndCombo, state)
  If state
    ShowWindow_(hWndCombo, #SW_HIDE)
  Else
    ShowWindow_(hWndCombo, #SW_SHOW)
  EndIf
EndProcedure


Procedure APICombo_RemoveGadgetItem(hWndCombo, item)
  SendMessage_(hWndCombo, #CB_DELETESTRING, item, 0)
EndProcedure


Procedure APICombo_ResizeGadget(hWndCombo, x, y, width, height)
  Protected wp.WINDOWPLACEMENT, dropHeight, rc.RECT, borderHeight
  ;First the control itself including the drop down height.
    wp\Length = SizeOf(WINDOWPLACEMENT)
    If GetWindowPlacement_(hWndCombo, wp)
      If x = #PB_Ignore
        x = wp\rcNormalPosition\left
      EndIf
      If y = #PB_Ignore
        y = wp\rcNormalPosition\top
      EndIf
      If width = #PB_Ignore
        width = wp\rcNormalPosition\right - wp\rcNormalPosition\left
      EndIf
      SendMessage_(hWndCombo, #CB_GETDROPPEDCONTROLRECT, 0, rc)
      dropHeight = rc\bottom - rc\top
      MoveWindow_(hWndCombo, x, y, width, dropHeight, 1)
    ;Now the selection field.
      If height <> #PB_Ignore
        borderHeight = GetWindowLongPtr_(hWndCombo, #GWL_USERDATA)
        SendMessage_(hWndCombo, #CB_SETITEMHEIGHT, -1, height-borderHeight)    
      EndIf
    EndIf
EndProcedure


Procedure APICombo_SetGadgetItemData(hWndCombo, item, userData)
  SendMessage_(hWndCombo, #CB_SETITEMDATA, item, userData)
EndProcedure


Procedure APICombo_SetGadgetItemText(hWndCombo, item, text$)
  Protected userData
  userData = SendMessage_(hWndCombo, #CB_GETITEMDATA, item, 0) ;Preserve the userdata!
  If SendMessage_(hWndCombo, #CB_DELETESTRING, item, 0) <> -1
    SendMessage_(hWndCombo, #CB_INSERTSTRING, item, text$)
    SendMessage_(hWndCombo, #CB_SETITEMDATA, item, userData)
  EndIf
EndProcedure


Procedure APICombo_SetGadgetState(hWndCombo, state)
  SendMessage_(hWndCombo, #CB_SETCURSEL, state, 0)
EndProcedure
  

Procedure APICombo_SetGadgetText(hWndCombo, text$)
  Protected item
  If GetWindowLongPtr_(hWndCombo, #GWL_STYLE) & #CBS_SIMPLE ;Not editable.
    If text$
      item = SendMessage_(hWndCombo, #CB_FINDSTRINGEXACT, -1, @text$)
      If item <> -1
        SendMessage_(hWndCombo, #CB_SETCURSEL, item, 0)
      EndIf
    Else
      SendMessage_(hWndCombo, #CB_SETCURSEL, -1, 0)
    EndIf
  Else ;Editable
    SetWindowText_(hWndCombo, text$)
  EndIf
EndProcedure


DisableExplicit

CompilerEndIf

Demo...

Code: Select all

XIncludeFile "apiCombo.pbi"

hWnd = OpenWindow(0, 0, 0, 270, 60, "API Combo Control", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If hWnd
  hWndCombo = APIComboGadget(hWnd, 10, 10, 250, 20)
  If hWndCombo
    For i = 0 To 9
      APICombo_AddGadgetItem(hWndCombo, -1, "Item " + Str(i))
    Next
    APICombo_SetGadgetState(hWndCombo, 2)
  EndIf
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: ComboBox api wrapper...

Posted: Fri Apr 02, 2010 7:29 pm
by +18
many thanks srod :D

Re: ComboBox api wrapper...

Posted: Fri Apr 02, 2010 9:03 pm
by srod
+18 wrote:many thanks srod :D
You're welcome.

Have added several additional functions; APICombo_DisableGadget(), APICombo_FreeGadget(), APICombo_GadgetHeight(), APICombo_GadgetWidth(), APICombo_GadgetX(), APICombo_GadgetY() and APICombo_HideGadget(). This gives better coverage of the basic functions etc.

Re: ComboBox api wrapper...

Posted: Fri Apr 30, 2010 8:34 am
by Seldon
Thank you srod !!! That's what I was going to do myself !

Re: ComboBox api wrapper...

Posted: Fri Apr 30, 2010 9:29 am
by srod
Seldon wrote:Thank you srod !!! That's what I was going to do myself !
You're welcome Seldon. 8)

Re: ComboBox api wrapper...

Posted: Tue May 25, 2010 11:10 pm
by zxtunes.com
srod please tell me, perhaps to remove the restriction on the size of a picture in combobox gadget? 16x16 is the Middle Ages. I've seen a bunch of programs that use large images in the combobox.

Example: Image

Re: ComboBox api wrapper...

Posted: Wed May 26, 2010 10:13 am
by srod
Sorry, are you working with a comboboxex or an old combobox?