ComboBoxLib — Dropdown List Control Library

Complete functionality for creating and managing dropdown list (combo box) controls in Plan9Basic. A combo box shows one selected item with an expandable dropdown list of choices. Features include item management, index-based selection, search by text, dropdown size control, alignment and margins, focus control, drag support, and a comprehensive event system. 101 functions.

CategoryCountDescription
Error Handling4combobox_error, errormsg$, strerror$, clearerror
Creation & Destruction3combobox# (2 overloads), combobox_free
Items Management8add, insert, delete, clear, count, item (get/set), indexof
Selection4itemindex (get/set), selected$, dropdowncount (get/set)
Position & Size14x, y, width, height (get/set), bounds#, move#, size#
Alignment & Margins12align (get/set), margin#, margins#, marginleft/top/right/bottom (get/set)
Visibility & State6visible, enabled, opacity (get/set)
Focus5isfocused, setfocus#, resetfocus#, taborder (get/set)
Interaction6canfocus, hittest, dragmode (get/set)
Tag & Parent6tag (get/set), parent# (get/set), bringtofront#, sendtoback#
Events3315 event types × set/get + clearcallbacks#

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportWin32/Win64
Linux✅ Full SupportGTK-based
Android✅ Full SupportNative picker on mobile

Error Handling

FunctionSignatureDescription
combobox_error()combobox_error@Last error code (0 = no error)
combobox_errormsg$()combobox_errormsg$@Last error message as string
combobox_strerror$(code)combobox_strerror$@nDescription for a given error code
combobox_clearerror()combobox_clearerror@Clear the error state

Numeric Values Reference

Control Alignment combobox_align#

ValueDescription
0None (absolute positioning)
1Top
2Left
3Right
4Bottom
9Client (fill parent)

Drag Mode combobox_dragmode#

ValueDescription
0None (default)
1Automatic drag enabled

Creation & Destruction

FunctionSignatureDescription
combobox#(parent#)combobox#@#Create combo box with default position (0, 0)
combobox#(parent#, x, y, w, h)combobox#@#nnnnCreate with position and size
combobox_free(cb#)combobox_free@#Destroy combo box and release resources
╯ plan9basic
let cb# = combobox#(frm#, 50, 50, 200, 30)

' Cleanup
combobox_free(cb#)

Items Management

FunctionSignatureDescription
combobox_add(cb#, text$)combobox_add@#$Add item to the end of the list; returns the new index
combobox_insert(cb#, index, text$)combobox_insert@#n$Insert item at a specific index (0-based)
combobox_delete(cb#, index)combobox_delete@#nDelete item at the given index
combobox_clear(cb#)combobox_clear@#Remove all items from the list
combobox_count(cb#)combobox_count@#Get the number of items
combobox_item$(cb#, index)combobox_item$@#nGet the text of an item by index
combobox_item#(cb#, index, text$)combobox_item#@#n$Set the text of an item by index
combobox_indexof(cb#, text$)combobox_indexof@#$Find item by text; returns index or -1 if not found
╯ plan9basic
' Build a list
combobox_add(cb#, "Apple")
combobox_add(cb#, "Banana")
combobox_add(cb#, "Cherry")

println "Items: " + str$(combobox_count(cb#))   ' 3

' Find an item
let idx = combobox_indexof(cb#, "Banana")  ' Returns 1

' Modify an item
combobox_item#(cb#, 1, "Blueberry")

' Insert at position 0
combobox_insert(cb#, 0, "Avocado")

' Delete first item
combobox_delete(cb#, 0)

' Clear all
combobox_clear(cb#)

Selection

FunctionSignatureDescription
combobox_itemindex(cb#)combobox_itemindex@#Get the selected index (-1 if nothing selected)
combobox_itemindex#(cb#, index)combobox_itemindex#@#nSet the selected index
combobox_selected$(cb#)combobox_selected$@#Get the text of the selected item
combobox_dropdowncount(cb#)combobox_dropdowncount@#Get number of visible items in the dropdown
combobox_dropdowncount#(cb#, n)combobox_dropdowncount#@#nSet number of visible items in the dropdown
╯ plan9basic
' Select first item
combobox_itemindex#(cb#, 0)

' Read selection
let idx = combobox_itemindex(cb#)
let txt$ = combobox_selected$(cb#)
println "Selected [" + str$(idx) + "]: " + txt$

' Show more items in the dropdown
combobox_dropdowncount#(cb#, 8)
ⓘ Note: combobox_itemindex returns -1 when no item is selected. Always check for -1 before accessing the selected text.

Position & Size

FunctionSignatureDescription
combobox_x(cb#)combobox_x@#Get X position
combobox_x#(cb#, x)combobox_x#@#nSet X position
combobox_y(cb#)combobox_y@#Get Y position
combobox_y#(cb#, y)combobox_y#@#nSet Y position
combobox_width(cb#)combobox_width@#Get width
combobox_width#(cb#, w)combobox_width#@#nSet width
combobox_height(cb#)combobox_height@#Get height
combobox_height#(cb#, h)combobox_height#@#nSet height
combobox_bounds#(cb#, x, y, w, h)combobox_bounds#@#nnnnSet position and size in one call
combobox_move#(cb#, x, y)combobox_move#@#nnSet position only
combobox_size#(cb#, w, h)combobox_size#@#nnSet size only
╯ plan9basic
combobox_bounds#(cb#, 50, 50, 200, 30)

Alignment & Margins

When combobox_align# is set to a value other than 0, the combo box is automatically positioned by its parent. Margins control spacing when alignment is active.

FunctionSignatureDescription
combobox_align(cb#)combobox_align@#Get control alignment mode
combobox_align#(cb#, n)combobox_align#@#nSet control alignment (0=none, 1=top, 2=left, 3=right, 4=bottom, 9=client)
combobox_margin#(cb#, n)combobox_margin#@#nSet uniform margin on all four sides
combobox_margins#(cb#, l, t, r, b)combobox_margins#@#nnnnSet individual margins (left, top, right, bottom)
combobox_marginleft(cb#)combobox_marginleft@#Get left margin
combobox_marginleft#(cb#, n)combobox_marginleft#@#nSet left margin
combobox_margintop(cb#)combobox_margintop@#Get top margin
combobox_margintop#(cb#, n)combobox_margintop#@#nSet top margin
combobox_marginright(cb#)combobox_marginright@#Get right margin
combobox_marginright#(cb#, n)combobox_marginright#@#nSet right margin
combobox_marginbottom(cb#)combobox_marginbottom@#Get bottom margin
combobox_marginbottom#(cb#, n)combobox_marginbottom#@#nSet bottom margin
╯ plan9basic
' Dock to top of a panel
combobox_align#(cb#, 1)
combobox_margin#(cb#, 5)

Visibility & State

FunctionSignatureDescription
combobox_visible(cb#)combobox_visible@#Get visibility (0/1)
combobox_visible#(cb#, n)combobox_visible#@#nSet visibility (0=hidden, 1=visible)
combobox_enabled(cb#)combobox_enabled@#Get enabled state (0/1)
combobox_enabled#(cb#, n)combobox_enabled#@#nSet enabled state (0=disabled/grayed, 1=enabled)
combobox_opacity(cb#)combobox_opacity@#Get opacity (0.0–1.0)
combobox_opacity#(cb#, value)combobox_opacity#@#nSet opacity (0.0=transparent, 1.0=opaque)
╯ plan9basic
' Disable until a prerequisite is met
combobox_enabled#(cbCity#, 0)

' Enable after country is selected
combobox_enabled#(cbCity#, 1)

Focus

FunctionSignatureDescription
combobox_isfocused(cb#)combobox_isfocused@#Is this combo box focused? (0/1)
combobox_setfocus#(cb#)combobox_setfocus#@#Give keyboard focus
combobox_resetfocus#(cb#)combobox_resetfocus#@#Release focus
combobox_taborder(cb#)combobox_taborder@#Get tab order index
combobox_taborder#(cb#, n)combobox_taborder#@#nSet tab order index
╯ plan9basic
combobox_taborder#(cbCountry#, 1)
combobox_taborder#(cbCity#, 2)

Interaction

FunctionSignatureDescription
combobox_canfocus(cb#)combobox_canfocus@#Get whether combo box can receive focus (0/1)
combobox_canfocus#(cb#, n)combobox_canfocus#@#nSet whether combo box can receive focus
combobox_hittest(cb#)combobox_hittest@#Get hit-test state (0/1)
combobox_hittest#(cb#, n)combobox_hittest#@#nEnable/disable mouse hit testing
combobox_dragmode(cb#)combobox_dragmode@#Get drag mode (0=none, 1=automatic)
combobox_dragmode#(cb#, n)combobox_dragmode#@#nSet drag mode

Tag & Parent

FunctionSignatureDescription
combobox_tag(cb#)combobox_tag@#Get user-defined integer tag
combobox_tag#(cb#, n)combobox_tag#@#nSet user-defined integer tag
combobox_parent#(cb#)combobox_parent#@#Get parent control pointer
combobox_parent#(cb#, parent#)combobox_parent#@##Move combo box to a different parent
combobox_bringtofront#(cb#)combobox_bringtofront#@#Bring to front of Z-order
combobox_sendtoback#(cb#)combobox_sendtoback#@#Send to back of Z-order

Events

Each event has a setter (combobox_onXXX#(cb#, func$)) and a getter (combobox_onXXX$(cb#)). Use combobox_clearcallbacks#(cb#) to disconnect all callbacks at once.

Selection & Focus Events

Event SetterGetterCallback SignatureWhen It Fires
combobox_onchange#(cb#, func$)combobox_onchange$(cb#)function name(sender#)When the selected item changes
combobox_onclick#(cb#, func$)combobox_onclick$(cb#)function name(sender#)When the combo box is clicked
combobox_ondblclick#(cb#, func$)combobox_ondblclick$(cb#)function name(sender#)When double-clicked
combobox_onenter#(cb#, func$)combobox_onenter$(cb#)function name(sender#)When the control receives focus
combobox_onexit#(cb#, func$)combobox_onexit$(cb#)function name(sender#)When the control loses focus
ⓘ Note: OnChange is the primary event for combo boxes. It fires whenever the user picks a different item or when combobox_itemindex# changes the selection programmatically.

Keyboard Events

Event SetterGetterCallback Signature
combobox_onkeydown#(cb#, func$)combobox_onkeydown$(cb#)function name(sender#, key, keychar$, shift$)
combobox_onkeyup#(cb#, func$)combobox_onkeyup$(cb#)function name(sender#, key, keychar$, shift$)

Mouse Events

Event SetterGetterCallback Signature
combobox_onmousedown#(cb#, func$)combobox_onmousedown$(cb#)function name(sender#, button, x, y, shift$)
combobox_onmouseup#(cb#, func$)combobox_onmouseup$(cb#)function name(sender#, button, x, y, shift$)
combobox_onmousemove#(cb#, func$)combobox_onmousemove$(cb#)function name(sender#, x, y, shift$)
combobox_onmouseenter#(cb#, func$)combobox_onmouseenter$(cb#)function name(sender#)
combobox_onmouseleave#(cb#, func$)combobox_onmouseleave$(cb#)function name(sender#)

Other Events

Event SetterGetterCallback Signature
combobox_onresize#(cb#, func$)combobox_onresize$(cb#)function name(sender#)
combobox_ondragenter#(cb#, func$)combobox_ondragenter$(cb#)function name(sender#)
combobox_ondragover#(cb#, func$)combobox_ondragover$(cb#)function name(sender#)
combobox_ondragdrop#(cb#, func$)combobox_ondragdrop$(cb#)function name(sender#)
combobox_ondragleave#(cb#, func$)combobox_ondragleave$(cb#)function name(sender#)
combobox_clearcallbacks#(cb#)Disconnect all event callbacks

Complete Examples

Country Selection

╯ country.bas
function OnCountrySelected(sender#)
    println "You selected: " + combobox_selected$(sender#)
endfunction

let frm# = form#("Country Selector", 400, 200)
form_position#(frm#, 4)

let lblCountry# = label#(frm#, "Select your country:")
label_move#(lblCountry#, 50, 30)

let cbCountry# = combobox#(frm#, 50, 55, 200, 30)
combobox_add(cbCountry#, "United States")
combobox_add(cbCountry#, "United Kingdom")
combobox_add(cbCountry#, "Canada")
combobox_add(cbCountry#, "Australia")
combobox_add(cbCountry#, "Germany")
combobox_add(cbCountry#, "Brazil")

combobox_dropdowncount#(cbCountry#, 6)
combobox_onchange#(cbCountry#, "OnCountrySelected")

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Linked ComboBoxes (Country → City)

╯ linked.bas
function OnCountryChanged(sender#) local country$
    country$ = combobox_selected$(sender#)
    combobox_clear(cbCity#)

    if country$ = "USA" then
        combobox_add(cbCity#, "New York")
        combobox_add(cbCity#, "Los Angeles")
        combobox_add(cbCity#, "Chicago")
    elseif country$ = "UK" then
        combobox_add(cbCity#, "London")
        combobox_add(cbCity#, "Manchester")
    elseif country$ = "Brazil" then
        combobox_add(cbCity#, "S\u00e3o Paulo")
        combobox_add(cbCity#, "Rio de Janeiro")
    endif

    combobox_enabled#(cbCity#, 1)
    combobox_itemindex#(cbCity#, 0)
endfunction

let cbCountry# = Pointer#(0)
let cbCity# = Pointer#(0)

let frm# = form#("Location", 400, 200)
form_position#(frm#, 4)

label#(frm#, "Country:", 50, 20)
cbCountry# = combobox#(frm#, 50, 45, 200, 30)
combobox_add(cbCountry#, "USA")
combobox_add(cbCountry#, "UK")
combobox_add(cbCountry#, "Brazil")
combobox_onchange#(cbCountry#, "OnCountryChanged")

label#(frm#, "City:", 50, 90)
cbCity# = combobox#(frm#, 50, 115, 200, 30)
combobox_enabled#(cbCity#, 0)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Item Search

╯ search.bas
function OnSearch(sender#) local search$, idx
    search$ = edit_text$(edtSearch#)
    idx = combobox_indexof(cb#, search$)
    if idx >= 0 then
        combobox_itemindex#(cb#, idx)
        label_text#(lblResult#, "Found at index " + str$(idx))
    else
        label_text#(lblResult#, "Not found")
    endif
endfunction

let frm# = form#("Search Demo", 400, 250)
form_position#(frm#, 4)

let cb# = combobox#(frm#, 20, 20, 200, 30)
combobox_add(cb#, "Apple")
combobox_add(cb#, "Banana")
combobox_add(cb#, "Cherry")
combobox_add(cb#, "Date")
combobox_add(cb#, "Elderberry")

label#(frm#, "Search:", 20, 70)
let edtSearch# = edit#(frm#, 20, 92, 200, 28)

let btnSearch# = button#(frm#, "Find", 230, 92, 60, 28)
button_onclick#(btnSearch#, "OnSearch")

let lblResult# = label#(frm#, "")
label_move#(lblResult#, 20, 140)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Dynamic Item Management

╯ manager.bas
function OnAdd(sender#) local txt$
    txt$ = edit_text$(edtItem#)
    if len(txt$) > 0 then
        combobox_add(cb#, txt$)
        edit_text#(edtItem#, "")
        UpdateCount()
    endif
endfunction

function OnRemove(sender#) local idx
    idx = combobox_itemindex(cb#)
    if idx >= 0 then
        combobox_delete(cb#, idx)
        UpdateCount()
    endif
endfunction

function OnClear(sender#)
    combobox_clear(cb#)
    UpdateCount()
endfunction

function UpdateCount()
    label_text#(lblCount#, "Items: " + str$(combobox_count(cb#)))
endfunction

let frm# = form#("Item Manager", 400, 250)
form_position#(frm#, 4)

let cb# = combobox#(frm#, 20, 20, 200, 30)
let edtItem# = edit#(frm#, 20, 65, 200, 28)
edit_prompt#(edtItem#, "New item text...")

let btnAdd# = button#(frm#, "Add", 230, 65, 60, 28)
let btnRemove# = button#(frm#, "Remove", 230, 20, 70, 28)
let btnClear# = button#(frm#, "Clear All", 310, 20, 75, 28)

button_onclick#(btnAdd#, "OnAdd")
button_onclick#(btnRemove#, "OnRemove")
button_onclick#(btnClear#, "OnClear")

let lblCount# = label#(frm#, "Items: 0")
label_move#(lblCount#, 20, 110)

form_show(frm#)

while form_visible(frm#) = 1
    processmessages()
end while

Best Practices

PracticeWhy
Use combobox_onchange# as the primary eventFires when the selection actually changes
Check for combobox_itemindex(cb#) = -1No item is selected; avoid accessing invalid selection
Use combobox_dropdowncount# for long listsShows more items in the dropdown, reducing scrolling
Use combobox_indexof to find items by textReturns -1 if not found; avoids manual loops
Disable dependent combo boxes until readyUse combobox_enabled#(cb#, 0) until a prerequisite is met
Set combobox_taborder#Enables logical Tab navigation between form controls
Use combobox_tag# for shared callbacksIdentify which combo box changed without global variable lookups

Quick Reference

FunctionSignatureDescription
combobox_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
combobox#(parent#[, x, y, w, h])variousCreate (2 overloads)
combobox_free(cb#)combobox_free@#Destroy
combobox_add / insert / delete / clear / count / item / indexofvariousItems management (8)
combobox_itemindex / selected$ / dropdowncountvariousSelection (5)
combobox_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (14)
combobox_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
combobox_visible / enabled / opacityvariousVisibility & state (6)
combobox_isfocused / setfocus# / resetfocus# / tabordervariousFocus (5)
combobox_canfocus / hittest / dragmodevariousInteraction (6)
combobox_tag / parent# / bringtofront# / sendtoback#variousTag & parent (6)
combobox_onchange/onclick/ondblclick/onenter/onexit/onkeydown/onkeyup/onmousedown/up/move/enter/leave/onresize/ondragenter/over/drop/leavevariousEvents set+get (32)
combobox_clearcallbacks#combobox_clearcallbacks#@#Disconnect all events

101 functions. Part of the Plan9Basic GUI library system.