Skip to content

SelectorBar

Header: winui/ui/navigation/SelectorBar.hpp. Spec: winui/ui/navigation/SelectorBar.hpp.

A row of text segments, each with an optional icon. Exactly one is selected, marked by an accent pill under its text.

The items own no content, so the app switches what is shown below in on_selection_changed(). A press on an item selects it, and with focus, Left/Right move the selection. The whole strip is one tab stop. The declarative form is ui::SelectorBar.

Example:

auto  panel = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto* bar   = panel->add(std::make_unique<ui::SelectorBarControl>(
    std::vector<ui::SelectorBarItem>{"Recent", "Shared", "Favorites"}));
auto* shown = panel->add(std::make_unique<ui::TextControl>("Recent files"));
bar->on_selection_changed([bar, shown](std::size_t) { shown->set_text(bar->selected_text() + " files"); });
window.set_content(std::move(panel));

ui::SelectorBar

A horizontal segmented selector. Builds a ui::SelectorBarControl.

Typically paired with a ui::Match that shows the page for the selected segment.

Example:

ui::Property<std::size_t> tab{0};

window.set_content(ui::VerticalStack{
    .content = {
        ui::SelectorBar{
            .items          = {{"Recent", ui::Symbol::Clock}, "Shared", {"Favorites", ui::Symbol::Favorite}},
            .selected_index = tab,
        },
        ui::Match<std::size_t>{
            .value   = tab,
            .content = [](const std::size_t& i) -> ui::Spec
            { return ui::Text{.text = std::format("Page {}", i + 1)}; },
        },
    },
});

Every field, in the order a designated initializer names them:

ui::SelectorBar{
    .items, .selected_index, .style, .margin, .width, .height, .min_width, .min_height,
    .max_width, .max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip,
    .enabled, .accessibility, .on_selection_changed, .on_pointer_entered, .on_pointer_exited,
    .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control
}

Fields, in declaration order (designators must follow it):

Field Type Default
items ui::Binding<std::vector<ui::SelectorBarItem>> The segments, left to right: text, each with an optional icon.
selected_index ui::TwoWayField<std::size_t> {0} The selected segment; clamped into the item range.
on_selection_changed ui::Callback<void(std::size_t)> Fires with the new index when the selection changes by a click, the arrow keys or a bound write. A write that lands on the current segment does not fire it.
on_pointer_entered ui::Action The pointer moved onto the control.
on_pointer_exited ui::Action The pointer left the control.
on_got_focus ui::Action Keyboard focus arrived on the control, or on anything inside it, from outside it. A control with nothing focusable in it never gets focus, and never raises this.
on_lost_focus ui::Action Keyboard focus left the control and everything inside it.
on_key_down ui::Callback<ui::Handling(const ui::KeyEvent&)> A key pressed while focus is on the control or inside it, before the control's own handling; ui::Handled stops it there (Element::on_key_down()).
on_wheel ui::Callback<ui::Handling(const ui::PointerEvent&)> A wheel turn over the control, before the control scrolls; ui::Handled stops it there (Element::on_wheel()).
control ui::ControlOut<ui::SelectorBar> Out: the handle that receives the built control.

Plus the common fields style, margin, width, height, min_width, min_height, max_width, max_height, horizontal_alignment, vertical_alignment, visible, tool_tip, enabled, accessibility every spec carries (conventions).

build

std::unique_ptr<Element> build()&&

Consumes the spec and returns the built ui::SelectorBarControl; the caller owns it.

ui::SelectorBarControl

Derives from ui::Element, ui::ValueProvider.

A row of text segments, each with an optional icon. Exactly one is selected, marked by an accent pill under its text.

The items own no content, so the app switches what is shown below in on_selection_changed(). A press on an item selects it, and with focus, Left/Right move the selection. The whole strip is one tab stop. The declarative form is ui::SelectorBar.

Example:

auto  panel = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto* bar   = panel->add(std::make_unique<ui::SelectorBarControl>(
    std::vector<ui::SelectorBarItem>{"Recent", "Shared", "Favorites"}));
auto* shown = panel->add(std::make_unique<ui::TextControl>("Recent files"));
bar->on_selection_changed([bar, shown](std::size_t) { shown->set_text(bar->selected_text() + " files"); });
window.set_content(std::move(panel));

SelectorBarControl

SelectorBarControl() = default

An empty strip: nothing drawn, not focusable.

SelectorBarControl

SelectorBarControl(std::vector<SelectorBarItem> items, std::size_t selected_index = 0)

A strip of items, selected_index selected (clamped). Raises nothing.

items

const std::vector<SelectorBarItem>& items() const

The items, in order.

set_items

void set_items(std::vector<SelectorBarItem> items)

Replaces the item list and resets the selection to index 0 without raising on_selection_changed(). Updates the layout.

selected_index

std::size_t selected_index() const

The selected item's index; 0 while the list is empty.

set_selected_index

void set_selected_index(std::size_t index)

Selects the item at index, clamped to the item list. Does nothing, and fires nothing, if the item is already selected or the list is empty.

selected_text

const std::string& selected_text() const

The currently selected item's text, or an empty string if there are no items.

on_selection_changed

void on_selection_changed(Callback<void(std::size_t)> handler)

Fired whenever the selection changes: an item click, the arrow keys or set_selected_index(). A call that lands on the already selected item does not fire it.

focused

bool focused() const

Whether the strip holds keyboard focus.

focusable

bool focusable() const override

Not a tab stop with fewer than two items, since there is nothing to switch.

automation_role

AutomationRole automation_role() const override

AutomationRole::Tab. The items have no content of their own, so the strip exposes the selected item's text as a read-only value.

measure_override

Size measure_override(Size available, const MeasureContext& context) const override

A single row sized to fit each item's own text, without stretching to fill the strip, plus room for the pill at the bottom of every item.

render_override

void render_override(Renderer& renderer, const RenderContext& context) const override

Each item's icon and text, the selected one's pill, and the focus ring while focused.

pointer_override

bool pointer_override(const PointerEvent& e) override

Hover tracking, and a press on an item selects it.

tick_override

void tick_override(Duration delta) override

Advances the selection pill's grow-in.

enabled_changed

void enabled_changed() override

is_enabled() flipped, through set_enabled() here or on an ancestor, or a move to another parent. Drop any press or hover state. The element is redrawn either way. No-op by default.

key_override

bool key_override(const KeyEvent& e) override

ArrowLeft/ArrowRight select the previous/next item while focused (no wrap-around).

focus_changed

void focus_changed(bool focused) override

Called by Window as focus moves; redraws.

focus_ring_rect

Rect focus_ring_rect(const Theme& theme) const override

A square ring, a little tighter around the strip than the usual focus ring.

focus_ring_corner_radius

float focus_ring_corner_radius(const Theme&) const override

The ring's corner radius: the theme's control radius by default.

struct SelectorBarItem

One segment of a SelectorBar: its text and an optional icon before it.

Converts from a string, so a list of plain strings needs no item type spelled out: .items = {"Recent", "Shared"}, or with icons .items = {{"Recent", ui::Symbol::Clock}, {"Shared", ui::Symbol::Share}}.

text

std::string text

The segment's text.

icon

IconSource icon

Drawn before the text at 0.8 of a 20-DIP symbol; empty draws none.

SelectorBarItem

SelectorBarItem(std::string item_text, IconSource icon = {})

A segment showing item_text, with icon before it (empty: none).

SelectorBarItem

SelectorBarItem(const char* item_text)

A segment showing item_text.

Tests

  • tests/test_selector_bar.cpp