Skip to main content

Module segmented_control

Module segmented_control 

Source
Expand description

SegmentedControl — mutually exclusive segments in a horizontal row.

Each segment is a real composed widget — a centered icon + label with a reactive tint — built from a Segment descriptor. Selection is bound to a Signal<Option<SegmentId>>: keyed, not positional, so inserting or removing a segment never silently re-points the selection at a different one. The chrome (rounded frame, hover tint, selected-segment surface) is delegated to the active SegmentedControlStyle.

const LIST: SegmentId = SegmentId::from_u64(1);
const GRID: SegmentId = SegmentId::from_u64(2);

let view = ctx.signal(Some(LIST));
SegmentedControl::new(view.clone())
    .segment(Segment::new(tr!(list_view())).id(LIST).icon(|| IconWidget::list(14.0)))
    .segment(Segment::new(tr!(grid_view())).id(GRID).icon(|| IconWidget::grid(14.0)))

// Pairing with a Switcher:
Switcher::new(segmented_control::index_signal(&view, &[LIST, GRID]))

§When to use

  • Use a SegmentedControl for mutually exclusive modes that read well as a compact horizontal strip (view mode, time period).
  • Prefer a ComboBox when the options are many and the strip form buys nothing — though a segmented control no longer breaks down at seven segments, because it overflows (below).
  • Prefer RadioButton / RadioTileGroup when the options need vertical space or descriptions.

§Width: overflow, not squeeze

When the segments do not fit, the ones that do not fit move into a trailing chevron menu rather than all of them compressing into ellipsised stubs (SegmentOverflow::Menu, the default; opt out with SegmentOverflow::Compress).

Declaration order is stable, with exactly one exception: the selected segment is always visible. If it would have been pushed into the menu it takes the last slot, and it stays there until another segment is chosen from the menu — so the strip does not reshuffle under the pointer, and the promotion is forgotten once the control is wide enough to show everything again.

Declared: [A][B][C][D][E][F][G]   fits 4 + chevron

start, A selected     [A][B][C][D][v]   menu: E F G
pick F from menu      [A][B][C][F][v]   menu: D E G
click A (F stays)     [A][B][C][F][v]   menu: D E G
widen to full fit     [A][B][C][D][E][F][G]

§Accessibility

Role::RadioGroup on the control with active_descendant pointing at the selected segment; Role::RadioButton per segment, carrying “N of M” over the whole segment list — including segments currently in the overflow menu, which are still reachable. Arrow keys cycle selection (RTL-aware, resolved at event time) and Home/End jump to the ends, both skipping disabled segments; stepping onto an overflowed segment promotes it into view. Increment/Decrement AT actions mirror the arrows.

The strip is one tab stop. While the control is overflowing the chevron adds a second, because an overflow menu that no keyboard can reach is not an overflow menu; it cannot join the arrow sequence, since here arrows move selection rather than a roving focus.

Structs§

Segment
One segment descriptor: a localized label with a stable SegmentId, an optional leading icon, a hover tooltip, and reactive disabled / visible flags.
SegmentId
Stable identity of a segment. Cheap to copy; survives rebuilds, locale changes, and segments being inserted around it.
SegmentedControl
A segmented control binding a Signal<Option<SegmentId>> to a row of mutually exclusive segments. Build the segment list with segment or segments.

Enums§

SegmentDisplay
What a segment paints: its icon, its label, or both.
SegmentOverflow
What the control does when its segments do not fit.
SegmentSizing
How the visible segments divide the control’s width.

Functions§

index_signal
Derive a Switcher-compatible index from a keyed selection.