Releases: go-widgets/toolkit
Release list
v0.277.0 — a scroll view and a form field were both walls to the keyboard
A scroll view and a form field were both walls to the keyboard
Neither implemented focusableChildren, so the focus walker could not see the controls inside them. The compiler says it plainly once a test asks:
*ScrollView does not implement focusEnumerator (missing method focusableChildren)
*FormField does not implement focusEnumerator (missing method focusableChildren)
Every other single-child wrapper here already had it — AlignBox, Padding, PopoverHost, and the four layout containers. These two were missed, and the cost is not small: a scrolling panel of controls has none of them reachable by Tab, however many there are, and a form of labelled inputs has none of them at all. Found from go-pdfkit/app, whose settings panels are exactly that shape.
Reaching them is only half of it
A child's Bounds do not move when the view scrolls: SetBounds anchors the child at the viewport's origin with the whole content's height, and the offset is applied when it is drawn. So enumerating the children hands the focus walker every control including the ones below the fold — ten controls 24 high in a view 72 high leaves eight of them out of sight — and Tab would move the cursor somewhere nobody can see it.
That is a worse defect than the one being fixed, not a smaller one. So the walk now reveals what it moved to:
revealFocusedasks everyScrollViewunder the container to scroll its focused descendant into the viewport.revealDeltasays how far along one axis: the near edge in when the control is before the window, the far edge in when it is after, nothing when it is already inside — and the near edge when the control is taller than the window can hold, because that is the end worth showing.
Only Tab and Shift+Tab do this. A click already lands on something visible.
The test
It tabs through all ten controls of a column three deep, forward and then backward, and requires every focused control to lie inside the window at the offset the view is actually at. Backward matters: a fix that only ever scrolls down passes the first half and fails the second.
100% statement coverage, go vet and -race clean, nine cross-compile targets.
v0.271.0 — IconGrid.MinCellW
A floor on the cell width, for a grid whose label identifies the cell rather than its icon: VITURE Luma Ultra under a 40-pixel icon was elided to VITURE …, which is the one thing the tile exists to say. A floor, so it changes nothing for a grid that does not set it, and scaled like every other metric.
v0.270.0 — Frame.Measure, and an unbounded axis
Frame.Measure(width) reports what a titled panel needs — its child plus border, padding and title bar — so a frame can be an item in a column or the child of a scroll view without a caller reproducing four of the toolkit's constants. The inset lives in one place now, so the layout and the measurement cannot disagree.
And a bug in what shipped: asking a Measurer for one axis passed zero on the other, and a Measurer takes what is available — so AlignBox and Padding could only answer nought, and anything that consulted one measured to nothing. measureUnbounded says unconstrained.
v0.269.0 — IconGrid: vector cells, a measure, and scaled metrics
IconCell.Icon takes an IconFunc, so a grid of device tiles needs no rasterised artwork (an Image still wins when both are set; a selected cell's icon draws in the accent). IconGrid.Measure(width) reports the height its rows need, so a grid composes as an item in a column or the child of a ScrollView instead of being given a height. And the cell metrics — padding, label band, selection field, chip — go through scaled(), so a magnified interface no longer gets a large icon in a 1x cell.
DrawIconGlasses joins the stock icon set: a headset is a device class, drawn rather than photographed.
v0.268.0 — natural size by default, and a layout check
A box item with neither Flex nor Size now takes the widget's natural size, not an equal flex share. That default is what the tempting way to add a widget does, and while it was "share the space equally" a caller who wanted a sensible column had to compute one in pixels. A widget that cannot measure itself still falls back to the equal share; VBox.Append/HBox.Append are unchanged.
LayoutProblems(root) walks a laid-out tree and reports every child outside its parent (always a defect) and every child nobody placed (usually one — four widgets in this package positioned their children only inside Draw). It belongs in a test, where a layout is checked with no display and nobody looking at a picture.
Canary: go-pdfkit/app, wasmdesk/wasmbox, go-news-reader/reader, go-widgets/tui and go-xrkit/desk all pass against it.
v0.267.0 — a click reaches a ScrollView's content
The content of a ScrollView was passive for clicks: a press neither scrollbar wanted began a pan and nothing was forwarded, so every control inside a scroll view was dead to the mouse — and a long form is exactly what a scroll view is for.
The click is now forwarded, translated by the scroll offset (which is how the content is painted). The pan still starts on the same press, and a press on a scrollbar still belongs to the scrollbar.
v0.266.0 — a Container measures itself
LayoutMeasurer is the optional Layout capability and Container.Measure asks it, so a page of widgets can BE content: a ScrollView sizes it (v0.265.0) and an Item{Natural: true} asks it (v0.264.0). BoxLayout and FitLayout implement it; a layout that cannot measure leaves the container reporting its bounds.
A flex item contributes only what it measures — flex means take what is left over, and a measurement has nothing left over — so a column of cards with a flex spacer measures exactly the cards.
v0.265.0 — ScrollView sizes a measurable child
Nothing in ScrollView gave the child bounds, and declaring the content extent was the caller's job. So a scroll view around a freshly built column showed nothing, and one whose content changed scrolled over a stale extent.
SetBounds now sizes a measurable child to the viewport width and the height it reports there, and declares the extent from the same numbers. An unmeasurable child, or a caller who declares the extent after SetBounds, is untouched. Content is never shorter than the viewport.
v0.264.0 — Item.Natural: a box sizes a child to what it measures
A box layout read Item.Size and Item.Flex and nothing else, so a run of cards or settings rows had to be a table of pixel constants the caller computed by hand — right at one window size and wrong at every other, with the run overflowing whatever was pinned below it when the window shrank.
Item.Natural, VBox.AddNatural and HBox.AddNatural size a child on the main axis from what it MEASURES, re-measured on every layout. A column asks the card family's question (WidthMeasurer: how tall at this width), a row the two-axis Measurer; the child's own bounds are the last resort. Ignored when Size or Flex is set.
v0.263.0 — SettingsGroup and SettingRow lay out in SetBounds
Same defect as v0.261.0, in the preferences family: a SettingsGroup positioned its rows, and each SettingRow its control, only inside Draw. A card that had never been painted reported every row and control at the origin with no size — so a click into a drop-down hit a zero-size rectangle and a host sizing a window from the tree measured nothing.
The card inset moves into a pure cardContent(r), so the layout and the paint cannot disagree.