Class ToolBar

java.lang.Object
limn.scene.Widget<ToolBar>
limn.components.ToolBar

public final class ToolBar extends Widget<ToolBar>
A horizontal strip of controls (buttons, toggles, segmented controls, Separators…) on a rounded Theme.surface background. Lays its items out from the leading edge, vertically centered, with a configurable gap. Purely a styled container: the items handle their own input.

The strip follows its resolved LayoutDirection: reading left to right the first item added is the leftmost, reading right to left it is the rightmost, and the order in between is the order it was added in either way. Only the placed coordinate moves — the padding, the gap and the measured width are the same numbers in both directions, so a bar cannot change size by changing side.

Sizes follow the ControlSize resolved on this widget: the padding on all four edges, the default gap and the inset of the separators addSeparator() builds come from the SizeTokens row; the border weight comes from Strokes and is the same at every step, which is what makes a bar and the buttons inside it read as one object.

The bar has no height table of its own: its height stays tallestChild + 2 * toolBarPad. Giving it one would let a bar full of MEDIUM buttons disagree with itself about how tall those buttons are, depending only on the bar's own step. Items added through addItem(limn.scene.Widget<?>) are children, so they inherit the bar's step: that propagation is the whole point of setting a step on a toolbar.

To an assistive technology this is one horizontal tool bar and nothing more. Every item is a widget that describes itself, in the order it was added in either direction, and the dividers addSeparator() builds are real Separators publishing their own rules. The bar says nothing on any item's behalf: it holds no notion of a selected one, carries no string that names itself, and takes no input at all, so it offers no verb either. An application that wants the strip named calls setAccessibleName or gives it a tooltip, and one that calls setAccessibleIgnored(true) on it takes every control inside it out of the tree.

  • Constructor Details

    • ToolBar

      public ToolBar()
  • Method Details

    • addItem

      public ToolBar addItem(Widget<?> item)
      Adds an item to the end of the bar.
    • addSeparator

      public ToolBar addSeparator()
      Adds a vertical divider between items, inset per the bar's step.
    • gap

      public ToolBar gap(float newGap)
      Overrides the gap between items, in points. Latches: the value survives every later ControlSize change. Leave it alone to follow the step's toolBarGap.
    • onMeasure

      protected Size onMeasure(Constraints constraints)
      Description copied from class: Widget
      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.

      Specified by:
      onMeasure in class Widget<ToolBar>
    • onLayout

      protected void onLayout()
      Description copied from class: Widget
      Containers position children here (measure + Widget.layoutBox(float, float, float, float) per child).
      Overrides:
      onLayout in class Widget<ToolBar>
    • onPaint

      protected void onPaint(Canvas canvas)
      Description copied from class: Widget
      Widget's own background/content, in local coordinates.
      Overrides:
      onPaint in class Widget<ToolBar>
    • onAccessibility

      protected void onAccessibility(Accessibility a)
      Describes this strip as one horizontal tool bar, and says nothing about what is in it.

      The role is unconditional — not gated on holding items, on the step, or on the direction — and it is the whole reason there is a node here at all. The class declares no name, is never focusable and owns no synthetic child, so a bar that said nothing would be deleted as scaffolding and its items hoisted into whatever holds it; and because the class paints its own surface and border, that deletion would name a toolkit class in an application's log and recommend striking it out, which on this widget takes every control in the bar with it. Declaring the painting decorative is the wrong answer for the same reason: the filled surface and the outline around it are the "these commands are one bar" fact, and that fact is exactly what the role carries.

      The orientation is fixed by the class and never read from the laid-out box. Layout only ever advances along x and only ever centres on y, and there is no vertical mode to ask for; the box, by contrast, is whatever the parent granted, so a bar squeezed into a tall, narrow constraint would announce itself vertical to anyone who inferred the axis from it. Mirroring does not reach it either: the bit names the axis the run of items lies along, and right to left that is the same axis walked the other way.

      No name is declared. The bar holds no string that names it, and one built here would have no source to compare against, so it would allocate on every damaged frame to conclude that nothing had moved. A tooltip names the node through the walk's free default, and an application's own name wins over that and demotes the tooltip to the description. Nothing is declared about an item either: a tool bar is not a selection container, so there is no position in a set to hand down, and an item wrapped in a stretchy box would not be a direct child for a hook to reach in any case. Two primitive writes and no string, so a damaged frame that changed nothing costs no memory.

      Overrides:
      onAccessibility in class Widget<ToolBar>
      Parameters:
      a - the node being described