Class RadioButton

java.lang.Object
limn.scene.Widget
limn.components.RadioButton

public class RadioButton extends Widget
A single-choice control: a ring that fills with a dot when selected. Radios in a ButtonGroup are mutually exclusive: selecting one deselects the rest. Unlike a Checkbox, clicking a selected radio does not turn it off. Selected by click, or Space/Enter when focused. Colours from Theme, extents from the SizeTokens row resolved on this widget, pens from Strokes.

The ring rides indicator, the same token as Checkbox's box, so a form mixing the two keeps every label on one optical column at every step.

The ring sits on the row's leading edge with the label running away from it, so both swap sides with the LayoutDirection resolved on this widget. The ring is a circle and the dot is concentric with it, so nothing inside the indicator has a side to reflect; only the column the pair occupies moves.

This row is under the 24 pt pointer target

The row is max(indicator, lineHeight) rather than the control-height ramp, and the indicator wins that max at every step (18 pt at MEDIUM), which is below the 24 pt target of WCAG 2.2 SC 2.5.8 (AA) on the axis that decides it: a label widens a target, it never heightens it. A radio's pointer target is exactly the ring-and-label box it paints.

The standard's own Spacing exception is what an application relies on: an undersized target conforms while a 24 pt circle centred on it clears every neighbour. A lone radio already satisfies that; a group (the normal case) does not until the pitch reaches 24, which is what Tokens.toggleColumnGap(limn.scene.Widget) gives. Stack a ButtonGroup's radios on that gap, not a tighter one.

  • Constructor Details

    • RadioButton

      public RadioButton(String text)
      A radio with a fixed label; see the I18nString constructor for localized text.
    • RadioButton

      public RadioButton(I18nString text)
      A radio button whose label follows the UI language; see I18nString.
  • Method Details

    • onChange

      public RadioButton onChange(Consumer<Boolean> listener)
      Fires with true when this radio becomes selected, false when a sibling takes over.
    • setText

      public RadioButton setText(String newText)
      Replaces the label with a fixed string. UI thread only.
    • isSelected

      public boolean isSelected()
      Whether this radio is the selected one in its group.
    • select

      public void select()
      Selects this radio (idempotent). In a group, deselects the previously selected sibling and notifies the group; standalone, just selects itself.
    • 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
    • baselineOffset

      protected float baselineOffset()
      Description copied from class: Widget
      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, (height() - metrics.height()) / 2 + metrics.ascent().

      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 Widget.moveChild(limn.scene.Widget, float, float), which moves without re-running layout.

      Overrides:
      baselineOffset in class Widget
    • onPaint

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

      protected float paintOutset()
      The focus circle is the only thing that paints outside the box: radius ring/2 + Strokes.FOCUS_GAP_INDICATOR with a centred Strokes.FOCUS_RING_THIN pen puts its outer ink 2.25pt past the indicator, which is flush with the widget's leading edge — the left one reading left to right and the right one reading right to left — and (since the row is the indicator at every step) with its top and bottom. One outset covers every side, so the edge the indicator moves to is already inside the damage and the direction is not an input here. Scene assumes only 1pt of AA feather, so without this the fading ring left stale pixels under partial rendering. Deliberately the same expression as Checkbox's: the two are in declared lockstep and must damage the same rectangle, or a form column mixing them repaints unevenly.
      Overrides:
      paintOutset in class Widget
    • onMouseEvent

      protected void onMouseEvent(MouseEvent event)
      Description copied from class: Widget
      Mouse events (bubbling); call event.consume() when handled.
      Overrides:
      onMouseEvent in class Widget
    • onKeyEvent

      protected void onKeyEvent(KeyEvent event)
      Description copied from class: Widget
      Key events (focused widget first, then ancestors).
      Overrides:
      onKeyEvent in class Widget
    • onFocusGained

      protected void onFocusGained()
      Description copied from class: Widget
      Called when this widget takes keyboard focus. Default: nothing.
      Overrides:
      onFocusGained in class Widget
    • onFocusLost

      protected void onFocusLost()
      Description copied from class: Widget
      Called when this widget loses keyboard focus. Default: nothing.
      Overrides:
      onFocusLost in class Widget