SpeedButtonLib — Speed Button Control Library

Flat, graphical toggle buttons ideal for toolbars, tool palettes, and grouped button sets. SpeedButtons support toggle behavior with StaysPressed, mutual exclusion via GroupIndex, and a pressed/released visual state. They combine the click simplicity of a button with the toggle semantics of a checkbox or radio button. 93 functions.

CategoryCountDescription
Error Handling4speedbutton_error, errormsg$, strerror$, clearerror
Creation & Destruction5speedbutton# (4 overloads), speedbutton_free
Text2text$ (get/set)
Font Properties12fontfamily$, fontsize, fontcolor$, bold, italic, underline, strikeout (get/set)
SpeedButton Properties6groupindex, stayspressed, down (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 & State10visible, enabled, opacity, hittest, dragmode (get/set)
Tag & Parent6tag (get/set), parent# (get/set), bringtofront#, sendtoback#
Events2210 event types × set/get + clearcallbacks#

Cross-Platform Support

PlatformStatusNotes
Windows✅ Full SupportWin32/Win64
Linux✅ Full SupportGTK-based
Android✅ Full SupportTouch-friendly

Error Handling

FunctionSignatureDescription
speedbutton_error()speedbutton_error@Last error code (0 = no error)
speedbutton_errormsg$()speedbutton_errormsg$@Last error message as string
speedbutton_strerror$(code)speedbutton_strerror$@nDescription for a given error code
speedbutton_clearerror()speedbutton_clearerror@Clear the error state

Numeric Values Reference

Control Alignment speedbutton_align#

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

Group Index speedbutton_groupindex#

ValueBehaviorUse Case
0Independent (no grouping)Standalone toggle buttons (Bold, Italic, Underline)
1+Mutually exclusive within same groupRadio-button behavior (tool selection, alignment)

Drag Mode speedbutton_dragmode#

ValueDescription
0None (default)
1Automatic drag enabled

Creation & Destruction

FunctionSignatureDescription
speedbutton#(parent#)speedbutton#@#Create with default size
speedbutton#(parent#, text$)speedbutton#@#$Create with text label
speedbutton#(parent#, x, y, w, h)speedbutton#@#nnnnCreate with position and size
speedbutton#(parent#, text$, x, y, w, h)speedbutton#@#$nnnnCreate with text, position, and size
speedbutton_free(btn#)speedbutton_free@#Destroy speed button
╯ plan9basic
' Typical toolbar button
let btnBold# = speedbutton#(toolbar#, "B", 5, 5, 30, 30)

' Button with just position/size
let btn# = speedbutton#(frm#, 10, 10, 80, 30)

Text

FunctionSignatureDescription
speedbutton_text$(btn#)speedbutton_text$@#Get button text
speedbutton_text#(btn#, text$)speedbutton_text#@#$Set button text

Font Properties

FunctionSignatureDescription
speedbutton_fontfamily$(btn#)speedbutton_fontfamily$@#Get font family name
speedbutton_fontfamily#(btn#, family$)speedbutton_fontfamily#@#$Set font family
speedbutton_fontsize(btn#)speedbutton_fontsize@#Get font size
speedbutton_fontsize#(btn#, size)speedbutton_fontsize#@#nSet font size
speedbutton_fontcolor$(btn#)speedbutton_fontcolor$@#Get font color as hex string
speedbutton_fontcolor#(btn#, color$)speedbutton_fontcolor#@#$Set font color (e.g., "#FF0000")
speedbutton_bold(btn#)speedbutton_bold@#Get bold state (0/1)
speedbutton_bold#(btn#, n)speedbutton_bold#@#nSet bold
speedbutton_italic(btn#)speedbutton_italic@#Get italic state (0/1)
speedbutton_italic#(btn#, n)speedbutton_italic#@#nSet italic
speedbutton_underline(btn#)speedbutton_underline@#Get underline state (0/1)
speedbutton_underline#(btn#, n)speedbutton_underline#@#nSet underline
speedbutton_strikeout(btn#)speedbutton_strikeout@#Get strikeout state (0/1)
speedbutton_strikeout#(btn#, n)speedbutton_strikeout#@#nSet strikeout
╯ plan9basic
' Style the bold button to look bold
let btnBold# = speedbutton#(toolbar#, "B", 5, 5, 30, 30)
speedbutton_bold#(btnBold#, 1)
speedbutton_fontsize#(btnBold#, 14)

' Italic button
let btnItalic# = speedbutton#(toolbar#, "I", 40, 5, 30, 30)
speedbutton_italic#(btnItalic#, 1)

SpeedButton-Specific Properties

These three property pairs define the toggle and grouping behavior that makes SpeedButtons unique.

FunctionSignatureDescription
speedbutton_groupindex(btn#)speedbutton_groupindex@#Get group index (0 = independent, no group)
speedbutton_groupindex#(btn#, n)speedbutton_groupindex#@#nSet group index
speedbutton_stayspressed(btn#)speedbutton_stayspressed@#Get toggle mode (0=momentary, 1=toggle)
speedbutton_stayspressed#(btn#, n)speedbutton_stayspressed#@#nEnable/disable toggle behavior
speedbutton_down(btn#)speedbutton_down@#Get pressed state (0=up, 1=down)
speedbutton_down#(btn#, n)speedbutton_down#@#nSet pressed state programmatically

How GroupIndex and StaysPressed Work Together

GroupIndexStaysPressedBehaviorExample
00Momentary push button (click and release)Action buttons (Copy, Paste, Delete)
01Independent toggle (each button toggles on/off independently)Formatting (Bold, Italic, Underline)
1+(automatic)Mutually exclusive group (only one can be pressed at a time)Tool selection, alignment, view modes
╯ plan9basic
' Independent toggles (each can be on/off)
speedbutton_stayspressed#(btnBold#, 1)
speedbutton_stayspressed#(btnItalic#, 1)
speedbutton_stayspressed#(btnUnder#, 1)

' Mutually exclusive group
speedbutton_groupindex#(btnLeft#, 1)
speedbutton_groupindex#(btnCenter#, 1)
speedbutton_groupindex#(btnRight#, 1)
speedbutton_down#(btnLeft#, 1)  ' Start with Left selected

' Check state in a handler
if speedbutton_down(btnBold#) = 1 then
    println "Bold is ON"
endif
⚠ Warning: When using GroupIndex > 0, StaysPressed is automatically enabled. You only need to set StaysPressed explicitly for independent toggles (GroupIndex = 0).
ⓘ Note: Within a group, clicking an already-pressed button does not depress it — one button in the group is always pressed. This matches radio button semantics.

Position & Size

FunctionSignatureDescription
speedbutton_x(btn#)speedbutton_x@#Get X position
speedbutton_x#(btn#, x)speedbutton_x#@#nSet X position
speedbutton_y(btn#)speedbutton_y@#Get Y position
speedbutton_y#(btn#, y)speedbutton_y#@#nSet Y position
speedbutton_width(btn#)speedbutton_width@#Get width
speedbutton_width#(btn#, w)speedbutton_width#@#nSet width
speedbutton_height(btn#)speedbutton_height@#Get height
speedbutton_height#(btn#, h)speedbutton_height#@#nSet height
speedbutton_bounds#(btn#, x, y, w, h)speedbutton_bounds#@#nnnnSet position and size in one call
speedbutton_move#(btn#, x, y)speedbutton_move#@#nnSet position only
speedbutton_size#(btn#, w, h)speedbutton_size#@#nnSet size only

Alignment & Margins

FunctionSignatureDescription
speedbutton_align(btn#)speedbutton_align@#Get control alignment
speedbutton_align#(btn#, n)speedbutton_align#@#nSet alignment
speedbutton_margin#(btn#, n)speedbutton_margin#@#nSet uniform margin on all four sides
speedbutton_margins#(btn#, l, t, r, b)speedbutton_margins#@#nnnnSet individual margins
speedbutton_marginleft(btn#)speedbutton_marginleft@#Get left margin
speedbutton_marginleft#(btn#, n)speedbutton_marginleft#@#nSet left margin
speedbutton_margintop(btn#)speedbutton_margintop@#Get top margin
speedbutton_margintop#(btn#, n)speedbutton_margintop#@#nSet top margin
speedbutton_marginright(btn#)speedbutton_marginright@#Get right margin
speedbutton_marginright#(btn#, n)speedbutton_marginright#@#nSet right margin
speedbutton_marginbottom(btn#)speedbutton_marginbottom@#Get bottom margin
speedbutton_marginbottom#(btn#, n)speedbutton_marginbottom#@#nSet bottom margin

Visibility & State

FunctionSignatureDescription
speedbutton_visible(btn#)speedbutton_visible@#Get visibility (0/1)
speedbutton_visible#(btn#, n)speedbutton_visible#@#nSet visibility
speedbutton_enabled(btn#)speedbutton_enabled@#Get enabled state (0/1)
speedbutton_enabled#(btn#, n)speedbutton_enabled#@#nSet enabled state
speedbutton_opacity(btn#)speedbutton_opacity@#Get opacity (0.0–1.0)
speedbutton_opacity#(btn#, value)speedbutton_opacity#@#nSet opacity
speedbutton_hittest(btn#)speedbutton_hittest@#Get hit-test state (0/1)
speedbutton_hittest#(btn#, n)speedbutton_hittest#@#nEnable/disable mouse hit testing
speedbutton_dragmode(btn#)speedbutton_dragmode@#Get drag mode (0=none, 1=auto)
speedbutton_dragmode#(btn#, n)speedbutton_dragmode#@#nSet drag mode

Tag & Parent

FunctionSignatureDescription
speedbutton_tag(btn#)speedbutton_tag@#Get user-defined integer tag
speedbutton_tag#(btn#, n)speedbutton_tag#@#nSet user-defined integer tag
speedbutton_parent#(btn#)speedbutton_parent#@#Get parent control pointer
speedbutton_parent#(btn#, parent#)speedbutton_parent#@##Move speed button to a different parent
speedbutton_bringtofront#(btn#)speedbutton_bringtofront#@#Bring to front of Z-order
speedbutton_sendtoback#(btn#)speedbutton_sendtoback#@#Send to back of Z-order

Events

Each event has a setter (speedbutton_onXXX#(btn#, func$)) and a getter (speedbutton_onXXX$(btn#)). Use speedbutton_clearcallbacks#(btn#) to disconnect all callbacks at once.

Click & Resize Events

Event SetterGetterCallback Signature
speedbutton_onclick#(btn#, func$)speedbutton_onclick$(btn#)function name(sender#)
speedbutton_onresize#(btn#, func$)speedbutton_onresize$(btn#)function name(sender#)
ⓘ Note: In the OnClick handler, use speedbutton_down(sender#) to check the new pressed state after the click. For grouped buttons, use speedbutton_text$(sender#) to identify which button was clicked.

Mouse Events

Event SetterGetterCallback Signature
speedbutton_onmousedown#(btn#, func$)speedbutton_onmousedown$(btn#)function name(sender#, button, x, y, shift$)
speedbutton_onmouseup#(btn#, func$)speedbutton_onmouseup$(btn#)function name(sender#, button, x, y, shift$)
speedbutton_onmousemove#(btn#, func$)speedbutton_onmousemove$(btn#)function name(sender#, x, y, shift$)
speedbutton_onmouseenter#(btn#, func$)speedbutton_onmouseenter$(btn#)function name(sender#)
speedbutton_onmouseleave#(btn#, func$)speedbutton_onmouseleave$(btn#)function name(sender#)

Drag Events

Event SetterGetterCallback Signature
speedbutton_ondragenter#(btn#, func$)speedbutton_ondragenter$(btn#)function name(sender#, x, y)
speedbutton_ondragover#(btn#, func$)speedbutton_ondragover$(btn#)function name(sender#, x, y)
speedbutton_ondragdrop#(btn#, func$)speedbutton_ondragdrop$(btn#)function name(sender#, x, y)
speedbutton_ondragleave#(btn#, func$)speedbutton_ondragleave$(btn#)function name(sender#)
speedbutton_clearcallbacks#(btn#)Disconnect all event callbacks

SpeedButton vs Button vs CheckBox vs RadioButton

FeatureSpeedButtonButtonCheckBoxRadioButton
Visual StyleFlat / toolbarRaised / standardBox with tickCircle with dot
Toggle BehaviorOptional (StaysPressed)No (momentary)Always toggleAlways toggle
Mutual ExclusionOptional (GroupIndex)NoNoYes (by parent)
Built-in TextYesYesYesYes
Font StylingYes (bold, italic, etc.)YesLimitedLimited
Focus / Tab OrderNoYesYesYes
Best ForToolbars, formatting, tool palettesActions, dialogsForms, settings listsSingle-choice selections

Complete Examples

Formatting Toolbar (Independent Toggles)

╯ toolbar.bas
function UpdateStyle(sender#)
    memo_bold#(mem#, speedbutton_down(btnBold#))
    memo_italic#(mem#, speedbutton_down(btnItalic#))
    memo_underline#(mem#, speedbutton_down(btnUnder#))
endfunction

let frm# = form#("Toolbar Demo", 500, 350)
form_position#(frm#, 4)

' Toolbar panel docked to top
let toolbar# = panel#(frm#, 0, 0, 500, 40)
panel_align#(toolbar#, 1)

' Independent toggle buttons (GroupIndex = 0)
let btnBold# = speedbutton#(toolbar#, "B", 5, 5, 30, 30)
speedbutton_bold#(btnBold#, 1)
speedbutton_stayspressed#(btnBold#, 1)

let btnItalic# = speedbutton#(toolbar#, "I", 40, 5, 30, 30)
speedbutton_italic#(btnItalic#, 1)
speedbutton_stayspressed#(btnItalic#, 1)

let btnUnder# = speedbutton#(toolbar#, "U", 75, 5, 30, 30)
speedbutton_underline#(btnUnder#, 1)
speedbutton_stayspressed#(btnUnder#, 1)

' Text area
let mem# = memo#(frm#, 10, 50, 480, 290)
memo_align#(mem#, 9)
memo_margin#(mem#, 10)

speedbutton_onclick#(btnBold#, "UpdateStyle")
speedbutton_onclick#(btnItalic#, "UpdateStyle")
speedbutton_onclick#(btnUnder#, "UpdateStyle")

form_show(frm#)

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

Alignment Group (Mutually Exclusive)

╯ alignment.bas
function OnAlign(sender#) local txt$
    txt$ = speedbutton_text$(sender#)
    label_text#(lblResult#, "Current: " + txt$)
endfunction

let frm# = form#("Alignment Options", 300, 200)
form_position#(frm#, 4)

label#(frm#, "Select Alignment:", 20, 20)

' Mutually exclusive group (GroupIndex = 1)
let btnLeft# = speedbutton#(frm#, "Left", 20, 50, 80, 30)
let btnCenter# = speedbutton#(frm#, "Center", 105, 50, 80, 30)
let btnRight# = speedbutton#(frm#, "Right", 190, 50, 80, 30)

speedbutton_groupindex#(btnLeft#, 1)
speedbutton_groupindex#(btnCenter#, 1)
speedbutton_groupindex#(btnRight#, 1)
speedbutton_down#(btnLeft#, 1)  ' Start selected

let lblResult# = label#(frm#, "Current: Left")
label_move#(lblResult#, 20, 100)

speedbutton_onclick#(btnLeft#, "OnAlign")
speedbutton_onclick#(btnCenter#, "OnAlign")
speedbutton_onclick#(btnRight#, "OnAlign")

form_show(frm#)

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

Tool Palette

╯ toolpalette.bas
function OnTool(sender#)
    label_text#(lblTool#, "Tool: " + speedbutton_text$(sender#))
endfunction

let frm# = form#("Tool Palette", 200, 300)
form_position#(frm#, 4)

' Tool buttons - mutually exclusive (GroupIndex = 1)
let btnSelect# = speedbutton#(frm#, "Select", 10, 10, 80, 30)
let btnPen# = speedbutton#(frm#, "Pen", 10, 45, 80, 30)
let btnBrush# = speedbutton#(frm#, "Brush", 10, 80, 80, 30)
let btnEraser# = speedbutton#(frm#, "Eraser", 10, 115, 80, 30)
let btnFill# = speedbutton#(frm#, "Fill", 10, 150, 80, 30)

speedbutton_groupindex#(btnSelect#, 1)
speedbutton_groupindex#(btnPen#, 1)
speedbutton_groupindex#(btnBrush#, 1)
speedbutton_groupindex#(btnEraser#, 1)
speedbutton_groupindex#(btnFill#, 1)
speedbutton_down#(btnSelect#, 1)

let lblTool# = label#(frm#, "Tool: Select")
label_move#(lblTool#, 10, 200)

speedbutton_onclick#(btnSelect#, "OnTool")
speedbutton_onclick#(btnPen#, "OnTool")
speedbutton_onclick#(btnBrush#, "OnTool")
speedbutton_onclick#(btnEraser#, "OnTool")
speedbutton_onclick#(btnFill#, "OnTool")

form_show(frm#)

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

Mixed Toolbar (Groups + Independent)

╯ mixedtoolbar.bas
function OnFormatBtn(sender#)
    println speedbutton_text$(sender#) + ": " + str$(speedbutton_down(sender#))
endfunction

function OnAlignBtn(sender#)
    println "Align: " + speedbutton_text$(sender#)
endfunction

let frm# = form#("Mixed Toolbar", 500, 100)
form_position#(frm#, 4)

' --- Independent toggles (formatting) ---
let btnB# = speedbutton#(frm#, "B", 10, 10, 30, 30)
speedbutton_bold#(btnB#, 1)
speedbutton_stayspressed#(btnB#, 1)

let btnI# = speedbutton#(frm#, "I", 45, 10, 30, 30)
speedbutton_italic#(btnI#, 1)
speedbutton_stayspressed#(btnI#, 1)

let btnU# = speedbutton#(frm#, "U", 80, 10, 30, 30)
speedbutton_underline#(btnU#, 1)
speedbutton_stayspressed#(btnU#, 1)

' --- Mutually exclusive group (alignment) ---
let btnL# = speedbutton#(frm#, "Left", 140, 10, 60, 30)
let btnC# = speedbutton#(frm#, "Center", 205, 10, 60, 30)
let btnR# = speedbutton#(frm#, "Right", 270, 10, 60, 30)

speedbutton_groupindex#(btnL#, 1)
speedbutton_groupindex#(btnC#, 1)
speedbutton_groupindex#(btnR#, 1)
speedbutton_down#(btnL#, 1)

speedbutton_onclick#(btnB#, "OnFormatBtn")
speedbutton_onclick#(btnI#, "OnFormatBtn")
speedbutton_onclick#(btnU#, "OnFormatBtn")
speedbutton_onclick#(btnL#, "OnAlignBtn")
speedbutton_onclick#(btnC#, "OnAlignBtn")
speedbutton_onclick#(btnR#, "OnAlignBtn")

form_show(frm#)

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

Best Practices

PracticeWhy
Use GroupIndex > 0 for mutual exclusionButtons with the same GroupIndex act like radio buttons (only one pressed at a time)
Use GroupIndex = 0 + StaysPressed = 1 for independent togglesEach button toggles on/off independently (Bold, Italic, Underline)
Check speedbutton_down() for toggle stateReturns 1 if pressed, 0 if released
Place in a Panel for organized toolbarsPanel with align = 1 (Top) creates a docked toolbar area
Style button text to match functionMake the “B” button bold, the “I” button italic — visual affordance
Use multiple GroupIndex values for separate groupsGroup 1 for alignment, Group 2 for view mode — groups are independent of each other
SpeedButtons don't receive focusUse regular Button if keyboard/tab navigation is needed
⚠ Warning: SpeedButtons do not participate in tab order and cannot receive keyboard focus. If you need keyboard-accessible toggle buttons, consider using CheckBox or regular Button with manual state management.

Quick Reference

FunctionSignatureDescription
speedbutton_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
speedbutton#(parent#[, text$][, x, y, w, h])variousCreate (4 overloads)
speedbutton_free(btn#)speedbutton_free@#Destroy
speedbutton_text$ (get/set)variousText (2)
speedbutton_fontfamily$ / fontsize / fontcolor$ / bold / italic / underline / strikeoutvariousFont properties (12)
speedbutton_groupindex / stayspressed / down (get/set)variousSpeedButton properties (6)
speedbutton_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (14)
speedbutton_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
speedbutton_visible / enabled / opacity / hittest / dragmodevariousVisibility & state (10)
speedbutton_tag / parent# / bringtofront# / sendtoback#variousTag & parent (6)
speedbutton_onclick/onresize/onmousedown/up/move/enter/leave/ondragenter/over/drop/leavevariousEvents set+get (21)
speedbutton_clearcallbacks#speedbutton_clearcallbacks#@#Disconnect all events

93 functions. Part of the Plan9Basic GUI library system.