Documentation
¶
Overview ¶
Package core defines the fundamental interfaces of the Bellui toolkit.
These interfaces form the backbone of every Bellui application: CanvasObject for anything that can be drawn, Widget for interactive components, Canvas for the rendering surface, Layout for arranging objects, and [Window] for the top-level UI container.
This package depends only on bellui/geo and bellui/event (both leaf packages), making it safe to import from anywhere in the framework.
import "github.com/belluikit/bellui/core"
Index ¶
- Constants
- Variables
- func NotifyActivation(obj CanvasObject, viaKeyboard bool)
- func NotifyToolTip(obj CanvasObject, c Canvas)
- func WalkAccessibleTree(root CanvasObject, children ChildrenFunc, visit func(AccessibleNode, int) bool)
- type Accessible
- type AccessibleAction
- type AccessibleActioner
- type AccessibleActiveDescendant
- type AccessibleConcealed
- type AccessibleDescriber
- type AccessibleGridDimensioner
- type AccessibleGridItem
- type AccessibleIdentified
- type AccessibleLabelOverrider
- type AccessibleLeveler
- type AccessibleNode
- type AccessibleRole
- type AccessibleScrollIntoView
- type AccessibleState
- type AccessibleStateful
- type AccessibleTextLayouter
- type AccessibleTexter
- type AccessibleValuer
- type AccessibleVirtualCellRealizer
- type AccessibleVirtualNode
- type AccessibleVirtualNodeProvider
- type Canvas
- type CanvasObject
- type ChildrenFunc
- type Disableable
- type DragImageProvider
- type DragPayloadProvider
- type DragTarget
- type DragTargetEvent
- type Layout
- type OverlayStack
- type Shortcut
- type ToolTipable
- type Transformable
- type Widget
- type WidgetRenderer
Constants ¶
const ( ActionPress = "press" // Button, link, menu item ActionToggle = "toggle" // Checkbox, switch ActionIncrement = "increment" // Slider, spinbox ActionDecrement = "decrement" // Slider, spinbox ActionExpand = "expand" // Accordion, tree node ActionCollapse = "collapse" // Accordion, tree node ActionSelect = "select" // List item, tab ActionDismiss = "dismiss" // Dialog, toast, snackbar ActionRename = "rename" // Tree/list rows with inline rename ActionDelete = "delete" // Tree/list rows, removable chips ActionUndo = "undo" // Text editors with undo history ActionRedo = "redo" // Text editors with redo history )
Standard action names for use in AccessibleActioner implementations.
Variables ¶
var ( ShowToolTip func(obj CanvasObject, c Canvas) HideToolTip func() )
ShowToolTip and HideToolTip are an optional hook installed by the widget package to render hover tooltips; both are nil until then, so a driver that runs without the widget package (or before it initializes) pays a single nil check per pointer move. The seam mirrors the OnActivation / SetFontFallbackRegister hook pattern, keeping core widget-free.
A driver calls NotifyToolTip when the tooltip target under the pointer changes: with the new ToolTipable target (which starts the show delay), or with nil (which hides any visible tooltip). Both run on the main goroutine from the driver's hover dispatch. The installed controller owns the delay timer, the bubble overlay and its lifecycle.
var OnActivation func(obj CanvasObject, viaKeyboard bool)
OnActivation is an optional hook invoked once each time an interactive object is activated: a pointer tap, or a screen-reader "press"/"toggle"/"select" action (screen-reader activations route through the same Tapped dispatch, so they are covered for free). It is nil unless a consumer installs it, so an app that never imports a consumer pays a single nil check per activation.
The seam mirrors the SetFontFallbackRegister/RegisterTextMeasure hook pattern: a package var wired by an optional peripheral package, keeping core dependency-free and widget-free. The analytics package's EnableAutoCapture is the reference consumer. viaKeyboard is true when the activation came from a keyboard Enter/Space on the focused object rather than a pointer tap.
It is always called on the main goroutine, from the driver's input dispatch, right where the object's Tapped is fired. Keep the callback cheap and non-blocking; hand heavy work to a queue (as the analytics tracker does).
Functions ¶
func NotifyActivation ¶
func NotifyActivation(obj CanvasObject, viaKeyboard bool)
NotifyActivation invokes OnActivation when a consumer is installed. Drivers call it at their tap/activate dispatch sites, once per activation, right where the object's Tapped is fired. It is a single nil check when no consumer is registered.
func NotifyToolTip ¶
func NotifyToolTip(obj CanvasObject, c Canvas)
NotifyToolTip forwards a tooltip target change to the installed controller. A nil obj hides any visible tooltip; a non-empty ToolTipable obj starts the show delay. It is a single nil check when no controller is registered.
func WalkAccessibleTree ¶
func WalkAccessibleTree(root CanvasObject, children ChildrenFunc, visit func(AccessibleNode, int) bool)
WalkAccessibleTree traverses the visible object tree starting at root, calling visit for each object that implements Accessible. The walk is depth-first, parent before children. The int parameter to visit is the current depth (root = 0). If visit returns true, the walk stops immediately.
The children function is used to obtain child objects; callers in the driver layer supply a function that reads the render cache, while test code can provide a simpler implementation.
Types ¶
type Accessible ¶
type Accessible interface {
// AccessibleRole returns the semantic role of this widget.
AccessibleRole() AccessibleRole
// AccessibleLabel returns the human-readable name of this widget.
// For a button this is the button text; for an entry, the placeholder.
AccessibleLabel() string
}
Accessible is implemented by widgets that provide semantic information for assistive technologies such as screen readers.
Widgets opt in by implementing this interface, following the same composition pattern as Disableable or event.Tappable.
type AccessibleAction ¶
type AccessibleAction struct {
Name string // Machine-readable name (e.g. "press", "toggle")
Description string // Human-readable description
}
AccessibleAction represents a named action that a widget supports.
type AccessibleActioner ¶
type AccessibleActioner interface {
// AccessibleActions returns the list of actions this widget supports.
AccessibleActions() []AccessibleAction
// PerformAccessibleAction invokes the named action.
// Unknown or unsupported names are silently ignored.
PerformAccessibleAction(name string)
}
AccessibleActioner reports supported actions and allows invoking them by name. Platform bridges translate these to platform-specific action protocols (NSAccessibilityAction, ATK_ACTION, UIA Invoke).
type AccessibleActiveDescendant ¶
type AccessibleActiveDescendant interface {
// AccessibleActiveDescendant returns the stable identity of the currently
// focused descendant, or nil when the container itself holds AT focus (no
// internal cursor, or the cursor is on the container as a whole).
AccessibleActiveDescendant() any
}
AccessibleActiveDescendant is implemented by a focusable container that manages an internal keyboard cursor over descendant items — a data grid moving a cell cursor with the arrow keys, a tree or virtualized list moving a row cursor. The container is the single event.Focusable that receives the key events, but assistive technology should follow and announce the item the cursor is on, not the container as a whole. This is the ARIA aria-activedescendant analog.
It designates the AT-focused descendant by stable identity — the [AccessibleIdentity] key of a realized descendant, or the AccessibleVirtualNode.ID of a virtual one (both ride the shared AccessibleNode.NodeID channel). Platform bridges resolve AT focus to the descendant whose NodeID matches this key and raise a platform focus-change event when the cursor moves to a different descendant, so a screen reader speaks each item during arrow-key navigation.
This is an AT-only focus designation: it must not change which object Canvas.Focused reports, since that would reroute real keyboard event delivery. The designated descendant must already be a node in the reconciled tree — realized, or within a provider's virtual window (AccessibleVirtualNodeProvider); the container is responsible for scrolling its cursor into that window. A descendant that also marks itself StateFocused reports keyboard focus to the platform even without matching by identity.
type AccessibleConcealed ¶
type AccessibleConcealed interface {
// AccessibleConcealed reports whether the widget currently conceals its
// content (e.g. a password field). When true, semantic auto-capture omits
// the widget.
AccessibleConcealed() bool
}
AccessibleConcealed is implemented by widgets whose content is sensitive and must be excluded wholesale from semantic auto-capture (and similar introspection) — a password Entry, or any field showing concealed text. Auto-capture (analytics.EnableAutoCapture) skips a target that reports true, belt-and-suspenders on top of never capturing values in the first place.
It is distinct from RolePasswordField: a masked-role widget still exposes a role and label, whereas a concealed one opts out of capture entirely.
type AccessibleDescriber ¶
type AccessibleDescriber interface {
// AccessibleDescription returns help text describing the widget's purpose.
AccessibleDescription() string
}
AccessibleDescriber optionally provides a longer description beyond the label. Useful for icon-only buttons or complex widgets where the label alone is insufficient.
type AccessibleGridDimensioner ¶
type AccessibleGridDimensioner interface {
// AccessibleGridDimensions returns the row and column count of the grid
// as currently presented — including rows that are scrolled off-screen or
// otherwise not realized, but reflecting the current sort and filter. A
// filtered grid reports the filtered length, not the unfiltered source
// total, so it matches the "row R of N" a screen reader announces against
// the AccessibleCellPosition display coordinates.
AccessibleGridDimensions() (rows, cols int)
}
AccessibleGridDimensioner reports the dimensions of a table or grid container. Virtualized tables realize only the visible cells, so without this the full extent is invisible to assistive technologies — platform bridges map it to dimension-aware patterns (the UIA Grid pattern's RowCount/ColumnCount).
type AccessibleGridItem ¶
type AccessibleGridItem interface {
// AccessibleCellPosition returns the cell's zero-based row and column in
// the grid's current presentation order — the position as the user
// perceives it, after any sort, filter or scroll. It is a display
// coordinate, not a stable source/model index: a re-sort or re-filter
// changes it, mirroring the on-screen layout that platform grid patterns
// (UIA GridItem Row/Column, NSAccessibility AXRow order) expect. Stable
// data identity — for letting assistive-tech focus follow a record across
// reindexing — travels on a separate channel ([AccessibleVirtualNode.ID]
// for virtualized rows, [AccessibleIdentified] for realized cells), never
// on this coordinate.
AccessibleCellPosition() (row, col int)
}
AccessibleGridItem reports the coordinates of a cell within its table or grid. Platform bridges map this to coordinate-aware patterns (NSAccessibility row/column indexes, UIA GridItem).
type AccessibleIdentified ¶
type AccessibleIdentified interface {
// AccessibleIdentity returns a stable, COMPARABLE key for the logical item
// this node represents (it is used as a map key; a non-comparable value
// panics). It must be unique within the window: incorporate an owner
// reference (e.g. the owning widget) if a bare index could collide with
// another widget's. Return nil to fall back to CanvasObject identity.
AccessibleIdentity() any
}
AccessibleIdentified gives a node a stable data identity independent of its CanvasObject. Platform bridges normally reconcile a realized node by its object pointer, but a virtualized collection (a table/list with a million logical rows) recycles a small pool of cell objects across the data, so the same object represents a different record after a sort, scroll or filter. A node that reports an identity is reconciled by that key instead, so its platform element — and the assistive-tech cursor on it — follows the record rather than the recycled screen slot.
This is the realized-node counterpart of AccessibleVirtualNode.ID (which carries the identity of a node that has no CanvasObject at all); both feed the same AccessibleNode.NodeID identity channel.
type AccessibleLabelOverrider ¶
type AccessibleLabelOverrider interface {
// AccessibilityLabel returns the application-supplied label, or an
// empty string when no override is set.
AccessibilityLabel() string
}
AccessibleLabelOverrider optionally provides an application-supplied accessible label that takes precedence over Accessible.AccessibleLabel. It is the plumbing behind widget.BaseWidget.SetAccessibilityLabel: widgets without intrinsic text (icon-only buttons, images) return an empty label from AccessibleLabel, and the application names them explicitly.
type AccessibleLeveler ¶
type AccessibleLeveler interface {
// AccessibleLevel returns the 1-based nesting level (a root item is 1).
AccessibleLevel() int
}
AccessibleLeveler reports the nesting depth of an item in a hierarchy, such as a tree node. Rendered trees lay rows out flat, so without this the outline structure is invisible to assistive technologies.
type AccessibleNode ¶
type AccessibleNode struct {
Object CanvasObject
Role AccessibleRole
Label string
Description string // Empty if Object does not implement AccessibleDescriber
Value string // Empty if Object does not implement AccessibleValuer
State AccessibleState
Actions []AccessibleAction
HasRange bool // False when AccessibleRange returned the (0, 0, 0) "not applicable" sentinel
RangeMin float64
RangeMax float64
RangeCurrent float64
HasCellPosition bool // True when Object implements AccessibleGridItem
CellRow, CellCol int // Display coordinates in current presentation order (see AccessibleGridItem)
Level int // 1-based hierarchy level; 0 when Object does not implement AccessibleLeveler
HasGridDims bool // True when Object implements AccessibleGridDimensioner
GridRows, GridCols int // Current presented extent, filter-aware (see AccessibleGridDimensioner)
// NodeID is a stable identity used by platform bridges to reconcile this
// node's element across walks instead of keying by CanvasObject: from
// AccessibleIdentified for a realized node, or AccessibleVirtualNode.ID for
// a virtual one. Nil ⇒ key by Object (the default for most widgets).
NodeID any
}
AccessibleNode provides a snapshot of accessibility properties for a node discovered during a tree walk. Fields are populated via type assertions on the underlying CanvasObject.
func SnapshotAccessible ¶
func SnapshotAccessible(obj CanvasObject) (node AccessibleNode, ok bool)
SnapshotAccessible captures the accessibility properties of obj into an AccessibleNode. ok is false when obj does not implement Accessible. The optional interfaces (AccessibleDescriber, AccessibleValuer, AccessibleStateful, AccessibleActioner) are queried the same way WalkAccessibleTree does for each visited node.
StateDisabled is additionally derived from Disableable: an object reporting Disabled() gets the bit whether or not it implements AccessibleStateful, so a disabled widget is never announced as actionable.
type AccessibleRole ¶
type AccessibleRole int
AccessibleRole identifies the semantic purpose of a widget for assistive technologies. Values are inspired by WAI-ARIA roles.
const ( RoleNone AccessibleRole = iota // Not semantically meaningful RoleButton // Clickable action trigger RoleCheckbox // Toggleable boolean RoleRadioButton // One-of-N selection RoleRadioGroup // Container for radio buttons RoleSwitch // On/off toggle RoleTextBox // Single-line text input RoleMultiLineTextBox // Multi-line text input RolePasswordField // Masked text input RoleComboBox // Dropdown selector RoleSearchField // Search input RoleSlider // Range selection RoleSpinButton // Numeric stepper RoleProgressBar // Determinate/indeterminate progress RoleLabel // Static text RoleLink // Hyperlink RoleImage // Image content RoleList // Scrollable list container RoleListItem // Item within a list RoleTree // Hierarchical tree RoleTreeItem // Item within a tree RoleTable // Data table RoleTableRow // Row in a table RoleTableCell // Cell in a table RoleGrid // Grid layout RoleTab // Tab button RoleTabList // Container of tabs RoleTabPanel // Content panel for a tab RoleMenu // Menu container RoleMenuItem // Item in a menu RoleMenuBar // Top-level menu bar RoleToolbar // Toolbar container RoleDialog // Modal dialog RoleAlertDialog // Confirmation/alert dialog RoleForm // Form container RoleGroup // Generic grouping RoleAccordion // Expandable section container RoleCard // Card container RoleBadge // Notification indicator RoleStatus // Status message (toast/snackbar) RoleTooltip // Tooltip popup RoleSeparator // Visual separator RoleScrollBar // Scroll indicator RoleRegion // Generic landmark region RoleHeading // Section heading text )
func (AccessibleRole) ChildrenPresentational ¶
func (r AccessibleRole) ChildrenPresentational() bool
ChildrenPresentational reports whether the descendants of a widget with this role are presentation details that must not appear in the semantic tree. It mirrors WAI-ARIA's "children presentational" characteristic: a button is announced as one control, so the internal text widget that paints its label carries no semantics of its own. Tree walkers drop the accessible descendants of such a node.
Text-bearing roles that can host embedded interactive controls (text inputs with an action button, rich text with hyperlinks) are not in this set — see AccessibleRole.NonInteractiveChildrenPresentational.
func (AccessibleRole) NonInteractiveChildrenPresentational ¶
func (r AccessibleRole) NonInteractiveChildrenPresentational() bool
NonInteractiveChildrenPresentational reports whether the widget's non-interactive accessible descendants are presentation details while its interactive descendants remain part of the semantic tree. This covers bellui's text-bearing controls: their renderers are built from internal accessible text widgets that would duplicate the control's own label or value (and are dropped), but they can also host real embedded controls that must stay reachable — an Entry's ActionItem button (a DateEntry's calendar, a SearchField's clear button) or hyperlinks inside rich text.
Tree walkers keep the descendants that expose actions or respond to taps and drop the rest. WAI-ARIA does not mark textbox as children presentational; this is the analogous, selective treatment.
func (AccessibleRole) String ¶
func (r AccessibleRole) String() string
String returns a human-readable name for the role, or "AccessibleRole(n)" for an unrecognized value. It is intended for debugging and developer tooling (logs, the widget inspector); assistive-technology backends map roles to their own platform constants rather than using this text.
type AccessibleScrollIntoView ¶
type AccessibleScrollIntoView interface {
// AccessibleScrollCellIntoView scrolls the container so the cell at the
// zero-based display (row, col) — the same coordinate space as
// [AccessibleGridDimensioner] — becomes visible and realized. Out-of-range
// coordinates are ignored. Called on the main goroutine, like other
// accessible actions.
AccessibleScrollCellIntoView(row, col int)
}
AccessibleScrollIntoView is implemented by a virtualized grid or list to bring a not-currently-realized cell into the visible viewport when assistive technology explicitly realizes it — the UIA VirtualizedItem pattern's Realize, or a VoiceOver activate on an off-screen cell. It is deliberately separate from the read path (AccessibleVirtualCellRealizer.AccessibleRealizeCell) so that merely announcing an off-screen row as the AT cursor passes over it does not move the viewport; only an explicit realize/activate scrolls.
type AccessibleState ¶
type AccessibleState uint32
AccessibleState is a bitmask of boolean states for assistive technologies.
const ( StateChecked AccessibleState = 1 << iota // Checkbox/switch is on StateExpanded // Accordion/tree node is open StateSelected // List/tab item is selected StateDisabled // Widget is disabled StateFocused // Widget has keyboard focus StateRequired // Form field is required StateReadOnly // Text field is read-only StatePartial // Indeterminate check state StateModal // Dialog is modal )
func (AccessibleState) Has ¶
func (s AccessibleState) Has(flag AccessibleState) bool
Has reports whether s contains the given state flag.
type AccessibleStateful ¶
type AccessibleStateful interface {
// AccessibleState returns the current state flags.
// Only flags relevant to the widget's role are meaningful.
AccessibleState() AccessibleState
}
AccessibleStateful reports dynamic boolean states such as "checked", "expanded", or "selected". Platform bridges use this to communicate widget state to assistive technologies.
type AccessibleTextLayouter ¶
type AccessibleTextLayouter interface {
AccessibleTexter
// AccessibleLineCount returns the number of visual (soft-wrapped) lines.
AccessibleLineCount() int
// AccessibleLineForOffset returns the zero-based visual line containing
// the rune offset, clamped to the content.
AccessibleLineForOffset(off int) int
// AccessibleLineRange returns the half-open rune range [start, end) of
// the zero-based visual line: end is the start of the following line —
// covering a terminating newline or the soft-wrap boundary — or the
// content length on the last line. ok is false for a line out of range.
AccessibleLineRange(line int) (start, end int, ok bool)
// AccessibleRangeBounds returns one rectangle per visual line touched by
// the half-open rune range [start, end), clipped to the widget's visible
// viewport: lines scrolled out of view are omitted, so the result stays
// bounded by the viewport no matter how large the range. A degenerate
// range (start == end) yields the caret rectangle at that offset. An
// empty slice means no part of the range is currently visible, or
// geometry is unavailable. On bidirectional rows the per-line rectangle
// spans the range's endpoints and may over- or under-cover reordered runs.
AccessibleRangeBounds(start, end int) []geo.Rectangle
}
AccessibleTextLayouter is an optional extension of AccessibleTexter for text widgets that can expose their visual layout: soft-wrapped (visual) line boundaries and the on-screen geometry of text ranges (pre-rebrand tracker #990). Platform bridges use it for line-granularity navigation that matches what the user sees (an AccessibleTexter alone yields logical, newline-delimited lines) and for the range-geometry queries behind screen-reader magnifiers and cursor tracking (AXBoundsForRange, the UIA GetBoundingRectangles, Android's character-location extra). Widgets without it degrade to logical lines and element-level geometry.
All offsets are rune indices into AccessibleTexter.AccessibleText, and all geometry is in the widget's own coordinate space adjusted for its current scroll offset — the same space as event.PreeditPositioner's caret rectangle — so bridges translate with the widget's absolute canvas position exactly as they do for the IME caret.
type AccessibleTexter ¶
type AccessibleTexter interface {
// AccessibleText returns the text assistive technology reads and
// navigates. Password fields return a masked representation of the
// same rune length, never the secret.
AccessibleText() string
// AccessibleSelection returns the selection as a half-open rune range
// with start <= end; when nothing is selected both are the caret offset.
AccessibleSelection() (start, end int)
// AccessibleCaret returns the rune offset of the insertion point.
AccessibleCaret() int
// SetAccessibleSelection selects [start, end), clamped to the content;
// equal offsets place the caret there with no selection.
SetAccessibleSelection(start, end int)
// ReplaceAccessibleSelection replaces the current selection with text —
// or inserts it at the caret when nothing is selected — as one
// undo-recorded edit.
ReplaceAccessibleSelection(text string)
}
AccessibleTexter exposes the text content, caret and selection of a text widget to assistive technologies, and lets them edit it. Platform bridges map this to their text protocols (the NSAccessibility text attributes, the UIA Text pattern); without it a screen reader can read a text field's value but cannot track the caret, read the selection or edit by voice.
All offsets are rune indices into AccessibleTexter.AccessibleText; bridges convert to their platform's code-unit space. Mutating calls go through the widget's normal gated, undo-recorded edit paths and are no-ops on read-only or disabled widgets.
type AccessibleValuer ¶
type AccessibleValuer interface {
// AccessibleValue returns a human-readable representation of the
// current value (e.g. "42", "50%").
AccessibleValue() string
// AccessibleRange returns the minimum, maximum, and current numeric
// values. Returns (0, 0, 0) if a numeric range is not applicable.
//
// The sentinel means a widget whose range is genuinely 0..0 with a
// current value of 0 (e.g. a slider constructed with min == max == 0)
// is reported as having no range; such a range is degenerate — there
// is nothing for assistive technology to adjust — so this is the
// intended behavior.
AccessibleRange() (min, max, current float64)
}
AccessibleValuer reports the current value and valid range of a widget. Implemented by sliders, spin boxes, progress bars, and similar range-based widgets.
type AccessibleVirtualCellRealizer ¶
type AccessibleVirtualCellRealizer interface {
// AccessibleRealizeCell returns the semantic node for the cell at the given
// zero-based (row, col) in the grid's current presentation order — the same
// display coordinate space as [AccessibleGridItem.AccessibleCellPosition] and
// [AccessibleGridDimensioner.AccessibleGridDimensions], filter- and
// sort-aware. ok is false when the coordinates are out of range.
//
// The returned node may have off-screen bounds; the bridge positions the AT
// cursor on it without requiring visibility. Set [AccessibleVirtualNode.ID] to
// the cell's stable data identity so the element tracks the record across
// reindexing, and the embedded [AccessibleNode]'s HasCellPosition / CellRow /
// CellCol so the bridge places it in the grid. A read must have no visible
// side effect — in particular it must not scroll; the explicit bring-into-view
// path is [AccessibleScrollIntoView].
AccessibleRealizeCell(row, col int) (AccessibleVirtualNode, bool)
}
AccessibleVirtualCellRealizer lets assistive technology reach a grid or list cell that is NOT in the current viewport window. A virtualized container realizes only the visible cells and reports the full extent via AccessibleGridDimensioner; AccessibleVirtualNodeProvider surfaces only the near-viewport window so the tree walk stays O(viewport). This interface answers a targeted request for one off-window cell the screen reader navigated to — its table navigation reads a cell the user has not scrolled to — without the container materializing every logical row.
The cell is delivered to the platform bridge on demand and becomes a transient element there; it never flows through the bounds-aware tree walk, so an off-screen realized cell is not culled the way an off-screen node emitted by AccessibleVirtualNodeProvider would be. Platform bridges map this to the lazy item patterns: the UIA ItemContainer pattern (FindItemByProperty) and NSAccessibility's accessibilityCell(forColumn:row:).
type AccessibleVirtualNode ¶
type AccessibleVirtualNode struct {
AccessibleNode // Object is nil for virtual nodes
Pos geo.Position // top-left relative to the providing widget
Size geo.Size
// ID is a stable identity for the region (e.g. the segment that
// produced it), letting platform backends reconcile elements across
// updates the way they key real nodes by CanvasObject.
ID any
}
AccessibleVirtualNode is a semantic node that is not backed by its own CanvasObject: a region inside a widget that renders several logical elements itself, such as a heading inside a RichText document. Bounds are relative to the providing widget; tree walkers convert them to absolute coordinates and attach the node as a child of the provider's node.
type AccessibleVirtualNodeProvider ¶
type AccessibleVirtualNodeProvider interface {
// AccessibleVirtualNodes returns the current virtual nodes in reading
// order — a bounded window for virtualized collections (see the type
// doc). Implementations return nil when nothing is rendered yet.
AccessibleVirtualNodes() []AccessibleVirtualNode
}
AccessibleVirtualNodeProvider is implemented by widgets that expose semantic regions without dedicated CanvasObjects. The provider is consulted by bounds-aware tree walkers after the widget's real accessible descendants are collected.
Windowing (virtualized grids/lists). A provider backing a large virtualized collection — a table with a million logical rows that realizes only the visible cells — must NOT return a node per logical item: the walk allocates and sorts every returned node each pass. Instead return a bounded window (typically the rows near the viewport) and report the full extent through AccessibleGridDimensioner on the container, so assistive tech hears "row R of N" without the walk touching all N. Each windowed node still carries its own coordinates: for a grid, emit flat RoleTableCell nodes with HasCellPosition/CellRow/CellCol set on the embedded AccessibleNode (platform bridges group them into rows by CellRow — no nested row nodes are needed), and set AccessibleVirtualNode.ID to a stable per-item key so the backend can track a node across walks. Nodes whose bounds fall entirely outside the container's clip are culled by the backends; surfacing rows beyond the viewport for assistive-tech to navigate into (lazy realization) is a platform-virtualization concern tracked separately, not something a provider achieves by returning off-screen nodes here.
type Canvas ¶
type Canvas interface {
Content() CanvasObject
SetContent(CanvasObject)
Refresh(CanvasObject)
Focus(event.Focusable)
FocusNext()
FocusPrevious()
Unfocus()
Focused() event.Focusable
Size() geo.Size
Scale() float32
Overlays() OverlayStack
OnTypedRune() func(rune)
SetOnTypedRune(func(rune))
OnTypedKey() func(*event.KeyEvent)
SetOnTypedKey(func(*event.KeyEvent))
AddShortcut(shortcut Shortcut, handler func(shortcut Shortcut))
RemoveShortcut(shortcut Shortcut)
Capture() image.Image
PixelCoordinateForPosition(geo.Position) (int, int)
InteractiveArea() (geo.Position, geo.Size)
}
Canvas defines a graphical canvas to which a CanvasObject can be added. Each canvas has a scale which is automatically applied during the render process.
type CanvasObject ¶
type CanvasObject interface {
MinSize() geo.Size
Move(geo.Position)
Position() geo.Position
Resize(geo.Size)
Size() geo.Size
Hide()
Visible() bool
Show()
Refresh()
}
CanvasObject describes any graphical object that can be added to a canvas. Objects have a size and position that can be controlled through this API.
type ChildrenFunc ¶
type ChildrenFunc func(CanvasObject) []CanvasObject
ChildrenFunc returns the child objects of a given CanvasObject. Callers provide this to abstract away the difference between containers (direct children) and widgets (renderer children). Implementations typically use the internal render cache.
type Disableable ¶
type Disableable interface {
Enable()
Disable()
Disabled() bool
}
Disableable describes any CanvasObject that can be disabled.
type DragImageProvider ¶
type DragImageProvider interface {
// DragImage returns the object to paint under the pointer during a drag, or
// nil for no ghost. It is read once when the drag starts.
DragImage() CanvasObject
}
DragImageProvider is an optional extension of a drag source (event.Draggable): when a drag begins the driver paints the returned object as a "ghost" that follows the pointer, and removes it when the drag ends. Return nil for no ghost. It gives in-canvas drag-and-drop a visual affordance without every app hand-rolling a following overlay (pre-rebrand tracker #819).
Since: 1.0
type DragPayloadProvider ¶
type DragPayloadProvider interface {
// DragPayload returns the value delivered to drop targets, or nil.
DragPayload() any
}
DragPayloadProvider is an optional extension of a drag source (event.Draggable): the returned value is carried to a DragTarget as the in-app drag payload (e.g. the palette entry being inserted, the card being moved). It is read once when the drag starts. Implementing it (or DragImageProvider) also marks the drag as an in-canvas DnD drag, which is what enables DragTarget routing — so a plain draggable (slider, scrollbar) never triggers drop-target callbacks.
Since: 1.0
type DragTarget ¶
type DragTarget interface {
// DragEnter fires when the pointer enters the target during a drag.
DragEnter(*DragTargetEvent)
// DragOver fires on every move while the pointer stays over the target.
DragOver(*DragTargetEvent)
// DragLeave fires when the pointer leaves the target (or the drag ends
// elsewhere) without dropping on it.
DragLeave()
// Drop fires when the drag is released over the target.
Drop(*DragTargetEvent)
}
DragTarget is the in-canvas counterpart of bellui.Droppable (which accepts OS file drops): a CanvasObject that accepts an in-app widget drag. The driver routes enter/over/leave/drop to the deepest DragTarget under the pointer, carrying the source-declared payload (DragPayloadProvider) — so targets get live hover callbacks (to highlight themselves) instead of every app re-implementing pointer hit-testing during a drag.
Routing happens only for in-canvas DnD drags — those whose source implements DragPayloadProvider or DragImageProvider — so ordinary draggables never reach a DragTarget.
Since: 1.0
type DragTargetEvent ¶
DragTargetEvent carries the in-app drag payload and the pointer position to a DragTarget during an in-canvas drag (pre-rebrand tracker #819). Position is relative to the target's top-left; AbsolutePosition is in canvas coordinates.
Since: 1.0
type Layout ¶
type Layout interface {
Layout([]CanvasObject, geo.Size)
MinSize(objects []CanvasObject) geo.Size
}
Layout defines how CanvasObjects may be laid out in a specified Size.
type OverlayStack ¶
type OverlayStack interface {
Add(overlay CanvasObject)
List() []CanvasObject
Remove(overlay CanvasObject)
Top() CanvasObject
}
OverlayStack is a stack of CanvasObjects used as overlays of a Canvas.
type Shortcut ¶
type Shortcut interface {
ShortcutName() string
}
Shortcut describes a keyboard shortcut (e.g. Ctrl+C).
type ToolTipable ¶
type ToolTipable interface {
ToolTip() string
}
ToolTipable is implemented by a CanvasObject that offers hover tooltip text. widget.BaseWidget satisfies it through SetToolTipText, so any widget can carry a tooltip with widget.Button{...}.SetToolTipText("New file"). A non-empty ToolTip() tells the driver to show a hover bubble after a short delay; an empty string means the object has no tooltip.
This is the driver-level replacement for the overlay-based widget.Tooltip, which never fired on the glfw desktop driver: the driver delivers hover to the widget itself reliably, so tooltips ride that instead of an invisible hit-test overlay (pre-rebrand tracker #800).
type Transformable ¶
Transformable describes a CanvasObject that supports a 2D affine transform. The transform is applied in addition to the object's position and size. When objects in a tree implement Transformable, their transforms compose: a child's world transform is parent.worldTransform * Translate(child.Position()) * child.Transform().
type Widget ¶
type Widget interface {
CanvasObject
// CreateRenderer returns a new WidgetRenderer for this widget.
CreateRenderer() WidgetRenderer
}
Widget defines the standard behaviours of any widget. This extends CanvasObject. A widget behaves in the same basic way but will encapsulate many child objects to create the rendered widget.
type WidgetRenderer ¶
type WidgetRenderer interface {
Destroy()
Layout(geo.Size)
MinSize() geo.Size
Objects() []CanvasObject
Refresh()
}
WidgetRenderer defines the behaviour of a widget's implementation.