Package limn.scene

Class Widget<W extends Widget<W>>

java.lang.Object
limn.scene.Widget<W>
Direct Known Subclasses:
Avatar, AvatarGroup, Badge, Button, CalendarView, Card, Chart, Checkbox, ColorPicker, ColorPickerButton, ComboBox, Container, DateField, DatePicker, Expanded, Expander, Field, ImageView, Label, ListView, MediaControls, MenuBar, Opacity, Padding, PrintPreview, ProgressBar, RadioButton, RangeSlider, ScrollBar, ScrollView, SegmentedControl, Separator, SizedBox, Slider, Spinner, SplitPane, Surface, TabbedPane, Table, TextArea, TextField, TokenBox, ToolBar, Transform, Tree, VideoView, Viewport3D

public abstract class Widget<W extends Widget<W>> extends Object
Base of the widget tree. A widget has bounds in its parent's coordinate space, visibility/enabled/focusable flags, children, and takes part in the two-phase layout (measure(limn.scene.Constraints) → layoutBox(float, float, float, float)), per-frame painting and event bubbling.

Thread confinement is a hard rule: every tree/state mutation calls Ui.checkUiThread() and throws off the UI thread.

Invalidation model: nothing repaints on its own. invalidate() asks for a frame and records this widget's bounds as damage; a scene with partial rendering on (the default) then repaints only the damaged region, one without it repaints the window, and either way the loop goes back to sleep once nothing is asking. markNeedsLayout() additionally re-runs measure/layout, which repaints everything. A change that goes through neither is not drawn: every setter here invalidates, but a field written directly (from a posted task, a timer, a background result) does not, and neither does anything a custom onPaint(limn.graphics.Canvas) reads from outside the tree.

  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    protected boolean
    Whether this widget edits text and should drive the platform input method (IME): the scene enables the IME while such a widget holds focus and disables it otherwise, so composition never intercepts keys meant for non-text UI.
    protected @Nullable String
    The chord of the access letter this widget, a caption, gives the widget it labels, or null: what a reader is told reaches the field.
    protected Widget<?>
    The widget a label bound to this one names: this widget, unless it is a composite whose keyboard lands on an inner control, in which case that control.
    protected @Nullable I18nString
    The text this widget offers when it is named as another's label, or null when it is not the kind of widget that captions anything.
    protected void
    add(int index, Widget<?> child)
    Inserts a child at a position in children() (UI thread only).
    protected void
    add(Widget<?> child)
    Appends a child (UI thread only).
    protected final void
    The announcing half alone: this widget's watchers, then its scene's watchers, and no handler at any origin.
    protected float
    How far outside its box a widget that paints from its backdrop reads the pixels behind it, in points: a blur's radius, a refracting rim's depth.
    protected float
    Distance from this widget's top edge to its first text baseline, in logical points: the alignment reference for Flex.CrossAlignment.BASELINE.
    protected static float
    Reads child's baselineOffset().
    protected @Nullable Rect
    The caret rectangle in scene coordinates (logical points) used to place the IME candidate window; null when there is no caret to anchor (or the widget is not laid out yet).
    final List<Widget<?>>
    The children, in paint and hit-test order: an unmodifiable view of live state.
    protected final Clipboard
    System clipboard (never null; a local no-op when detached).
    protected float
    clipHeight(Widget<?> child)
    The height of the rectangle this widget clips child to; see clipX(Widget).
    protected boolean
    Whether paintChildren(limn.graphics.Canvas) clips its children to this widget's bounds (scroll views, list viewports, tab strips).
    protected float
    clipWidth(Widget<?> child)
    The width of the rectangle this widget clips child to; see clipX(Widget).
    protected float
    clipX(Widget<?> child)
    The left edge, in this widget's own coordinates, of the rectangle clipsChildren() clips child to.
    protected float
    clipY(Widget<?> child)
    The top edge of the rectangle this widget clips child to; see clipX(Widget).
     
    @Nullable Cursor
     
    final @Nullable ControlSize
     
    final @Nullable LayoutDirection
     
    final @Nullable Locale
     
    protected final boolean
    Whether the focus this widget is being given arrived by Shift+Tab, walking backward: a widget with more than one stop of its own (a table's header and its rows) enters at its last stop then, and at its first otherwise, so that the two directions mirror.
    protected final boolean
    How the focus this widget is being given arrived: true for Tab or Shift+Tab, false for a click, a requestFocus() from code, or focus restored when an overlay closed.
    protected void
    Runs this widget's application handler for a change it has just announced.
    final float
    Laid-out height in logical points; 0 until the first layout pass.
    final @Nullable Widget<?>
    hitTest(float localX, float localY)
    The deepest widget under a point, this one, or null: what a press at the point lands on.
    protected final @Nullable Widget<?>
    hitTestChild(Widget<?> child, float localX, float localY)
    Asks one child what a point lands on: maps the point from this widget's space into the child's and calls the child's hitTest(float, float).
    final @Nullable String
    id()
     
    @Nullable ImageCursor
     
    final @Nullable Widget<?>
     
    final void
    Requests a repaint (event-driven: the loop wakes and redraws once).
    final void
    invalidate(float x, float y, float width, float height)
    Requests a repaint of a region in this widget's local coordinates: the fine-grained invalidate() for widgets that know exactly which pixels changed (a blinking caret, one cell of a grid).
    final void
    Says that something about this widget an assistive technology would care about has changed, when nothing repainted and nothing moved.
    final boolean
    Whether this widget accepts input: it and every ancestor are enabled.
    final boolean
    Whether keyboard focus can land here: false for containers and static chrome.
    final boolean
    Whether this widget currently holds its scene's keyboard focus.
    final boolean
    Whether this widget reads right to left: layoutDirection() is RTL.
    final boolean
    The flag setEnabled(boolean) sets on this widget, whatever its ancestors say: the widget's own half of isEnabled(), which answers for the whole ancestry.
    final boolean
    Whether this widget is drawn by every container above it, as well as visible through them.
    final boolean
    This widget's own visibility flag; see isShowing() for whether it is on screen.
    protected final boolean
     
    final void
    layoutBox(float x, float y, float width, float height)
    Parent assigns final bounds (parent coords); then onLayout() places children.
     
    final Locale
     
    final Vec2
    localToScene(float x, float y)
    Where a point of this widget's space lies in the scene: the widget's own offsets and each ancestor's, summed to the scene's root, through anything an ancestor draws its children through on the way.
    final Rect
    localToSceneBounds(float x, float y, float width, float height)
    The rectangle, in the scene, that a rectangle of this widget's space covers: its bounds there, as an axis-aligned box, which is the rectangle itself moved when nothing above turns it.
    final void
    Asks for this widget's own subtree to be laid out again, without declaring that the frame is a full repaint: the form for a container whose insides move while its box does not, such as a virtualised list mounting and recycling rows as it scrolls.
    final void
    Marks this widget's measure dirty and schedules a scene layout pass.
    protected final void
    Marks this widget's measure dirty and asks for a layout that repaints only what it moves: the form for a widget whose size may change for a reason of its own, such as a label whose text changed width.
    final float
     
    final float
     
    final Size
    measure(Constraints constraints)
    Measures the preferred size under constraints.
    final float
     
    final float
     
    protected static void
    moveChild(Widget<?> child, float x, float y)
    Moves a child without re-running layout: the scroll fast path (size is unchanged; only the offset moves).
    protected void
    moveChild(Widget<?> child, int index)
    Moves a child to another position in children() without taking it out of the tree (UI thread only): what remove(limn.scene.Widget<?>) and add(int, Widget) would do in two steps, without the detaching between them, so the focus, the hover and the press inside it stay where they are.
    protected void
    moveChild(Widget<?> child, int index, Change.Origin origin)
    moveChild(Widget, int), announcing the move with who asked for it: a container whose user moved a child says so in the one CHILDREN change the move makes, which then reaches its handler as a user's change does.
    protected final ShapedText.Direction
    What a run of text with no strong character of its own falls back to: this widget's resolved direction, as the shaper's neutral base.
    protected final void
    Announces a change that has already settled, and then runs the handler if the origin is USER: the last statement of an ordinary mutator, after the state, the layout marks, the focus move and the reveal.
    protected final void
    notifyTextEdit(Change.Origin origin, int offset, int removed, int inserted)
    The same as notifyChange(limn.scene.Change), for a text edit, taking the edit's shape rather than a built value so that a keystroke on a tree nobody watches constructs nothing.
    Watches every change to this widget, from every origin, without touching whatever handler the application registered.
    protected void
    Says what this widget is, for an assistive technology.
    protected boolean
    Performs an action an assistive technology asked of this widget, as the user.
    protected void
    Adds what only this widget knows about one of its children: the role a mounted list cell takes, its position in the data, its selected state.
    protected boolean
    Performs a verb this widget claimed on one of its widget children: a list's SELECT on a row that is the application's own cell, published on the row where a reader addresses it and performed by the list, which is the only thing that knows what selecting that row means.
    protected void
    Says who one of this widget's children is, before that child describes itself: the identity key a container that pools its children owns and nothing else can, and, for a container that draws its rows, the synthetic row the child hangs under.
    protected void
    Called when this widget enters a scene (attached to the tree).
    protected boolean
    Whether this widget can do an editing command now: copy with something selected, paste with something to paste, undo with something to take back.
    protected void
    Committed text input (focused widget first, then ancestors).
    protected void
    Called when this widget leaves the scene: detached from the tree, moved into another scene (told this before the onAttached() of the scene it joins), or still in it when the scene's window closes, which detaches every widget the scene has.
    protected void
    The drag this widget was last asked about in onDragOver(limn.scene.event.DragEvent) is no longer over it, whether it accepted or not: whatever it drew for the drag goes, the mark of the drop's place or the sign that it refuses.
    protected void
    A drag is over this widget, or has moved on it.
    protected @Nullable Drag
    Asked when a drag may begin on this widget: the pointer was pressed here and has moved a few points, or the drag key was pressed while this widget had the focus.
    protected void
    What was dragged is dropped here: on the widget that accepted it last.
    protected boolean
    Does an editing command, as the user's own act.
    protected void
    Called when this widget takes keyboard focus.
    protected void
    Called when this widget loses keyboard focus.
    protected @Nullable Widget<?>
    onHitTest(float localX, float localY)
    What this widget answers for a point that reached it: one of its children's answers, itself, or null to let the point through to what is beneath it.
    protected void
    Key events (focused widget first, then ancestors).
    protected void
    Containers position children here (measure + layoutBox(float, float, float, float) per child).
    protected abstract Size
    onMeasure(Constraints constraints)
    Reports the size this widget wants within constraints.
    protected void
    Mouse events (bubbling); call event.consume() when handled.
    protected void
    onPaint(Canvas canvas)
    Widget's own background/content, in local coordinates.
    protected void
    Painted after children (scrollbars, focus rings…).
    protected void
    In-progress IME composition ("preedit") for this widget while it is focused: the still-composing text, shown inline but not yet committed (the commit later arrives as onCharTyped(limn.scene.event.CharEvent)).
    protected boolean
    Performs an action addressed to one of this widget's synthetic children: a menu row, a combo option, a chart series — something this widget draws and never instantiated as a widget.
    protected boolean
    overlayPassesPointer(float sceneX, float sceneY)
    When this widget is the active modal overlay, whether a pointer hit at the given scene point should fall through to the content beneath it instead of being captured.
    protected void
    Children pass; override to clip (e.g.
    protected float
    How far beyond this widget's bounds its painting may reach, in logical points: its own painting and any descendant no ancestor clips (a drop shadow, a glow, a child positioned outside the parent's box).
    protected boolean
    Whether what onPaint(limn.graphics.Canvas) draws is material rather than meaning: a wash, a blur, a shadow, a rule.
    protected boolean
    Whether this widget's picture is made partly of the pixels behind it: a wash, a frost, a refraction.
    final void
    Paints this widget and its children (canvas origin = this widget).
    final @Nullable Widget<?>
    The parent this widget was added to, or null while it is unattached.
    protected void
    remove(Widget<?> child)
    Removes a child (UI thread only); protected for the reason add(Widget) is.
    protected void
    remove(Widget<?> child, Change.Origin origin)
    remove(Widget), announcing the removal with who asked for it: a container whose user closed a child says so in the one CHILDREN change the removal makes.
    final void
    Asks the scene to move keyboard focus here (UI thread only).
    protected final void
    The same, for a component moving focus as part of a gesture it is handling: a tab strip's arrow key, a radio group's.
    final void
    Asks every Scrollable ancestor, innermost first, to scroll this widget's bounds into view (each is handed the bounds in its own local coordinates, re-read after inner scrolls so nested scrollables compose).
    final void
    revealInView(float rectX, float rectY, float rectWidth, float rectHeight)
    Reveals one rectangle of this widget's own content, in this widget's coordinates, through every scrolling ancestor — what revealInView() does for the whole widget.
    protected final void
    The handler half alone: runs this widget's handler for a change this widget has already announced, and nothing at any origin but USER.
    final @Nullable Scene
    The scene this widget belongs to, or null until it is added to one.
    protected final long
    The nanosecond clock this widget's scene animates on, or the wall clock while it belongs to no scene.
    final Vec2
    sceneToLocal(float sceneX, float sceneY)
    Where a point of the scene lies in this widget's space: what a widget does with a pointer event's position, which is the scene's, to know where in itself the pointer is.
    protected final W
    This widget as its own type, which is what every setter here returns so that a chain of them keeps the type it started with: new Button("OK").setEnabled(false) is a Button.
    final W
    setAccessibleDescribedBy(@Nullable Widget<?> source)
    Describes this widget from another widget's text, the way the message beneath a field says why the field is invalid.
    final W
    Describes this widget with a fixed string.
    final W
    Describes this widget at more length than its name does, for an assistive technology.
    final W
    setAccessibleIgnored(boolean ignored)
    Removes this widget and its subtree from the accessible tree: a spacer, a decorative rule, an image that repeats what the text beside it already says.
    final W
    setAccessibleLabelledBy(@Nullable Widget<?> label)
    Names this widget from another widget's text, the way a form's caption names the field it sits beside.
    final W
    setAccessibleName(@Nullable String name)
    Names this widget with a fixed string.
    final W
    setAccessibleName(@Nullable I18nString name)
    Names this widget for an assistive technology, overriding whatever it would have derived for itself.
    final W
    Says what this widget is, overriding whatever role it would have declared.
    final W
    setControlSize(@Nullable ControlSize size)
    Sets the step for this widget and every descendant that does not declare its own; it inherits down the tree like setCursor(limn.backend.Cursor).
    final W
    setCursor(@Nullable Cursor cursor)
    Sets the mouse cursor shown while the pointer is over this widget (and any descendant that does not set its own, since cursor inherits down the tree).
    final W
    setEnabled(boolean enabled)
    Enables or disables input for this widget and its subtree: while it is disabled, isEnabled() answers false here and on every descendant, whatever their own flags say, and each takes its own flag back when this one is enabled again.
    final W
    setFocusable(boolean focusable)
    Declares whether this widget can take keyboard focus.
    final W
    setId(@Nullable String id)
    Names this widget for the code that looks it up: Scene.find(String), a test's driver clicking it by id, and a tool that drives the running application from outside, which finds it by the same id through the system's accessibility: UI Automation's automation id on Windows, the accessibility identifier on macOS, the accessible id on Linux.
    final W
    setImageCursor(@Nullable ImageCursor cursor)
    Sets a custom ImageCursor shown while the pointer is over this widget (inherits down the tree like setCursor(limn.backend.Cursor)).
    final W
    setInheritanceHost(@Nullable Widget<?> host)
    Links this widget's inherited axes — its ControlSize, its LayoutDirection and its locale alike — to host, for the case the tree cannot express: a widget that is the root of its own Scene (a popup or dialog window) or a overlay, both of which have no parent.
    final W
    setLayoutDirection(@Nullable LayoutDirection direction)
    Sets the layout direction for this widget and every descendant that does not declare its own; it inherits down the tree like setControlSize(limn.scene.ControlSize).
    final W
    setLocale(@Nullable Locale locale)
    Sets the locale for this widget and every descendant that does not declare its own; it inherits down the tree like setControlSize(limn.scene.ControlSize).
    final W
    setMaxHeight(float height)
    Keeps this widget at most height points tall wherever its parent lets it choose its height; see setMinWidth(float).
    final W
    setMaxWidth(float width)
    Keeps this widget at most width points wide wherever its parent lets it choose its width, the bound a paragraph or a form needs so that it does not run the width of a wide window; see setMinWidth(float) for where a bound takes effect.
    final W
    setMinHeight(float height)
    Keeps this widget at least height points tall wherever its parent lets it choose its height; see setMinWidth(float).
    final W
    setMinWidth(float width)
    Keeps this widget at least width points wide wherever its parent lets it choose its width.
    protected final void
    setPresentedElsewhere(boolean value)
    Takes this widget out of the scene's layout, painting and reading, or puts it back, for a widget whose content something outside the scene is showing: a menu bar the system holds in its own bar.
    final W
    setTooltip(@Nullable String text)
    Sets the hover tooltip text (null clears it).
    final W
    setTooltip(@Nullable I18nString text)
    Sets a tooltip that follows the UI language (null clears it).
    final W
    setVisible(boolean visible)
    Shows or hides this widget and its subtree, re-running layout so siblings take the space back.
    protected final ShapedText
    shapeText(String text, Font font)
    Shapes one line of text the way this widget reads: the first-strong rule decides for any string that can decide for itself, and neutralBase() decides for the rest.
    protected final TextRuler
    Text measurer for layout-time metrics (never null; NONE when detached).
    @Nullable String
     
    @Nullable I18nString
     
    final float
    Laid-out width in logical points; 0 until the first layout pass.
    final float
    x()
    Where layout put this widget's left edge, in its parent's space: the layout position, before anything an ancestor draws its children through.
    final float
    y()
    Where layout put this widget's top edge, in its parent's space; see x().

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • Widget

      public Widget()
  • Method Details

    • self

      protected final W self()
      This widget as its own type, which is what every setter here returns so that a chain of them keeps the type it started with: new Button("OK").setEnabled(false) is a Button. The one unchecked cast in the class: a widget declares itself as its own type argument (Button extends Widget<Button>), so it is always true.
      Returns:
      this
    • parent

      public final @Nullable Widget<?> parent()
      The parent this widget was added to, or null while it is unattached.
    • children

      public final List<Widget<?>> children()
      The children, in paint and hit-test order: an unmodifiable view of live state.
    • add

      protected void add(Widget<?> child)
      Appends a child (UI thread only). Protected: a widget arranges children of its own, and only a Container takes them from outside.

      A widget that is a scene's root, or an overlay on a scene's stack, is refused before anything moves, here and on every path a widget takes a child through (a container's add, a component's setter of its content): the scene that holds it would go on naming it as its own. That scene lets go of it when it is taken off the stack (Scene.removeOverlay(limn.scene.Widget<?>)), when the scene is given another root (Scene.setRoot(limn.scene.Widget<?>)), or when its window closes.

      Parameters:
      child - the child to append; never null
      Throws:
      NullPointerException - if child is null
      IllegalArgumentException - if child already has a parent, or is an ancestor of this widget, a scene's root, or an overlay on a scene's stack
    • add

      protected void add(int index, Widget<?> child)
      Inserts a child at a position in children() (UI thread only).

      add(Widget) appends, which is right for every container that builds its children once and in the order they are meant to be read. It is wrong for one that mounts them on demand from both ends: a virtualized list scrolling back up realizes the rows above its anchor in descending order, and appending each would leave children() — which is reading order and Tab order both — holding the order the rows happened to be realized in rather than the order the data is in. Re-adding a child to move it is not the alternative: remove(limn.scene.Widget<?>) detaches the subtree, which revokes the focus, hover and press inside it.

      Parameters:
      index - where the child goes, in [0, children().size()]
      child - the child to insert; never null
      Throws:
      IndexOutOfBoundsException - if index is outside that range
      NullPointerException - if child is null
      IllegalArgumentException - if child already has a parent, or is an ancestor of this widget, a scene's root, or an overlay on a scene's stack, as add(Widget) says
    • moveChild

      protected void moveChild(Widget<?> child, int index)
      Moves a child to another position in children() without taking it out of the tree (UI thread only): what remove(limn.scene.Widget<?>) and add(int, Widget) would do in two steps, without the detaching between them, so the focus, the hover and the press inside it stay where they are. A tab dragged along its bar keeps the press that drags it.
      Parameters:
      child - a child of this widget
      index - where it goes, in [0, children().size())
      Throws:
      IllegalArgumentException - if child is not a child of this widget
      IndexOutOfBoundsException - if index is outside that range
    • moveChild

      protected void moveChild(Widget<?> child, int index, Change.Origin origin)
      moveChild(Widget, int), announcing the move with who asked for it: a container whose user moved a child says so in the one CHILDREN change the move makes, which then reaches its handler as a user's change does.
      Parameters:
      child - a child of this widget
      index - where it goes, in [0, children().size())
      origin - who asked for the move
      Throws:
      IllegalArgumentException - if child is not a child of this widget
      IndexOutOfBoundsException - if index is outside that range
    • remove

      protected void remove(Widget<?> child)
      Removes a child (UI thread only); protected for the reason add(Widget) is.
    • remove

      protected void remove(Widget<?> child, Change.Origin origin)
      remove(Widget), announcing the removal with who asked for it: a container whose user closed a child says so in the one CHILDREN change the removal makes.
      Parameters:
      child - the child to take out; nothing happens for one that is not a child
      origin - who asked for it
    • onAttached

      protected void onAttached()
      Called when this widget enters a scene (attached to the tree). scene() is the scene it just joined. Fires top-down, so a parent runs before its children. Default no-op.
    • onDetached

      protected void onDetached()
      Called when this widget leaves the scene: detached from the tree, moved into another scene (told this before the onAttached() of the scene it joins), or still in it when the scene's window closes, which detaches every widget the scene has. What was taken in onAttached() from something that outlives the window (a listener's place in a list of the process's, a resource of the system's) is given back here.

      scene() still answers the scene being left, and becomes null once this returns, so releasing something the scene owns needs no field of your own to remember it by. Fires bottom-up, so children run before their parent, and every one of them can still reach the scene.

      Release resources here, but GPU resources must be handed to Scene.disposeLater(limn.graphics.GpuSurface) (disposal needs the owning GL context, which is only current inside a frame). Not called on setVisible(boolean). Default no-op.

    • scene

      public final @Nullable Scene scene()
      The scene this widget belongs to, or null until it is added to one.
    • sceneNanos

      protected final long sceneNanos()
      The nanosecond clock this widget's scene animates on, or the wall clock while it belongs to no scene.

      For a widget that keeps a timer of its own -- a hold before a fade, a delay before a reveal -- and would otherwise read System.nanoTime() directly. A scene's clock is injectable precisely so a test can move time by decree instead of waiting for it, and a timer read off the wall clock is the one part of such a widget that injection would not reach: it expires on its own schedule, in the middle of whatever a test was measuring.

      Returns:
      nanoseconds on the scene's clock, comparable only with other readings of it
    • x

      public final float x()
      Where layout put this widget's left edge, in its parent's space: the layout position, before anything an ancestor draws its children through. For where the widget is in the scene, ask localToScene(float, float) or localToSceneBounds(float, float, float, float).
      Returns:
      x in parent coordinates
    • y

      public final float y()
      Where layout put this widget's top edge, in its parent's space; see x().
      Returns:
      y in parent coordinates
    • width

      public final float width()
      Laid-out width in logical points; 0 until the first layout pass.
    • height

      public final float height()
      Laid-out height in logical points; 0 until the first layout pass.
    • localToScene

      public final Vec2 localToScene(float x, float y)
      Where a point of this widget's space lies in the scene: the widget's own offsets and each ancestor's, summed to the scene's root, through anything an ancestor draws its children through on the way.

      The middle of a widget, where a click on it lands, is widget.localToScene(widget.width() / 2, widget.height() / 2). A point that cannot be seen because it lies behind the eye answers (NaN, NaN).

      Parameters:
      x - a point's x in this widget's space
      y - a point's y in this widget's space
      Returns:
      the point in the scene's space
    • sceneToLocal

      public final Vec2 sceneToLocal(float sceneX, float sceneY)
      Where a point of the scene lies in this widget's space: what a widget does with a pointer event's position, which is the scene's, to know where in itself the pointer is.

      Answers (NaN, NaN) for a scene point that falls on no point of this widget's plane: one an ancestor draws the widget turned edge-on at, or collapsed, or one that would lie behind the eye. NaN fails every comparison, so the usual test p.x() >= 0 && p.x() < width() already counts such a point outside the widget. The point of a DRAG or a RELEASE the widget receives while it holds the pointer is not one of these: the scene withholds a drag that has left the widget's plane and releases it at the last point it had there, so a drag handler computes with finite numbers and needs no guard of its own, but for a release on a widget of which nothing can be seen, its plane exactly edge-on or its whole box behind the eye, which has no point to give (see MouseEvent).

      Parameters:
      sceneX - a point's x in the scene
      sceneY - a point's y in the scene
      Returns:
      the point in this widget's space, or (NaN, NaN)
    • localToSceneBounds

      public final Rect localToSceneBounds(float x, float y, float width, float height)
      The rectangle, in the scene, that a rectangle of this widget's space covers: its bounds there, as an axis-aligned box, which is the rectangle itself moved when nothing above turns it. What a popup is anchored to, what a drag image starts from and what the accessible tree publishes; the widget's own box in the scene is widget.localToSceneBounds(0, 0, widget.width(), widget.height()).

      The part of the rectangle that would lie behind the eye is cut away before the bounds are taken; a rectangle wholly behind it answers a rectangle of no size at NaN.

      Parameters:
      x - the rectangle's left, in this widget's space
      y - its top
      width - its width
      height - its height
      Returns:
      its bounds in the scene
    • revealInView

      public final void revealInView()
      Asks every Scrollable ancestor, innermost first, to scroll this widget's bounds into view (each is handed the bounds in its own local coordinates, re-read after inner scrolls so nested scrollables compose). A no-op when everything is already visible. The Scene calls this on focus changes, so keyboard traversal reveals the focused widget.

      The bounds are grown by paintOutset() first, because the bounds are not what has to be visible. A focus ring is drawn outside the box it belongs to — Strokes.FOCUS_RING_OUTSET is 3 points for a Button, and the ring is the whole reason the widget is being revealed. Revealing the bare bounds parks the widget flush against the viewport's clip, which is exactly where the ring is chopped: the reveal reported success and the reader could not see what was focused.

      Nothing opts in and nothing is configured. Every widget already declares how far it paints, for partial rendering, and a widget that paints nothing outside its box returns 0 and reveals exactly as it did before. A viewport too small to hold bounds-plus-outset aligns the near edge, the same rule Scrollable.revealRect(float, float, float, float) already applies to any oversize rectangle.

    • revealInView

      public final void revealInView(float rectX, float rectY, float rectWidth, float rectHeight)
      Reveals one rectangle of this widget's own content, in this widget's coordinates, through every scrolling ancestor — what revealInView() does for the whole widget.

      For a widget whose parts are not widgets: a calendar's day cell, a table's row, a chart's point. Such a part has no box of its own to reveal and no paintOutset() of its own to grow by, so the rectangle is taken as given, and a caller that draws outside it passes the larger rectangle rather than relying on an inflation this method cannot know the size of. Added on 2026-09-17, when a reader's SCROLL_INTO_VIEW on a day cell had to move the scroll view the calendar sits in and the whole-widget reveal would have scrolled the calendar's own edge into view instead.

      Parameters:
      rectX - the rectangle's left, in this widget's coordinates
      rectY - the rectangle's top, in this widget's coordinates
      rectWidth - its width
      rectHeight - its height
    • isVisible

      public final boolean isVisible()
      This widget's own visibility flag; see isShowing() for whether it is on screen.
    • isShowing

      public final boolean isShowing()
      Whether this widget is drawn by every container above it, as well as visible through them.

      A Transform that draws its child as nothing, a back face turned to the viewer while it hides back faces, a scale of 0 on either axis, a plane seen exactly edge-on, leaves everything inside not showing, and out of reach as a hidden container leaves it: out of the Tab order, an access letter's and the pointer's reach, the focus, the hover and a press taken out of it as the change is made, and published to assistive technologies as hidden. Nothing of it is changed: it is showing again, and in reach, as soon as the face turns back or the scale returns; the focus it lost is not given back.

      Returns:
      whether this widget is actually on screen: attached to a scene, visible together with every ancestor (unlike isVisible(), which reflects only this widget's own flag), drawn by every transform above it, and not scrolled fully out of an ancestor that clips (a scroll viewport), nor drawn wholly behind the eye or outside such an ancestor by a transform. Animations use this to pause while their widget is inside a hidden container (an unselected tab) or clipped out of view; without it, a progress bar scrolled away would keep ticking the frame loop at full rate while painting nothing. The repaint that reveals the widget re-arms them (the established re-arm-on-paint pattern).
    • setVisible

      public final W setVisible(boolean visible)
      Shows or hides this widget and its subtree, re-running layout so siblings take the space back. Hiding revokes focus, hover and any press inside the subtree. UI thread only.

      Announces VISIBLE/CODE, and after the revocation's FOCUS/ADJUSTMENT when hiding took the focus away: the settling order of this record in the smallest case there is, with the call's own aspect last.

      final, like the three setters beside it, because an override that forgot super would silently reopen the hole this closes -- a widget whose visibility changed and told nobody -- and because a subclass wanting to react to its own visibility has observeChanges(limn.scene.ChangeObserver).

    • setPresentedElsewhere

      protected final void setPresentedElsewhere(boolean value)
      Takes this widget out of the scene's layout, painting and reading, or puts it back, for a widget whose content something outside the scene is showing: a menu bar the system holds in its own bar. While it is so, the widget is laid out as an invisible one is, with no box and no gap beside it, and isVisible() answers false; isVisibleByItsOwnFlag() still says what setVisible(boolean) was told.

      Not a change of the widget's own visibility, and announced as none. UI thread only.

    • isVisibleByItsOwnFlag

      protected final boolean isVisibleByItsOwnFlag()
      Returns:
      what setVisible(boolean) was last told, whatever setPresentedElsewhere(boolean) says
    • isEnabled

      public final boolean isEnabled()
      Whether this widget accepts input: it and every ancestor are enabled. A disabled widget still occupies its box.

      The effective state, as isShowing() is to isVisible(), and not the flag setEnabled(boolean) sets, which isSelfEnabled() reads: disabling a form disables every control in it, so each of them paints its disabled look, refuses the focus and is published to assistive technologies as not enabled, from this one reading. When it answered with the widget's own flag alone, a button inside a disabled section looked enabled, took the focus from code or from a dialog closing, and ran its action on Enter, while the pointer and Tab already passed it by.

      Returns:
      whether this widget and all its ancestors are enabled
    • isSelfEnabled

      public final boolean isSelfEnabled()
      The flag setEnabled(boolean) sets on this widget, whatever its ancestors say: the widget's own half of isEnabled(), which answers for the whole ancestry.

      The pair is isVisible() and isShowing() the other way round: there the short name is the widget's own flag and the longer one the effective state, here isEnabled() is the effective state, because that is what nearly every caller asks (may this control take input now?), and this is the flag. Read it to change the flag relative to itself: w.setEnabled(!w.isSelfEnabled()) toggles the control inside a disabled form as it does outside one, where w.setEnabled(!w.isEnabled()) would write true over a control the application had disabled, and the control would come back enabled with the form.

      Returns:
      what setEnabled(boolean) was last told; true until it is told otherwise
    • setEnabled

      public final W setEnabled(boolean enabled)
      Enables or disables input for this widget and its subtree: while it is disabled, isEnabled() answers false here and on every descendant, whatever their own flags say, and each takes its own flag back when this one is enabled again. The flag itself is isSelfEnabled(). Repaints without re-laying-out, since the box does not change; disabling revokes focus, hover and any press inside the subtree. UI thread only.

      Announces ENABLED/CODE on this widget whenever its flag changes, then on every descendant whose isEnabled() changed with it, in tree order (a parent before its children, siblings first to last): not on one disabled by its own flag or under another disabled container, whose state did not move, and on none at all when an ancestor of this widget is disabled. Each descendant is checked again on its turn, so one a watcher has since moved out of the subtree, or whose state a watcher undid, is not told of a state it does not have. All of it after the revocation's FOCUS when disabling took the focus away. Moving a widget to another parent announces no ENABLED, though its isEnabled() may change with the move. final for the reason setVisible(boolean) is.

    • isFocusable

      public final boolean isFocusable()
      Whether keyboard focus can land here: false for containers and static chrome.
    • setFocusable

      public final W setFocusable(boolean focusable)
      Declares whether this widget can take keyboard focus. Does not move focus away if it currently holds it. UI thread only.

      It neither repaints nor re-lays-out, because being focusable changes nothing on screen until the focus actually arrives. It does tell the accessible tree, and this is the sharper of the two entry points that reach nothing else: being focusable is both a published state and the thing that keeps a widget in the tree at all, so making a scaffold widget focusable changes what the tree contains — and would otherwise do so silently, on the next unrelated repaint.

      It announces FOCUSABLE/CODE, which is the only way this change is observable at all: it produces no frame, so nothing sampling the tree could ever see it. The guard in front is what keeps that honest where a roving-focus reassignment writes false over every non-holder in a group on every selection change.

    • cursor

      public @Nullable Cursor cursor()
      Returns:
      the mouse cursor this widget requests while hovered, or null to inherit from an ancestor (the scene falls back to Cursor.DEFAULT at the root). Non-final so a component can override it with a state-dependent shape.
    • setCursor

      public final W setCursor(@Nullable Cursor cursor)
      Sets the mouse cursor shown while the pointer is over this widget (and any descendant that does not set its own, since cursor inherits down the tree). null restores inheritance. UI thread only.
      Returns:
      this widget
    • imageCursor

      public @Nullable ImageCursor imageCursor()
      Returns:
      the custom image cursor this widget requests while hovered, or null to inherit. Resolved like cursor(), with an image cursor winning over a shape on the same widget.
    • setImageCursor

      public final W setImageCursor(@Nullable ImageCursor cursor)
      Sets a custom ImageCursor shown while the pointer is over this widget (inherits down the tree like setCursor(limn.backend.Cursor)). null restores inheritance/shape resolution. UI thread only.
      Returns:
      this widget
    • tooltip

      public @Nullable String tooltip()
      Returns:
      the hover tooltip text for this widget, or null/empty for none. The scene shows it after a short dwell, near the pointer. Resolved by walking up from the hovered leaf (like cursor), under this widget's own locale: a tooltip belongs to the subtree it annotates, and the scene painting it is outside any pass that would put that locale in scope.
    • tooltipSource

      public @Nullable I18nString tooltipSource()
      Returns:
      the localizable string behind tooltip(), or null for none. The "is it set here" reader, matching the text()/textSource() pairs the components expose: a tooltip is the natural description of an icon-only control and the natural name when it has no other, and neither can be re-resolved when the translation epoch moves unless the string itself is reachable.
    • setTooltip

      public final W setTooltip(@Nullable String text)
      Sets the hover tooltip text (null clears it). UI thread only.
    • setTooltip

      public final W setTooltip(@Nullable I18nString text)
      Sets a tooltip that follows the UI language (null clears it). UI thread only.

      It repaints nothing, because a tooltip is painted only while it is showing and the scene re-reads it then. It does tell the accessible tree, because a tooltip is a description there and often a name, and a change that paints nothing would otherwise reach a screen reader on the next unrelated repaint, or never.

      Announces DESCRIPTION/CODE, which is the other change here that produces no frame. The guard in front of it compares by value and not by reference, and that is load-bearing rather than a nicety: the String overload wraps its argument in a fresh I18nString on every call, so a != guard would never hold and every repeated setTooltip("Play") would announce a description that did not change. I18nString answers this already, over its key and its English.

    • isFocused

      public final boolean isFocused()
      Whether this widget currently holds its scene's keyboard focus.
    • requestFocus

      public final void requestFocus()
      Asks the scene to move keyboard focus here (UI thread only).

      This is the method an application calls, so the focus move it makes is CODE.

    • requestFocus

      protected final void requestFocus(Change.Origin origin)
      The same, for a component moving focus as part of a gesture it is handling: a tab strip's arrow key, a radio group's. Announces FOCUS with origin on the widget losing focus and on the widget gaining it.

      protected and not package-private, because the two components that need it are in limn.components and this is limn.scene. That places it where a component author can reach it and an application cannot -- which is the right side of the line, since labelling the origin is a component author's obligation and an application asserting that it is the user would be a claim the toolkit cannot check. A component reaches it on another widget through a package-private one-liner on that widget's own class, the way a radio group already drives its members.

      Parameters:
      origin - what moved the focus
    • declaredControlSize

      public final @Nullable ControlSize declaredControlSize()
      Returns:
      the step this widget declares for itself and its subtree, or null when it inherits. This is the "is it set here" reader; use controlSize() for the effective value (cf. isVisible() vs isShowing()).
    • controlSize

      public final ControlSize controlSize()
      Returns:
      the effective size step, never null: this widget's declared value, else the nearest declaring ancestor's, else its scene default, else its host's, else ControlSize.processDefault().

      Read this inside onMeasure(limn.scene.Constraints), onPaint(limn.graphics.Canvas) or an event handler. Never in a constructor or a field initializer: a widget has no parent while it is being constructed, so the answer there is the process default no matter what the eventual parent declares, and a captured value can never be corrected.

      Steady-state cost is one long compare and one field read. On the first resolution after an epoch bump this recurses one step and delegates, so a top-down measure or paint pass re-memoizes the whole tree in O(n) links total.

      final by contract: measure(limn.scene.Constraints) keys its cache on the resolved step, so a subclass that computed a step on the fly would produce sizes the invalidation system cannot see. A composite that owns widgets outside its own subtree links them with setInheritanceHost(limn.scene.Widget<?>) instead of overriding anything.

    • setControlSize

      public final W setControlSize(@Nullable ControlSize size)
      Sets the step for this widget and every descendant that does not declare its own; it inherits down the tree like setCursor(limn.backend.Cursor). null restores inheritance. Re-measures whatever actually changed and repaints; a descendant that declares its own step keeps its measure cache. No-op when unchanged. UI thread only.
    • inheritanceHost

      public final @Nullable Widget<?> inheritanceHost()
      Returns:
      the widget this one's inherited axes resolve through when the tree cannot say, or null when there is none. Every popup, menu and dialog root writes this link, and it is the only path from such a root back to the control that opened it: the accessible tree publishes that link as a relation in both directions, so a client walking either way finds the other.
      See Also:
    • setInheritanceHost

      public final W setInheritanceHost(@Nullable Widget<?> host)
      Links this widget's inherited axes — its ControlSize, its LayoutDirection and its locale alike — to host, for the case the tree cannot express: a widget that is the root of its own Scene (a popup or dialog window) or a overlay, both of which have no parent. One link carries them all, because it says "this parentless panel belongs to that widget", which is a fact about no single axis; a second link that could name a different widget per axis would be a bug with no honest resolution.

      The chain then continues from host, live, so a later change on the host reaches the popup while it is open, which explicit forwarding could not do (and which would additionally convert an inherited value into a declared one, pinning the popup if a process default changed underneath it). null unlinks. UI thread only.

      Consulted after this widget's own scene default, so a popup scene that declares a step or a direction keeps it and one that declares nothing falls through to its host.

      Install it before anything sizes the surface. A native popup or dialog measures its content to size its window before binding a scene; installing the host after that sizes the window at the process defaults and then re-measures the content at the owner's step inside a wrongly-sized window.

      Live resolution is not live repaint. A hosted root in its own scene resolves the new value on its next pass, but nothing marks that scene dirty when the owner's axis changes, so a component holding an open popup has to ask for the pass itself.

      Parameters:
      host - the widget to resolve through, or null to unlink
      Throws:
      IllegalArgumentException - if host resolves through this widget
    • declaredLayoutDirection

      public final @Nullable LayoutDirection declaredLayoutDirection()
      Returns:
      the direction this widget declares for itself and its subtree, or null when it inherits. The "is it set here" reader; use layoutDirection() for the effective value.
    • layoutDirection

      public final LayoutDirection layoutDirection()
      Returns:
      the effective layout direction, never null: this widget's declared value, else the nearest declaring ancestor's, else its scene default, else its host's, else LayoutDirection.processDefault().

      Read this inside onMeasure(limn.scene.Constraints), onPaint(limn.graphics.Canvas), onLayout() or an event handler, and resolve it once per pass into a local. Never in a constructor or a field initializer: a widget has no parent while it is being constructed, so the answer there is the process default no matter what the eventual parent declares, and a captured value can never be corrected. Two resolutions that disagree inside one onPaint put the caret on one side and the selection band on the other.

      Steady-state cost is one long compare and one field read, and the epoch is its own: a control-size change does not invalidate this memo, and this does not invalidate that one. On the first resolution after a bump this recurses one step and delegates, so a top-down pass re-memoizes the whole tree in O(n) links total.

      final by contract, for controlSize()'s reason: measure(limn.scene.Constraints) keys its cache on the resolved direction, so a subclass computing one on the fly would produce sizes the invalidation system cannot see.

    • isRightToLeft

      public final boolean isRightToLeft()
      Whether this widget reads right to left: layoutDirection() is RTL. The test every mirrored pass makes, here once rather than as a private method in each widget. Read it where layoutDirection() may be read: in a pass or an event handler, never in a constructor.
      Returns:
      whether the resolved direction is right to left
    • setLayoutDirection

      public final W setLayoutDirection(@Nullable LayoutDirection direction)
      Sets the layout direction for this widget and every descendant that does not declare its own; it inherits down the tree like setControlSize(limn.scene.ControlSize). null restores inheritance. Re-measures whatever actually changed and repaints; a descendant that declares its own direction keeps its measure cache. No-op when unchanged. UI thread only.
    • declaredLocale

      public final @Nullable Locale declaredLocale()
      Returns:
      the locale this widget declares for itself and its subtree, or null when it inherits. The "is it set here" reader; use locale() for the effective value.
    • locale

      public final Locale locale()
      Returns:
      the effective locale, never null: this widget's declared value, else the nearest declaring ancestor's, else its scene default, else its host's, else the process locale. The language this subtree's strings resolve in, its numbers take their digits from, and its text breaks lines under; it is not a direction — a Hebrew-locale subtree still lays out by its layoutDirection(), and the two axes are declared separately because they genuinely vary separately.

      Widgets rarely need to read this. While the toolkit is inside this widget's measure, layout, paint or an event handler, I18n.locale() already answers it (the pass holds it in scope), so I18nString.get(), I18n.localizeDigits and every other locale reader is correct unchanged. Read it explicitly to hand the answer somewhere the scope cannot follow: a posted task, a native window's title.

      Never read it in a constructor or a field initializer, for the reason the other axes forbid it: a widget has no parent while it is being constructed, so the answer there is the process locale no matter what the eventual parent declares.

      Steady-state cost is two long compares and a field read. The memo is validated against its own epoch and I18n.epoch(), because the chain bottoms out in the process locale and I18n.setLocale(java.util.Locale) cannot reach a counter in this package; a bundle registration therefore re-resolves this memo spuriously, one link per widget, which is the recorded price of keeping the axes' writers apart.

      final by contract, for controlSize()'s reason: measure(limn.scene.Constraints) keys its cache on the resolved locale.

    • setLocale

      public final W setLocale(@Nullable Locale locale)
      Sets the locale for this widget and every descendant that does not declare its own; it inherits down the tree like setControlSize(limn.scene.ControlSize). null restores inheritance. This is the escape hatch from one process-wide locale: the recorded case is a Hebrew interface holding a left-to-right, English-locale code pane, where reading everything off the process locale is the shortcut that breaks it.

      The declared locale is retained while the declaration stands, so every bundle keeps a prepared table for it; clearing or replacing the declaration releases it. A widget discarded while still declaring one keeps that retain — clear the declaration (or accept a resident table per language the process ever declared, which is usually one) when a locale-declaring subtree is dropped for good.

      Re-measures whatever actually changed and repaints; a descendant that declares its own locale keeps its measure cache. No-op when unchanged. UI thread only.

    • baselineOffset

      protected float baselineOffset()
      Distance from this widget's top edge to its first text baseline, in logical points: the alignment reference for Flex.CrossAlignment.BASELINE. Default height(): align on the bottom edge, the correct fallback for a widget with no text. Text-bearing components override with the expression they already paint with; a single-line control's is textRuler().centredBaseline(font, height()), which stands the line's capitals in the middle of the box.

      Valid only once this widget has been given a box. Flex guarantees that: it lays every child of a BASELINE line out at cross position 0 first, reads the baselines, then repositions with moveChild(limn.scene.Widget<?>, int), which moves without re-running layout.

    • baselineOffsetOf

      protected static float baselineOffsetOf(Widget<?> child)
      Reads child's baselineOffset(). For container authors, the same protected static bridge shape as moveChild(limn.scene.Widget<?>, int), and necessary for the same reason: baselineOffset() is protected, so a Flex in limn.scene.layout cannot invoke it on another instance (JLS 6.6.2.1), but a protected static member carries no qualifying-type restriction.
    • setMinWidth

      public final W setMinWidth(float width)
      Keeps this widget at least width points wide wherever its parent lets it choose its width. 0, the default, is no minimum.

      The parent wins. A bound narrows what the parent allows and never overrides it: a widget whose parent fixes its width (the scene's root, which is the window's size; a STRETCH column; a flexible child along its row or column, whose share Expanded.atLeast and atMost bound instead) takes that width whatever its bounds say. Where the parent leaves the choice open, as a column does across and a row does for a child that is not flexible, the widget's natural size is brought within its bounds. UI thread only.

      Parameters:
      width - the narrowest, in logical points
      Returns:
      this widget
      Throws:
      IllegalArgumentException - when negative, NaN or infinite, or above maxWidth()
    • setMaxWidth

      public final W setMaxWidth(float width)
      Keeps this widget at most width points wide wherever its parent lets it choose its width, the bound a paragraph or a form needs so that it does not run the width of a wide window; see setMinWidth(float) for where a bound takes effect. Constraints.UNBOUNDED_LIMIT, the default, is no maximum. UI thread only.
      Parameters:
      width - the widest, in logical points
      Returns:
      this widget
      Throws:
      IllegalArgumentException - when negative or NaN, or below minWidth()
    • setMinHeight

      public final W setMinHeight(float height)
      Keeps this widget at least height points tall wherever its parent lets it choose its height; see setMinWidth(float). 0, the default, is no minimum. UI thread only.
      Parameters:
      height - the shortest, in logical points
      Returns:
      this widget
      Throws:
      IllegalArgumentException - when negative, NaN or infinite, or above maxHeight()
    • setMaxHeight

      public final W setMaxHeight(float height)
      Keeps this widget at most height points tall wherever its parent lets it choose its height; see setMinWidth(float). Constraints.UNBOUNDED_LIMIT, the default, is no maximum. UI thread only.
      Parameters:
      height - the tallest, in logical points
      Returns:
      this widget
      Throws:
      IllegalArgumentException - when negative or NaN, or below minHeight()
    • minWidth

      public final float minWidth()
      Returns:
      the minimum width setMinWidth(float) set, 0 for none
    • maxWidth

      public final float maxWidth()
      Returns:
      the maximum width setMaxWidth(float) set, Constraints.UNBOUNDED_LIMIT for none
    • minHeight

      public final float minHeight()
      Returns:
      the minimum height setMinHeight(float) set, 0 for none
    • maxHeight

      public final float maxHeight()
      Returns:
      the maximum height setMaxHeight(float) set, Constraints.UNBOUNDED_LIMIT for none
    • measure

      public final Size measure(Constraints constraints)
      Measures the preferred size under constraints. Results are cached until markNeedsLayout(), and the cache key includes the resolved axes — the control size, the layout direction and the locale, as one MeasuredAxes value — so a container's change on any axis re-measures exactly the descendants whose resolved value actually changed and leaves overriding subtrees on their caches. That is why no deep-invalidation API is needed for any axis. Subclasses implement onMeasure(limn.scene.Constraints).

      The direction belongs in the key because a line of mixed content genuinely measures a fraction of a point differently in the two directions: the paragraph direction decides which bidi level a boundary neutral takes, which decides which run it extends, which decides which face measures it. The locale belongs there because a keyed string resolves to different text under a different language, and a number to different digits. A cache that cannot see an axis returns a stale size.

      The widget's effective locale is held in scope while onMeasure(limn.scene.Constraints) runs, so everything the measure resolves or formats — an I18nString, a chart tick, a line break — answers in this subtree's language without the subclass doing anything.

      Correctness is a property of the key: the only way this can return a stale size is if the resolved axes and the constraints and needsMeasure all say nothing changed, in which case nothing did.

    • onMeasure

      protected abstract Size onMeasure(Constraints constraints)
      Reports the size this widget wants within constraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.

      Resolve the ControlSize and the LayoutDirection once each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, and I18n.locale() answers it wherever text is resolved.

    • layoutBox

      public final void layoutBox(float x, float y, float width, float height)
      Parent assigns final bounds (parent coords); then onLayout() places children.
    • onLayout

      protected void onLayout()
      Containers position children here (measure + layoutBox(float, float, float, float) per child).
    • moveChild

      protected static void moveChild(Widget<?> child, float x, float y)
      Moves a child without re-running layout: the scroll fast path (size is unchanged; only the offset moves). For container authors.
    • markNeedsLayout

      public final void markNeedsLayout()
      Marks this widget's measure dirty and schedules a scene layout pass.
    • markNeedsLayoutInPlace

      protected final void markNeedsLayoutInPlace()
      Marks this widget's measure dirty and asks for a layout that repaints only what it moves: the form for a widget whose size may change for a reason of its own, such as a label whose text changed width.

      It is the pass setVisible(boolean) uses. The scene climbs from the parent re-running each ancestor's own measure against the constraints it last had, stops at the first whose size did not change, lays that one out in place, and repaints the children that moved, where they were and where they went, plus this widget. Because each ancestor's own layout code runs, a parent that measures a child twice (loose to learn what it wants, then tight) sees the new size as a full pass would; whatever the scene cannot compare, it lays out in full. markNeedsLayout() remains the form that makes no such claim.

    • markNeedsContainedLayout

      public final void markNeedsContainedLayout()
      Asks for this widget's own subtree to be laid out again, without declaring that the frame is a full repaint: the form for a container whose insides move while its box does not, such as a virtualised list mounting and recycling rows as it scrolls.

      A scene treats an ordinary markNeedsLayout() as full damage, because a layout pass may move any widget without that widget invalidating where it used to be. This is the narrow case where that cannot happen, and it is narrow on purpose:

      • the widget must clip its children, so nothing inside it can paint outside the rectangle that gets damaged;
      • its own measured size must come out unchanged. The scene re-measures against the constraints its parent last gave it and compares: if the size moved, the parent's layout is stale and the scene falls back to a full pass, so getting this wrong costs a frame rather than correctness.

      Damage is this widget's bounds. A widget that paints outside them still has its paintOutset() honoured, because the scene damages through the same path invalidate() uses.

      Adding or removing children from inside the pass is expected and does not escalate. That is what a list does when it recycles a row. The same call from anywhere else, or for a widget outside the subtree being laid out, escalates the way it always did.

    • invalidate

      public final void invalidate()
      Requests a repaint (event-driven: the loop wakes and redraws once). Also records this widget's bounds as damage so a scene with partial rendering on, which is the default, repaints only the changed region. The region is the bounds grown by paintOutset(): a widget whose painting extends beyond its bounds by a fixed reach (a shadow, a focus ring) answers that reach there, and this covers it. Scene.damage(Rect) is for painting somewhere else in the scene, outside any such reach.
    • invalidate

      public final void invalidate(float x, float y, float width, float height)
      Requests a repaint of a region in this widget's local coordinates: the fine-grained invalidate() for widgets that know exactly which pixels changed (a blinking caret, one cell of a grid). Under partial rendering only that region is repainted; regions may extend beyond this widget's bounds.
    • textRuler

      protected final TextRuler textRuler()
      Text measurer for layout-time metrics (never null; NONE when detached).
    • neutralBase

      protected final ShapedText.Direction neutralBase()
      What a run of text with no strong character of its own falls back to: this widget's resolved direction, as the shaper's neutral base. A caption that is a bare number, a clock face or a punctuation mark reads the way the interface around it reads, and the first-strong rule cannot know that; the widget can. It is a fallback and not an imposition — a Latin caption in a right-to-left tree still reads left to right, because a strong character already decided it.

      Read it where layoutDirection() may be read: in a pass or an event handler, never in a constructor or a field initializer.

    • shapeText

      protected final ShapedText shapeText(String text, Font font)
      Shapes one line of text the way this widget reads: the first-strong rule decides for any string that can decide for itself, and neutralBase() decides for the rest. This is the way for a widget to get a line. Hold the result (see ShapedText.matches for the idiom), take the natural width from the line's own metrics, and hand the line itself to the canvas.

      A chart is the widget this matters most to, and the reason is worth keeping in view: its chrome is application data that is very often entirely neutral — a series named 2024, a tooltip row reading 3.5, a category called Q1. Not one of those has a strong character, so the first-strong rule has nothing to decide with and the fallback decides all of it, and the fallback is the direction of the interface, which only the widget knows. A series named Vendas is unaffected, because its V already decided.

      The alternatives quietly drop the direction: Canvas.drawText(String, …) and TextRuler.measure carry no base, so they resolve every all-neutral string — a count, a year, a price — with a hard-coded left-to-right fallback, which is right almost always and silent when it is not. Neither signature can gain a direction (the ruler is a @FunctionalInterface every test fake satisfies with a lambda), so the seam is here, on the widget, which is the one place that knows the answer.

    • clipboard

      protected final Clipboard clipboard()
      System clipboard (never null; a local no-op when detached).
    • paintWidget

      public final void paintWidget(Canvas canvas)
      Paints this widget and its children (canvas origin = this widget).

      It leaves the canvas at the depth it found it. A widget's paint may push clips and transforms, down its own branch and through code the toolkit does not own (an application's icon, an adapter's row, a 3D render callback), and it may stop halfway by throwing. Either a forgotten restore() or a throw would otherwise leak a save() into every ancestor still unwinding, and the frame would end unbalanced with the warning naming nobody, because whatever caused it left the stack long before.

      So the depth is taken before and trimmed back after, in a finally. Individual containers still guard their own clips, which is more precise; this is the net under them, not a licence to stop.

      An imbalance on a NORMAL return is a plain bug in the widget rather than fallout from something else, so it is reported once per class. On an exceptional return nothing is reported: the throw is already being handled, and a second message about its side effect would only bury it.

      An Opacity container below 1 draws its subtree as one picture: the canvas's layer is opened around the three paints over what the subtree paints as partial rendering reckons it, each widget's box grown by a pixel and its paintOutset(), a child's past this one's edge included (paintedBounds()), and the trim that closes every save closes it too. At 0 nothing is painted, as for a widget that misses the clip; at 1 no layer is opened, unless an ancestor's paint left a BlendMode other than normal in force, under which the container's subtree is one picture blended once at every opacity, as Canvas.saveLayer(float, float, float, float, float) draws it. Every other widget opens nothing here.

    • paintOutset

      protected float paintOutset()
      How far beyond this widget's bounds its painting may reach, in logical points: its own painting and any descendant no ancestor clips (a drop shadow, a glow, a child positioned outside the parent's box). Partial rendering uses it both ways: invalidate() damage grows by it, and a repaint pass skips this subtree only when bounds + outset miss the pass region; painting farther than declared leaves stale pixels.

      The work is divided by who knows the number. A widget declares what it paints itself outside its box: Label's icon overhang, the focus ring Button, Checkbox and RadioButton draw outside theirs. A widget that lays out children and does not clip them declares how far they may paint past it, because a ring on a child at its edge hangs past it too, and a pass landing only in that band would otherwise skip it and never reach the child. Every layout the toolkit ships does that by default with the reach the theme gives a focus ring, and takes another number through its public paintOverflow, which sets what this hook answers; a layout an application writes inherits both by extending limn.scene.layout.Container, and one that extends this class directly overrides this hook itself. A widget that clips its children declares only its own painting, since the clip bounds theirs.

      Asked of every widget a repaint pass considers, and on every invalidate(), so an override answers in constant time without allocating: a number held or looked up, never a walk over the children. Default 0: everything stays inside the bounds, which is true for most leaves.

    • onPaint

      protected void onPaint(Canvas canvas)
      Widget's own background/content, in local coordinates.
    • clipsChildren

      protected boolean clipsChildren()
      Whether paintChildren(limn.graphics.Canvas) clips its children to this widget's bounds (scroll views, list viewports, tab strips). Partial rendering uses it to clamp a descendant's invalidate() damage to the visible region; a widget scrolled out of view damages nothing. Any override that clips in paintChildren should also override this, and one whose clip is smaller than its box for some child should override the four clip accessors below too.
    • clipX

      protected float clipX(Widget<?> child)
      The left edge, in this widget's own coordinates, of the rectangle clipsChildren() clips child to.

      The whole box by default. A widget that paints one child inside an inset -- a scroll pane whose reserved gutters hold its bars, clipping the content to the viewport and the bars to the box -- answers per child, so that isShowing() and the damage clamp agree with what it paints: until it did, a descendant lying wholly inside the gutter was published on screen in the very rectangle the bar occupies. Consulted only while clipsChildren() is true, and it must not allocate, because the showing test runs for every node of every accessible walk.

      Parameters:
      child - the direct child the clipped descendant is under
      Returns:
      the clip rectangle's left edge
    • clipY

      protected float clipY(Widget<?> child)
      The top edge of the rectangle this widget clips child to; see clipX(Widget).
      Parameters:
      child - the direct child the clipped descendant is under
      Returns:
      the clip rectangle's top edge
    • clipWidth

      protected float clipWidth(Widget<?> child)
      The width of the rectangle this widget clips child to; see clipX(Widget).
      Parameters:
      child - the direct child the clipped descendant is under
      Returns:
      the clip rectangle's width
    • clipHeight

      protected float clipHeight(Widget<?> child)
      The height of the rectangle this widget clips child to; see clipX(Widget).
      Parameters:
      child - the direct child the clipped descendant is under
      Returns:
      the clip rectangle's height
    • paintChildren

      protected void paintChildren(Canvas canvas)
      Children pass; override to clip (e.g. scroll views).

      Indexed rather than an enhanced for, for the reason Scene's own overlay loop already carries: an iterator here is an allocation per widget per frame, and an idle window is the one place in this toolkit that is not allowed to allocate at all. A subtree of two hundred widgets was paying two hundred short-lived objects a frame to walk a list it can index.

    • onPaintOverlay

      protected void onPaintOverlay(Canvas canvas)
      Painted after children (scrollbars, focus rings…).
    • hitTest

      public final @Nullable Widget<?> hitTest(float localX, float localY)
      The deepest widget under a point, this one, or null: what a press at the point lands on. The point is in this widget's space; sceneToLocal(float, float) turns a scene point into it.

      null for a widget that is not visible or not enabled, for one whose subtree is passing out of reach, and for a point outside its box, a point of NaN included; otherwise what onHitTest(float, float) answers. One exception to the box: a widget that does not clip its children lets a point outside it through to a descendant drawn moved there, and answers that descendant or null, never itself. Final, so that these hold for every widget and no container's own answer can skip them: a widget decides only where, inside itself, a point that reached it lands.

      Parameters:
      localX - the point's x in this widget's space
      localY - the point's y in this widget's space
      Returns:
      the widget the point lands on, or null to let it through to what is beneath
    • onHitTest

      protected @Nullable Widget<?> onHitTest(float localX, float localY)
      What this widget answers for a point that reached it: one of its children's answers, itself, or null to let the point through to what is beneath it. Called by hitTest(float, float) only for a widget that is visible, enabled and in reach, with the point inside its box or where it draws a descendant moved past it, so an override checks none of that again.

      The default asks each child through hitTestChild(limn.scene.Widget<?>, float, float), the last first because it is painted on top, and answers the first that is hit, or this widget when none is. A widget overrides it to ask one child before the others (a scroll bar over the content it scrolls), to keep a part of itself from its children, or to be transparent to the pointer.

      Parameters:
      localX - the point's x in this widget's space
      localY - the point's y in this widget's space
      Returns:
      the widget the point lands on, or null
    • hitTestChild

      protected final @Nullable Widget<?> hitTestChild(Widget<?> child, float localX, float localY)
      Asks one child what a point lands on: maps the point from this widget's space into the child's and calls the child's hitTest(float, float). The only way a widget reaches a child's hit test, so that where this widget draws the child, and not only where layout put it, is where the pointer finds it: null where this widget clips the child away, its clip rectangle for that child.
      Parameters:
      child - a child of this widget
      localX - the point's x in this widget's space
      localY - the point's y in this widget's space
      Returns:
      what the child answers
      Throws:
      IllegalArgumentException - if child is not a child of this widget
    • overlayPassesPointer

      protected boolean overlayPassesPointer(float sceneX, float sceneY)
      When this widget is the active modal overlay, whether a pointer hit at the given scene point should fall through to the content beneath it instead of being captured. Default false: an overlay owns all pointer input. The in-scene menu overrides this so the menu bar behind the fullscreen fallback keeps hover-switching and its cursor, exactly as it does when the menu is a separate native window.
    • onMouseEvent

      protected void onMouseEvent(MouseEvent event)
      Mouse events (bubbling); call event.consume() when handled.
    • onKeyEvent

      protected void onKeyEvent(KeyEvent event)
      Key events (focused widget first, then ancestors).
    • onCanEdit

      protected boolean onCanEdit(EditCommand command)
      Whether this widget can do an editing command now: copy with something selected, paste with something to paste, undo with something to take back. Scene.canEdit(limn.scene.EditCommand) asks the widget that has the keyboard and then each of its ancestors, and a menu's item of an editing role is enabled by the answer.

      A widget answers for the commands it takes from the keyboard, and does for the command what it does for the key.

      Returns:
      false here: a widget edits nothing until it says so
    • onEdit

      protected boolean onEdit(EditCommand command)
      Does an editing command, as the user's own act. Called on the first widget, from the one with the keyboard upward, whose onCanEdit(limn.scene.EditCommand) answered true.
      Returns:
      whether it was done
    • onCharTyped

      protected void onCharTyped(CharEvent event)
      Committed text input (focused widget first, then ancestors).
    • onPreedit

      protected void onPreedit(PreeditEvent event)
      In-progress IME composition ("preedit") for this widget while it is focused: the still-composing text, shown inline but not yet committed (the commit later arrives as onCharTyped(limn.scene.event.CharEvent)). Only widgets that accept text input receive it. Default: ignored.
    • acceptsTextInput

      protected boolean acceptsTextInput()
      Whether this widget edits text and should drive the platform input method (IME): the scene enables the IME while such a widget holds focus and disables it otherwise, so composition never intercepts keys meant for non-text UI. Text widgets override this to true. Default: false.
    • caretRect

      protected @Nullable Rect caretRect()
      The caret rectangle in scene coordinates (logical points) used to place the IME candidate window; null when there is no caret to anchor (or the widget is not laid out yet). Consulted by the scene only while this widget is focused and acceptsTextInput() is true.
    • onDragStart

      protected @Nullable Drag onDragStart(DragStartEvent event)
      Asked when a drag may begin on this widget: the pointer was pressed here and has moved a few points, or the drag key was pressed while this widget had the focus. The question bubbles from the widget under the pointer, and the first Drag answered starts the drag; the press is then over for the widget that had it. Default: null, which leaves the gesture to the DRAG events it has always been.
      Parameters:
      event - where the press began, and whether the keyboard asked
      Returns:
      what to drag, or null
    • onDragOver

      protected void onDragOver(DragEvent event)
      A drag is over this widget, or has moved on it. A widget that would take what is offered calls event.accept() and marks where the drop would land; one that says nothing passes the question to its parent, and may show that it refuses. The question goes to the widget under the pointer and then to each enabled ancestor in turn, up to the first that accepts. It is asked again on every move, so that the answer can depend on the place, and again when the content under a still pointer scrolls: a pointer drag resting near an edge of a scrolling view it is over, or past one, scrolls that view. In a keyboard drag only the widget the drag key, Tab or an arrow brings the drag to is asked. Files dragged in from the system arrive the same way, their offer holding DataFormat.FILES. Whatever this draws, accepting or not, onDragExit(limn.scene.event.DragEvent) takes away. Default: says nothing.
      Parameters:
      event - what is offered and where
    • onDragExit

      protected void onDragExit(DragEvent event)
      The drag this widget was last asked about in onDragOver(limn.scene.event.DragEvent) is no longer over it, whether it accepted or not: whatever it drew for the drag goes, the mark of the drop's place or the sign that it refuses. It comes once, at the first of these: a move whose question no longer reaches this widget (the pointer left it, or a widget under the pointer accepted before it was asked); the drag called off, by Escape, another button, the window losing the focus or the source leaving; the drag leaving the window; the drop, on another widget or over this one with no widget taking it; this widget taken out of the scene, hidden or disabled while the drag is over it. In a keyboard drag a widget that does not accept hears it at once, the drag going on to the next, and the target when the drag moves on or ends. A drag from another window or program is told the same. Never after onDrop(limn.scene.event.DropEvent): the widget handed the drop hears no exit. Default: nothing.
      Parameters:
      event - the drag as it leaves
    • onDrop

      protected void onDrop(DropEvent event)
      What was dragged is dropped here: on the widget that accepted it last. Read what is wanted from event.offer() and carry out event.action(); whatever marked the place goes now, since no onDragExit(limn.scene.event.DragEvent) follows. Default: nothing.
      Parameters:
      event - what was dropped and where
    • observeChanges

      public final Subscription observeChanges(ChangeObserver observer)
      Watches every change to this widget, from every origin, without touching whatever handler the application registered.

      A watcher hears what a handler does not: a value a caller wrote, a selection the widget adjusted by itself, a focus move, a label's new text. It is the channel a two-way binding, an inspector, a test and anything describing this tree to something outside it uses, and any number of parties may use it at once without being able to disturb each other or the application.

      The subscription belongs to the widget: it survives detach and re-attach, costs nothing to keep across the mount and unmount a recycled list cell performs on every frame of a scroll, and dies with the widget, so there are no weak references here and none are needed. A late subscriber is owed nothing -- there is no replay and no priming call, because nothing can enumerate every aspect of an arbitrary widget and a synthetic change is indistinguishable from a real one to a listener that pushes an undo entry or plays a sound. What a late subscriber does instead is read the widget: subscribe, then read.

      Parameters:
      observer - told about every change to this widget; never null
      Returns:
      a handle that unregisters; cancelling it twice is a no-op. UI thread
    • notifyChange

      protected final void notifyChange(Change change)
      Announces a change that has already settled, and then runs the handler if the origin is USER: the last statement of an ordinary mutator, after the state, the layout marks, the focus move and the reveal.

      Exactly announceChange(limn.scene.Change) followed by runHandler(limn.scene.Change) -- the two halves in one call, which is what every seam but a compound's wants. The order it delivers in is the guarantee:

      1. this widget's watchers, in registration order;
      2. the watchers of the scene this widget is in, if it is in one;
      3. this widget's handler, if the origin is USER.

      The handler runs last, and that is load-bearing rather than arbitrary: a handler may mutate other widgets and each of those mutations announces itself as it happens, so a handler that ran first would have every consequence of a change announced before the change itself, and a watcher would see a label's new text before the checkbox that caused it.

      Announce only what moved: a mutator handed the state it already holds calls nothing. Where a call moved other aspects on its way to its own, those are announced in the order they settled and the call's own aspect last, which is the signal that the call is finished.

      Parameters:
      change - what changed on this widget, and what moved it
      Throws:
      IllegalStateException - if called from inside a paint. UI thread
    • announceChange

      protected final void announceChange(Change change)
      The announcing half alone: this widget's watchers, then its scene's watchers, and no handler at any origin.

      For a compound whose members must all be announced before any handler runs -- a radio group's leaver and enterer -- which is its only caller in this repository. A seam that calls this owes a matching runHandler(limn.scene.Change) for the same change, or it has silently disabled the application's handler.

      Parameters:
      change - what changed on this widget, and what moved it
      Throws:
      IllegalStateException - if called from inside a paint. UI thread
    • runHandler

      protected final void runHandler(Change change)
      The handler half alone: runs this widget's handler for a change this widget has already announced, and nothing at any origin but USER.

      It takes the whole change rather than its aspect, because the origin is what decides whether the handler runs at all -- which is what lets a compound seam hand it every member's change without branching once per member.

      Parameters:
      change - the change this widget has just announced
    • notifyTextEdit

      protected final void notifyTextEdit(Change.Origin origin, int offset, int removed, int inserted)
      The same as notifyChange(limn.scene.Change), for a text edit, taking the edit's shape rather than a built value so that a keystroke on a tree nobody watches constructs nothing. The three numbers come from the editing model, which is the only thing that has them.

      There is no announce-only sibling: no compound in this repository spans a text edit.

      It reaches the handler exactly as notifyChange does, and without a Change to hand to runHandler(limn.scene.Change): the handler half needs only the aspect and the origin, and both are already here. So after every watcher has run it calls handleUserChange(TEXT) when origin is USER, and nothing when it is not -- a user keystroke on a widget nobody watches still reaches the application's handler and still allocates nothing on this path.

      Parameters:
      origin - what moved the edit
      offset - where the damaged range begins, in chars
      removed - how many chars it replaced
      inserted - how many chars it inserted
      Throws:
      IllegalStateException - if called from inside a paint. UI thread
    • handleUserChange

      protected void handleUserChange(Change.Aspect aspect)
      Runs this widget's application handler for a change it has just announced. Called by runHandler(limn.scene.Change), and so by notifyChange(limn.scene.Change), only for a USER origin and after every watcher has run.

      A component overrides it once and switches on the aspect, reading its own accessors for the payload: a slider passes value(), a combo box selectedIndex(), a text field text(). A component with no handler does not override it.

      An override that does not recognise the aspect must call super, because a subclass of a component that has a handler inherits that component's dispatch through this method: a SearchField that overrode this for its own aspect and did not chain would silently delete TextField's. The ordering lives in the base class, this is the one link in it a subclass can break, and the contract test drives every subclass through its parent's gestures to catch one that does.

      Parameters:
      aspect - what changed; the origin is USER or this is not called
    • onAccessibility

      protected void onAccessibility(Accessibility a)
      Says what this widget is, for an assistive technology.

      Called on the UI thread inside the publish step, with this widget's own locale in scope, and never from a paint. A widget that overrides nothing still gets a node with its bounds, its enabled, focusable, visible and showing states, its language, its children in tree order, the focus and scroll-into-view verbs when it is focusable, and its tooltip as a name when nothing else supplied one. What it does not get is a role: a widget that declares no role, no name, no description, no state, no verb and no facet is scaffolding, and the tree removes it and hoists its children in its place, so that a screen reader hears the controls rather than the boxes.

      Nothing here may allocate. The builder's setters take a facet's fields rather than a facet, and a name is handed over as the localizable string this widget holds rather than as a resolved one, so that a frame which damaged this widget and changed nothing about it costs a comparison and no memory at all. Accessibility states the two rules and what breaks when they are ignored.

      Parameters:
      a - the node being described; write into it, and never keep it
    • onAccessibilityChildIdentity

      protected void onAccessibilityChildIdentity(Widget<?> child, Accessibility a)
      Says who one of this widget's children is, before that child describes itself: the identity key a container that pools its children owns and nothing else can, and, for a container that draws its rows, the synthetic row the child hangs under.

      Called on the UI thread before the child's node exists, so the only two things that may be written here are the two above; a fact about the child — its role, its position, a state — goes in onAccessibilityChild(limn.scene.Widget<?>, limn.accessibility.Accessibility), which runs after the child's own hook. The split is what makes identity right: the child's node is begun under the identifier the key decides, so its name is carried over from the last frame under that identifier, and every node it declares inside itself — a synthetic child, a widget it holds — is scoped under it and follows the row when the child is recycled.

      Parameters:
      child - the child about to be described
      a - the builder, open only for the two identity calls
    • onAccessibilityChild

      protected void onAccessibilityChild(Widget<?> child, Accessibility a)
      Adds what only this widget knows about one of its children: the role a mounted list cell takes, its position in the data, its selected state.

      Called on the UI thread with the child's node current and this widget's locale in scope, after the child has described itself, so what is written here wins. The child's identity is not decided here but in onAccessibilityChildIdentity(limn.scene.Widget<?>, limn.accessibility.Accessibility), which runs first; Accessibility.key(long) refuses to be called from here.

      This is the only place Accessibility.delegate(limn.accessibility.Accessible.Action) may be called: a verb this widget claims on the child — a list's SELECT on a row — is published on the child's node and routed to onAccessibilityChildAction(limn.scene.Widget<?>, long, limn.accessibility.Accessible.Action, limn.accessibility.Accessible.Argument). The builder refuses a delegation from anywhere else, and refuses one here for a verb the child declared for itself, for a verb that takes an argument, and for FOCUS or SCROLL_INTO_VIEW on a focusable child, which the walk performs on its own. A verb written here with Accessibility.action(limn.accessibility.Accessible.Action) would be dispatched to the child's own onAccessibilityAction(limn.accessibility.Accessible.Action, limn.accessibility.Accessible.Argument), which is why a child hook writes facts and delegates verbs.

      Parameters:
      child - the child being described
      a - the child's node
    • onAccessibilityAction

      protected boolean onAccessibilityAction(Accessible.Action action, Accessible.Argument arg)
      Performs an action an assistive technology asked of this widget, as the user.

      Called on the UI thread from a posted task, after the scene has re-checked that this widget is still attached, still enabled with every ancestor, still showing and still reachable. The widget performs its own action: it reaches its own private from-the-user path with its own guards, so an assistive technology's toggle notifies the application exactly as a click does and no component has to grow a public method that re-derives a guard it already has.

      The platform is not told the answer. It was answered from the published snapshot before this ran: the bridge accepts a verb the node publishes and refuses one it does not, synchronously, and the post that reaches here carries no reply back. So false here is honest bookkeeping and nothing more — a refused PRESS raises no INVOKED — and the one contract a reader can see is the published one: a node accepts exactly the parameterless verbs in its action facet plus the setters its writable facets imply. A widget that would answer true for a verb it did not publish is a defect the gallery ratchet in limn-demo reports; a widget that accepts a synonym publishes it.

      Parameters:
      action - what was asked; one of the seventeen, including the four that carry an argument
      arg - the argument, or Accessible.Argument.NONE
      Returns:
      whether this widget did it. false is the honest answer for a verb it does not offer.
    • onAccessibilityChildAction

      protected boolean onAccessibilityChildAction(Widget<?> child, long key, Accessible.Action action, Accessible.Argument arg)
      Performs a verb this widget claimed on one of its widget children: a list's SELECT on a row that is the application's own cell, published on the row where a reader addresses it and performed by the list, which is the only thing that knows what selecting that row means.

      Called on the UI thread from a posted task, after the scene re-checked the child the way it re-checks any node an action lands on, and that this widget is still its parent — with one difference: the child need only be visible, and it is this widget that must be showing, because this widget performs the verb and a cursor row kept outside its viewport is not showing. The child is named twice on purpose: by the key this widget gave it in onAccessibilityChildIdentity(limn.scene.Widget<?>, limn.accessibility.Accessibility), which is how a pooling container thinks of a row, and by the widget itself, for a container that keys nothing. Every verb the child declared for itself still reaches the child's own onAccessibilityAction(limn.accessibility.Accessible.Action, limn.accessibility.Accessible.Argument); only the verbs this widget delegated arrive here.

      Parameters:
      child - the child the verb was addressed to
      key - the identity key this widget gave that child, or 0 when it gave none
      action - what was asked
      arg - the argument, or Accessible.Argument.NONE
      Returns:
      whether this widget did it
    • onSyntheticAction

      protected boolean onSyntheticAction(long key, Accessible.Action action, Accessible.Argument arg)
      Performs an action addressed to one of this widget's synthetic children: a menu row, a combo option, a chart series — something this widget draws and never instantiated as a widget.

      Separate from onAccessibilityAction(limn.accessibility.Accessible.Action, limn.accessibility.Accessible.Argument) deliberately, and not distinguished by a sentinel key: a model index of zero is a legitimate key, so the two cannot share one hook without the widget having to guess which of them it is in.

      Parameters:
      key - the key this widget gave that child when it declared it
      action - what was asked
      arg - the argument, or Accessible.Argument.NONE
      Returns:
      whether this widget did it
    • paintsFromBackdrop

      protected boolean paintsFromBackdrop()
      Whether this widget's picture is made partly of the pixels behind it: a wash, a frost, a refraction. Default false.

      It exists for one mode and is inert outside it. With partial rendering on, a frame repaints only what was invalidated, and a widget like this can be stale without having changed at all: nothing about it moved, but what it is made of did. That was the mode's known limit, and this is its fix. A widget that answers true is registered with its scene, and its rectangle joins the damage of any frame whose damage reaches it.

      Reaching it is over-approximated on purpose. What actually stales the picture is a change behind it, and the test here is any intersection, front or back. Deciding front from back means knowing paint order, which the damage list does not carry; the over-approximation costs a repaint of something already being painted over and can never miss one. That is the right way round for a correctness rule.

      Answer it from the class rather than from state: it is read when the widget joins a scene, not on every frame. A widget whose answer could change with a setter would have to re-register, and nothing in this toolkit needs that — a backdrop panel is built with an effect and never loses it.

      Returns:
      whether the pixels behind this widget are part of what it draws
    • backdropReach

      protected float backdropReach()
      How far outside its box a widget that paints from its backdrop reads the pixels behind it, in points: a blur's radius, a refracting rim's depth. Default 0. Consulted on every frame, so it may follow the widget's state.

      The scene widens the rectangle it adds to a frame's damage by this much, for two reasons that are the same reason. A change that far from the widget changes its picture, so it has to repaint. And it has to be repainted together with that margin: outside the frame's passes the margin holds the last frame finished, with whatever was painted over it, where a whole frame lets the widget read it before anything later is drawn. A scroll bar laid over the end of a bar of frosted glass came out blurred into the glass on every partial repaint, and only there.

      Returns:
      the reach, 0 or more
    • paintsDecoration

      protected boolean paintsDecoration()
      Whether what onPaint(limn.graphics.Canvas) draws is material rather than meaning: a wash, a blur, a shadow, a rule. Default false.

      A widget that draws its own content and declares nothing is removed from the accessible tree by the transparency rule, and the toolkit says so once per class — because the usual cause is a gauge or a sparkline nobody named, and the interface it drew is then simply absent with nothing said. That guard asks "does this class draw?", which reflection can answer; it cannot ask whether the drawing means anything, and this widget is the only thing that can. Overriding this to true is that answer, and the removal then happens in silence.

      It is not setAccessibleIgnored(boolean), and the difference is the subtree. Ignored takes this widget's children out of the tree with it, which on a panel whose whole purpose is to sit behind controls hides every control it wraps. Saying the painting is decoration changes nothing about the tree at all: the node is removed exactly as it would have been, the children hoist into its place, and only the warning goes away.

      Answer it true only for a class whose drawing a reader loses nothing by never hearing about. A widget that paints information is named or given a role instead; there is no third answer that leaves the picture out and keeps the user informed.

      Returns:
      whether this widget's own drawing carries no information
    • setAccessibleLabelledBy

      public final W setAccessibleLabelledBy(@Nullable Widget<?> label)
      Names this widget from another widget's text, the way a form's caption names the field it sits beside. UI thread only.

      One at a time, and declared rather than inferred. A caption that merely sits near a field does not name it: proximity is a layout accident, and a tree built from it says confident wrong things. So the link is written, it replaces any previous one, and passing null removes it. The named node carries a Accessible.Relation.LABELLED_BY relation to the label, so a client that would rather read the label's own node than a copied string can walk to it.

      The text is read from the label on every publish rather than copied here, so a caption that changes its string, or is re-resolved into another language, renames what it labels with nothing to keep in step. A widget that has no text to offer names nothing, and the relation still stands.

      An explicit setAccessibleName(limn.i18n.I18nString) still wins over this, and this wins over whatever the widget would have derived for itself.

      Parameters:
      label - the widget whose text names this one, or null to remove the link
      See Also:
    • accessibleLabelText

      protected @Nullable I18nString accessibleLabelText()
      The text this widget offers when it is named as another's label, or null when it is not the kind of widget that captions anything.

      Overridden by the widgets that are captions in their own right; everything else declines, which is why a link to one names nothing rather than inventing a string from its children.

      Returns:
      the caption text, or null
    • accessibleLabelAccessKey

      protected @Nullable String accessibleLabelAccessKey()
      The chord of the access letter this widget, a caption, gives the widget it labels, or null: what a reader is told reaches the field. Default none.
      Returns:
      the access key's display form, or null
    • accessibleLabelTarget

      protected Widget<?> accessibleLabelTarget()
      The widget a label bound to this one names: this widget, unless it is a composite whose keyboard lands on an inner control, in which case that control.

      A form's caption is bound to the widget the application holds — a date picker — and what a reader arrives at is the field inside it. Naming the group would put the caption on a node the keyboard never lands on and leave the focused field nameless. So a composite answers the child that should carry the caption, and the publish step names that child from the label with NameFrom.LABEL, gives it the LABELLED_BY relation, resolves the label's own LABEL_FOR to it, and leaves this widget's node without either — a group that declares nothing else is then transparent. The answer may redirect again (a composite inside a composite) and it must be a descendant of this widget: anything else is refused by the walk, loudly, because a caption that lands on a stranger is exactly the confidently wrong name the toolkit refuses to infer.

      A name and a description written on this widget with setAccessibleName(limn.i18n.I18nString) and setAccessibleDescription(limn.i18n.I18nString) go to the same widget, for the same reason: they are meant for the node a reader reaches. What that widget was given itself wins over them, as its own caption wins over one sent down to it.

      Called on the UI thread by the publish step, while a label is bound to this widget or a name or a description is written on it. A widget that answers null keeps them itself.

      Returns:
      the widget that carries a label bound to this one; this by default
      See Also:
    • setAccessibleDescribedBy

      public final W setAccessibleDescribedBy(@Nullable Widget<?> source)
      Describes this widget from another widget's text, the way the message beneath a field says why the field is invalid. UI thread only.

      The same rule as setAccessibleLabelledBy(limn.scene.Widget<?>): declared and never inferred, one at a time, null removes it, and the text is read from the source on every publish so a message that changes its string describes with nothing to keep in step. The described node carries a Accessible.Relation.DESCRIBED_BY relation to the source, so a client may read either.

      A bound description beats the tooltip the walk would otherwise fall back on, and an explicit setAccessibleDescription(limn.i18n.I18nString) beats both.

      Parameters:
      source - the widget whose text describes this one, or null to remove the link
      See Also:
    • setId

      public final W setId(@Nullable String id)
      Names this widget for the code that looks it up: Scene.find(String), a test's driver clicking it by id, and a tool that drives the running application from outside, which finds it by the same id through the system's accessibility: UI Automation's automation id on Windows, the accessibility identifier on macOS, the accessible id on Linux. Nobody sees an id and no screen reader speaks one; that is setAccessibleName(limn.i18n.I18nString). An id need not be unique: a lookup answers the first match. A widget given none is published under a number that holds while it stays in the scene. UI thread only.
      Parameters:
      id - the id, or null for none (the default)
      Returns:
      this widget
    • id

      public final @Nullable String id()
      Returns:
      the id setId(java.lang.String) gave, or null
    • setAccessibleName

      public final W setAccessibleName(@Nullable I18nString name)
      Names this widget for an assistive technology, overriding whatever it would have derived for itself. UI thread only.

      An application-set name always wins, so renaming a component never requires subclassing it. It is resolved under this widget's own locale, like every other name in the tree. On a composite whose keyboard lands on a part inside it, it names that part; see accessibleLabelTarget().

      Parameters:
      name - the name, or null to let the widget name itself again
    • setAccessibleName

      public final W setAccessibleName(@Nullable String name)
      Names this widget with a fixed string. UI thread only.
      Parameters:
      name - the name, or null to let the widget name itself again
    • setAccessibleDescription

      public final W setAccessibleDescription(@Nullable I18nString text)
      Describes this widget at more length than its name does, for an assistive technology. UI thread only. On a composite whose keyboard lands on a part inside it, it describes that part, as setAccessibleName(limn.i18n.I18nString) names it.
      Parameters:
      text - the description, or null to let the widget describe itself again
    • setAccessibleDescription

      public final W setAccessibleDescription(@Nullable String text)
      Describes this widget with a fixed string. UI thread only.
      Parameters:
      text - the description, or null to let the widget describe itself again
    • setAccessibleRole

      public final W setAccessibleRole(@Nullable Accessible.Role role)
      Says what this widget is, overriding whatever role it would have declared. UI thread only.

      This is also how a custom widget that paints its own content joins the tree at all: a widget that declares no role is scaffolding and is removed, and the toolkit warns once per class when the class it removes paints something.

      Parameters:
      role - the role, or null to let the widget declare its own
    • setAccessibleIgnored

      public final W setAccessibleIgnored(boolean ignored)
      Removes this widget and its subtree from the accessible tree: a spacer, a decorative rule, an image that repeats what the text beside it already says. UI thread only.

      Not for a control that can be operated. Marking one of those decorative is not a deferral, it is hiding it from the one user who cannot see it.

      Parameters:
      ignored - whether to leave this widget out of the tree entirely
    • invalidateAccessible

      public final void invalidateAccessible()
      Says that something about this widget an assistive technology would care about has changed, when nothing repainted and nothing moved.

      Almost nothing needs this. The accessible tree is rebuilt from the funnel every repaint goes through, so a value, a state, a caret and a selection all reach it already. What does not is a change that paints nothing at all — an application writing a field behind a setter's back, or setting one of the four accessibility overrides above, all of which call this themselves.

      It sets the flag whether or not anything is listening, so switching a bridge on mid-session needs no audit of what was missed, and that costs one store. It buys the frame that reads the flag only while something is listening, because a flag set with no frame coming is a no-op with a comforting name.

    • onFocusGained

      protected void onFocusGained()
      Called when this widget takes keyboard focus. Default: nothing.
    • focusArrivedByTraversal

      protected final boolean focusArrivedByTraversal()
      How the focus this widget is being given arrived: true for Tab or Shift+Tab, false for a click, a requestFocus() from code, or focus restored when an overlay closed.

      The distinction exists because several desktop conventions apply to one and not the other: a single-line field selects its contents when tabbed into, so the next keystroke replaces them, and must not when clicked into, where the click placed a caret the user chose.

      Only meaningful inside onFocusGained(). Asked at any other time it answers false, because the flag is set for exactly the duration of the traversal that raised it. A widget that stored the answer to consult later would be reading the last traversal in the scene, not its own.

      Returns:
      whether Tab brought the focus here
    • focusArrivedBackward

      protected final boolean focusArrivedBackward()
      Whether the focus this widget is being given arrived by Shift+Tab, walking backward: a widget with more than one stop of its own (a table's header and its rows) enters at its last stop then, and at its first otherwise, so that the two directions mirror. false for a forward Tab and for every arrival that is not a traversal. Only meaningful inside onFocusGained(), as focusArrivedByTraversal() is.
      Returns:
      whether Shift+Tab brought the focus here
    • onFocusLost

      protected void onFocusLost()
      Called when this widget loses keyboard focus. Default: nothing.