Expand description
Accessibility as data: the semantic tree of a frame, derived from what
nodes do and from the role and label props a view declares.
A view rarely builds anything here. It sets NodeSpec::role,
NodeSpec::label, description, live and the value props; the core
derives an AccessTree of AccessNodes (roles from behaviour,
names from labels or text, plain boxes elided) that a driver reads with
crate::Core::access_tree and hands to the platform through
AccessKit. Requests from assistive technology come back as
crate::InputEvent::Access carrying an AccessRequest and resolve
inside the core: activating a button emits the same event a click
would. Ui::announce queues an Announcement for a one-off message
with no node behind it. Headless tests assert on the tree directly.
use kui_core::{AccessAction, Core, NodeSpec, Role, Size, TextStyle};
let mut core = Core::new();
let mut ui = core.frame(Size::new(400.0, 300.0), 1.0);
ui.window_title("Demo");
// An `on_click` node is a button; `label` names it when it has no text.
ui.leaf_keyed("save", NodeSpec::row().size(24.0, 24.0).on_click("save").label("Save"));
ui.text("Ready", TextStyle::new(14.0));
ui.finish();
let tree = core.access_tree();
assert_eq!(tree.root().map(|n| n.role), Some(Role::Window));
let button = tree.nodes.iter().find(|n| n.role == Role::Button).unwrap();
assert_eq!(button.name.as_deref(), Some("Save"));
assert!(button.supports(AccessAction::Click));Text is the one place the tree goes below the node: an editor carries
its laid-out lines as AccessRuns and its caret and selection as
positions in them, which is what a screen reader needs to read by
character, word and line. An app that draws its own text in an
on_key sink gets the same by declaring role="multilineTextInput"
on the sink, role="line" on each line, and caret /
selectionAnchor byte offsets on the lines that hold them.
Structs§
- Access
Node - One semantic node of a frame.
- Access
Request - A request from assistive technology, delivered as
crate::InputEvent::Access. - Access
Run - One visual line (or a piece of one) of an editor’s text, with what a
screen reader needs to read it by character and word and to place a
caret: every character’s byte length, x position and width. A line
that continues into another ends with its
"\n", counted as a character of zero width. Runs longer thanRUN_CHARScharacters are split, so indices fit the platform’s byte-sized ones. - Access
Tree - The semantic nodes of a finished frame, in tree order (a parent always precedes its descendants; the root comes first).
- Announcement
- One thing to say once, with no node behind it: “Saved”, “3 results”.
Queued by
Core::announceand drained byCore::take_announcements, the way window commands, audio commands and warnings are: an announcement is an event on a timeline, and the frame’s tree has no place to keep one. - Scroll
State - A scroll view’s offsets and range (logical px).
- TextPos
- A position in an editor’s text: a run and a character index into it
(
character == char countis the end of the run).
Enums§
- Access
Action - What assistive technology can ask of a node. Each node advertises the
subset it supports (
AccessNode::actions), and a request for one arrives ascrate::InputEvent::Access. - Live
- How urgently a reader should read a change it was not asked to read:
ARIA’s
aria-live, AccessKit’sLive. Declared on the node holding the text (liveprop) and, for a one-off with no node behind it, the politeness of anAnnouncement. - Orientation
- How a container arranges its items, for the platform to announce
(
AXOrientation, UIA’sOrientation). Derived from the container’sdirand never declared: the layout is what arranges the items, so a row that says it is a column would be a fact with two owners. It is an announcement and not a gate — the arrows move both ways whatever this says — so a container whose visual arrangement does not match itsdircosts a less precise announcement rather than a dead keyboard. - Role
- What a node is to assistive technology. Most of these a view declares
(
roleprop;schema::ROLESis that list, and the wire order); the ones the core derives from a node’s content and behaviour instead areschema::DERIVED_ONLY, which says what derives each. Every variant is on one list or the other —schema’severy_role_is_declarable_or_derivedfails when a new one is on neither.
Constants§
- RUN_
CHARS - Longest run, in characters (the platform indexes them in a byte).
Type Aliases§
- Label
- The label type on
NodeSpec: shared, so cloning a spec is a refcount bump and a Rust view can keep oneArc<str>across frames.