Page 1 of 1

Icons in a ComboBoxGadget()

Posted: Thu Mar 24, 2005 12:43 am
by Kale
Any easy way to include icons into a ComboBoxGadget()? I want to build an icon selection combo, got any ideas where to start? :?:

Posted: Thu Mar 24, 2005 5:01 am
by Sparkie
Kale wrote:Any easy way to include icons into a ComboBoxGadget()?
Well ease of use depends on how much control you need. AFAIK, you'll have to use WIN32 API to create your own "ComboBoxEx" control. This is my first attempt, so clean it up and optimize at will. ;)

Code: Select all

;--> ComboBoxEx Constants
#CBEIF_DI_SETITEM = $10000000
#CBEIF_IMAGE = 2
#CBEIF_INDENT = $10
#CBEIF_LPARAM = $20
#CBEIF_OVERLAY = 8
#CBEIF_SELECTEDIMAGE = 4
#CBEIF_TEXT = 1
#CBEM_INSERTITEMA = #WM_USER + 1
#CBEM_SETIMAGELIST = #WM_USER + 2
;--> ComboBoxEx Structure for adding items
cbi.COMBOBOXEXITEM
cbi\mask = #CBEIF_TEXT | #CBEIF_IMAGE | #CBEIF_SELECTEDIMAGE
;--> Create our 4 images
Dim images(3)
images(0) = CreateImage(0, 16, 16)
StartDrawing(ImageOutput())
Box(0, 0, 16, 16, RGB(255, 0, 0))
StopDrawing()
images(1) = CreateImage(1, 16, 16)
StartDrawing(ImageOutput())
Box(0, 0, 16, 16, RGB(0, 255, 0))
StopDrawing()
images(2) = CreateImage(2, 16, 16)
StartDrawing(ImageOutput())
Box(0, 0, 16, 16, RGB(0, 0, 255))
StopDrawing()
images(3) = CreateImage(3, 16, 16)
StartDrawing(ImageOutput())
Box(0, 0, 16, 16, RGB(255, 255, 0))
StopDrawing()
If OpenWindow(0, 0, 0, 270, 140, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "ComboBoxEx") And CreateGadgetList(WindowID(0))
  ;--> Create ComboBoxEx
  hCombo = CreateWindowEx_(0, "ComboBoxEx32", "", #WS_BORDER | #WS_CHILD | #WS_VISIBLE | #CBS_DROPDOWN, 10, 10, 200, 200, WindowID(), 0, GetModuleHandle_(0), 0)
  ;--> Create ImageList and add our 4 images
  hComboIl= ImageList_Create_(16, 16, #ILC_COLOR24, 0, 50)
  For i = 0 To 3
    ImageList_Add_(hComboIl, images(i), 0)
    FreeImage(i)
  Next i
  ;--> Send ImageList to ComboBoxEx
  SendMessage_(hCombo, #CBEM_SETIMAGELIST, 0, hComboIl)
  ;--> Add our items to ComboBoxEx
  For i = 0 To 3
    cbi\iItem = -1
    itemText$ = "ComboBoxEx Item " + Str(i)
    cbi\pszText = @itemText$
    cbi\cchTextMax = Len(itemText$)
    cbi\iImage = i
    cbi\iSelectedImage = i
    SendMessage_(hCombo, #CBEM_INSERTITEMA, 0, @cbi)
  Next i
  quit = #False
  Repeat
    event = WaitWindowEvent()
    If event = #PB_Event_CloseWindow
      ImageList_Destroy_(hComboIl)
      quit = #True
    EndIf
  Until quit = #True
EndIf

Posted: Thu Mar 24, 2005 9:06 am
by gnozal
Thanks.
Sparkie, you are a living code archive :lol:

Posted: Thu Mar 24, 2005 6:41 pm
by Kale
Thanks Sparkie! :)

Posted: Fri Mar 25, 2005 4:38 pm
by Kale
See below...

Posted: Fri Mar 25, 2005 5:54 pm
by Sparkie
I'm at work now so not much time to debug. First thing I see is ImageList_Add_() is returning -1 (Failed), so I'd start there. :wink:

I can take a closer look later when I am at home. :)

Posted: Fri Mar 25, 2005 6:18 pm
by Sparkie
Try this...
replace

Code: Select all

hImageList= ImageList_Create_(IconWidth, IconHeight, #ILC_COLOR24, 0, ArrayCount) 
with

Code: Select all

hImageList= ImageList_Create_(IconWidth, IconHeight, #ILC_MASK, 0, ArrayCount)
replace

Code: Select all

ImageList_Add_(hImageList, hCurrentImage, 0)
with

Code: Select all

ImageList_ReplaceIcon_(hImageList, -1, hCurrentImage)

Posted: Fri Mar 25, 2005 9:36 pm
by Kale
Ta for you help Sparkie, i think i have something i can work with now. :)

Code: Select all

;===========================================================================
;-CONSTANTS
;===========================================================================

#APP_NAME = "Name"

#MAX_NUMBER_OF_COMBO_ITEMS = 20

;ComboBoxEx Constants
#CBEIF_DI_SETITEM = $10000000
#CBEIF_IMAGE = 2
#CBEIF_INDENT = $10
#CBEIF_LPARAM = $20
#CBEIF_OVERLAY = 8
#CBEIF_SELECTEDIMAGE = 4
#CBEIF_TEXT = 1
#CBEM_INSERTITEMA = #WM_USER + 1
#CBEM_SETIMAGELIST = #WM_USER + 2
#CBEM_GETIMAGELIST = #WM_USER + 3

Enumeration
    #WINDOW_ROOT
EndEnumeration

;===========================================================================
;-GLOBAL FLAGS / VARIABLES / STRUCTURES / ARRAYS
;===========================================================================

Structure COMBOITEM
    hImage.l
    Text.s
EndStructure

Dim ComboContents.COMBOITEM(#MAX_NUMBER_OF_COMBO_ITEMS - 1)

ComboContents(0)\hImage = CatchImage(0, ?Image1)
ComboContents(0)\Text = "User"

ComboContents(1)\hImage = CatchImage(1, ?Image2)
ComboContents(1)\Text = "Headphones"

ComboContents(2)\hImage = CatchImage(2, ?Image3)
ComboContents(2)\Text = "Gameboy"

ComboContents(3)\hImage = CatchImage(3, ?Image4)
ComboContents(3)\Text = "Afro"

ComboContents(4)\hImage = CatchImage(4, ?Image5)
ComboContents(4)\Text = "Little Man"

;===========================================================================
;-PROCEDURES
;===========================================================================

;Handle an error
Procedure HandleError(Result, Text.s)
    If Result = 0 : MessageRequester("Error", Text, #PB_MessageRequester_Ok) : End : EndIf
EndProcedure

;create a IconComboEx gadget
Procedure IconComboExGadget(WindowID, x, y, Width, Height)
    hComboBox = CreateWindowEx_(0, "ComboBoxEx32", "", #WS_BORDER | #WS_CHILD | #WS_VISIBLE | #CBS_DROPDOWN, x, y, Width, Height, WindowID, 0, GetModuleHandle_(0), 0)
    ProcedureReturn hComboBox
EndProcedure

;Assign contents to the IconComboEx gadget
Procedure AssignComboExContents(hComboBox, *ArrayOfImageHandles, IconWidth, IconHeight, ArrayCount)
    ;clear the current list in case it has already been filled
    SendMessage_(hComboBox, #CB_RESETCONTENT, 0, 0)
    ;if an image list exists then destroy it before creating a new one
    If hImageList
        ImageList_Destroy_(hImageList)
    EndIf
    ;create a new image list
    hImageList = ImageList_Create_(IconWidth, IconHeight, #ILC_MASK, 0, ArrayCount)
    ;set up the structure for the combo text contents
    ComboItem.COMBOBOXEXITEM
    ComboItem\mask = #CBEIF_TEXT | #CBEIF_IMAGE | #CBEIF_SELECTEDIMAGE
    For x = 0 To (ArrayCount - 1) * 8 Step 8
        If PeekL(*ArrayOfImageHandles + x) And PeekS(PeekL((*ArrayOfImageHandles + x) + 4))
            ;get current values
            hCurrentImage = PeekL(*ArrayOfImageHandles + x)
            CurrentText.s = PeekS(PeekL((*ArrayOfImageHandles + x) + 4))
            ;add the current image to the image list
            ImageList_ReplaceIcon_(hImageList, -1, hCurrentImage)
        EndIf
    Next x
    ;assign the image list to the combo
    SendMessage_(hComboBox, #CBEM_SETIMAGELIST, 0, hImageList)
    For x = 0 To (ArrayCount - 1) * 8 Step 8
        If PeekL(*ArrayOfImageHandles + x) And PeekS(PeekL((*ArrayOfImageHandles + x) + 4))
            ;get current values
            hCurrentImage = PeekL(*ArrayOfImageHandles + x)
            CurrentText.s = PeekS(PeekL((*ArrayOfImageHandles + x) + 4))
            ;construct the combo text
            ComboItem\iItem = -1
            ComboItem\pszText = @CurrentText
            ComboItem\cchTextMax = Len(CurrentText)
            ComboItem\iImage = ImageNumber
            ComboItem\iSelectedImage = ImageNumber
            ImageNumber + 1
            ;assign the text to the combo
            SendMessage_(hComboBox, #CBEM_INSERTITEMA, 0, @ComboItem)
        EndIf
    Next x
    ;set the top item to display in the list
    SendMessage_(hComboBox, #CB_SETCURSEL, 0, 0)
EndProcedure

;===========================================================================
;-GEOMETRY
;===========================================================================

HandleError(OpenWindow(#WINDOW_ROOT, 0, 0, 300, 300, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, #APP_NAME), "Main window could not be created.")
HandleError(CreateGadgetList(WindowID(#WINDOW_ROOT)), "Gadget list for the main window could not be created.")

hComboBox = IconComboExGadget(WindowID(#WINDOW_ROOT), 10, 10, 280, 200)
AssignComboExContents(hComboBox, @ComboContents(), 16, 16, #MAX_NUMBER_OF_COMBO_ITEMS)

ListIconGadget(1, 10, 50, 280, 200, "Icon Test", 240)
For x = 0 To #MAX_NUMBER_OF_COMBO_ITEMS - 1
    If ComboContents(x)\Text And ComboContents(x)\hImage
        AddGadgetItem(1, -1, ComboContents(x)\Text, ComboContents(x)\hImage)
    EndIf
Next x

;===========================================================================
;-MAIN LOOP
;===========================================================================

Repeat
    EventID.l = WaitWindowEvent()
    Select EventID
    
        Case #PB_Event_CloseWindow
            ImageList_Destroy_(SendMessage_(hComboBox, #CBEM_GETIMAGELIST, 0, 0))
            End
    
        Case #PB_EventMenu
            Select EventMenuID()
                ;Case #MENU
                    ;Command
            EndSelect

        Case #PB_EventGadget

            Select EventlParam()
                Case hComboBox
                    CurrentIndex = SendMessage_(hComboBox, #CB_GETCURSEL, 0, 0)
                    Debug "Current Index: " + Str(CurrentIndex)
                    Debug "Current Index Text: " + ComboContents(CurrentIndex)\Text
                    Debug "Current Index Image Handle: " + Str(ComboContents(CurrentIndex)\hImage)
                    Debug ""
            EndSelect
        
            Select EventGadgetID()
                ;Case #GADGET
                    ;Command
            EndSelect

    EndSelect
ForEver

End

;===========================================================================
;-BINARY INCLUDES
;===========================================================================

DataSection
    Image1:
        IncludeBinary "images\account1.ico"
    Image2:
        IncludeBinary "images\account2.ico"
    Image3:
        IncludeBinary "images\account3.ico"
    Image4:
        IncludeBinary "images\account4.ico"
    Image5:
        IncludeBinary "images\account5.ico"
EndDataSection
Click the link for updated code/images, etc. Download

Posted: Sat Mar 26, 2005 5:17 pm
by Sparkie
Nice job Kale. Glad to help. :)

It appears as though you can also use icons in a standard PB ComboBoxGadget, but it requires #CBS_OWNERDRAWFIXED where you do all the drawing. I haven't tried it yet, but if I get a chance later, I'll give it a go. ;)