ListBoxLib — List Box Control Library

Complete functionality for creating and managing list box controls in Plan9Basic. A list box displays a scrollable list of items that users can select. Features include single and multi-select modes, item pointer access, search by text, font and text styling, alignment and margins, drag support, and a comprehensive event system. 126 functions (121 listbox + 5 listboxitem).

CategoryCountDescription
Error Handling4listbox_error, errormsg$, strerror$, clearerror
Creation & Destruction3listbox# (2 overloads), listbox_free
Item Management6add, additem#, insert, delete, clear, count
Item Access3item$ (get), item# (set), itemat#
Selection4itemindex (get/set), selected$, indexof
Multi-Select7multiselect (get/set), isselected, selectitem#, selectall, clearselection, selcount
Position & Size14x, y, width, height (get/set), bounds#, move#, size#
Alignment & Margins12align (get/set), margin#, margins#, marginleft/top/right/bottom (get/set)
Visibility & State10visible, enabled, opacity, hittest, dragmode (get/set)
Focus5focus, isfocused, canfocus (get/set), taborder (get/set)
Tag & Parent4tag (get/set), parent# (get/set)
Events3516 event types × set/get + clearcallbacks#
ListBoxItem5listboxitem_text (get/set), index, isselected (get/set)
Font Styling14fontcolor, fontsize, fontfamily, bold, italic, underline, strikeout — each get/set, applied to all items

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportWin32/Win64
Linux✅ Full SupportGTK-based
Android✅ Full SupportMobile-optimized

Error Handling

FunctionSignatureDescription
listbox_error()listbox_error@Last error code (0 = no error)
listbox_errormsg$()listbox_errormsg$@Last error message as string
listbox_strerror$(code)listbox_strerror$@nDescription for a given error code
listbox_clearerror()listbox_clearerror@Clear the error state

Numeric Values Reference

Control Alignment listbox_align#

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

Drag Mode listbox_dragmode#

ValueDescription
0None (default)
1Automatic drag enabled

Creation & Destruction

FunctionSignatureDescription
listbox#(parent#)listbox#@#Create list box with default size
listbox#(parent#, x, y, w, h)listbox#@#nnnnCreate with position and size
listbox_free(lst#)listbox_free@#Destroy list box and release resources
╯ plan9basic
let lst# = listbox#(frm#, 50, 50, 200, 180)

' Cleanup
listbox_free(lst#)

Item Management

FunctionSignatureDescription
listbox_add(lst#, text$)listbox_add@#$Add item to the end; returns the new index
listbox_additem#(lst#, text$)listbox_additem#@#$Add item; returns item pointer (for listboxitem_* functions)
listbox_insert(lst#, index, text$)listbox_insert@#n$Insert item at a specific index (0-based)
listbox_delete(lst#, index)listbox_delete@#nDelete item at the given index
listbox_clear(lst#)listbox_clear@#Remove all items
listbox_count(lst#)listbox_count@#Get the total number of items
╯ plan9basic
' Build a list
listbox_add(lst#, "Apple")
listbox_add(lst#, "Banana")
listbox_add(lst#, "Cherry")

' Add and keep pointer
let item# = listbox_additem#(lst#, "Date")

' Insert at position 1
listbox_insert(lst#, 1, "Avocado")

' Delete first item
listbox_delete(lst#, 0)

println "Items: " + str$(listbox_count(lst#))

' Clear all
listbox_clear(lst#)
ⓘ Note: listbox_add returns the numeric index of the new item. listbox_additem# returns a pointer to the item object — use this when you need to call listboxitem_* functions later.

Item Access

FunctionSignatureDescription
listbox_item$(lst#, index)listbox_item$@#nGet item text at index (0-based)
listbox_item#(lst#, index, text$)listbox_item#@#n$Set item text at index
listbox_itemat#(lst#, index)listbox_itemat#@#nGet item object pointer at index
╯ plan9basic
' Read item text
let txt$ = listbox_item$(lst#, 0)

' Modify item text
listbox_item#(lst#, 0, "Modified Apple")

' Get item pointer for listboxitem_* access
let item# = listbox_itemat#(lst#, 0)

Selection

FunctionSignatureDescription
listbox_itemindex(lst#)listbox_itemindex@#Get selected index (-1 if nothing selected)
listbox_itemindex#(lst#, index)listbox_itemindex#@#nSet selected index
listbox_selected$(lst#)listbox_selected$@#Get text of the currently selected item
listbox_indexof(lst#, text$)listbox_indexof@#$Find item by text; returns index or -1 if not found
╯ plan9basic
' Select first item
listbox_itemindex#(lst#, 0)

' Read selection
let idx = listbox_itemindex(lst#)
if idx >= 0 then
    println "Selected: " + listbox_selected$(lst#)
endif

' Find by text
let pos = listbox_indexof(lst#, "Cherry")
if pos >= 0 then
    listbox_itemindex#(lst#, pos)
endif
⚠ Warning: listbox_itemindex returns -1 when no item is selected. Always check before using the index to access item text.

Multi-Select

When multi-select is enabled, users can select multiple items by clicking while holding Shift or Ctrl.

FunctionSignatureDescription
listbox_multiselect(lst#)listbox_multiselect@#Get multi-select mode (0=single, 1=multi)
listbox_multiselect#(lst#, n)listbox_multiselect#@#nEnable/disable multi-select mode
listbox_isselected(lst#, index)listbox_isselected@#nCheck if a specific item is selected (0/1)
listbox_selectitem#(lst#, index, n)listbox_selectitem#@#nnSet selection state for a specific item (0=deselect, 1=select)
listbox_selectall(lst#)listbox_selectall@#Select all items
listbox_clearselection(lst#)listbox_clearselection@#Deselect all items
listbox_selcount(lst#)listbox_selcount@#Get the number of currently selected items
╯ plan9basic
' Enable multi-select
listbox_multiselect#(lst#, 1)

' Select specific items
listbox_selectitem#(lst#, 0, 1)  ' Select first
listbox_selectitem#(lst#, 2, 1)  ' Select third

' Check count
println "Selected: " + str$(listbox_selcount(lst#))

' Iterate selected items
for i = 0 to listbox_count(lst#) - 1
    if listbox_isselected(lst#, i) = 1 then
        println "  " + listbox_item$(lst#, i)
    endif
next

' Select all / clear all
listbox_selectall(lst#)
listbox_clearselection(lst#)

Position & Size

FunctionSignatureDescription
listbox_x(lst#)listbox_x@#Get X position
listbox_x#(lst#, x)listbox_x#@#nSet X position
listbox_y(lst#)listbox_y@#Get Y position
listbox_y#(lst#, y)listbox_y#@#nSet Y position
listbox_width(lst#)listbox_width@#Get width
listbox_width#(lst#, w)listbox_width#@#nSet width
listbox_height(lst#)listbox_height@#Get height
listbox_height#(lst#, h)listbox_height#@#nSet height
listbox_bounds#(lst#, x, y, w, h)listbox_bounds#@#nnnnSet position and size in one call
listbox_move#(lst#, x, y)listbox_move#@#nnSet position only
listbox_size#(lst#, w, h)listbox_size#@#nnSet size only

Alignment & Margins

FunctionSignatureDescription
listbox_align(lst#)listbox_align@#Get control alignment mode
listbox_align#(lst#, n)listbox_align#@#nSet alignment (0=none, 1=top, 2=left, 3=right, 4=bottom, 9=client)
listbox_margin#(lst#, n)listbox_margin#@#nSet uniform margin on all four sides
listbox_margins#(lst#, l, t, r, b)listbox_margins#@#nnnnSet individual margins (left, top, right, bottom)
listbox_marginleft(lst#)listbox_marginleft@#Get left margin
listbox_marginleft#(lst#, n)listbox_marginleft#@#nSet left margin
listbox_margintop(lst#)listbox_margintop@#Get top margin
listbox_margintop#(lst#, n)listbox_margintop#@#nSet top margin
listbox_marginright(lst#)listbox_marginright@#Get right margin
listbox_marginright#(lst#, n)listbox_marginright#@#nSet right margin
listbox_marginbottom(lst#)listbox_marginbottom@#Get bottom margin
listbox_marginbottom#(lst#, n)listbox_marginbottom#@#nSet bottom margin
╯ plan9basic
' Fill remaining space in a form
listbox_align#(lst#, 9)    ' Client
listbox_margin#(lst#, 5)   ' 5px spacing

Visibility & State

FunctionSignatureDescription
listbox_visible(lst#)listbox_visible@#Get visibility (0/1)
listbox_visible#(lst#, n)listbox_visible#@#nSet visibility
listbox_enabled(lst#)listbox_enabled@#Get enabled state (0/1)
listbox_enabled#(lst#, n)listbox_enabled#@#nSet enabled state
listbox_opacity(lst#)listbox_opacity@#Get opacity (0.0–1.0)
listbox_opacity#(lst#, value)listbox_opacity#@#nSet opacity
listbox_hittest(lst#)listbox_hittest@#Get hit-test state (0/1)
listbox_hittest#(lst#, n)listbox_hittest#@#nEnable/disable mouse hit testing
listbox_dragmode(lst#)listbox_dragmode@#Get drag mode (0=none, 1=automatic)
listbox_dragmode#(lst#, n)listbox_dragmode#@#nSet drag mode

Focus

FunctionSignatureDescription
listbox_focus(lst#)listbox_focus@#Set focus to the list box
listbox_isfocused(lst#)listbox_isfocused@#Is this list box focused? (0/1)
listbox_canfocus(lst#)listbox_canfocus@#Get whether list box can receive focus (0/1)
listbox_canfocus#(lst#, n)listbox_canfocus#@#nSet whether list box can receive focus
listbox_taborder(lst#)listbox_taborder@#Get tab order index
listbox_taborder#(lst#, n)listbox_taborder#@#nSet tab order index
ⓘ Note: listbox_focus is a legacy setter (equivalent to setfocus# in other libraries). Use listbox_isfocused to check focus state.

Tag & Parent

FunctionSignatureDescription
listbox_tag(lst#)listbox_tag@#Get user-defined integer tag
listbox_tag#(lst#, n)listbox_tag#@#nSet user-defined integer tag
listbox_parent#(lst#)listbox_parent#@#Get parent control pointer
listbox_parent#(lst#, parent#)listbox_parent#@##Move list box to a different parent

Events

Each event has a setter (listbox_onXXX#(lst#, func$)) and a getter (listbox_onXXX$(lst#)). Use listbox_clearcallbacks#(lst#) to disconnect all callbacks at once.

Selection & Focus Events

Event SetterGetterCallback SignatureWhen It Fires
listbox_onchange#(lst#, func$)listbox_onchange$(lst#)function name(sender#)When the selection changes
listbox_onitemclick#(lst#, func$)listbox_onitemclick$(lst#)function name(sender#, item#)When a specific item is clicked (provides item pointer)
listbox_onclick#(lst#, func$)listbox_onclick$(lst#)function name(sender#)When the list box is clicked
listbox_ondblclick#(lst#, func$)listbox_ondblclick$(lst#)function name(sender#)When double-clicked
listbox_onenter#(lst#, func$)listbox_onenter$(lst#)function name(sender#)When the control receives focus
listbox_onexit#(lst#, func$)listbox_onexit$(lst#)function name(sender#)When the control loses focus
ⓘ Note: Two events are useful for selection changes. OnChange uses the standard single-pointer signature function f(sender#) and is the recommended choice for most cases — read the selected text with listbox_selected$(sender#). OnItemClick uses a two-pointer signature function f(sender#, item#) and gives direct access to the clicked item via listboxitem_text$, listboxitem_index, and listboxitem_isselected. Use OnItemClick when you need the item pointer itself; use OnChange for simpler selection handling.

Keyboard Events

Event SetterGetterCallback Signature
listbox_onkeydown#(lst#, func$)listbox_onkeydown$(lst#)function name(sender#, key, keychar$, shift$)
listbox_onkeyup#(lst#, func$)listbox_onkeyup$(lst#)function name(sender#, key, keychar$, shift$)

Mouse Events

Event SetterGetterCallback Signature
listbox_onmousedown#(lst#, func$)listbox_onmousedown$(lst#)function name(sender#, button, x, y, shift$)
listbox_onmouseup#(lst#, func$)listbox_onmouseup$(lst#)function name(sender#, button, x, y, shift$)
listbox_onmousemove#(lst#, func$)listbox_onmousemove$(lst#)function name(sender#, x, y, shift$)
listbox_onmouseenter#(lst#, func$)listbox_onmouseenter$(lst#)function name(sender#)
listbox_onmouseleave#(lst#, func$)listbox_onmouseleave$(lst#)function name(sender#)

Other Events

Event SetterGetterCallback Signature
listbox_onresize#(lst#, func$)listbox_onresize$(lst#)function name(sender#)
listbox_ondragenter#(lst#, func$)listbox_ondragenter$(lst#)function name(sender#, x, y)
listbox_ondragover#(lst#, func$)listbox_ondragover$(lst#)function name(sender#, x, y)
listbox_ondragdrop#(lst#, func$)listbox_ondragdrop$(lst#)function name(sender#, x, y)
listbox_ondragleave#(lst#, func$)listbox_ondragleave$(lst#)function name(sender#)
listbox_clearcallbacks#(lst#)Disconnect all event callbacks
ⓘ Note: ListBoxLib drag event callbacks include x, y parameters (unlike most other libraries), providing the drop coordinates within the list box.

ListBoxItem Functions

When you have an item pointer (from listbox_additem#, listbox_itemat#, or the OnItemClick callback), you can manipulate items directly:

FunctionSignatureDescription
listboxitem_text$(item#)listboxitem_text$@#Get the text of an item
listboxitem_text#(item#, text$)listboxitem_text#@#$Set the text of an item
listboxitem_index(item#)listboxitem_index@#Get the current index of the item in the list
listboxitem_isselected(item#)listboxitem_isselected@#Check if the item is selected (0/1)
listboxitem_isselected#(item#, n)listboxitem_isselected#@#nSet the selection state of the item
╯ plan9basic
' Add and keep a pointer
let item# = listbox_additem#(lst#, "My Item")

' Read via pointer
println listboxitem_text$(item#)       ' "My Item"
println str$(listboxitem_index(item#))  ' 0

' Modify via pointer
listboxitem_text#(item#, "Modified Item")
listboxitem_isselected#(item#, 1)       ' Select it

' Get pointer for existing item
let ptr# = listbox_itemat#(lst#, 2)
println listboxitem_text$(ptr#)
ⓘ Note: Item pointers remain valid as long as the item exists in the list. If you delete the item, the pointer becomes invalid.

Font Styling

These functions apply text styling to all current items in the list. Because TListBox is a TStyledControl without its own TextSettings, styling is applied per-item — each TListBoxItem is a TTextControl that supports the same TextSettings mechanism used by buttons, labels, and edits.

⚠ Important: Font functions apply only to items already in the list at the time of the call. The correct usage pattern is to populate all items first with listbox_add, then call the styling functions once.
GetterSetterDescription
listbox_fontcolor$(lst#)listbox_fontcolor#(lst#, color$)Get/set text color of all items (hex string, e.g. "#ffffff")
listbox_fontsize(lst#)listbox_fontsize#(lst#, size)Get/set font size of all items
listbox_fontfamily$(lst#)listbox_fontfamily#(lst#, family$)Get/set font family of all items
listbox_bold(lst#)listbox_bold#(lst#, n)Get/set bold style (0/1)
listbox_italic(lst#)listbox_italic#(lst#, n)Get/set italic style (0/1)
listbox_underline(lst#)listbox_underline#(lst#, n)Get/set underline style (0/1)
listbox_strikeout(lst#)listbox_strikeout#(lst#, n)Get/set strikeout style (0/1)

Getters read from the first item (ListItems[0]). They return the default value (empty string, 0) if the list is empty.

╯ plan9basic
' Build the list first, then style
let lst# = listbox#(frm#, 10, 10, 200, 180)
listbox_add(lst#, "Alpha")
listbox_add(lst#, "Beta")
listbox_add(lst#, "Gamma")

' Apply styling after all items are added
listbox_fontcolor#(lst#, "#ffffff")
listbox_fontsize#(lst#, 14)
listbox_bold#(lst#, 1)

' Read back the current color (reads from first item)
println listbox_fontcolor$(lst#)  ' "#ffffffff"
╯ dark-theme dropdown (custom combobox pattern)
' Custom dropdown using edit# + button# + listbox# (no TComboBox needed)
let edt# = edit#(frm#, 10, 10, 160, 30)
edit_readonly#(edt#, 1)
edit_text#(edt#, "random")
edit_fontcolor#(edt#, "#ffffff")

let btnArrow# = button#(frm#, 170, 10, 30, 30)
button_text#(btnArrow#, "▼")
button_onclick#(btnArrow#, "OnToggle")

' Background rectangle (workaround for listbox fill limitation)
let lstBg# = rectangle#(frm#, 10, 42, 190, 150)
rectangle_fill#(lstBg#, "#0f3460")
rectangle_stroke#(lstBg#, "#e94560")
rectangle_visible#(lstBg#, 0)

' Popup listbox — created LAST for z-order
let lst# = listbox#(frm#, 10, 42, 190, 150)
listbox_add(lst#, "random")
listbox_add(lst#, "dev")
listbox_add(lst#, "science")
listbox_fontcolor#(lst#, "#ffffff")  ' style after populating
listbox_visible#(lst#, 0)
listbox_onchange#(lst#, "OnSelected")

let dropOpen = 0

function OnToggle(sender#)
    if dropOpen = 0 then
        listbox_visible#(lst#, 1)
        rectangle_visible#(lstBg#, 1)
        dropOpen = 1
    else
        listbox_visible#(lst#, 0)
        rectangle_visible#(lstBg#, 0)
        dropOpen = 0
    endif
endfunction

function OnSelected(sender#) local sel$
    sel$ = listbox_selected$(sender#)
    edit_text#(edt#, sel$)
    listbox_visible#(lst#, 0)
    rectangle_visible#(lstBg#, 0)
    dropOpen = 0
endfunction
ⓘ Note: The listbox background colour cannot be set directly because TListBox is a TStyledControl. The workaround is a rectangle# positioned immediately before the listbox in creation order — FMX natural z-order places the listbox on top of the rectangle automatically.

Complete Examples

Simple Selection List

╯ selector.bas
function OnChange(sender#) local idx, txt$
    idx = listbox_itemindex(sender#)
    if idx >= 0 then
        txt$ = listbox_item$(sender#, idx)
        label_text#(lblSelected#, "Selected: " + txt$)
    endif
endfunction

let frm# = form#("Fruit Selector", 400, 300)
form_position#(frm#, 4)

let lst# = listbox#(frm#, 50, 50, 150, 180)
listbox_add(lst#, "Apple")
listbox_add(lst#, "Banana")
listbox_add(lst#, "Cherry")
listbox_add(lst#, "Date")
listbox_add(lst#, "Elderberry")

let lblSelected# = label#(frm#, "Selected: none")
label_move#(lblSelected#, 220, 100)

listbox_onchange#(lst#, "OnChange")

form_show(frm#)

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

Add and Remove Items

╯ manager.bas
function UpdateCount()
    label_text#(lblCount#, "Items: " + str$(listbox_count(lst#)))
endfunction

function OnAdd(sender#) local txt$
    txt$ = edit_text$(edt#)
    if txt$ <> "" then
        listbox_add(lst#, txt$)
        edit_text#(edt#, "")
        UpdateCount()
    endif
endfunction

function OnRemove(sender#) local idx
    idx = listbox_itemindex(lst#)
    if idx >= 0 then
        listbox_delete(lst#, idx)
        UpdateCount()
    endif
endfunction

function OnClear(sender#)
    listbox_clear(lst#)
    UpdateCount()
endfunction

let frm# = form#("List Manager", 500, 350)
form_position#(frm#, 4)

let lst# = listbox#(frm#, 50, 50, 200, 200)
let edt# = edit#(frm#, 50, 270, 200, 28)
edit_prompt#(edt#, "Enter item text...")

let btnAdd# = button#(frm#, "Add", 270, 50, 80, 30)
let btnRemove# = button#(frm#, "Remove", 270, 90, 80, 30)
let btnClear# = button#(frm#, "Clear All", 270, 130, 80, 30)
let lblCount# = label#(frm#, "Items: 0")
label_move#(lblCount#, 270, 180)

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

form_show(frm#)

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

Two-List Transfer

╯ transfer.bas
function OnAddToSelected(sender#) local idx, txt$
    idx = listbox_itemindex(lstAvail#)
    if idx >= 0 then
        txt$ = listbox_item$(lstAvail#, idx)
        listbox_add(lstSel#, txt$)
        listbox_delete(lstAvail#, idx)
    endif
endfunction

function OnRemoveFromSelected(sender#) local idx, txt$
    idx = listbox_itemindex(lstSel#)
    if idx >= 0 then
        txt$ = listbox_item$(lstSel#, idx)
        listbox_add(lstAvail#, txt$)
        listbox_delete(lstSel#, idx)
    endif
endfunction

let frm# = form#("List Transfer", 550, 350)
form_position#(frm#, 4)

label#(frm#, "Available:", 50, 20)
let lstAvail# = listbox#(frm#, 50, 45, 180, 200)

label#(frm#, "Selected:", 320, 20)
let lstSel# = listbox#(frm#, 320, 45, 180, 200)

let btnAdd# = button#(frm#, ">>", 245, 100, 60, 30)
let btnRemove# = button#(frm#, "<<", 245, 140, 60, 30)

listbox_add(lstAvail#, "Item A")
listbox_add(lstAvail#, "Item B")
listbox_add(lstAvail#, "Item C")
listbox_add(lstAvail#, "Item D")
listbox_add(lstAvail#, "Item E")

button_onclick#(btnAdd#, "OnAddToSelected")
button_onclick#(btnRemove#, "OnRemoveFromSelected")

form_show(frm#)

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

Multi-Select with Statistics

╯ multiselect.bas
function OnListChange(sender#)
    label_text#(lblCount#, "Selected: " + str$(listbox_selcount(sender#)))
endfunction

function OnSelectAll(sender#)
    listbox_selectall(lst#)
    OnListChange(lst#)
endfunction

function OnClearSel(sender#)
    listbox_clearselection(lst#)
    OnListChange(lst#)
endfunction

function OnShowSel(sender#) local i, cnt
    cnt = listbox_count(lst#)
    println "Selected items:"
    for i = 0 to cnt - 1
        if listbox_isselected(lst#, i) = 1 then
            println "  " + listbox_item$(lst#, i)
        endif
    next
endfunction

let frm# = form#("Multi-Select Demo", 450, 350)
form_position#(frm#, 4)

let lst# = listbox#(frm#, 50, 50, 200, 200)
listbox_multiselect#(lst#, 1)

listbox_add(lst#, "Option 1")
listbox_add(lst#, "Option 2")
listbox_add(lst#, "Option 3")
listbox_add(lst#, "Option 4")
listbox_add(lst#, "Option 5")

let btnSelectAll# = button#(frm#, "Select All", 270, 50, 100, 30)
let btnClearSel# = button#(frm#, "Clear Selection", 270, 90, 100, 30)
let btnShowSel# = button#(frm#, "Show Selected", 270, 130, 100, 30)
let lblCount# = label#(frm#, "Selected: 0")
label_move#(lblCount#, 270, 180)

button_onclick#(btnSelectAll#, "OnSelectAll")
button_onclick#(btnClearSel#, "OnClearSel")
button_onclick#(btnShowSel#, "OnShowSel")
listbox_onchange#(lst#, "OnListChange")

form_show(frm#)

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

Item Pointer Demo

╯ itemptr.bas
function OnModify(sender#) local txt$
    txt$ = listboxitem_text$(item1#)
    listboxitem_text#(item1#, txt$ + " [modified]")
endfunction

let frm# = form#("Item Pointer Demo", 400, 300)
form_position#(frm#, 4)

let lst# = listbox#(frm#, 50, 50, 200, 180)

let item1# = listbox_additem#(lst#, "First Item")
listbox_add(lst#, "Second Item")
listbox_add(lst#, "Third Item")

let btnModify# = button#(frm#, "Modify First", 270, 50, 100, 30)
button_onclick#(btnModify#, "OnModify")

form_show(frm#)

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

Best Practices

PracticeWhy
Check listbox_itemindex for -1 before useNothing selected; accessing invalid index causes errors
Use listbox_onchange# for selection trackingFires when the selection changes
Use listbox_onitemclick# for item-specific actionsProvides item pointer directly in the callback
Use listbox_add for simple casesReturns the numeric index
Use listbox_additem# when you need the item pointerReturns a pointer for listboxitem_* functions
Call listbox_clear before repopulatingPrevents duplicate entries when refreshing data
Use listbox_indexof to find itemsReturns -1 if not found; avoids manual loops
Enable multi-select with listbox_multiselect#(lst#, 1)Allows users to select multiple items with Shift/Ctrl+click

Quick Reference

FunctionSignatureDescription
listbox_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
listbox#(parent#[, x, y, w, h])variousCreate (2 overloads)
listbox_free(lst#)listbox_free@#Destroy
listbox_add / additem# / insert / delete / clear / countvariousItem management (6)
listbox_item$ / item# / itemat#variousItem access (3)
listbox_itemindex / selected$ / indexofvariousSelection (4)
listbox_multiselect / isselected / selectitem# / selectall / clearselection / selcountvariousMulti-select (7)
listbox_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (14)
listbox_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
listbox_visible / enabled / opacity / hittest / dragmodevariousVisibility & state (10)
listbox_focus / isfocused / canfocus / tabordervariousFocus (6)
listbox_tag / parent#variousTag & parent (4)
listbox_onchange/onitemclick/onclick/ondblclick/onenter/onexit/onkeydown/onkeyup/onmousedown/up/move/enter/leave/onresize/ondragenter/over/drop/leavevariousEvents set+get (34)
listbox_clearcallbacks#listbox_clearcallbacks#@#Disconnect all events
listboxitem_text / index / isselectedvariousItem pointer functions (5)
listbox_fontcolor / fontsize / fontfamilylistbox_fontcolor#@#$  listbox_fontsize#@#n  listbox_fontfamily#@#$Font colour, size, family — applied to all items (6)
listbox_bold / italic / underline / strikeoutlistbox_bold#@#n  listbox_italic#@#n  listbox_underline#@#n  listbox_strikeout#@#nFont style flags — applied to all items (8)

126 functions (121 listbox + 5 listboxitem). Part of the Plan9Basic GUI library system.