Documentation
¶
Overview ¶
Package widgets is the pure-Go, Ruby-runtime-independent core of the Ruby `widgets` gem: a live widget UI toolkit — buttons, labels, text fields, lists, menus and the container/layout system that arranges them — shaped so that github.com/go-embedded-ruby/ruby (rbgo) can bind it as `require "widgets"` and build real pixel UIs.
It is a thin adapter over github.com/go-widgets/toolkit (the widget set and its container/layout model) and github.com/go-widgets/painter (the pixel rasteriser). Unlike the stateless data adapters of the go-ruby-* family (opentype, regexp, erb, …), a Module here owns a LIVE object graph: every widget and container is stored under an integer handle the Ruby side keeps, and every operation — mutate, compose, lay out, render, dispatch an event — is addressed by that handle and returns a Ruby-shaped value: a Hash (map[string]any), an Array ([]any) or a scalar. A single dynamic entry point, Call, dispatches a Ruby-style snake_case method name to the matching Module method and coerces the arguments, which is exactly what an rbgo binding drives from method_missing. Nothing here imports the Ruby runtime, so the package is equally usable as a standalone Go library.
The object graph ¶
- Constructors return an opaque integer handle: Button, Label, Entry, TextView, CheckButton, DropDown, ListBox, Menu, MenuBar for leaves; Container (a config-driven fit/box/border/card layout), HBox, VBox, Grid, Frame, Dock and Border for containers.
- Mutators address a handle: SetText/Text, SetChecked/Checked, Select, SetStyle, SetSpacing and the package-wide SetTheme.
- Composition wires the tree: AddWidget, Add (with a flex/size/region Hash), AddFixed, AddFlex, Attach (grid), DockAt, SetRegion (border), AddMenu, SetActive (card) and SetLayout.
- Layout + query: SetBounds, Layout (at the origin) and Bounds.
- Render paints a tree into an RGBA pixel buffer; Dispatch routes an input event into it.
The render seam ¶
Render(root, w, h) lays the tree out to fill a w×h surface and paints it, returning {"pixels": <RGBA bytes>, "stride": w*4, "w": w, "h": h}. The pixels are 4 bytes per pixel, row-major, top-left origin — exactly what a host (wasmbox) blits into a canvas or SharedArrayBuffer.
The event seam ¶
Dispatch(root, {"kind" => "click", "x" => …, "y" => …}) routes the event into the tree by hit-testing container bounds, then reports {"fired": [callback ids…], "repaint": bool}. A widget is wired to a callback by passing a callback identifier to its constructor (Button, Entry, CheckButton, DropDown, ListBox and Menu items); when it fires, its identifier appears in the "fired" Array so the Ruby side can invoke the matching block.
Usage from Go ¶
m := widgets.NewModule()
root := m.VBox()
title := m.Label("Hello")
ok := m.Button("OK", "on_ok")
_ = m.AddWidget(root, title)
_ = m.AddWidget(root, ok)
_ = m.Layout(root, 200, 80)
img, _ := m.Render(root, 200, 80) // {"pixels":…, "stride":800, "w":200, "h":80}
out, _ := m.Dispatch(ok, map[string]any{"kind": "click"})
// out["fired"] == []any{"on_ok"}
Usage from Ruby ¶
Under rbgo, `require "widgets"` gives a Widgets module whose snake_case methods are these operations, returning Ruby Hashes, Arrays and scalars:
require "widgets"
root = Widgets.v_box
ok = Widgets.button("OK", "on_ok")
Widgets.add_widget(root, ok)
Widgets.layout(root, 200, 80)
img = Widgets.render(root, 200, 80) # => { "pixels" => …, "stride" => 800, … }
fired = Widgets.dispatch(ok, { "kind" => "click" }) # => { "fired" => ["on_ok"], … }
The `require "widgets"` binding lives in rbgo (a thin method_missing shim over Call); it is pending in that repo.
Example ¶
Example builds a two-widget column, lays it out, renders it to a pixel buffer and routes a click into the button — every result a Ruby-shaped value.
package main
import (
"fmt"
"github.com/go-ruby-widgets/widgets"
)
func main() {
m := widgets.NewModule()
root := m.VBox()
title := m.Label("Hello")
ok := m.Button("OK", "on_ok")
_ = m.AddWidget(root, title)
_ = m.AddWidget(root, ok)
_ = m.Layout(root, 200, 80)
img, _ := m.Render(root, 200, 80)
fmt.Println("stride:", img["stride"], "w:", img["w"], "h:", img["h"])
out, _ := m.Dispatch(ok, map[string]any{"kind": "click"})
fmt.Println("fired:", out["fired"], "repaint:", out["repaint"])
}
Output: stride: 800 w: 200 h: 80 fired: [on_ok] repaint: true
Index ¶
- func Call(recv any, method string, args ...any) (any, error)
- func Methods(recv any) []string
- type Module
- func (m *Module) Add(parent, child int, opts map[string]any) error
- func (m *Module) AddFixed(parent, child, size int) error
- func (m *Module) AddFlex(parent, child, flex int) error
- func (m *Module) AddMenu(bar int, name string, menu int) error
- func (m *Module) AddWidget(parent, child int) error
- func (m *Module) Attach(parent, child, col, row int) error
- func (m *Module) Backdrop(fill, grid string, step int) (int, error)
- func (m *Module) Border() int
- func (m *Module) Bounds(id int) (map[string]any, error)
- func (m *Module) Button(label, callback string) int
- func (m *Module) CheckButton(label string, checked bool, callback string) int
- func (m *Module) Checked(id int) (bool, error)
- func (m *Module) Container(layout string) (int, error)
- func (m *Module) Decoration(spec map[string]any) (int, error)
- func (m *Module) Dispatch(id int, ev map[string]any) (map[string]any, error)
- func (m *Module) Dock(body int) (int, error)
- func (m *Module) DockAt(parent, child int, side string, size int) error
- func (m *Module) DropDown(options []any, selected int, callback string) int
- func (m *Module) Entry(initial, callback string) int
- func (m *Module) Frame(child int) (int, error)
- func (m *Module) Grid(cols, rows int) int
- func (m *Module) HBox() int
- func (m *Module) Label(text string) int
- func (m *Module) Layout(id, w, h int) error
- func (m *Module) ListBox(items []any, callback string) int
- func (m *Module) Menu(items []any) int
- func (m *Module) MenuBar() int
- func (m *Module) Render(id, w, h int) (map[string]any, error)
- func (m *Module) Select(id, idx int) error
- func (m *Module) SetActive(container, idx int) error
- func (m *Module) SetBounds(id, x, y, w, h int) error
- func (m *Module) SetChecked(id int, v bool) error
- func (m *Module) SetLayout(container int, layout string) error
- func (m *Module) SetRegion(parent, child int, region string, size int) error
- func (m *Module) SetSpacing(id, n int) error
- func (m *Module) SetStyle(id int, style string) error
- func (m *Module) SetText(id int, s string) error
- func (m *Module) SetTheme(name string) error
- func (m *Module) Text(id int) (string, error)
- func (m *Module) TextView(initial string) int
- func (m *Module) VBox() int
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Call ¶
Call dispatches a Ruby-style snake_case method name to the matching exported method of the Module, coercing each Ruby-supplied argument to the Go parameter type. Trailing arguments may be omitted (they default to nil/zero). The result is the method's Ruby-shaped return value (or nil for a method that returns nothing); a trailing error return is unwrapped into Call's own error. This is the single entry point an rbgo binding drives from method_missing.
Types ¶
type Module ¶
type Module struct {
// contains filtered or unexported fields
}
Module is the stateful Ruby receiver: the `Widgets` module under rbgo. Unlike the stateless data adapters (opentype, regexp, …) a Module owns a live widget tree — every constructed widget or container is stored under an integer handle the Ruby side references, and every mutation, layout, render and event dispatch is addressed by that handle. A Module is NOT safe for concurrent use (its handle table and pending-callback list are mutated in place).
func NewModule ¶
func NewModule() *Module
NewModule returns a fresh Module with an empty handle table and the default light theme. Handles count up from 1, so a 0 handle always means "none" (used by Frame/Dock to mean a nil child/body).
func (*Module) Add ¶
Add appends child to a Container with an explicit item config Hash: "flex" (proportional weight), "size" (fixed main-axis extent) and "region" ("north"/"south"/"east"/"west"/"center" for a border layout). A nil Hash is the zero config.
func (*Module) AddWidget ¶
AddWidget appends child to a Container, HBox or VBox with the default per-item config (an equal share in a box, the centre of a border layout).
func (*Module) Backdrop ¶ added in v0.2.0
Backdrop constructs a decorative full-bounds ground: a solid fill and, when step > 0, a regular grid of 1-unit lines every step units. It paints no children and handles no events — the plain backing a host composites a scene on top of (a desktop wallpaper, a canvas backing sheet, a chart plot area).
fill and grid are "#rrggbb" or "#rrggbbaa" hex strings; an empty string selects the theme's Background (fill) or Border (grid) at render time. A malformed colour is an error, reported by Call. step <= 0 draws no grid.
func (*Module) Button ¶
Button constructs a push button labelled label. When callback is non-empty it is fired (reported by Dispatch) on every click.
func (*Module) CheckButton ¶
CheckButton constructs a labelled checkbox. When callback is non-empty it fires on every toggle.
func (*Module) Container ¶
Container constructs a config-driven container whose children are placed by a named layout: "fit" (fill), "box"/"hbox" (a row), "vbox" (a column), "border" (edge regions + centre) or "card" (one visible child). An unknown name is an error, reported by Call.
func (*Module) Decoration ¶ added in v0.3.0
Decoration constructs a toolkit.WindowDecoration — a window's frame chrome (title-bar band + caption + buttons + border + optional shadow + resize grip) painted with EXPLICIT colours and EXPLICIT frame-local geometry — from a Ruby spec Hash, and returns its handle.
The host (a compositor) owns the window model and its hit-testing, so it passes the exact rects it hit-tests against plus the palette its style needs; the widget only paints. The body region is left transparent so the host composites the decoration over a live window body.
Recognised spec keys (all optional; absent = zero/omitted):
"title" String the caption
"title_ink" hex caption colour
"title_color" hex title-bar band fill
"titlebar" [x,y,w,h] band rect (frame-local)
"title_center" Bool centre the caption (default: left)
"hairline" hex band bottom hairline ("" = none)
"border" [x,y,w,h] full frame extent (frame-local)
"border_color" hex border stroke ("" = none)
"shadow" hex faux drop shadow past the border ("" = none)
"grip" [x,y,w,h] resize-grip rect (frame-local)
"show_grip" Bool draw the grip
"grip_color" hex grip diagonals colour
"buttons" [Hash] the title-bar button cluster, each:
"rect" [x,y,w,h] (frame-local)
"shape" "rect" | "circle" (default "rect")
"face" hex face fill
"outline" hex circle outline ("" = none)
"glyph" "none"|"close"|"minimize"|"maximize"
"glyph_ink" hex glyph colour
A malformed colour, rect or enum value is an error, surfaced by Call.
func (*Module) Dispatch ¶
Dispatch routes an input event into a tree and reports the outcome. The ev Hash carries "kind" ("click"/"keydown"/"keyup"/"char"/"mousedrag"/"mouseup"), "x"/"y" (widget-local pixels), "code" (key/char text) and Bool "ctrl"/"shift". The result Hash is "fired" (an Array of the callback identifiers that ran, in order) and a Bool "repaint" (whether any callback ran, i.e. the tree may have changed).
func (*Module) Dock ¶
Dock constructs an edge-docking container around body (pass 0 for a bars-only frame); attach bars with DockAt.
func (*Module) DockAt ¶
DockAt attaches child to an edge ("top"/"bottom"/"left"/"right") of a Dock, reserving size pixels along that edge's axis.
func (*Module) DropDown ¶
DropDown constructs a drop-down selector over options (a Ruby Array of strings) with the given initial selection. When callback is non-empty it fires on every Select.
func (*Module) Entry ¶
Entry constructs a single-line text field seeded with initial. When callback is non-empty it fires on every value change and on submit (Enter).
func (*Module) Frame ¶
Frame constructs a 1-pixel-bordered panel around child; pass a 0 child for an empty frame.
func (*Module) HBox ¶
HBox constructs an imperative horizontal box (children added with AddWidget / AddFixed / AddFlex).
func (*Module) ListBox ¶
ListBox constructs a scrollable single-column list over items (a Ruby Array of strings). When callback is non-empty it fires on every row activation.
func (*Module) Menu ¶
Menu constructs a vertical popover menu from items — a Ruby Array of Hashes, each with "label", optional "shortcut", a Bool "separator" and an "action" (a callback identifier fired when the row is chosen). Non-Hash elements are skipped.
func (*Module) MenuBar ¶
MenuBar constructs an empty horizontal menu bar; attach menus with AddMenu.
func (*Module) Render ¶
Render lays a tree out to fill a w×h surface and paints it, returning a Hash with the RGBA "pixels" (4 bytes per pixel, row-major, top-left origin), "stride" (the byte offset between rows, i.e. w*4) and "w"/"h". A host (wasmbox) blits pixels straight into a canvas / SharedArrayBuffer.
func (*Module) Select ¶
Select changes the selection of a DropDown (which also fires its callback) or a ListBox.
func (*Module) SetActive ¶
SetActive selects the visible child of a Container backed by a card layout.
func (*Module) SetBounds ¶
SetBounds positions a widget (or the root of a tree) at (x, y) with size w×h, running the toolkit layout over any descendants.
func (*Module) SetChecked ¶
SetChecked sets a CheckButton's state.
func (*Module) SetRegion ¶
SetRegion assigns child to a Border region ("north"/"south"/"east"/"west"/ "center"), with size the edge band's thickness (ignored for the centre).
func (*Module) SetSpacing ¶
SetSpacing sets the inter-child gap of an HBox, VBox or Grid.
func (*Module) SetStyle ¶
SetStyle sets a Button's resting appearance: "default", "prominent" or "secondary".