RadioButtonLib — Radio Button Control Library

Complete functionality for creating and managing radio button controls in Plan9Basic. Radio buttons allow users to select one option from a mutually exclusive group of choices. Features include named groups for multiple independent selections on the same form, full font styling, alignment and margins, drag support, and a comprehensive event system. 110 functions.

CategoryCountDescription
Error Handling4radiobutton_error, errormsg$, strerror$, clearerror
Creation & Destruction5radiobutton# (4 overloads), radiobutton_free
Checked State2radiobutton_ischecked (get/set)
Group Name2radiobutton_groupname (get/set)
Text & Font16text, fontfamily, fontsize, fontcolor, bold, italic, underline, strikeout (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#
Events3215 event types × set/get + clearcallbacks#

Cross-Platform Support

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

Error Handling

FunctionSignatureDescription
radiobutton_error()radiobutton_error@Last error code (0 = no error)
radiobutton_errormsg$()radiobutton_errormsg$@Last error message as string
radiobutton_strerror$(code)radiobutton_strerror$@nDescription for a given error code
radiobutton_clearerror()radiobutton_clearerror@Clear the error state

Numeric Values Reference

Control Alignment radiobutton_align#

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

Drag Mode radiobutton_dragmode#

ValueDescription
0None (default)
1Automatic drag enabled

Creation & Destruction

FunctionSignatureDescription
radiobutton#(parent#)radiobutton#@#Create with default size
radiobutton#(parent#, text$)radiobutton#@#$Create with label text
radiobutton#(parent#, x, y, w, h)radiobutton#@#nnnnCreate at position and size
radiobutton#(parent#, text$, x, y, w, h)radiobutton#@#$nnnnCreate with text, position, and size
radiobutton_free(rb#)radiobutton_free@#Destroy radio button and release resources
╯ plan9basic
' Common creation patterns
let rb# = radiobutton#(frm#, "Option A")

' With full positioning
let rb# = radiobutton#(frm#, "Option B", 20, 50, 150, 22)

' Cleanup
radiobutton_free(rb#)

Checked State

FunctionSignatureDescription
radiobutton_ischecked(rb#)radiobutton_ischecked@#Get checked state (0=unchecked, 1=checked)
radiobutton_ischecked#(rb#, n)radiobutton_ischecked#@#nSet checked state
╯ plan9basic
' Set default selection
radiobutton_ischecked#(rbOption1#, 1)

' Check which is selected
if radiobutton_ischecked(rbOption1#) = 1 then
    println "Option 1 selected"
endif
ⓘ Note: When you check a radio button, all other radio buttons in the same group (same parent and group name) are automatically unchecked. This is the standard mutually-exclusive behavior.

Group Name

FunctionSignatureDescription
radiobutton_groupname$(rb#)radiobutton_groupname$@#Get the group name
radiobutton_groupname#(rb#, name$)radiobutton_groupname#@#$Set the group name

Radio buttons with the same GroupName are mutually exclusive within their parent container. By default, all radio buttons on the same parent are in one unnamed group. Use named groups to create independent sets of choices on the same form.

╯ plan9basic
' Two independent groups on the same form

' Group 1: Color selection
radiobutton_groupname#(rbRed#, "color")
radiobutton_groupname#(rbGreen#, "color")
radiobutton_groupname#(rbBlue#, "color")

' Group 2: Size selection
radiobutton_groupname#(rbSmall#, "size")
radiobutton_groupname#(rbMedium#, "size")
radiobutton_groupname#(rbLarge#, "size")

' Selecting "Red" only deselects Green/Blue, not size options
⚠ Warning: Without radiobutton_groupname#, all radio buttons on the same parent form act as one group. Selecting any one will deselect all others. Use named groups whenever you have multiple questions or categories on the same form.

Text & Font

FunctionSignatureDescription
radiobutton_text$(rb#)radiobutton_text$@#Get label text
radiobutton_text#(rb#, text$)radiobutton_text#@#$Set label text
radiobutton_fontfamily$(rb#)radiobutton_fontfamily$@#Get font family name
radiobutton_fontfamily#(rb#, family$)radiobutton_fontfamily#@#$Set font family
radiobutton_fontsize(rb#)radiobutton_fontsize@#Get font size
radiobutton_fontsize#(rb#, size)radiobutton_fontsize#@#nSet font size
radiobutton_fontcolor$(rb#)radiobutton_fontcolor$@#Get font color
radiobutton_fontcolor#(rb#, color$)radiobutton_fontcolor#@#$Set font color
radiobutton_bold(rb#)radiobutton_bold@#Get bold state (0/1)
radiobutton_bold#(rb#, n)radiobutton_bold#@#nSet bold (0/1)
radiobutton_italic(rb#)radiobutton_italic@#Get italic state (0/1)
radiobutton_italic#(rb#, n)radiobutton_italic#@#nSet italic (0/1)
radiobutton_underline(rb#)radiobutton_underline@#Get underline state (0/1)
radiobutton_underline#(rb#, n)radiobutton_underline#@#nSet underline (0/1)
radiobutton_strikeout(rb#)radiobutton_strikeout@#Get strikeout state (0/1)
radiobutton_strikeout#(rb#, n)radiobutton_strikeout#@#nSet strikeout (0/1)
╯ plan9basic
radiobutton_fontfamily#(rb#, "Arial")
radiobutton_fontsize#(rb#, 14)
radiobutton_fontcolor#(rb#, "#333333")
radiobutton_bold#(rb#, 1)

Position & Size

FunctionSignatureDescription
radiobutton_x(rb#)radiobutton_x@#Get X position
radiobutton_x#(rb#, x)radiobutton_x#@#nSet X position
radiobutton_y(rb#)radiobutton_y@#Get Y position
radiobutton_y#(rb#, y)radiobutton_y#@#nSet Y position
radiobutton_width(rb#)radiobutton_width@#Get width
radiobutton_width#(rb#, w)radiobutton_width#@#nSet width
radiobutton_height(rb#)radiobutton_height@#Get height
radiobutton_height#(rb#, h)radiobutton_height#@#nSet height
radiobutton_bounds#(rb#, x, y, w, h)radiobutton_bounds#@#nnnnSet position and size in one call
radiobutton_move#(rb#, x, y)radiobutton_move#@#nnSet position only
radiobutton_size#(rb#, w, h)radiobutton_size#@#nnSet size only
╯ plan9basic
' Typical radio button layout
let rb1# = radiobutton#(frm#, "Option A", 20, 50, 150, 22)
let rb2# = radiobutton#(frm#, "Option B", 20, 77, 150, 22)
let rb3# = radiobutton#(frm#, "Option C", 20, 104, 150, 22)
ⓘ Note: Keep 25–30 pixels of vertical spacing between radio buttons for comfortable reading. Ensure the width is large enough to display the full label text.

Alignment & Margins

FunctionSignatureDescription
radiobutton_align(rb#)radiobutton_align@#Get control alignment mode
radiobutton_align#(rb#, n)radiobutton_align#@#nSet control alignment (0=none, 1=top, 2=left, 3=right, 4=bottom, 9=client)
radiobutton_margin#(rb#, n)radiobutton_margin#@#nSet uniform margin on all four sides
radiobutton_margins#(rb#, l, t, r, b)radiobutton_margins#@#nnnnSet individual margins (left, top, right, bottom)
radiobutton_marginleft(rb#)radiobutton_marginleft@#Get left margin
radiobutton_marginleft#(rb#, n)radiobutton_marginleft#@#nSet left margin
radiobutton_margintop(rb#)radiobutton_margintop@#Get top margin
radiobutton_margintop#(rb#, n)radiobutton_margintop#@#nSet top margin
radiobutton_marginright(rb#)radiobutton_marginright@#Get right margin
radiobutton_marginright#(rb#, n)radiobutton_marginright#@#nSet right margin
radiobutton_marginbottom(rb#)radiobutton_marginbottom@#Get bottom margin
radiobutton_marginbottom#(rb#, n)radiobutton_marginbottom#@#nSet bottom margin
╯ plan9basic
' Stack radio buttons at the top of a panel
radiobutton_align#(rb1#, 1)    ' Align top
radiobutton_margins#(rb1#, 10, 5, 0, 0)

Visibility & State

FunctionSignatureDescription
radiobutton_visible(rb#)radiobutton_visible@#Get visibility (0/1)
radiobutton_visible#(rb#, n)radiobutton_visible#@#nSet visibility (0=hidden, 1=visible)
radiobutton_enabled(rb#)radiobutton_enabled@#Get enabled state (0/1)
radiobutton_enabled#(rb#, n)radiobutton_enabled#@#nSet enabled state (0=disabled/grayed, 1=enabled)
radiobutton_opacity(rb#)radiobutton_opacity@#Get opacity (0.0–1.0)
radiobutton_opacity#(rb#, value)radiobutton_opacity#@#nSet opacity (0.0=transparent, 1.0=opaque)

Focus

FunctionSignatureDescription
radiobutton_isfocused(rb#)radiobutton_isfocused@#Is this radio button focused? (0/1)
radiobutton_setfocus#(rb#)radiobutton_setfocus#@#Give keyboard focus
radiobutton_resetfocus#(rb#)radiobutton_resetfocus#@#Release focus
radiobutton_taborder(rb#)radiobutton_taborder@#Get tab order index
radiobutton_taborder#(rb#, n)radiobutton_taborder#@#nSet tab order index

Interaction

FunctionSignatureDescription
radiobutton_canfocus(rb#)radiobutton_canfocus@#Get whether radio button can receive focus (0/1)
radiobutton_canfocus#(rb#, n)radiobutton_canfocus#@#nSet whether radio button can receive focus
radiobutton_hittest(rb#)radiobutton_hittest@#Get hit-test state (0/1)
radiobutton_hittest#(rb#, n)radiobutton_hittest#@#nEnable/disable mouse hit testing
radiobutton_dragmode(rb#)radiobutton_dragmode@#Get drag mode (0=none, 1=automatic)
radiobutton_dragmode#(rb#, n)radiobutton_dragmode#@#nSet drag mode

Tag & Parent

FunctionSignatureDescription
radiobutton_tag(rb#)radiobutton_tag@#Get user-defined integer tag
radiobutton_tag#(rb#, n)radiobutton_tag#@#nSet user-defined integer tag
radiobutton_parent#(rb#)radiobutton_parent#@#Get parent control pointer
radiobutton_parent#(rb#, parent#)radiobutton_parent#@##Move radio button to a different parent
radiobutton_bringtofront#(rb#)radiobutton_bringtofront#@#Bring to front of Z-order
radiobutton_sendtoback#(rb#)radiobutton_sendtoback#@#Send to back of Z-order

Events

Each event has a setter (radiobutton_onXXX#(rb#, func$)) and a getter (radiobutton_onXXX$(rb#)). Use radiobutton_clearcallbacks#(rb#) to disconnect all callbacks at once.

State & Focus Events

Event SetterGetterCallback Signature
radiobutton_onchange#(rb#, func$)radiobutton_onchange$(rb#)function name(sender#)
radiobutton_onclick#(rb#, func$)radiobutton_onclick$(rb#)function name(sender#)
radiobutton_ondblclick#(rb#, func$)radiobutton_ondblclick$(rb#)function name(sender#)
radiobutton_onenter#(rb#, func$)radiobutton_onenter$(rb#)function name(sender#)
radiobutton_onexit#(rb#, func$)radiobutton_onexit$(rb#)function name(sender#)
ⓘ Note: OnChange is the primary event for radio buttons. It fires when the selection changes. Assign the same callback to all buttons in a group to handle the change centrally.

Keyboard Events

Event SetterGetterCallback Signature
radiobutton_onkeydown#(rb#, func$)radiobutton_onkeydown$(rb#)function name(sender#, key, keychar$, shift$)
radiobutton_onkeyup#(rb#, func$)radiobutton_onkeyup$(rb#)function name(sender#, key, keychar$, shift$)

Mouse Events

Event SetterGetterCallback Signature
radiobutton_onmousedown#(rb#, func$)radiobutton_onmousedown$(rb#)function name(sender#, button, x, y, shift$)
radiobutton_onmouseup#(rb#, func$)radiobutton_onmouseup$(rb#)function name(sender#, button, x, y, shift$)
radiobutton_onmousemove#(rb#, func$)radiobutton_onmousemove$(rb#)function name(sender#, x, y, shift$)
radiobutton_onmouseenter#(rb#, func$)radiobutton_onmouseenter$(rb#)function name(sender#)
radiobutton_onmouseleave#(rb#, func$)radiobutton_onmouseleave$(rb#)function name(sender#)

Other Events

Event SetterGetterCallback Signature
radiobutton_onresize#(rb#, func$)radiobutton_onresize$(rb#)function name(sender#)
radiobutton_ondragenter#(rb#, func$)radiobutton_ondragenter$(rb#)function name(sender#)
radiobutton_ondragover#(rb#, func$)radiobutton_ondragover$(rb#)function name(sender#)
radiobutton_ondragdrop#(rb#, func$)radiobutton_ondragdrop$(rb#)function name(sender#)
radiobutton_ondragleave#(rb#, func$)radiobutton_ondragleave$(rb#)function name(sender#)
radiobutton_clearcallbacks#(rb#)Disconnect all event callbacks

Complete Examples

Survey Form (Multiple Groups)

╯ survey.bas
function OnSubmit(sender#) local age$, sat$
    age$ = "Not selected"
    if radiobutton_ischecked(rbAge1#) = 1 then age$ = "Under 18"
    if radiobutton_ischecked(rbAge2#) = 1 then age$ = "18-35"
    if radiobutton_ischecked(rbAge3#) = 1 then age$ = "36-55"
    if radiobutton_ischecked(rbAge4#) = 1 then age$ = "Over 55"

    sat$ = "Not selected"
    if radiobutton_ischecked(rbSat1#) = 1 then sat$ = "Very satisfied"
    if radiobutton_ischecked(rbSat2#) = 1 then sat$ = "Satisfied"
    if radiobutton_ischecked(rbSat3#) = 1 then sat$ = "Neutral"
    if radiobutton_ischecked(rbSat4#) = 1 then sat$ = "Dissatisfied"

    label_text#(lblResult#, "Age: " + age$ + " | Satisfaction: " + sat$)
endfunction

let frm# = form#("Customer Survey", 350, 300)
form_position#(frm#, 4)

' Question 1: Age group
let lblAge# = label#(frm#, "Your age group:")
label_move#(lblAge#, 20, 20)
label_bold#(lblAge#, 1)

let rbAge1# = radiobutton#(frm#, "Under 18", 20, 45, 120, 22)
let rbAge2# = radiobutton#(frm#, "18-35", 20, 70, 120, 22)
let rbAge3# = radiobutton#(frm#, "36-55", 20, 95, 120, 22)
let rbAge4# = radiobutton#(frm#, "Over 55", 20, 120, 120, 22)
radiobutton_groupname#(rbAge1#, "age")
radiobutton_groupname#(rbAge2#, "age")
radiobutton_groupname#(rbAge3#, "age")
radiobutton_groupname#(rbAge4#, "age")

' Question 2: Satisfaction
let lblSat# = label#(frm#, "Satisfaction level:")
label_move#(lblSat#, 180, 20)
label_bold#(lblSat#, 1)

let rbSat1# = radiobutton#(frm#, "Very satisfied", 180, 45, 150, 22)
let rbSat2# = radiobutton#(frm#, "Satisfied", 180, 70, 150, 22)
let rbSat3# = radiobutton#(frm#, "Neutral", 180, 95, 150, 22)
let rbSat4# = radiobutton#(frm#, "Dissatisfied", 180, 120, 150, 22)
radiobutton_groupname#(rbSat1#, "satisfaction")
radiobutton_groupname#(rbSat2#, "satisfaction")
radiobutton_groupname#(rbSat3#, "satisfaction")
radiobutton_groupname#(rbSat4#, "satisfaction")

let btnSubmit# = button#(frm#, "Submit", 125, 200, 100, 35)
button_onclick#(btnSubmit#, "OnSubmit")

let lblResult# = label#(frm#, "")
label_bounds#(lblResult#, 20, 250, 310, 40)

form_show(frm#)

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

Theme Selector

╯ theme.bas
function OnThemeChange(sender#)
    if radiobutton_ischecked(rbLight#) = 1 then
        label_text#(lblPreview#, "Preview: Light theme")
    elseif radiobutton_ischecked(rbDark#) = 1 then
        label_text#(lblPreview#, "Preview: Dark theme")
    elseif radiobutton_ischecked(rbSystem#) = 1 then
        label_text#(lblPreview#, "Preview: System default")
    endif
endfunction

let frm# = form#("Theme Settings", 280, 200)
form_position#(frm#, 4)

let lblTheme# = label#(frm#, "Select theme:")
label_move#(lblTheme#, 20, 20)

let rbLight# = radiobutton#(frm#, "Light", 20, 50, 100, 22)
let rbDark# = radiobutton#(frm#, "Dark", 20, 80, 100, 22)
let rbSystem# = radiobutton#(frm#, "System Default", 20, 110, 150, 22)
radiobutton_ischecked#(rbLight#, 1)

radiobutton_onchange#(rbLight#, "OnThemeChange")
radiobutton_onchange#(rbDark#, "OnThemeChange")
radiobutton_onchange#(rbSystem#, "OnThemeChange")

let lblPreview# = label#(frm#, "Preview: Light theme")
label_move#(lblPreview#, 20, 150)
label_fontsize#(lblPreview#, 12)

form_show(frm#)

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

Quiz with Scoring

╯ quiz.bas
function OnCheck(sender#) local score
    score = 0
    if radiobutton_ischecked(rbQ1B#) = 1 then score = score + 1
    if radiobutton_ischecked(rbQ2B#) = 1 then score = score + 1
    label_text#(lblScore#, "Score: " + str$(score) + " / 2")
endfunction

let frm# = form#("Quiz", 400, 350)
form_position#(frm#, 4)

' Question 1
let lblQ1# = label#(frm#, "1. What is the capital of France?")
label_move#(lblQ1#, 20, 20)
label_bold#(lblQ1#, 1)

let rbQ1A# = radiobutton#(frm#, "London", 30, 45, 150, 22)
let rbQ1B# = radiobutton#(frm#, "Paris", 30, 70, 150, 22)
let rbQ1C# = radiobutton#(frm#, "Berlin", 30, 95, 150, 22)
radiobutton_groupname#(rbQ1A#, "q1")
radiobutton_groupname#(rbQ1B#, "q1")
radiobutton_groupname#(rbQ1C#, "q1")

' Question 2
let lblQ2# = label#(frm#, "2. What is 7 x 8?")
label_move#(lblQ2#, 20, 130)
label_bold#(lblQ2#, 1)

let rbQ2A# = radiobutton#(frm#, "54", 30, 155, 150, 22)
let rbQ2B# = radiobutton#(frm#, "56", 30, 180, 150, 22)
let rbQ2C# = radiobutton#(frm#, "58", 30, 205, 150, 22)
radiobutton_groupname#(rbQ2A#, "q2")
radiobutton_groupname#(rbQ2B#, "q2")
radiobutton_groupname#(rbQ2C#, "q2")

let btnCheck# = button#(frm#, "Check Answers", 140, 250, 120, 35)
button_onclick#(btnCheck#, "OnCheck")

let lblScore# = label#(frm#, "")
label_move#(lblScore#, 20, 300)
label_fontsize#(lblScore#, 14)

form_show(frm#)

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

Payment Method

╯ payment.bas
function OnContinue(sender#) local method$
    method$ = ""
    if radiobutton_ischecked(rbCard#) = 1 then method$ = "Credit Card"
    if radiobutton_ischecked(rbPaypal#) = 1 then method$ = "PayPal"
    if radiobutton_ischecked(rbBank#) = 1 then method$ = "Bank Transfer"
    if radiobutton_ischecked(rbCash#) = 1 then method$ = "Cash on Delivery"
    println "Selected payment: " + method$
endfunction

let frm# = form#("Payment", 300, 220)
form_position#(frm#, 4)

let lblPay# = label#(frm#, "Payment method:")
label_move#(lblPay#, 20, 20)
label_bold#(lblPay#, 1)

let rbCard# = radiobutton#(frm#, "Credit Card", 20, 50, 150, 22)
let rbPaypal# = radiobutton#(frm#, "PayPal", 20, 80, 150, 22)
let rbBank# = radiobutton#(frm#, "Bank Transfer", 20, 110, 150, 22)
let rbCash# = radiobutton#(frm#, "Cash on Delivery", 20, 140, 170, 22)
radiobutton_ischecked#(rbCard#, 1)

let btnContinue# = button#(frm#, "Continue", 100, 175, 100, 35)
button_onclick#(btnContinue#, "OnContinue")

form_show(frm#)

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

Best Practices

PracticeWhy
Use radiobutton_groupname# for multiple groupsPrevents all radio buttons on a form from acting as one group
Always set a default selectionCall radiobutton_ischecked#(rb#, 1) on one button per group
Use radiobutton_onchange# as the primary eventFires only when the selection actually changes
Assign the same callback to all buttons in a groupHandle the change centrally instead of per-button
Ensure width accommodates the full label textShort widths can clip the label
Use 25–30px vertical spacing between optionsComfortable touch and click targets
Group related options visuallyUse bold labels and spacing to separate question groups

Quick Reference

FunctionSignatureDescription
radiobutton_error / errormsg$ / strerror$ / clearerrorvariousError handling (4)
radiobutton#(parent#[, text$][, x, y, w, h])variousCreate (4 overloads)
radiobutton_free(rb#)radiobutton_free@#Destroy
radiobutton_ischecked (get/set)variousChecked state (2)
radiobutton_groupname (get/set)variousGroup name (2)
radiobutton_text / fontfamily / fontsize / fontcolor / bold / italic / underline / strikeoutvariousText & font (16)
radiobutton_x/y/width/height (get/set) / bounds# / move# / size#variousPosition & size (14)
radiobutton_align / margin# / margins# / margin[left/top/right/bottom]variousAlignment & margins (12)
radiobutton_visible / enabled / opacityvariousVisibility & state (6)
radiobutton_isfocused / setfocus# / resetfocus# / tabordervariousFocus (5)
radiobutton_canfocus / hittest / dragmodevariousInteraction (6)
radiobutton_tag / parent# / bringtofront# / sendtoback#variousTag & parent (6)
radiobutton_onchange/onclick/ondblclick/onenter/onexit/onkeydown/onkeyup/onmousedown/up/move/enter/leave/onresize/ondragenter/over/drop/leavevariousEvents set+get (31)
radiobutton_clearcallbacks#radiobutton_clearcallbacks#@#Disconnect all events

110 functions. Part of the Plan9Basic GUI library system.