Class Accessibility
One object per scene, reused down every walk and across every frame. A widget's describe hook is handed this and writes into whichever node the walk is currently on; nothing it writes constructs a facet, a string or a set. That is the whole reason the setters take a facet's fields rather than a facet: a record per node per walk would allocate on exactly the frames this design promises allocate nothing, and a blinking caret in a window of two hundred nodes would then be two hundred short-lived objects a second. The records are built once, in the copy, and only for nodes that carry them.
Two rules a widget author has to know, and they are the same rule twice.
First: a name is an I18nString and is compared by source. Hand over the
string object the widget holds, not a resolved string. The comparison is then a reference, a
locale and an epoch, and a repaint that changed nothing re-resolves nothing. A subtree that
changes language moves the locale, so every name under it is re-resolved exactly once and
diffed, with no subscription anywhere.
Second: a derived string is never built here. A formatted value, a masked line, a
text field's contents have no source to compare, so they are handed over from the widget's own
cache together with the counter that cache was filled against — name(String, long, Accessible.NameFrom), valueText(String, long), text(java.lang.String, long, int, limn.graphics.ShapedText.Affinity, int, int, int, limn.graphics.Rect, boolean). The comparison is two
longs and never two strings. A widget that formats a string inside its describe
hook stays correct and stops being free: it allocates one string per damaged frame to conclude
that nothing changed, which is the defect the publish-cost test exists to catch. The general
form, for whoever adds the next one: if a field's comparison allocates, the field needs a
cheaper witness, and a monotonic counter on the model is usually it.
The publish step drives the rest of this class — the methods that begin and end nodes, apply the inherited state bits and produce the tree. Those are public because the scene is in another package and for no other reason; a widget calls none of them.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceWhatresolveRelations(limn.accessibility.Accessibility.RelationResolver)turns a relation's target into a node identifier with. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intHow many differing nodes a single publish reports individually before the difference stops being a list of events and becomes "everything changed". -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidGives this node its access letter's chord, as a user would read it ("Alt+N"): the letter a menu title, a button or a field's label marks.voidaction(Accessible.Action action) Offers a verb on this node.voidaction(Accessible.Action... actions) Offers several verbs on this node.voidaction(Accessible.Action first, Accessible.Action second) Offers two verbs on this node.voidbounds(float x, float y, float width, float height) Places a synthetic child's box, in the coordinates of the widget that declared it.voidcell(int row, int column) Declares that this node is one cell of a table, at a row and a column as shown.voidcell(int row, int column, CellFacet.Sort sort) Declares that this node is one cell of a table, at a row and a column as shown, and which way its column's rows are running.booleanchanged()Whether what the walk just produced differs, anywhere, from what was published last.voidchild(long key) Begins a synthetic child of the node being described: something the widget draws but never instantiated as a widget — a menu column, a menu row, a combo option, a chart series.voidcontainerlessSelectionItem(boolean selected, int positionInSet, int sizeOfSet) Declares that this node is one member of a selection that no node holds: a radio button, whose group is not a widget and has no box.voiddelegate(Accessible.Action action) Offers a verb on this widget child that this widget's parent performs: a row'sSELECT, published on the row's cell where the platform addresses it and routed by the scene to the container'sonAccessibilityChildActionhook with the child's key.voiddescription(@Nullable String cached, long witness) Describes this node from a string the widget derived and is holding.voiddescription(@Nullable I18nString source) Describes this node at more length than its name does: what a tooltip says when the tooltip is not already the name.voiddisabled()Says that the synthetic child being described cannot be operated even though its owner can: a calendar day the bounds or the filter refuse, a scroll chevron with nothing left to scroll.voiddrop()Discards the nodebegin(long, int, java.util.Locale, float, float, float, float)began, as though it had never been started: what the publish step does to a container that turned out to be scaffolding.voidemptyValue(double min, double max, double step, boolean readOnly) Declares that this node's state is a number in a range and that it holds no number right now: a date segment nobody has typed into.voidend()Ends the nodebegin(long, int, java.util.Locale, float, float, float, float)began, making its parent current again.voidendChild()Closes the synthetic childchild(long)opened.voidexpand(boolean expanded) Declares that this node opens and closes.booleanhasName()Whether the node being described has a name yet, so that the publish step knows whether one of its free defaults still has somewhere to go.booleanhasRole()Whether anything has said what the node being described is.voidhierarchy(int level, int row, int rowCount) Declares where this node stands in an outline: a tree row's depth and its flat index among the rows the outline shows open, the two numbersHierarchyFacetexplains.voidignore()Removes this node and its children from the tree: a spacer, a decorative rule, a mark a widget draws that carries no information.voidkey(long key) Gives the child about to be described the identity key its parent chose for it, from inside the parent's identity hook and nowhere else.voidkeyBinding(@Nullable String display) Gives this node's primary action the keystroke that performs it, as a user would read it.voidname(@Nullable String cached, long witness, Accessible.NameFrom from) Names this node from a string the widget derived and is already holding, together with the counter its cache was filled against.voidname(@Nullable I18nString source) Names this node from a localizable string, with the provenanceAccessible.NameFrom.CONTENT: the widget's own painted text.voidname(@Nullable I18nString source, Accessible.NameFrom from) Names this node from a localizable string the widget holds, and says where the name came from.intvoidSays that the synthetic child being described is scrolled out of its owner's viewport, so that it publishes withoutSHOWINGwhile its owner still shows.publish(long focusedId, int screenX, int screenY, float factor, boolean positioning) Turns the walk into an immutable tree, and the difference from the last one into events.voidrelation(Accessible.Relation kind, @Nullable Object target) Links this node to another one.voidrole(Accessible.Role role) Declares what this node is.voidscroll(double horizontalPercent, double verticalPercent, double horizontalViewSize, double verticalViewSize, boolean horizontallyScrollable, boolean verticallyScrollable) Declares that this node scrolls, in the fractions aScrollFacetcarries;scrollFrom(double, double, double, double, double, double, double, double)computes them from offsets and extents.voidscrollFrom(double offsetX, double maxX, double viewportWidth, double contentWidth, double offsetY, double maxY, double viewportHeight, double contentHeight) The scroll facet folded from the geometry every scrolling widget holds: per axis, how far it has scrolled, how far it can, and how big the viewport and the content are.voidselection(boolean multiSelectable, boolean required) Declares that this node holds a selection among its descendants.voidselectionItem(boolean selected, int positionInSet, int sizeOfSet) Declares that this node is one member of a container's selection.voidslider(Accessible.State orientation, double value, double min, double max, double step) A slider in one call: the role, the axis its value runs along, the value and the two step verbs.voidstate(Accessible.State state) Sets a state on this node; the same asstate(Accessible.State, boolean)withtrue.voidstate(Accessible.State state, boolean on) Sets a state on this node.voidtable(int rowCount, int columnCount) Declares that this node is a grid of rows and columns over data.voidtext(@Nullable String cached, long witness, int caretOffset, ShapedText.Affinity caretAffinity, int selectionStart, int selectionEnd, int lineCount, @Nullable Rect caretRect, boolean readOnly) Declares that this node holds text, handing over the string the widget already has together with the counter its editing model bumps.voidtoggle(@Nullable ToggleFacet.State state) Declares that this node carries a checked state.voidunder(long syntheticKey) Hangs the child about to be described under one of this widget's own synthetic children rather than under this widget's node: aTable's widget cell under the syntheticROWit sits in, so a reader walking the row finds the control among its cells.voidvalue(double value, double min, double max, double step) Declares that this node's state is a number in a range.voidvalue(double value, double min, double max, double step, boolean readOnly) value(double, double, double, double), for a number the user may be shown and not set: a read-only value accepts noSET_VALUEand publishes no step verbs.voidGives the value a display form: what the widget shows instead of the number, handed over from the widget's own cache with the counter that cache was filled against.voidwindow(boolean modal, boolean canMaximize, boolean canMinimize, WindowFacet.State state) Declares that this node is a real top-level window.
-
Field Details
-
EVENT_BUDGET
public static final int EVENT_BUDGETHow many differing nodes a single publish reports individually before the difference stops being a list of events and becomes "everything changed".The bound is here rather than in each bridge so that all three get the same guarantee from one implementation, and so that it can be asserted without a platform. Past it the publish emits one
AccessibleEvent.Type.INVALIDATED, which a bridge answers by reconciling whatever it holds against the tree it was just handed — a full sweep, which is stronger than replaying the events that were dropped and is the operation it needs on a rebind anyway. Outside the budget, and handed over after the collapse as after any publish, is the reserved tail: the per-parent structure changes, the final focus change, the single cursor change, the per-container selection changes and the window activation events — the events a reader is directed by, which the demo's dialog opening was three events short of losing.- See Also:
-
-
Constructor Details
-
Accessibility
public Accessibility()A builder with no nodes and nothing published. One per scene.
-
-
Method Details
-
role
Declares what this node is. A node that declares nothing else is scaffolding and is removed from the tree with its children hoisted in its place, so declaring a role is how a widget stays in the tree at all.- Parameters:
role- the role; nevernull- Throws:
NullPointerException- ifroleisnull
-
hasRole
public boolean hasRole()Whether anything has said what the node being described is.The publish step asks, because a widget the keyboard can land on and nobody named is a defect it has to report rather than a group box it can quietly publish.
- Returns:
- whether
role(Accessible.Role)was called on this node
-
name
Names this node from a localizable string the widget holds, and says where the name came from.Resolved under the node's own language, once, and carried over unresolved on every later frame where the string, the language and the translation epoch are all unchanged.
A name that resolves to nothing carries no provenance. A widget hands over the string it holds whether or not the application filled it — a text field's placeholder is
I18nString.EMPTYuntil one is set — and the empty string names nothing, which is what lets the walk's own defaults still land. The provenance has to follow the same rule, or the node says it was named by a placeholder it does not have: a fact about where nothing came from, which one platform would then act on by choosing an attribute for it. So an empty name is published with the default,Accessible.NameFrom.CONTENT, whatever the caller said, and the caller's provenance is kept only for a name that exists.- Parameters:
source- the widget's own string;nullclears the namefrom- where the name came from, which decides which attribute one platform publishes it in- Throws:
NullPointerException- iffromisnull
-
name
Names this node from a localizable string, with the provenanceAccessible.NameFrom.CONTENT: the widget's own painted text.- Parameters:
source- the widget's own string;nullclears the name
-
name
Names this node from a string the widget derived and is already holding, together with the counter its cache was filled against.This is the form for a formatted name — anything built with a format call, which is never cached and therefore has no source to compare. Building the string inside the describe hook instead leaves the node correct and makes every damaged frame allocate.
An empty string carries no provenance, for the reason
name(I18nString, Accessible.NameFrom)gives.- Parameters:
cached- the string the widget is holding;nullclears the namewitness- a value that changes whenevercacheddoes, and is otherwise meaninglessfrom- where the name came from- Throws:
NullPointerException- iffromisnull
-
description
Describes this node at more length than its name does: what a tooltip says when the tooltip is not already the name.- Parameters:
source- the widget's own string;nullclears the description
-
description
Describes this node from a string the widget derived and is holding.- Parameters:
cached- the string;nullclears the descriptionwitness- a value that changes whenevercacheddoes
-
state
Sets a state on this node.Two groups of states are refused here rather than stored, and refused loudly, the way
action(Accessible.Action)refuses a verb that takes an argument. The states a facet expresses — checked, mixed, expanded, expandable, selected, selectable, read-only — are derived from that facet, so one fact keeps one home: declare the facet. The five the publish step owns — enabled, visible, showing, focusable and focused — belong to the walk, because the tree has to agree with a keyboard whose traversal stops at the first ancestor that is hidden or disabled and at the layer that owns input, which a widget describing itself cannot see; a synthetic child narrows two of them throughoffScreen()anddisabled(). Until 2026-09-14 such a call was dropped in silence, and a widget carried a dead line for months that no reader ever heard.- Parameters:
state- what to set; nevernullon- whether it holds- Throws:
NullPointerException- ifstateisnullIllegalArgumentException- if the state is a facet's or the publish step's to derive
-
state
Sets a state on this node; the same asstate(Accessible.State, boolean)withtrue.- Parameters:
state- what to set
-
toggle
Declares that this node carries a checked state.- Parameters:
state- whether it is off, on, or neither;nullremoves the facet
-
value
public void value(double value, double min, double max, double step) Declares that this node's state is a number in a range.A value that advances on its own is rounded here, by the widget, to the resolution a user can act on: a playing video writes whole seconds. The comparison sees what it is given, so an unrounded position copies the whole tree once per frame for the length of the film with nobody touching anything.
- Parameters:
value- the current valuemin- the smallest the node acceptsmax- the largeststep- one increment, or0for none
-
slider
A slider in one call: the role, the axis its value runs along, the value and the two step verbs. Six widgets describe themselves this way and each used to write the four lines; the pair of verbs is the two-argument form, which allocates nothing.- Parameters:
orientation-Accessible.State.HORIZONTALorAccessible.State.VERTICALvalue- the current valuemin- the least valuemax- the greatest valuestep- what one increment moves by
-
value
public void value(double value, double min, double max, double step, boolean readOnly) value(double, double, double, double), for a number the user may be shown and not set: a read-only value accepts noSET_VALUEand publishes no step verbs.- Parameters:
value- the current valuemin- the smallest the node acceptsmax- the largeststep- one increment, or0for nonereadOnly- whether the number is shown and never set
-
emptyValue
public void emptyValue(double min, double max, double step, boolean readOnly) Declares that this node's state is a number in a range and that it holds no number right now: a date segment nobody has typed into. The range stands, the text may say what is shown, and the number published is the minimum, for the platforms that must have one;ValueFacet.empty()is what says empty. Filling the number later is aAccessibleEvent.Type.VALUE_CHANGED, even when the number filled in is the minimum.- Parameters:
min- the smallest the node acceptsmax- the largeststep- one increment, or0for nonereadOnly- whether the value may be read and not set
-
valueText
Gives the value a display form: what the widget shows instead of the number, handed over from the widget's own cache with the counter that cache was filled against.- Parameters:
cached- the displayed string;nullmeans the number is the whole of itwitness- a value that changes whenevercacheddoes
-
selection
public void selection(boolean multiSelectable, boolean required) Declares that this node holds a selection among its descendants.Which of them are selected is on the descendants, in their own facet. Which of them the keyboard cursor is on is not this container's fact at all: it is the tree's, resolved by the publish step from the first descendant of the focused node published with
Accessible.State.ACTIVE(AccessibleTree.activeDescendant()), which a widget publishes only while it holds the keyboard.- Parameters:
multiSelectable- whether more than one may be selected at oncerequired- whether at least one always is
-
selectionItem
public void selectionItem(boolean selected, int positionInSet, int sizeOfSet) Declares that this node is one member of a container's selection.The position and the size are the model's numbers, not the tree's: a list that publishes only its realized rows still reports the true row count, so a user hears where they are in the data.
The facet's presence is what makes the node
Accessible.State.SELECTABLEon every node that declares it, exactly as the expand facet's presence is what makes a nodeEXPANDABLE: declaring that you are one member of a selection is saying you can be selected, and neither bit is a widget's to set. Until 2026-09-16 nothing in either module published it — an uncut grep of both mains found two hits in the whole tree, the enum constant and the AT-SPI bit it maps to — so the state never left the model. The live cost was measured on Fedora 44 and Ubuntu 24.04 on 2026-09-16: after Ctrl+A, Orca resolved all five selected rows and discarded every one of them, "believed to be layout only: … is not focusable, selectable, or expandable and lacks explicit name", and said nothing at all. Linux maps the bit (AtspiStates, bit 22); Windows carries the same fact through the SelectionItem pattern and macOS throughAXSelected's settability, so neither bridge changes.- Parameters:
selected- whether this member is selectedpositionInSet- its one-based position, or0when it has nonesizeOfSet- how many members the set holds, or0when that is unknown
-
containerlessSelectionItem
public void containerlessSelectionItem(boolean selected, int positionInSet, int sizeOfSet) Declares that this node is one member of a selection that no node holds: a radio button, whose group is not a widget and has no box. The numbers are as forselectionItem(boolean, int, int); what differs is that no selection change is raised on the node's published parent, which would be whatever layout ancestor survived transparency, and a bridge asked for the member's container answers none.- Parameters:
selected- whether this member is selectedpositionInSet- its one-based position among the members it counts, or0sizeOfSet- how many members there are, or0when there is no set
-
expand
public void expand(boolean expanded) Declares that this node opens and closes.The facet's presence is what makes the node
Accessible.State.EXPANDABLE, on every node that declares it (menu titles and submenu rows included), and its value is what makes itAccessible.State.EXPANDED; the Linux bridge derives its ownCOLLAPSEDfrom the two. Neither bit is a widget's to set.- Parameters:
expanded- whether it is open now
-
text
public void text(@Nullable String cached, long witness, int caretOffset, ShapedText.Affinity caretAffinity, int selectionStart, int selectionEnd, int lineCount, @Nullable Rect caretRect, boolean readOnly) Declares that this node holds text, handing over the string the widget already has together with the counter its editing model bumps.Every offset is a UTF-16 code unit. A masked field passes its mask here and offsets into that mask, never its own text and never the secret's offsets.
- Parameters:
cached- the text;nullremoves the facetwitness- a value that changes whenevercacheddoescaretOffset- where the caret sitscaretAffinity- which side of it the caret is on; nevernullselectionStart- where the selection begins, equal to its end when there is noneselectionEnd- where it endslineCount- how many lines the text hascaretRect- the caret's box in this node's own coordinates, ornull; the publish step carries it into the window's, as it does the node's boxreadOnly- whether the text may be read and not written- Throws:
NullPointerException- ifcaretAffinityisnull
-
scrollFrom
public void scrollFrom(double offsetX, double maxX, double viewportWidth, double contentWidth, double offsetY, double maxY, double viewportHeight, double contentHeight) The scroll facet folded from the geometry every scrolling widget holds: per axis, how far it has scrolled, how far it can, and how big the viewport and the content are.Seven widgets used to fold these into the facet's percentages themselves, and three of them forgot the one guard that matters: a viewport larger than its content is a fraction over one, which a platform reads as more than all of it. Here the view size is held to one, an axis with nothing to scroll answers zero and one, and a content of zero is "all of it" rather than a division by zero — which is also what keeps a
NaNout of a field the tree's difference compares with!=.- Parameters:
offsetX- how far the content has scrolled along x, from zeromaxX- how far it can; zero or less when the axis does not scrollviewportWidth- the width showncontentWidth- the width there is; zero or less when unknownoffsetY- how far the content has scrolled along y, from zeromaxY- how far it can; zero or less when the axis does not scrollviewportHeight- the height showncontentHeight- the height there is; zero or less when unknown
-
scroll
public void scroll(double horizontalPercent, double verticalPercent, double horizontalViewSize, double verticalViewSize, boolean horizontallyScrollable, boolean verticallyScrollable) Declares that this node scrolls, in the fractions aScrollFacetcarries;scrollFrom(double, double, double, double, double, double, double, double)computes them from offsets and extents.- Parameters:
horizontalPercent- where the viewport sits along the content's width, in0..1verticalPercent- where it sits along the content's height, in0..1horizontalViewSize- the fraction of the content's width the viewport showsverticalViewSize- the fraction of its height the viewport showshorizontallyScrollable- whether the content is wider than the viewportverticallyScrollable- whether it is taller
-
table
public void table(int rowCount, int columnCount) Declares that this node is a grid of rows and columns over data.Both counts are the model's, as
TableFacetsays: a table publishes only the rows it has realized and still reports how many there are.- Parameters:
rowCount- how many data rows the model holdscolumnCount- how many columns are shown
-
cell
public void cell(int row, int column) Declares that this node is one cell of a table, at a row and a column as shown.- Parameters:
row- the row as shown, from zero, or-1for a cell of the header rowcolumn- the column as shown, from zero
-
cell
Declares that this node is one cell of a table, at a row and a column as shown, and which way its column's rows are running.The direction is a fact about a header cell and is meaningless anywhere else: it is the column's sort, and the header is the control a reader presses to change it. Every other cell declares
CellFacet.Sort.NONE, and so does a header whose column is not the one the table is sorted by. The three bridges each carry it in their platform's own way; the localized phrase a header also puts in its description is not this, and neither replaces the other.- Parameters:
row- the row as shown, from zero, or-1for a cell of the header rowcolumn- the column as shown, from zerosort- which way this column's rows run; nevernull
-
hierarchy
public void hierarchy(int level, int row, int rowCount) Declares where this node stands in an outline: a tree row's depth and its flat index among the rows the outline shows open, the two numbersHierarchyFacetexplains. Its place among its siblings isselectionItem(boolean, int, int)'s.- Parameters:
level- how deep the row is, from one at a root, or0when unknownrow- which row of the outline this is, from one at the top, or0rowCount- how many rows the outline shows open, or0when unknown
-
window
public void window(boolean modal, boolean canMaximize, boolean canMinimize, WindowFacet.State state) Declares that this node is a real top-level window. A dialog drawn inside another window's scene is not one and must not call this.- Parameters:
modal- whether it blocks the windows it ownscanMaximize- whether the desktop offers a maximize actioncanMinimize- whether it offers a minimize actionstate- normal, minimized or maximized; nevernull- Throws:
NullPointerException- ifstateisnull
-
action
Offers a verb on this node.Only the parameterless verbs are publishable. A parameterised setter is advertised by the presence of the facet it sets, and offering it here would make one platform's action list unanswerable.
- Parameters:
action- the verb to offer- Throws:
NullPointerException- ifactionisnullIllegalArgumentException- if it takes an argument
-
action
Offers two verbs on this node.A pair rather than the variable-argument form below, because that one allocates an array per call and the publish step offers the same two on every focusable widget in the window, on every frame that walks. The general form is for a widget describing itself, where a handful of arrays a frame is not the same kind of cost.
- Parameters:
first- one verbsecond- the other- Throws:
NullPointerException- if either isnullIllegalArgumentException- if either takes an argument
-
action
Offers several verbs on this node.- Parameters:
actions- the verbs to offer- Throws:
NullPointerException- ifactionsor any of them isnullIllegalArgumentException- if one of them takes an argument
-
delegate
Offers a verb on this widget child that this widget's parent performs: a row'sSELECT, published on the row's cell where the platform addresses it and routed by the scene to the container'sonAccessibilityChildActionhook with the child's key.From
onAccessibilityChildonly, because that is where a container speaks about a child with the child's node open; and never for a verb the child already claimed in its own hook — a cell that is aButtonkeeps itsPRESS, and a container that claimed the same verb would have stolen it in silence, so the walk is refused rather than publish one verb with two performers. The child keeps every other verb it declared, and its identity is untouched: the node is still the child's, owned by the child for every verb but the delegated ones.- Parameters:
action- the verb the parent claims- Throws:
NullPointerException- ifactionisnullIllegalArgumentException- if it takes an argumentIllegalStateException- if called outsideonAccessibilityChild, or if the child already offers the verb itself
-
keyBinding
Gives this node's primary action the keystroke that performs it, as a user would read it.Kept only on a node that offers a verb: it is published with the node's
ActionFacet, which a node with no verb does not have.- Parameters:
display- the accelerator's display form, ornullfor none
-
accessKey
Gives this node its access letter's chord, as a user would read it ("Alt+N"): the letter a menu title, a button or a field's label marks. Not the accelerator; seekeyBinding(java.lang.String).Kept only on a node that offers a verb, as the key binding is: it is published with the node's
ActionFacet. A caption that names a field gives its key to the field, which is where the keyboard goes, and not to its own static text.- Parameters:
display- the chord's display form, ornullfor none
-
relation
Links this node to another one.The target is resolved by the publish step to the nearest node it actually published, and the relation is dropped when there is none: naming a node that was never published is worse than naming nothing, because every platform answers it with an element that does not resolve.
- Parameters:
kind- what the link means; nevernulltarget- theWidgetat the other end. Typed as an object because this package sits below the widget tree and names nothing in it; anything else resolves to no node and the relation is dropped.- Throws:
NullPointerException- ifkindisnull
-
ignore
public void ignore()Removes this node and its children from the tree: a spacer, a decorative rule, a mark a widget draws that carries no information.Not for a control that can be operated. Removing one of those is not a deferral, it is hiding it from the only user who cannot see it.
-
offScreen
public void offScreen()Says that the synthetic child being described is scrolled out of its owner's viewport, so that it publishes withoutSHOWINGwhile its owner still shows.A widget cannot set that state itself —
state(Accessible.State, boolean)refuses the five the publish step owns, because the walk works them out across the ancestry — and the publish step cannot work it out either, since a row clipped away inside a scrolled list is a fact only the owner's own row formula knows. So this is the one bit of the inherited set a widget contributes to, and it contributes it the way it can be checked: by handing over the answer its paint loop already computes, rather than by naming a rectangle twice.Clear by default and cleared for every child, so a scrolled-away row does not leave the next one marked. It says nothing about a widget's own node, which takes its showing bit from the widget tree.
- Throws:
IllegalStateException- if no synthetic child is open
-
disabled
public void disabled()Says that the synthetic child being described cannot be operated even though its owner can: a calendar day the bounds or the filter refuse, a scroll chevron with nothing left to scroll. It publishes withoutENABLEDwhile its owner keeps it.offScreen()'s shape, foroffScreen()'s reason: enabled is one of the states the publish step owns and a widget cannot set, and the step inherits it from the owner down onto every synthetic child, which is right for a menu row inside a disabled menu and wrong for a refused day inside an enabled calendar. So this is narrowing only: a child may be less enabled than its owner and never more, because the owner's bit is the keyboard's and a child published operable inside a disabled owner would be refused by the scene's action gate with nothing said about why. Clear by default and cleared for every child. It narrows through the nesting: a synthetic child declared inside a disabled one publishes withoutENABLEDtoo, whether or not it called this itself.It does not reach a widget, and the walk refuses the combination. A widget child a container hangs under a disabled synthetic node with
under(long)would take its enabled bit from the widget tree, as the scene's action gate does, and publishENABLEDand its verbs beneath its disabled row. No widget combines the two —Tableis the only caller ofunderand never disables a row, and this method's callers (a calendar's refused day and month, a segmented control's dead chevron, a combo's options and a menu's rows) hang no widget under the node — so the walk throws when an enabled container does, and the previous tree stands. A widget that needs it owes the walk and the gate the same narrowing in the same change.A disabled child carries no verb: the publish step withdraws every verb from a node that is not
ENABLED(inoperableAt(int)), so a refused day may declare itsSELECTand still publishes none, and a bridge reads the absence; a setter its facets would imply is implied only on a node that isENABLEDandVISIBLE(AccessibleNode.accepts(limn.accessibility.Accessible.Action)).- Throws:
IllegalStateException- if no synthetic child is open
-
key
public void key(long key) Gives the child about to be described the identity key its parent chose for it, from inside the parent's identity hook and nowhere else.This is what keeps a recycled list cell from carrying row three's identifier to row nine. A container that pools its children owns their identity, and nothing else can: the widget object is the wrong key the moment it is reused, and the data index is the right one.
It is answered before the child describes itself, and that ordering is the whole point. The child's node takes its identifier from the key before its own hook runs, so a name it hands over is looked up under the identifier it was published with last frame and carried over unresolved; and everything the child declares inside itself — a synthetic child of its own, a widget it holds — is scoped under that identifier too, so a composite cell recycled to another row carries none of the old row's inner elements with it. A key given from the describe-a-child hook would arrive after both, which is why that hook refuses it.
- Parameters:
key- a value unique among the children of the node this child hangs under, of both kinds — a widget cell keyed2and a synthetic cell keyed2under one row would be one element — and stable for as long as the child stands for the same thing- Throws:
IllegalStateException- if called outside the identity hook
-
under
public void under(long syntheticKey) Hangs the child about to be described under one of this widget's own synthetic children rather than under this widget's node: aTable's widget cell under the syntheticROWit sits in, so a reader walking the row finds the control among its cells.From the identity hook only, like
key(long), because where a node hangs is decided before it is begun. The synthetic child is named by the key its owner gave it inchild(long)during this same walk, and must exist: a parent naming a row it did not declare is a defect the walk reports rather than a child it quietly publishes elsewhere. The child's identity is then scoped under that synthetic node, not under this widget, sokey(long)need only be unique among the row's children. Among them it takes its place by column when it and they carry aCellFacet, and last otherwise. Its verbs stay its own: the walk still routes an action on it to the widget, never to the owner's synthetic hook.- Parameters:
syntheticKey- the key of the synthetic child of this widget the child hangs under- Throws:
IllegalStateException- if called outside the identity hook
-
child
public void child(long key) Begins a synthetic child of the node being described: something the widget draws but never instantiated as a widget — a menu column, a menu row, a combo option, a chart series.Synthetic children nest, so a menu row that opens a submenu owns that column. Every one of them must be closed with
endChild(), and each supplies its own bounds, because nothing else has them.- Parameters:
key- a value unique among this owner's synthetic children and stable for as long as the child stands for the same thing
-
endChild
public void endChild()Closes the synthetic childchild(long)opened.- Throws:
IllegalStateException- if no synthetic child is open
-
bounds
public void bounds(float x, float y, float width, float height) Places a synthetic child's box, in the coordinates of the widget that declared it.A widget's own node takes its box from its layout and never calls this; a synthetic child has no layout and must.
A negative width or height is published as zero, and the first one is logged: a box computed as a difference before the layout it depends on has run.
- Parameters:
x- the left edge, in the declaring widget's own coordinatesy- the top edgewidth- the widthheight- the height
-
end
public void end()Ends the nodebegin(long, int, java.util.Locale, float, float, float, float)began, making its parent current again. The publish step calls this. -
drop
public void drop()Discards the nodebegin(long, int, java.util.Locale, float, float, float, float)began, as though it had never been started: what the publish step does to a container that turned out to be scaffolding.- Throws:
IllegalStateException- if the node has already had children
-
nodeCount
public int nodeCount()- Returns:
- how many nodes the walk has produced so far
-
hasName
public boolean hasName()Whether the node being described has a name yet, so that the publish step knows whether one of its free defaults still has somewhere to go.- Returns:
- whether anything named this node
-
changed
public boolean changed()Whether what the walk just produced differs, anywhere, from what was published last.This is the question a damaged frame asks and the answer is usually no: damage is a coarse trigger, and a caret blink, a hover ripple and a chart tween all damage something and change no accessible fact. Answering it costs a comparison per field and allocates nothing.
- Returns:
- whether anything a reader could see has moved
-
publish
public AccessibleTree publish(long focusedId, int screenX, int screenY, float factor, boolean positioning) Turns the walk into an immutable tree, and the difference from the last one into events.This is the only step that allocates: the facet records are built here, and only for nodes that carry them.
- Parameters:
focusedId- the identifier of the node holding the keyboard focus, or0screenX- the window's content origin in native screen coordinatesscreenY- the same, verticallyfactor- the multiplier from logical points to native screen coordinatespositioning- whether the platform lets this window know where it is- Returns:
- the tree, ready to publish
-