ScrollBoxLib — Vertical Scroll Box Library
Vertically-scrolling container controls for Plan9Basic programs. A scroll box holds child controls that extend beyond the visible area and provides automatic vertical scrolling. Children are added to the scroll box as their parent and scroll with it transparently. 25 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 3 | scrollbox_error, scrollbox_strerror$, scrollbox_clearerror |
| Creation & Destruction | 3 | scrollbox# (2 overloads), scrollbox_free |
| Position & Size | 7 | x, y (get), move#, width, height (get/set) |
| Alignment | 2 | align (get/set) — full FireMonkey TAlignLayout (20 values) |
| Visibility & Opacity | 4 | visible, opacity (get/set) |
| Tag | 2 | tag (get/set) |
| ScrollBox-Specific | 4 | showscrollbars (get/set), contentwidth, contentheight |
Cross-Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ Full Support | Win32/Win64 |
| Linux | ✅ Full Support | GTK-based |
| Android | ✅ Full Support | Touch-optimized scrolling |
scrollbox_showscrollbars# setting controls whether the scroll indicator is drawn, but scrolling always works regardless of this setting.Error Handling
| Function | Signature | Description |
|---|---|---|
scrollbox_error() | scrollbox_error@ | Last error code (0 = no error) |
scrollbox_clearerror() | scrollbox_clearerror@ | Clear the error state |
scrollbox_strerror$(code) | scrollbox_strerror$@n | Description for a given error code |
Error Codes
| Code | Meaning |
|---|---|
| 0 | No error |
| 1 | Invalid or nil scroll box pointer |
| 2 | Invalid parent control |
| 3 | Invalid value |
| 4 | Scroll box creation failed |
let sb# = scrollbox#(frm#) if scrollbox_error() <> 0 then println "Error: " + scrollbox_strerror$(scrollbox_error()) endif
Alignment Values
ScrollBoxLib exposes the full FireMonkey TAlignLayout enumeration. The most commonly used values for scroll boxes are 9 (Client) for filling the available area and 0 (None) for manual positioning.
| Value | Name | Description | Typical Use |
|---|---|---|---|
| 0 | None | Manual positioning (x, y) | Fixed position, overlays |
| 1 | Top | Align to top of parent | Top-docked scroll lists |
| 2 | Left | Align to left of parent | Scrollable sidebars, nav menus |
| 3 | Right | Align to right of parent | Scrollable property panels |
| 4 | Bottom | Align to bottom of parent | Bottom-docked scroll areas |
| 5 | MostTop | Above all Top-aligned controls | Topmost priority positioning |
| 6 | MostBottom | Below all Bottom-aligned controls | Bottommost priority positioning |
| 7 | MostLeft | Before all Left-aligned controls | Leftmost priority positioning |
| 8 | MostRight | After all Right-aligned controls | Rightmost priority positioning |
| 9 | Client | Fill all remaining space | Main content area (most common) |
| 10 | Contents | Size to fit content | Auto-sizing scroll containers |
| 11 | Center | Center in parent (both axes) | Centered floating boxes |
| 12 | VertCenter | Center vertically, full width | Vertically centered bands |
| 13 | HorzCenter | Center horizontally, full height | Horizontally centered columns |
| 14 | Horizontal | Stretch full width, manual height | Full-width fixed-height bars |
| 15 | Vertical | Stretch full height, manual width | Full-height fixed-width columns |
| 16 | Scale | Scale proportionally with parent | Proportional layouts |
| 17 | Fit | Fit within parent, preserve ratio | Ratio-constrained containers |
| 18 | FitLeft | Fit and align to left | Left-biased fit layouts |
| 19 | FitRight | Fit and align to right | Right-biased fit layouts |
' Common alignment constants let ALIGN_NONE = 0 let ALIGN_LEFT = 2 let ALIGN_RIGHT = 3 let ALIGN_CLIENT = 9
Creation & Destruction
| Function | Signature | Description |
|---|---|---|
scrollbox#(parent#) | scrollbox#@# | Create scroll box filling the parent (Client alignment) |
scrollbox#(parent#, x, y, w, h) | scrollbox#@#nnnn | Create at a specific position and size (no alignment) |
scrollbox_free(sb#) | scrollbox_free@# | Destroy scroll box and free all resources |
' Fill the entire form let sb# = scrollbox#(frm#) ' At a specific position and size let sb# = scrollbox#(frm#, 10, 60, 300, 400) ' Children become scrollable automatically let lbl# = label#(sb#, "Line 1", 10, 10) ' Cleanup scrollbox_free(sb#)
scrollbox#(parent#) creates the scroll box with Client alignment, making it fill all available space in the parent. The five-argument overload sets alignment to None, allowing manual positioning. In both cases, any control created with sb# as its parent will scroll with the container.scrollbox_free destroys the scroll box and all its child controls. Do not reference any children after freeing the parent scroll box.Position & Size
Position getters return the current coordinates. Use scrollbox_move# to reposition the scroll box as a single atomic operation. Width and height each have independent getters and setters. Note that position and size only take effect when alignment is set to None (0) — aligned controls are positioned automatically by the parent.
| Function | Signature | Description |
|---|---|---|
scrollbox_x(sb#) | scrollbox_x@# | Get X position |
scrollbox_y(sb#) | scrollbox_y@# | Get Y position |
scrollbox_move#(sb#, x, y) | scrollbox_move#@#nn | Set position (X and Y together) |
scrollbox_width(sb#) | scrollbox_width@# | Get width |
scrollbox_width#(sb#, w) | scrollbox_width#@#n | Set width |
scrollbox_height(sb#) | scrollbox_height@# | Get height |
scrollbox_height#(sb#, h) | scrollbox_height#@#n | Set height |
' Create with manual positioning let sb# = scrollbox#(frm#, 20, 60, 300, 400) ' Reposition and resize scrollbox_move#(sb#, 10, 50) scrollbox_width#(sb#, 320) scrollbox_height#(sb#, 450) println "At: " + str$(scrollbox_x(sb#)) + ", " + str$(scrollbox_y(sb#)) println "Size: " + str$(scrollbox_width(sb#)) + " x " + str$(scrollbox_height(sb#))
scrollbox_bounds# setter. To set both position and size at creation time, use the five-argument scrollbox#(parent#, x, y, w, h) overload instead.Alignment
When alignment is set to any value other than None (0), the scroll box is automatically positioned and sized by its parent container. This is the recommended approach for most layouts. See the Alignment Values section for the full list of supported modes.
| Function | Signature | Description |
|---|---|---|
scrollbox_align(sb#) | scrollbox_align@# | Get the current alignment mode |
scrollbox_align#(sb#, n) | scrollbox_align#@#n | Set alignment (0–19, see Alignment Values) |
' Fill entire form (most common) scrollbox_align#(sb#, 9) ' Left sidebar, 220px wide scrollbox_width#(sb#, 220) scrollbox_align#(sb#, 2) ' Right panel, 200px wide scrollbox_width#(sb#, 200) scrollbox_align#(sb#, 3) println "Alignment: " + str$(scrollbox_align(sb#))
Visibility & Opacity
| Function | Signature | Description |
|---|---|---|
scrollbox_visible(sb#) | scrollbox_visible@# | Get visibility (0/1) |
scrollbox_visible#(sb#, v) | scrollbox_visible#@#n | Set visibility (0=hidden, 1=visible). Hides all children too. |
scrollbox_opacity(sb#) | scrollbox_opacity@# | Get opacity (0.0–1.0) |
scrollbox_opacity#(sb#, o) | scrollbox_opacity#@#n | Set opacity (0.0=transparent, 1.0=opaque). Affects all children. |
' Toggle a panel section visible/hidden scrollbox_visible#(sb#, 0) ' Hide scroll box and all children scrollbox_visible#(sb#, 1) ' Show again ' Fade effect scrollbox_opacity#(sb#, 0.4) ' 40% opacity (dim the entire list) scrollbox_opacity#(sb#, 1.0) ' Fully opaque
Tag
An integer tag value attached to the scroll box for user-defined purposes. Useful for identifying which scroll box triggered a callback when multiple scroll boxes share a handler, or for storing state without external variables.
| Function | Signature | Description |
|---|---|---|
scrollbox_tag(sb#) | scrollbox_tag@# | Get the user-defined integer tag |
scrollbox_tag#(sb#, n) | scrollbox_tag#@#n | Set the user-defined integer tag |
' Tag scroll boxes to identify which page they belong to scrollbox_tag#(sbDashboard#, 1) scrollbox_tag#(sbSettings#, 2) scrollbox_tag#(sbReports#, 3) function GetPage(sb#) local tag tag = scrollbox_tag(sb#) if tag = 1 then println "Dashboard" elseif tag = 2 then println "Settings" elseif tag = 3 then println "Reports" endif endfunction
ScrollBox-Specific Properties
These functions control the scroll bar indicator and allow querying the total extent of the scrollable content region.
| Function | Signature | Description |
|---|---|---|
scrollbox_showscrollbars(sb#) | scrollbox_showscrollbars@# | Get scroll bar visibility (0/1) |
scrollbox_showscrollbars#(sb#, v) | scrollbox_showscrollbars#@#n | Show (1) or hide (0) the scroll bar indicator |
scrollbox_contentwidth(sb#) | scrollbox_contentwidth@# | Get total scrollable content width |
scrollbox_contentheight(sb#) | scrollbox_contentheight@# | Get total scrollable content height |
' Show the scroll bar indicator scrollbox_showscrollbars#(sb#, 1) ' Hide it for a cleaner touch-friendly look scrollbox_showscrollbars#(sb#, 0) ' Query how far the content actually extends let cw = scrollbox_contentwidth(sb#) let ch = scrollbox_contentheight(sb#) println "Content: " + str$(cw) + " x " + str$(ch) ' Determine whether scrolling will actually occur if scrollbox_contentheight(sb#) > scrollbox_height(sb#) then println "Content overflows — scroll bar is useful" endif
scrollbox_contentwidth and scrollbox_contentheight report the ContentBounds of the scroll box — the bounding rectangle of all child controls combined. If no children have been added, both values are 0. These values update automatically as children are added or resized.Complete Examples
Scrollable Item List
let frm# = form#("Item List", 400, 500) form_position#(frm#, 4) ' Scroll box fills the entire form let sb# = scrollbox#(frm#) scrollbox_showscrollbars#(sb#, 1) ' Add 60 labels — they extend far beyond the visible area let i = 0 for i = 1 to 60 let lbl# = label#(sb#, "Item " + str$(i), 10, (i - 1) * 30) next form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Dynamic Content Builder
let itemCount = 0 let sb# = Pointer#(0) function OnAdd(sender#) local y itemCount = itemCount + 1 y = (itemCount - 1) * 36 let lbl# = label#(sb#, str$(itemCount) + ". Entry added", 12, y) label_fontsize#(lbl#, 13) endfunction let frm# = form#("Dynamic List", 420, 520) form_position#(frm#, 4) ' Toolbar at top let toolbar# = panel#(frm#, 420, 48) panel_align#(toolbar#, 1) let btnAdd# = button#(toolbar#, "+ Add Item", 8, 7, 120, 34) button_onclick#(btnAdd#, "OnAdd") ' Scroll box fills remaining space sb# = scrollbox#(frm#) scrollbox_showscrollbars#(sb#, 1) form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Scrollable Sidebar Navigation
let lblPage# = Pointer#(0) function OnNavClick(sender#) local tag tag = button_tag(sender#) label_text#(lblPage#, "Section " + str$(tag)) endfunction let frm# = form#("Sidebar Demo", 720, 540) form_position#(frm#, 4) ' Scrollable left sidebar — 15 nav buttons, more than fit in 540px let sb# = scrollbox#(frm#, 0, 0, 210, 540) scrollbox_align#(sb#, 2) ' Align left scrollbox_showscrollbars#(sb#, 0) ' Hide scroll bar for clean look let i = 0 for i = 1 to 15 let btn# = button#(sb#, "Section " + str$(i), 8, (i - 1) * 52 + 8, 192, 44) button_tag#(btn#, i) button_onclick#(btn#, "OnNavClick") next ' Main content fills the rest let main# = panel#(frm#) panel_align#(main#, 9) lblPage# = label#(main#, "Select a section") label_move#(lblPage#, 160, 240) label_fontsize#(lblPage#, 18) form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Content Size Query
let sb# = Pointer#(0) let lblInfo# = Pointer#(0) function OnMeasure(sender#) local cw, ch, overflow$ cw = scrollbox_contentwidth(sb#) ch = scrollbox_contentheight(sb#) if ch > scrollbox_height(sb#) then overflow$ = " [scrollable]" else overflow$ = " [fits]" endif label_text#(lblInfo#, str$(cw) + " x " + str$(ch) + overflow$) endfunction let frm# = form#("Content Size", 560, 440) form_position#(frm#, 4) let toolbar# = panel#(frm#, 560, 48) panel_align#(toolbar#, 1) let btnMeasure# = button#(toolbar#, "Measure Content", 8, 7, 160, 34) button_onclick#(btnMeasure#, "OnMeasure") lblInfo# = label#(toolbar#, "click Measure", 185, 15) sb# = scrollbox#(frm#) scrollbox_showscrollbars#(sb#, 1) let i = 0 for i = 1 to 40 let lbl# = label#(sb#, "Row " + str$(i) + " — some content here", 12, (i - 1) * 28) next form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Best Practices
| Practice | Why |
|---|---|
Use scrollbox#(parent#) (single arg) for main content areas | Automatically applies Client alignment — fills all available space without extra calls |
| Add children directly to the scroll box pointer | Any control created with sb# as parent scrolls automatically — no extra configuration needed |
Use scrollbox_align# instead of manual positioning where possible | Alignment adapts to window resize and different screen sizes across platforms |
Set scrollbox_showscrollbars#(sb#, 0) for touch-based UIs | Touch platforms scroll natively without a visible scrollbar; hiding it gives a cleaner, modern look |
Call scrollbox_contentheight to check overflow before showing the scroll bar | Avoid showing a scroll bar when there is nothing to scroll |
Initialize scroll box pointers with Pointer#(0) before callbacks | Callbacks may fire before the scroll box is assigned; a nil-initialized variable prevents crashes |
Space child controls consistently (e.g. (i - 1) * rowHeight) | Uniform row spacing makes content predictable and avoids overlap when adding items dynamically |
Do not reference children after calling scrollbox_free | scrollbox_free destroys child controls too; dangling pointers will cause runtime errors |
Quick Reference
| Function | Signature | Description |
|---|---|---|
scrollbox_error / clearerror / strerror$ | various | Error handling (3) |
scrollbox#(parent#) | scrollbox#@# | Create, Client alignment |
scrollbox#(parent#, x, y, w, h) | scrollbox#@#nnnn | Create at bounds, no alignment |
scrollbox_free(sb#) | scrollbox_free@# | Destroy (and all children) |
scrollbox_x / scrollbox_y | scrollbox_x@#, scrollbox_y@# | Get position (2) |
scrollbox_move#(sb#, x, y) | scrollbox_move#@#nn | Set position |
scrollbox_width / width# | scrollbox_width@#, scrollbox_width#@#n | Width get/set |
scrollbox_height / height# | scrollbox_height@#, scrollbox_height#@#n | Height get/set |
scrollbox_align / align# | scrollbox_align@#, scrollbox_align#@#n | Alignment get/set (0–19) |
scrollbox_visible / visible# | scrollbox_visible@#, scrollbox_visible#@#n | Visibility get/set |
scrollbox_opacity / opacity# | scrollbox_opacity@#, scrollbox_opacity#@#n | Opacity get/set (0.0–1.0) |
scrollbox_tag / tag# | scrollbox_tag@#, scrollbox_tag#@#n | User tag get/set |
scrollbox_showscrollbars / showscrollbars# | scrollbox_showscrollbars@#, scrollbox_showscrollbars#@#n | Scroll bar indicator get/set |
scrollbox_contentwidth(sb#) | scrollbox_contentwidth@# | Total content width (read-only) |
scrollbox_contentheight(sb#) | scrollbox_contentheight@# | Total content height (read-only) |
25 functions. Part of the Plan9Basic GUI library system.