Class SegmentedControl
RadioButton group or tabs. The selected segment is marked by an
accent indicator that slides between segments (animated like the
TabbedPane indicator). Click a segment, or move with Left/Right when
focused. Colours come from Theme; the box, the type and the gutters come
from the resolved ControlSize row (SizeTokens), while the
track border stays one weight at every step (Strokes).
Width: the track is exactly as wide as its segments need and no wider, centred in
whatever box the parent assigns. That matters because the common parent (a column with
STRETCH) hands every child the full row, and a pill track drawn edge to edge with
four short segments huddled at its left end reads as broken. The margins either side belong
to what is behind this control: a click landing on one selects nothing.
Overflow: when the segments do not fit, the strip becomes a clipped, scrollable
viewport with a chevron at each edge, the dead side drawn disabled rather than dropped,
since dropping it would resize the viewport and make the strip jump at the ends. The mouse
wheel scrolls it, a chevron click scrolls by most of a viewport, and selecting a segment by
any route (click, Left/Right, or setSelectedIndex(int)) scrolls it into view. Nothing
is ever painted outside the track. There is no all-segments popup, which is the one part of
the TabbedPane overflow story this control does not carry: its labels are handed in
by the caller and are few and short by construction, and a control that fits in a toolbar
row has nowhere to put a third piece of chrome.
Reading direction: the strip is a row of items in reading order, so it mirrors. The
segments are placed from the edge reading starts at, the back chevron sits in that same gutter
and points back towards the first segment, and Left selects the segment that is visually on the
left: a keyboard that walked the other way from the pointer would be arguing with the screen.
Home and End do not mirror, because they name the first and last segment rather
than a side. Only the placement moves; the track, the viewport and each label inside its own
segment are symmetric and stay where they are, and there is no mirror transform anywhere here.
This or a TabbedPane? Ask who owns the content. A segmented
control owns none: it takes labels and hands back an index, so the caller keeps
the content and switches it, which is what makes it the one that belongs in a
toolbar row, a form, or inside another widget that already owns what changes. A
tabbed pane is the opposite: you hand it the pages and it owns them, laying out
and painting only the selected one, and carrying the overflow story that owning
an unknown number of pages requires. Looking alike is not the test; a row of
labels is what both are, and what they do is where they split.
-
Constructor Summary
ConstructorsConstructorDescriptionSegmentedControl(List<String> segments) A control over the given segment labels; the first is selected. -
Method Summary
Modifier and TypeMethodDescriptionprotected floatDistance from this widget's top edge to its first text baseline, in logical points: the alignment reference forFlex.CrossAlignment.BASELINE.protected voidCalled when this widget takes keyboard focus.protected voidCalled when this widget loses keyboard focus.protected voidonKeyEvent(KeyEvent event) Key events (focused widget first, then ancestors).protected voidonLayout()Containers position children here (measure +Widget.layoutBox(float, float, float, float)per child).protected SizeonMeasure(Constraints constraints) Reports the size this widget wants withinconstraints.protected voidonMouseEvent(MouseEvent event) Mouse events (bubbling); callevent.consume()when handled.protected voidWidget's own background/content, in local coordinates.Called with the chosen index whenever the selection changes: a click, an arrow key and asetSelectedIndex(int)from code all arrive here.protected floatThe focus ring reachesStrokes.FOCUS_RING_OUTSETbeyond the box, and the scene inflates a widget's damage by1 + paintOutset().intThe selected segment's index; never negative, since the control refuses an empty segment list and so always has exactly one selection.setSelectedIndex(int index) Selects a segment, scrolls it into view and firesonSelect; code and a click take the same path, so a listener sees every change either way.Methods inherited from class limn.scene.Widget
acceptsTextInput, add, baselineOffsetOf, caretRect, children, clipboard, clipsChildren, controlSize, cursor, declaredControlSize, declaredLayoutDirection, declaredLocale, focusArrivedByTraversal, height, hitTest, imageCursor, invalidate, invalidate, isEnabled, isFocusable, isFocused, isShowing, isVisible, layoutBox, layoutDirection, locale, localToSceneX, localToSceneY, markNeedsContainedLayout, markNeedsLayout, measure, moveChild, neutralBase, onAttached, onCharTyped, onDetached, onFileDrop, onPaintOverlay, onPreedit, overlayPassesPointer, paintChildren, paintWidget, parent, remove, requestFocus, revealInView, scene, sceneToLocalX, sceneToLocalY, setControlSize, setCursor, setEnabled, setFocusable, setImageCursor, setInheritanceHost, setLayoutDirection, setLocale, setTooltip, setTooltip, setVisible, shapeText, textRuler, tooltip, width, x, y
-
Constructor Details
-
SegmentedControl
A control over the given segment labels; the first is selected. Needs at least one.
-
-
Method Details
-
onSelect
Called with the chosen index whenever the selection changes: a click, an arrow key and asetSelectedIndex(int)from code all arrive here. -
selectedIndex
public int selectedIndex()The selected segment's index; never negative, since the control refuses an empty segment list and so always has exactly one selection. There is nothing to clear to. -
setSelectedIndex
Selects a segment, scrolls it into view and firesonSelect; code and a click take the same path, so a listener sees every change either way. Re-selecting the current segment still reveals it (a caller asking for a segment is asking to be shown it) but changes nothing and fires nothing; that early return is what keeps two controls bound to each other from recursing, so do not remove it. UI thread only.- Parameters:
index- a segment in[0, segmentCount)- Throws:
IndexOutOfBoundsException- ifindexis not a segment. Arrowing past an end is not this: keyboard traversal stops at the end rather than raising.
-
onMeasure
Description copied from class:WidgetReports the size this widget wants withinconstraints. 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
ControlSizeand theLayoutDirectiononce each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, andI18n.locale()answers it wherever text is resolved. -
baselineOffset
protected float baselineOffset()Description copied from class:WidgetDistance from this widget's top edge to its first text baseline, in logical points: the alignment reference forFlex.CrossAlignment.BASELINE. Defaultheight(): 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.
Flexguarantees that: it lays every child of a BASELINE line out at cross position 0 first, reads the baselines, then repositions withWidget.moveChild(limn.scene.Widget, float, float), which moves without re-running layout.- Overrides:
baselineOffsetin classWidget
-
onLayout
protected void onLayout()Description copied from class:WidgetContainers position children here (measure +Widget.layoutBox(float, float, float, float)per child). -
onPaint
Description copied from class:WidgetWidget's own background/content, in local coordinates. -
paintOutset
protected float paintOutset()The focus ring reachesStrokes.FOCUS_RING_OUTSETbeyond the box, and the scene inflates a widget's damage by1 + paintOutset(). Without this the ring's fade-out sheds stale pixels under partial rendering.Declares reach only; it moves no ink.
- Overrides:
paintOutsetin classWidget
-
onFocusGained
protected void onFocusGained()Description copied from class:WidgetCalled when this widget takes keyboard focus. Default: nothing.- Overrides:
onFocusGainedin classWidget
-
onFocusLost
protected void onFocusLost()Description copied from class:WidgetCalled when this widget loses keyboard focus. Default: nothing.- Overrides:
onFocusLostin classWidget
-
onMouseEvent
Description copied from class:WidgetMouse events (bubbling); callevent.consume()when handled.- Overrides:
onMouseEventin classWidget
-
onKeyEvent
Description copied from class:WidgetKey events (focused widget first, then ancestors).- Overrides:
onKeyEventin classWidget
-