SwitchLib — Switch Control Library
Modern on/off toggle controls for Plan9Basic applications. Switches provide a touch-friendly toggle interface ideal for settings and preferences, with animated state transitions. Features include a dedicated OnSwitch event that fires only on actual state changes, programmatic toggle, alignment and margins, drag support, and a comprehensive event system. 91 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 4 | switch_error, errormsg$, strerror$, clearerror |
| Creation & Destruction | 3 | switch# (2 overloads), switch_free |
| Checked State | 3 | ischecked (get/set), toggle# |
| Position & Size | 14 | x, y, width, height (get/set), bounds#, move#, size# |
| Alignment & Margins | 12 | align (get/set), margin#, margins#, marginleft/top/right/bottom (get/set) |
| Visibility & State | 10 | visible, enabled, opacity, hittest, dragmode (get/set) |
| Focus | 7 | isfocused, setfocus#, resetfocus#, canfocus (get/set), taborder (get/set) |
| Tag & Parent | 6 | tag (get/set), parent# (get/set), bringtofront#, sendtoback# |
| Events | 32 | 15 event types × set/get + clearcallbacks# |
Cross-Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ Full Support | Win32/Win64 |
| Linux | ✅ Full Support | GTK-based |
| Android | ✅ Full Support | Touch-optimized toggle |
Error Handling
| Function | Signature | Description |
|---|---|---|
switch_error() | switch_error@ | Last error code (0 = no error) |
switch_errormsg$() | switch_errormsg$@ | Last error message as string |
switch_strerror$(code) | switch_strerror$@n | Description for a given error code |
switch_clearerror() | switch_clearerror@ | Clear the error state |
Numeric Values Reference
Control Alignment switch_align#
| Value | Description |
|---|---|
| 0 | None (absolute positioning) |
| 1 | Top |
| 2 | Left |
| 3 | Right |
| 4 | Bottom |
| 9 | Client (fill parent) |
Drag Mode switch_dragmode#
| Value | Description |
|---|---|
| 0 | None (default) |
| 1 | Automatic drag enabled |
Creation & Destruction
| Function | Signature | Description |
|---|---|---|
switch#(parent#) | switch#@# | Create switch with default size |
switch#(parent#, x, y, w, h) | switch#@#nnnn | Create with position and size |
switch_free(sw#) | switch_free@# | Destroy switch and release resources |
let sw# = switch#(frm#, 180, 45, 50, 25) ' Cleanup switch_free(sw#)
ⓘ Note: Switch controls have no built-in label text. Pair them with a
Label for descriptive text. Consider using larger dimensions (e.g., 60×30 or 80×40) on touch interfaces like Android and iOS.Checked State
| Function | Signature | Description |
|---|---|---|
switch_ischecked(sw#) | switch_ischecked@# | Get checked state (0=off, 1=on) |
switch_ischecked#(sw#, n) | switch_ischecked#@#n | Set checked state |
switch_toggle#(sw#) | switch_toggle#@# | Toggle current state (on→off or off→on) |
' Set switch on switch_ischecked#(sw#, 1) ' Read state if switch_ischecked(sw#) = 1 then println "ON" else println "OFF" endif ' Toggle (simpler than reading + setting) switch_toggle#(sw#)
ⓘ Note:
switch_toggle# is a convenience function — it reads the current state and flips it. Equivalent to switch_ischecked#(sw#, 1 - switch_ischecked(sw#)) but cleaner.Position & Size
| Function | Signature | Description |
|---|---|---|
switch_x(sw#) | switch_x@# | Get X position |
switch_x#(sw#, x) | switch_x#@#n | Set X position |
switch_y(sw#) | switch_y@# | Get Y position |
switch_y#(sw#, y) | switch_y#@#n | Set Y position |
switch_width(sw#) | switch_width@# | Get width |
switch_width#(sw#, w) | switch_width#@#n | Set width |
switch_height(sw#) | switch_height@# | Get height |
switch_height#(sw#, h) | switch_height#@#n | Set height |
switch_bounds#(sw#, x, y, w, h) | switch_bounds#@#nnnn | Set position and size in one call |
switch_move#(sw#, x, y) | switch_move#@#nn | Set position only |
switch_size#(sw#, w, h) | switch_size#@#nn | Set size only |
Alignment & Margins
| Function | Signature | Description |
|---|---|---|
switch_align(sw#) | switch_align@# | Get control alignment |
switch_align#(sw#, n) | switch_align#@#n | Set alignment (0=none, 1=top, 2=left, 3=right, 4=bottom, 9=client) |
switch_margin#(sw#, n) | switch_margin#@#n | Set uniform margin on all four sides |
switch_margins#(sw#, l, t, r, b) | switch_margins#@#nnnn | Set individual margins |
switch_marginleft(sw#) | switch_marginleft@# | Get left margin |
switch_marginleft#(sw#, n) | switch_marginleft#@#n | Set left margin |
switch_margintop(sw#) | switch_margintop@# | Get top margin |
switch_margintop#(sw#, n) | switch_margintop#@#n | Set top margin |
switch_marginright(sw#) | switch_marginright@# | Get right margin |
switch_marginright#(sw#, n) | switch_marginright#@#n | Set right margin |
switch_marginbottom(sw#) | switch_marginbottom@# | Get bottom margin |
switch_marginbottom#(sw#, n) | switch_marginbottom#@#n | Set bottom margin |
Visibility & State
| Function | Signature | Description |
|---|---|---|
switch_visible(sw#) | switch_visible@# | Get visibility (0/1) |
switch_visible#(sw#, n) | switch_visible#@#n | Set visibility |
switch_enabled(sw#) | switch_enabled@# | Get enabled state (0/1) |
switch_enabled#(sw#, n) | switch_enabled#@#n | Set enabled state |
switch_opacity(sw#) | switch_opacity@# | Get opacity (0.0–1.0) |
switch_opacity#(sw#, value) | switch_opacity#@#n | Set opacity |
switch_hittest(sw#) | switch_hittest@# | Get hit-test state (0/1) |
switch_hittest#(sw#, n) | switch_hittest#@#n | Enable/disable mouse hit testing |
switch_dragmode(sw#) | switch_dragmode@# | Get drag mode (0=none, 1=auto) |
switch_dragmode#(sw#, n) | switch_dragmode#@#n | Set drag mode |
' Disable a switch (grayed out, not interactive) switch_enabled#(sw#, 0) ' Semi-transparent switch_opacity#(sw#, 0.5)
Focus
| Function | Signature | Description |
|---|---|---|
switch_isfocused(sw#) | switch_isfocused@# | Is this switch focused? (0/1) |
switch_setfocus#(sw#) | switch_setfocus#@# | Set focus to the switch |
switch_resetfocus#(sw#) | switch_resetfocus#@# | Remove focus from the switch |
switch_canfocus(sw#) | switch_canfocus@# | Get whether switch can receive focus (0/1) |
switch_canfocus#(sw#, n) | switch_canfocus#@#n | Set whether switch can receive focus |
switch_taborder(sw#) | switch_taborder@# | Get tab order index |
switch_taborder#(sw#, n) | switch_taborder#@#n | Set tab order index |
Tag & Parent
| Function | Signature | Description |
|---|---|---|
switch_tag(sw#) | switch_tag@# | Get user-defined integer tag |
switch_tag#(sw#, n) | switch_tag#@#n | Set user-defined integer tag |
switch_parent#(sw#) | switch_parent#@# | Get parent control pointer |
switch_parent#(sw#, parent#) | switch_parent#@## | Move switch to a different parent |
switch_bringtofront#(sw#) | switch_bringtofront#@# | Bring to front of Z-order |
switch_sendtoback#(sw#) | switch_sendtoback#@# | Send to back of Z-order |
Events
Each event has a setter (switch_onXXX#(sw#, func$)) and a getter (switch_onXXX$(sw#)). Use switch_clearcallbacks#(sw#) to disconnect all callbacks at once.
State & Focus Events
| Event Setter | Getter | Callback Signature | When It Fires |
|---|---|---|---|
switch_onswitch#(sw#, func$) | switch_onswitch$(sw#) | function name(sender#) | When the switch state actually changes (on→off or off→on) |
switch_onclick#(sw#, func$) | switch_onclick$(sw#) | function name(sender#) | On any click, regardless of state change |
switch_ondblclick#(sw#, func$) | switch_ondblclick$(sw#) | function name(sender#) | When double-clicked |
switch_onenter#(sw#, func$) | switch_onenter$(sw#) | function name(sender#) | When the control receives focus |
switch_onexit#(sw#, func$) | switch_onexit$(sw#) | function name(sender#) | When the control loses focus |
switch_onresize#(sw#, func$) | switch_onresize$(sw#) | function name(sender#) | When the switch is resized |
⚠ Warning: OnSwitch vs OnClick: Use
OnSwitch to respond to state changes — it only fires when the switch actually toggles. OnClick fires on every click even if the state doesn't change. For settings and preferences, OnSwitch is almost always the correct choice.Keyboard Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
switch_onkeydown#(sw#, func$) | switch_onkeydown$(sw#) | function name(sender#, key, keychar$, shift$) |
switch_onkeyup#(sw#, func$) | switch_onkeyup$(sw#) | function name(sender#, key, keychar$, shift$) |
Mouse Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
switch_onmousedown#(sw#, func$) | switch_onmousedown$(sw#) | function name(sender#, button, x, y, shift$) |
switch_onmouseup#(sw#, func$) | switch_onmouseup$(sw#) | function name(sender#, button, x, y, shift$) |
switch_onmousemove#(sw#, func$) | switch_onmousemove$(sw#) | function name(sender#, x, y, shift$) |
switch_onmouseenter#(sw#, func$) | switch_onmouseenter$(sw#) | function name(sender#) |
switch_onmouseleave#(sw#, func$) | switch_onmouseleave$(sw#) | function name(sender#) |
Drag Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
switch_ondragenter#(sw#, func$) | switch_ondragenter$(sw#) | function name(sender#, x, y) |
switch_ondragover#(sw#, func$) | switch_ondragover$(sw#) | function name(sender#, x, y) |
switch_ondragdrop#(sw#, func$) | switch_ondragdrop$(sw#) | function name(sender#, x, y) |
switch_ondragleave#(sw#, func$) | switch_ondragleave$(sw#) | function name(sender#) |
switch_clearcallbacks#(sw#) | — | Disconnect all event callbacks |
Switch vs CheckBox
| Feature | Switch | CheckBox |
|---|---|---|
| Visual Style | Modern sliding toggle | Traditional checkbox with tick mark |
| Built-in Label | No (pair with Label) | Yes (checkbox_text#) |
| Animation | Animated slide transition | Instant check/uncheck |
| Touch Interface | Excellent (large hit area) | Smaller target |
| Primary Event | OnSwitch (state change only) | OnChange |
| Use Case | Settings, preferences, on/off toggles | Forms, checklists, multi-select options |
Use Switch for settings and preferences with clear on/off semantics. Use CheckBox for forms, checklists, and when you need a built-in label.
Complete Examples
Settings Panel
function OnApply(sender#) local settings$ settings$ = "Settings:" + chr$(10) if switch_ischecked(swNotif#) = 1 then settings$ = settings$ + "Notifications: ON" + chr$(10) else settings$ = settings$ + "Notifications: OFF" + chr$(10) endif if switch_ischecked(swSound#) = 1 then settings$ = settings$ + "Sound: ON" + chr$(10) else settings$ = settings$ + "Sound: OFF" + chr$(10) endif if switch_ischecked(swDark#) = 1 then settings$ = settings$ + "Dark Mode: ON" + chr$(10) else settings$ = settings$ + "Dark Mode: OFF" + chr$(10) endif if switch_ischecked(swSave#) = 1 then settings$ = settings$ + "Auto-Save: ON" else settings$ = settings$ + "Auto-Save: OFF" endif println settings$ endfunction let frm# = form#("Settings", 400, 350) form_position#(frm#, 4) label#(frm#, "Application Settings", 20, 15) label_fontsize#(lbl#, 16) label_bold#(lbl#, 1) label#(frm#, "Enable Notifications", 20, 60) let swNotif# = switch#(frm#, 300, 55, 50, 25) label#(frm#, "Sound Effects", 20, 100) let swSound# = switch#(frm#, 300, 95, 50, 25) label#(frm#, "Dark Mode", 20, 140) let swDark# = switch#(frm#, 300, 135, 50, 25) label#(frm#, "Auto-Save", 20, 180) let swSave# = switch#(frm#, 300, 175, 50, 25) switch_ischecked#(swSave#, 1) let btnApply# = button#(frm#, "Apply Settings", 140, 240, 120, 35) button_onclick#(btnApply#, "OnApply") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Interactive Toggle with Visual Feedback
function OnSwitchChange(sender#) if switch_ischecked(sender#) = 1 then label_text#(lblState#, "ON") label_fontcolor#(lblState#, "#00AA00") else label_text#(lblState#, "OFF") label_fontcolor#(lblState#, "#FF0000") endif endfunction function OnToggle(sender#) switch_toggle#(sw#) endfunction let frm# = form#("Toggle Demo", 350, 250) form_position#(frm#, 4) let sw# = switch#(frm#, 125, 50, 100, 40) let lblState# = label#(frm#, "OFF") label_move#(lblState#, 150, 110) label_fontsize#(lblState#, 24) label_bold#(lblState#, 1) label_fontcolor#(lblState#, "#FF0000") let btnToggle# = button#(frm#, "Toggle", 125, 170, 100, 35) switch_onswitch#(sw#, "OnSwitchChange") button_onclick#(btnToggle#, "OnToggle") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Feature Toggles with Dependencies
function OnMasterSwitch(sender#) local enabled enabled = switch_ischecked(sender#) switch_enabled#(swA#, enabled) switch_enabled#(swB#, enabled) switch_enabled#(swC#, enabled) if enabled = 0 then switch_ischecked#(swA#, 0) switch_ischecked#(swB#, 0) switch_ischecked#(swC#, 0) endif endfunction let frm# = form#("Feature Toggles", 400, 300) form_position#(frm#, 4) label#(frm#, "Enable All Features", 20, 30) label_bold#(lbl#, 1) let swMaster# = switch#(frm#, 300, 25, 50, 25) label#(frm#, " Feature A", 20, 70) let swA# = switch#(frm#, 300, 65, 50, 25) switch_enabled#(swA#, 0) label#(frm#, " Feature B", 20, 110) let swB# = switch#(frm#, 300, 105, 50, 25) switch_enabled#(swB#, 0) label#(frm#, " Feature C", 20, 150) let swC# = switch#(frm#, 300, 145, 50, 25) switch_enabled#(swC#, 0) switch_onswitch#(swMaster#, "OnMasterSwitch") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Real-Time Preview
function UpdatePreview(sender#) label_bold#(lblPreview#, switch_ischecked(swBold#)) label_italic#(lblPreview#, switch_ischecked(swItalic#)) if switch_ischecked(swLarge#) = 1 then label_fontsize#(lblPreview#, 20) else label_fontsize#(lblPreview#, 14) endif endfunction let frm# = form#("Preview Demo", 400, 300) form_position#(frm#, 4) let rectPreview# = rectangle#(frm#, 150, 20, 230, 150) rectangle_fill#(rectPreview#, "#FFFFFF") let lblPreview# = label#(frm#, "Preview Text") label_bounds#(lblPreview#, 160, 80, 210, 30) label_textalign#(lblPreview#, 0) label#(frm#, "Bold", 20, 30) let swBold# = switch#(frm#, 80, 25, 50, 25) label#(frm#, "Italic", 20, 70) let swItalic# = switch#(frm#, 80, 65, 50, 25) label#(frm#, "Large", 20, 110) let swLarge# = switch#(frm#, 80, 105, 50, 25) switch_onswitch#(swBold#, "UpdatePreview") switch_onswitch#(swItalic#, "UpdatePreview") switch_onswitch#(swLarge#, "UpdatePreview") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Best Practices
| Practice | Why |
|---|---|
Use OnSwitch for state changes | Only fires when the state actually changes (not on every click) |
| Pair switches with labels | Switch controls have no built-in text; use a Label next to each switch |
Use switch_toggle# for programmatic toggle | Cleaner than reading and setting the state manually |
| Increase size for touch interfaces | Default size is small; use larger dimensions (60×30+) on mobile |
| Disable dependent controls | Use switch_enabled# to gray out sub-options when a master switch is off |
| Visual feedback is automatic | The switch animates between on/off states; no manual animation needed |
| Use Switch for on/off settings | Use CheckBox for forms and checklists instead |
Quick Reference
| Function | Signature | Description |
|---|---|---|
switch_error / errormsg$ / strerror$ / clearerror | various | Error handling (4) |
switch#(parent#[, x, y, w, h]) | various | Create (2 overloads) |
switch_free(sw#) | switch_free@# | Destroy |
switch_ischecked (get/set) / toggle# | various | Checked state (3) |
switch_x/y/width/height (get/set) / bounds# / move# / size# | various | Position & size (14) |
switch_align / margin# / margins# / margin[left/top/right/bottom] | various | Alignment & margins (12) |
switch_visible / enabled / opacity / hittest / dragmode | various | Visibility & state (10) |
switch_isfocused / setfocus# / resetfocus# / canfocus / taborder | various | Focus (7) |
switch_tag / parent# / bringtofront# / sendtoback# | various | Tag & parent (6) |
switch_onswitch/onclick/ondblclick/onenter/onexit/onresize/onkeydown/onkeyup/onmousedown/up/move/enter/leave/ondragenter/over/drop/leave | various | Events set+get (31) |
switch_clearcallbacks# | switch_clearcallbacks#@# | Disconnect all events |
91 functions. Part of the Plan9Basic GUI library system.