Skip to content

NavigationShell

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

A navigation view: a pane of navigation items (left, compact, minimal or a top bar) beside a content area that shows the selected item's page.

Items are NavEntry values. The selection is reported as keys: an item's NavEntry::key, else its text, and "settings" for the Settings item. The positional calls (set_expanded(), text_at(), item_bounds()) take a pre-order index over the menu items, then the footer items, with Settings for the Settings item. A selected item shows its own content, or the view's content from set_content() when it has none. In Auto mode the pane adapts to the control's width. It opens and closes on its toggle button, and closes on a click outside when it overlays the content. It can host an AutoSuggestBox, a pane header, custom content and a footer, all owned by the view. The items are one tab stop with a keyboard cursor. The declarative form is ui::NavigationShell with ui::NavItem.

Example:

auto nav = std::make_unique<ui::NavigationShellControl>();
nav->set_pane_display_mode(ui::NavigationShellPaneDisplayMode::Left);
nav->set_pane_title("My app");
nav->add_item("Home", std::make_unique<ui::TextControl>("Welcome home"));
nav->add_item("Library", std::make_unique<ui::TextControl>("Your library"));
nav->on_selection_changed([](const std::string& key) {
    if (key == ui::NavigationShellControl::SettingsKey)
        std::println("open the settings page");
});
ui::NavigationShellControl* view = window.set_content(std::move(nav));
view->set_header(view->selected_key()); // "Home": the first item is selected, keyed by its text

// Or declaratively, with one shared content region driven by the selection:
ui::Property<std::string> page;
window.set_content(ui::NavigationShell{
    .selected_key      = page, // "home" at first, then whatever the user picks
    .pane_display_mode = ui::NavigationShellPaneDisplayMode::Top,
    .content           = ui::Text{.text = page},
    .items             = {ui::NavItem{.text = "Home", .key = "home", .icon = ui::symbol_glyph(ui::Symbol::Home)},
                          ui::NavItem{.text = "Mail", .key = "mail", .icon = ui::symbol_glyph(ui::Symbol::Mail)}},
});

ui::NavigationShell

A pane of navigation items over swappable content. Builds a ui::NavigationShellControl.

The selection is a key: an item's .key, else its text, and "settings" for the Settings item. Auto display mode picks Expanded, Compact or Minimal from the view's width against the two thresholds.

Example:

ui::Property<std::string> page{"mail"};

window.set_content(ui::NavigationShell{
    .selected_key         = page, // two-way: a click writes the new key
    .pane_display_mode    = ui::NavigationShellPaneDisplayMode::Left,
    .on_selection_changed = [&](const std::string& key) {
        if (key == ui::NavigationShellControl::SettingsKey)
            open_settings();
    },
    .items                = {
        ui::NavItem{ .text = "Home", .key = "home", .icon = ui::IconGlyph{0xE80F}, .content = ui::Text{ .text = "Welcome" } },
        ui::NavItem{ .text = "Mail", .key = "mail", .icon = ui::IconGlyph{0xE715}, .content = ui::Text{ .text = "Inbox" } },
    },
    .footer_items = { ui::NavItem{ .text = "Account", .key = "account", .icon = ui::glyphs::Contact } },
});

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

ui::NavigationShell{
    .header, .pane_title, .selected_key, .is_pane_open, .pane_width, .item_row_height,
    .pane_display_mode, .always_show_header, .settings_visible, .back_button_visible,
    .back_enabled, .pane_toggle_button_visible, .pane_visible, .selection_follows_focus,
    .compact_pane_length, .compact_mode_threshold_width, .expanded_mode_threshold_width,
    .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_item_invoked, .on_display_mode_changed, .on_pane_opening,
    .on_pane_opened, .on_pane_closing, .on_pane_closed, .on_back_requested,
    .on_pointer_entered, .on_pointer_exited, .on_got_focus, .on_lost_focus, .on_key_down,
    .on_wheel, .control, .content, .items, .footer_items, .auto_suggest_box,
    .pane_header_content, .pane_custom_content, .pane_footer_content
}

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

Field Type Default
header ui::Binding<std::string> The title over the content area; empty draws none.
pane_title ui::Binding<std::string> Text beside the hamburger button while the pane is open.
selected_key ui::TwoWayField<std::string> The selected item's key ("settings" for Settings). Empty, or a key no item has, leaves the first item selected. Bound two-way, the property then takes the key that is selected.
is_pane_open ui::TwoWayField<bool> {true} Whether the pane is open. A Minimal or Compact pane starts closed whatever this says; bind it to open one later.
pane_width ui::Binding<float> {320.0f} The expanded pane's width, in DIPs.
item_row_height ui::Binding<float> {40.0f} The height of one item row in the left pane, in DIPs (a 36-DIP pill in a 40-DIP slot).
pane_display_mode ui::Binding<ui::NavigationShellPaneDisplayMode> {ui::NavigationShellPaneDisplayMode::Auto} Where the items go: Left, Top, LeftCompact, LeftMinimal, or Auto (width-driven).
always_show_header ui::Binding<bool> {true} False shows the header only in Minimal mode.
settings_visible ui::Binding<bool> {true} Shows the built-in Settings item at the bottom of the pane.
back_button_visible ui::Binding<ui::AutoVisibility> {ui::AutoVisibility::Auto} Whether the back button shows; Auto behaves as Visible.
back_enabled ui::Binding<bool> {false} A visible back button is disabled until this is set (bind it to can_go_back).
pane_toggle_button_visible ui::Binding<bool> {true} Shows the hamburger button.
pane_visible ui::Binding<bool> {true} False hides the pane (and its toggle button) altogether.
selection_follows_focus ui::Binding<ui::NavigationShellSelectionFollowsFocus> {ui::NavigationShellSelectionFollowsFocus::Disabled} Whether moving the keyboard cursor also selects.
compact_pane_length ui::Binding<float> {48.0f} The closed pane's width in Compact mode, in DIPs.
compact_mode_threshold_width ui::Binding<float> {641.0f} The width below which Auto is Minimal.
expanded_mode_threshold_width ui::Binding<float> {1008.0f} The width from which Auto is Expanded (Left).
on_selection_changed ui::Callback<void(const std::string&)> Called with the new key whenever the selection moves.
on_item_invoked ui::Callback<void(const std::string&)> Called with the item's key on every click or Enter/Space on an item (Settings included), selected or not, before the selection moves.
on_display_mode_changed ui::Callback<void(ui::NavigationShellDisplayMode)> Called when the resolved mode changes, including on the first layout.
on_pane_opening ui::Callback<void()> Called when the pane is about to open.
on_pane_opened ui::Callback<void()> Called when the pane has opened.
on_pane_closing ui::Callback<ui::Decision()> Called when the pane is about to close; return ui::Cancel to keep it open.
on_pane_closed ui::Callback<void()> Called when the pane has closed.
on_back_requested ui::Callback<void()> Raised when the back button is clicked.
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::NavigationShell> Out: the handle that receives the built control.
content ui::Spec The shared content region, shown for any selected item that carries no .content of its own, typically a ui::NavigationFrame (ui::NavigationShellControl::set_content).
items ui::NavList The pane's entries, top to bottom.
footer_items ui::NavList Entries pinned to the bottom of the pane, above Settings.
auto_suggest_box ui::Spec A search box at the top of the pane.
pane_header_content ui::Spec Content beside the pane toggle button.
pane_custom_content ui::Spec Custom pane content: above the menu items, after them in Top mode.
pane_footer_content ui::Spec Content at the very bottom of the pane.

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::NavigationShellControl; the caller owns it.

ui::NavItem

One navigation entry: the text in the pane, the content shown while it is selected, and any nested items it groups. A non-empty children makes the row a collapsible group with a chevron.

.content may be left unset. The view's own ui::NavigationShell::content is then shown for this item.

Example:

ui::NavItem{ .text              = "Basic input",
             .key               = "input",
             .expanded          = true,
             .selects_on_invoke = false,
             .icon              = ui::IconGlyph{0xE73A},
             .children          = {
                 ui::NavItem{ .text = "Button", .key = "button", .content = ui::Text{ .text = "Button page" } },
                 ui::NavItem{ .text = "CheckBox", .key = "checkbox", .content = ui::Text{ .text = "CheckBox page" } },
             } }

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

ui::NavItem{
    .text, .key, .expanded, .selects_on_invoke, .icon, .kind, .tool_tip, .animated_icon,
    .content, .info_badge, .children
}

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

Field Type Default
text ui::Binding<std::string> The row's text, and its tooltip while the pane is compact. A bound item should have a .key, or its key changes with its text.
key std::string What identifies the item in .selected_key and the selection events. Empty uses the text. "settings" is taken by the Settings item.
expanded bool false A group starts with its children showing.
selects_on_invoke bool true Whether invoking the row selects it; false makes the row a pure heading.
icon ui::IconSource The row's icon.
kind ui::NavEntryKind ui::NavEntryKind::Item An item, a section header (text as its title) or a separator.
animated_icon const ui::AnimatedIconSource* nullptr An animated icon over this source (not owned), with icon as its fallback; the row plays its PointerOver/Pressed/Normal transitions.
content ui::Spec The page shown while this item is selected; unset falls back to the view's .content.
info_badge ui::Spec A ui::InfoBadge on the row; any other spec is ignored.
children ui::NavList The items nested under this one.

Plus the common fields tool_tip every spec carries (conventions).

ui::NavList

A built, owned list of navigation entries, the braced-list form of the move-only ui::NavEntry. Callers never name it, since a braced list of ui::NavItem{...} converts to it.

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

ui::NavList{
    .entries
}

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

Field Type Default
entries std::vector<Entry> The entries, in pane order.

operator=

NavList& operator=(const NavList&) = delete

operator=

NavList& operator=(NavList&&) = default

struct Entry

One entry with its content and badge already built; mirrors ui::NavItem's fields.

Field Type Default
text Binding<std::string>
key std::string
node std::unique_ptr<Element>
children std::vector<Entry>
expanded bool false
selects_on_invoke bool true
icon IconSource
info_badge std::unique_ptr<Element>
kind NavEntryKind NavEntryKind::Item
tool_tip std::string
animated_icon const AnimatedIconSource* nullptr

ui::NavigationShellControl

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

A navigation view: a pane of navigation items (left, compact, minimal or a top bar) beside a content area that shows the selected item's page.

Items are NavEntry values. The selection is reported as keys: an item's NavEntry::key, else its text, and "settings" for the Settings item. The positional calls (set_expanded(), text_at(), item_bounds()) take a pre-order index over the menu items, then the footer items, with Settings for the Settings item. A selected item shows its own content, or the view's content from set_content() when it has none. In Auto mode the pane adapts to the control's width. It opens and closes on its toggle button, and closes on a click outside when it overlays the content. It can host an AutoSuggestBox, a pane header, custom content and a footer, all owned by the view. The items are one tab stop with a keyboard cursor. The declarative form is ui::NavigationShell with ui::NavItem.

Example:

auto nav = std::make_unique<ui::NavigationShellControl>();
nav->set_pane_display_mode(ui::NavigationShellPaneDisplayMode::Left);
nav->set_pane_title("My app");
nav->add_item("Home", std::make_unique<ui::TextControl>("Welcome home"));
nav->add_item("Library", std::make_unique<ui::TextControl>("Your library"));
nav->on_selection_changed([](const std::string& key) {
    if (key == ui::NavigationShellControl::SettingsKey)
        std::println("open the settings page");
});
ui::NavigationShellControl* view = window.set_content(std::move(nav));
view->set_header(view->selected_key()); // "Home": the first item is selected, keyed by its text

// Or declaratively, with one shared content region driven by the selection:
ui::Property<std::string> page;
window.set_content(ui::NavigationShell{
    .selected_key      = page, // "home" at first, then whatever the user picks
    .pane_display_mode = ui::NavigationShellPaneDisplayMode::Top,
    .content           = ui::Text{.text = page},
    .items             = {ui::NavItem{.text = "Home", .key = "home", .icon = ui::symbol_glyph(ui::Symbol::Home)},
                          ui::NavItem{.text = "Mail", .key = "mail", .icon = ui::symbol_glyph(ui::Symbol::Mail)}},
});

Settings

static std::size_t Settings = static_cast<std::size_t>(-2)

The Settings item's index in the positional calls (text_at(), item_bounds(), set_selected_index()).

SettingsKey

static std::string_view SettingsKey = "settings"

The Settings item's key, as selected_key() reports it and set_selected_key() takes it.

NavigationShellControl()

An empty view in Auto mode with an open pane, the Settings item visible and the back button shown but disabled; it creates its own back, toggle, close and search buttons.

~NavigationShellControl() override
NavigationShellControl(const NavigationShellControl&) = delete

operator=

NavigationShellControl& operator=(const NavigationShellControl&) = delete

set_items

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

Replaces the menu items and resets the selection to the first selectable item. A selected Settings item stays selected. The keyboard cursor and the selection indicator's animation reset too.

void set_footer_items(std::vector<NavEntry> items)

Items at the bottom of the pane (the right of the top bar), above the Settings item, in the same selection model. Their indices follow every menu item's. Keeps the selection when it was a menu item or Settings.

add_item

template <typename T>
T* add_item(std::string text, std::unique_ptr<T> content)

Appends a leaf at the top level of the menu items, taking ownership of its content, and returns a non-owning observer to the content. The first item added becomes selected. Use set_items() for nested items.

set_content

template <typename T>
T* set_content(std::unique_ptr<T> content)

The content region used by any selected item whose own content is null, usually a NavigationFrame. Takes ownership and hands back a non-owning observer.

item_count

std::size_t item_count() const

Every item in the tree, menu and footer, collapsed ones included. This is the pre-order index space of selected_index() and set_expanded().

std::size_t footer_item_count() const

How many of those are footer items (the last ones).

visible_row_count

std::size_t visible_row_count() const

How many menu rows are currently drawn in the pane, i.e. not hidden inside a collapsed ancestor. Footer rows are not counted.

text_at

const std::string& text_at(std::size_t index) const

The text of the item at pre-order index ("Settings" for Settings), or an empty string if out of range.

set_text

void set_text(std::size_t index, std::string text)

Changes the text of the item at pre-order index; updates the layout and redraws. An item without a NavEntry::key is keyed by its text, so its key changes too. Out of range, and Settings, are no-ops.

key_at

const std::string& key_at(std::size_t index) const

The key of the item at pre-order index: its NavEntry::key, else its text; "settings" for Settings; empty out of range.

index_of

std::optional<std::size_t> index_of(std::string_view key) const

The pre-order index of the first item with key, Settings for "settings"; unset when no item has it.

info_badge_at

InfoBadgeControl* info_badge_at(std::size_t index) const

The badge of the item at pre-order index, or null.

set_info_badge

InfoBadgeControl* set_info_badge(std::size_t index, std::unique_ptr<InfoBadgeControl> badge)

Replaces (or with null, removes) the badge of the item at pre-order index, and returns the new one as an observer. Out of range is a no-op returning null.

set_selects_on_invoke

void set_selects_on_invoke(std::size_t index, bool selects)

Changes NavEntry::selects_on_invoke of the item at pre-order index. Out of range is a no-op.

item_at_row

std::optional<std::size_t> item_at_row(std::size_t row) const

The item drawn at menu row row (pre-order index); unset if out of range.

selected_key

const std::string& selected_key() const

The selected item's key ("settings" for Settings), or empty when nothing is selected.

set_selected_key

void set_selected_key(std::string_view key)

Selects the first item with key; "settings" selects the Settings item and an empty key clears the selection. A key no item has is a no-op, otherwise as set_selected_index().

selected_index

std::optional<std::size_t> selected_index() const

The selected item's pre-order index, or Settings; unset when nothing is selected.

set_selected_index

void set_selected_index(std::optional<std::size_t> index)

Selects the item at pre-order index, clamped to the item list. Settings selects the Settings item and unset clears the selection. Does nothing, and fires nothing, if the item is already selected, is a heading (selects_on_invoke == false), a header or a separator, or is Settings while it is hidden. Either way the left pane scrolls the item into view on the next layout, after laying out any expansion made just before.

settings_selected

bool settings_selected() const

Whether the Settings item is the selection.

on_selection_changed

void on_selection_changed(Callback<void(const std::string&)> handler)

Fired with the new key whenever the selection changes (a click, the keyboard, set_selected_key(), set_selected_index()); empty when it was cleared. A call that lands on the already-selected item does not fire it.

on_item_invoked

void on_item_invoked(Callback<void(const std::string&)> handler)

Fired with the item's key on every click or Enter/Space on an item, Settings included, whether or not it changes the selection. It is raised before the selection moves.

selection_follows_focus

NavigationShellSelectionFollowsFocus selection_follows_focus() const

Whether moving the keyboard cursor also selects. Disabled by default.

set_selection_follows_focus

void set_selection_follows_focus(NavigationShellSelectionFollowsFocus value)

Takes effect on the next cursor move; it does not select the item under the cursor now.

expanded

bool expanded(std::size_t index) const

Whether the group at pre-order index is expanded; false for a leaf or out of range.

set_expanded

void set_expanded(std::size_t index, bool expanded)

Expands or collapses the group at index. A no-op on an item with no children.

on_expanded_changed

void on_expanded_changed(Callback<void(const NavigationShellExpandedChangedArgs&)> handler)

Fired whenever a group's expansion changes, by click, chevron or keyboard.

pane_display_mode

NavigationShellPaneDisplayMode pane_display_mode() const

Where the items go. Auto (the default) adapts to the control's width.

set_pane_display_mode

void set_pane_display_mode(NavigationShellPaneDisplayMode mode)

Switching between LeftMinimal and Left opens or closes the pane to match; switching to Top closes it.

display_mode

NavigationShellDisplayMode display_mode() const

What the pane resolved to at the last arrange (Minimal until the first one).

on_display_mode_changed

void on_display_mode_changed(Callback<void(NavigationShellDisplayMode)> handler)

Raised from arrange when display_mode() resolves to a new value, including the first time.

compact_mode_threshold_width

float compact_mode_threshold_width() const

The width below which Auto is Minimal, in DIPs; 641 by default.

set_compact_mode_threshold_width

void set_compact_mode_threshold_width(float width)

Updates the layout; the new threshold applies from the next width change.

expanded_mode_threshold_width

float expanded_mode_threshold_width() const

The width from which Auto is Expanded, in DIPs; 1008 by default.

set_expanded_mode_threshold_width

void set_expanded_mode_threshold_width(float width)

Updates the layout; the new threshold applies from the next width change.

is_pane_open

bool is_pane_open() const

Whether the pane is open. Opening raises on_pane_opening and on_pane_opened; closing raises on_pane_closing (cancelable only for a light dismiss) and on_pane_closed. In Top mode the pane never opens.

set_pane_open

void set_pane_open(bool open)

Opens or closes the pane with the same slide a SidePane uses. Closing an Expanded pane this way counts as a user close, so growing back into Expanded does not reopen it.

on_pane_opening

void on_pane_opening(Callback<void()> handler)

Raised when the pane starts to open, before its transition.

on_pane_opened

void on_pane_opened(Callback<void()> handler)

Raised once the pane is open, as soon as its state flips (not after the slide).

on_pane_closing

void on_pane_closing(Callback<Decision()> handler)

Raised before the pane closes; return ui::Cancel to keep it open. Only a light dismiss can be canceled. The toggle button and set_pane_open(false) always close it.

on_pane_closed

void on_pane_closed(Callback<void()> handler)

Raised once the pane is closed, as soon as its state flips (not when canceled).

pane_width

float pane_width() const

The open pane's width in DIPs, 320 by default, clamped to the control's own width.

set_pane_width

void set_pane_width(float width)

Updates the layout. The width is clamped only when the pane is arranged.

compact_pane_length

float compact_pane_length() const

The closed strip's width in DIPs, 48 by default, which is also the width of the toggle and search buttons.

set_compact_pane_length

void set_compact_pane_length(float length)

Updates the layout with the new strip width.

is_pane_visible

bool is_pane_visible() const

Whether the pane shows (true). False hides the pane and its toggle button altogether.

set_pane_visible

void set_pane_visible(bool visible)

Shows or hides the pane; the layout adapts to it on the next arrange.

is_pane_toggle_button_visible

bool is_pane_toggle_button_visible() const

Whether the hamburger button shows (true).

set_pane_toggle_button_visible

void set_pane_toggle_button_visible(bool visible)

Shows or hides the hamburger button and updates the layout.

pane_title

const std::string& pane_title() const

The pane title, shown beside the hamburger while the pane is open.

set_pane_title

void set_pane_title(std::string title)

Sets the title (on the toggle button, or at the top bar's left in Top mode) and updates the layout.

back_button_visible

AutoVisibility back_button_visible() const

Whether the back button shows; Auto, the default, shows it.

set_back_button_visible

void set_back_button_visible(AutoVisibility visible)

Shows or hides the back button and updates the layout.

is_back_enabled

bool is_back_enabled() const

Whether the back button is enabled; false by default. A visible back button is disabled until this is set.

set_back_enabled

void set_back_enabled(bool enabled)

Enables or disables the back button; typically bound to a frame's can_go_back().

on_back_requested

void on_back_requested(Callback<void()> handler)

Raised when the back button is clicked.

is_settings_visible

bool is_settings_visible() const

Whether the Settings item shows at the end of the footer items (true).

set_settings_visible

void set_settings_visible(bool visible)

Shows or hides the Settings item; hiding it while selected clears the selection.

set_auto_suggest_box

template <typename T>
T* set_auto_suggest_box(std::unique_ptr<T> box)

The search box slot: any Element, placed in the pane under the toggle button (in the top bar's right in Top mode). Null removes it.

auto_suggest_box

Element* auto_suggest_box() const

The search box slot's element (owned by the view), or null.

set_pane_header_content

template <typename T>
T* set_pane_header_content(std::unique_ptr<T> header)

The pane header: any Element, under the toggle button, beside it in Top mode.

pane_header_content

Element* pane_header_content() const

The pane header element (owned by the view), or null.

set_pane_custom_content

template <typename T>
T* set_pane_custom_content(std::unique_ptr<T> content)

Custom pane content: any Element, above the menu items, after them in Top mode.

pane_custom_content

Element* pane_custom_content() const

The custom pane content element (owned by the view), or null.

template <typename T>
T* set_pane_footer_content(std::unique_ptr<T> footer)

The pane footer: any Element, above the footer items, before them in Top mode.

Element* pane_footer_content() const

The pane footer element (owned by the view), or null.

const std::string& header() const

The content's header text, drawn 28px SemiBold above the content. Empty (the default) draws no header row.

set_header

void set_header(std::string header)

Sets the header text and updates the content area's layout.

always_show_header

bool always_show_header() const

Whether the header shows in every display mode (true). False shows it only in Minimal.

set_always_show_header

void set_always_show_header(bool show)

Updates the content area's layout.

item_row_height

float item_row_height() const

The height of one item row in the left pane, in DIPs: 40 by default (a 36-DIP pill in a 40-DIP slot).

set_item_row_height

void set_item_row_height(float height)

Updates the pane's layout with the new row height.

pane_scroll_offset

float pane_scroll_offset() const

How far the menu items are scrolled, in DIPs. Menu items taller than their viewport scroll on the wheel and through an overlay scrollbar.

set_pane_scroll_offset

void set_pane_scroll_offset(float offset)

Scrolls the menu items, clamped to 0..(content height - viewport height) from the last arrange; redraws when it moved.

pane_bounds

Rect pane_bounds() const

The part of the pane showing right now (animation included); empty in Top mode and while a Minimal pane is closed.

content_bounds

Rect content_bounds() const

The content area: right of an inline pane, under the top bar in Top mode.

item_bounds

std::optional<Rect> item_bounds(std::size_t index) const

The drawn rect of the item at pre-order index (Settings for Settings), or nullopt if it has no row showing (hidden in a collapsed group, in the overflow, or scrolled away).

overflow_button_bounds

std::optional<Rect> overflow_button_bounds() const

The rect of the top bar's overflow ("More") button, or nullopt when nothing overflows.

in_overflow

bool in_overflow(std::size_t index) const

Whether the item at index is behind the overflow button in Top mode.

flyout_open

bool flyout_open() const

Whether a children or overflow flyout is open.

back_button

ButtonControl* back_button() const

The internal buttons, for automation: back, pane toggle, close (Minimal, while open) and search (the search box's stand-in while closed compact).

toggle_button

ButtonControl* toggle_button() const

The pane toggle (hamburger) button, owned by the view.

close_button

ButtonControl* close_button() const

The close button a Minimal pane shows while open, owned by the view.

search_button

ButtonControl* search_button() const

The search button shown in the search box's place while closed compact, owned by the view.

close_on_escape

bool close_on_escape(const KeyEvent& e)

Closes an overlaying pane on Escape, as a light dismiss. The window calls it while focus is inside the pane.

focused

bool focused() const

Whether the items' tab stop holds keyboard focus (the cursor's pill then shows the ring).

focusable

bool focusable() const override

The items are one tab stop whenever there is one to reach.

takes_focus_at

bool takes_focus_at(Point p) const override

That stop is the items alone. A press on the menu or footer rows, or on a slot in Top mode, focuses the view. A press on the hosted page reaches the controls there.

collect_focusables

void collect_focusables(std::vector<Element*>& out) override

In tab order: the back, close and toggle buttons, the pane header, the search button or search box, the pane custom content, the items (this), the pane footer, then the active content. While an overlaying pane is open, only the pane's own stops.

sync_native

void sync_native(NativeHost& host) override

Passes native-control hosting on to the owned elements and the active content only. Native controls on an inactive item's page are hidden.

automation_children

void automation_children(std::vector<Element*>& out) const override

Only the active content and the owned pane elements are automation children. The items are drawn rows, and the control exposes the selected item's text as a read-only value.

automation_role

AutomationRole automation_role() const override

AutomationRole::List.

build_visual_tree_override

void build_visual_tree_override(VisualTree& tree) const override

Adds the active content, which for_each_child() leaves out.

measure_override

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

Fills available on whichever axes are bounded.

arrange_override

void arrange_override(const Rect& final_rect, const ArrangeContext& context) override

Resolves the display mode for the new width (raising on_display_mode_changed), then lays out the pane or top bar, the header and the content.

render_override

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

Draws the pane or top bar, the rows with their selection indicator, the header, then the active content; an overlaying pane is drawn over the content.

pointer_override

bool pointer_override(const PointerEvent& e) override

Hover, press and click on the rows, chevrons and overflow button. A click on the content while an overlaying pane is open closes the pane.

wheel_override

bool wheel_override(const PointerEvent& e) override

Scrolls the pane; the content has had the turn first.

hit_test_children

void hit_test_children(Point p, std::vector<Element*>& out) const override

The buttons over everything, the row tooltip, the pane's elements, then the content where nothing covers it.

covers_children_at

bool covers_children_at(Point p) const override

The pane's overlay scrollbars.

clear_dirty_override

void clear_dirty_override(DirtyFlags flags) override

Clears the view's flags and those of every owned element.

tick_override

void tick_override(Duration delta) override

Advances the pane's open/close transition, the indicator's slide and the animated icons.

take_focus_request

FocusRequest take_focus_request() override

Asks the Window to move focus into an overlaying pane as it opens (and back out as it closes); the request is handed over once.

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

The items' keyboard model: the arrows move the cursor (selecting with selection_follows_focus()), Enter/Space invoke, Left/Right collapse and expand a group.

focus_changed

void focus_changed(bool focused) override

Gaining focus puts the cursor on the selected item when it has nowhere valid to be.

focus_ring_rect

Rect focus_ring_rect(const Theme& theme) const override

Around the item under the keyboard cursor; none while a flyout of the pane is open.

struct NavEntry

One navigation entry: the text in the pane, the content shown while it is selected, and any nested items it groups. It is plain data, not an Element, but it owns its content subtree.

That makes it move-only, so a std::vector<NavEntry> is built by pushing into it. For a braced list use ui::NavItem/ui::NavList from this header.

Example:

auto                      nav = std::make_unique<ui::NavigationShellControl>();
std::vector<ui::NavEntry> items;

ui::NavEntry home{"Home"};
home.icon    = ui::symbol_glyph(ui::Symbol::Home);
home.content = std::make_unique<ui::TextControl>("Welcome");
items.push_back(std::move(home));

ui::NavEntry mail{"Mail"};
mail.icon       = ui::symbol_glyph(ui::Symbol::Mail);
mail.expanded   = true;
mail.info_badge = std::make_unique<ui::InfoBadgeControl>();
mail.children.push_back(ui::NavEntry{"Inbox"});
mail.children.push_back(ui::NavEntry{"Sent"});
items.push_back(std::move(mail));

nav->set_items(std::move(items)); // pre-order indices: Home 0, Mail 1, Inbox 2, Sent 3

Field Type Default
text std::string The row's text; a header's title. Also the tooltip and the automation value when the item is selected.
content std::unique_ptr<Element> The content shown while this item is selected. May be null, and then the view's own content (NavigationShellControl::set_content) is shown instead. That is usually a NavigationFrame when the items carry no pages at all.
children std::vector<NavEntry> Nested items. A non-empty list makes this row a collapsible group with a chevron.
expanded bool false Whether a group shows its children inline in the left pane. False by default.
selects_on_invoke bool true Whether invoking the row selects it. False makes the row a pure heading: it still expands and collapses, but never becomes the selection.
icon IconSource The icon, drawn at 16 DIPs in the row's icon column: a Symbol, a glyph, a path or a picture.
info_badge std::unique_ptr<InfoBadgeControl> A badge drawn between the text and the chevron.
kind NavEntryKind NavEntryKind::Item An item, a section header or a separator. A header shows text and a separator nothing; neither is ever selected, invoked or given the keyboard cursor.
tool_tip std::string The row's tooltip. Empty shows the text, and only while the pane is closed compact. A non-empty one shows in every mode.
animated_icon std::unique_ptr<AnimatedIconControl> An animated icon, drawn instead of icon in the pane's rows and the top bar in the row's text color. Its state follows the row's: PointerOver while hovered, Pressed while pressed, Normal otherwise. icon still names the row's icon everywhere else (the overflow and children flyouts), so set it to the animated icon's fallback glyph.
key std::string What identifies the item in selected_key() and the selection events. Empty uses text. "settings" is taken by the Settings item.

struct NavigationShellExpandedChangedArgs

What NavigationShellControl::on_expanded_changed() gets: the group whose expansion changed, and whether it is expanded now.

Field Type Default
index std::size_t 0 The group's pre-order index.
expanded bool false True when it opened.

Enumerations

enum class NavigationShellPaneDisplayMode

Where a NavigationShell puts its items.

Value
Auto Expanded from expanded_mode_threshold_width() on, Minimal below compact_mode_threshold_width(), Compact between.
Left Always Expanded: an inline pane, a compact strip while closed.
Top The items in a 48-DIP bar across the top; what does not fit goes behind "More".
LeftCompact Always Compact: an icon strip, opening over the content.
LeftMinimal Always Minimal: no pane until the toggle button opens one over the content.
enum class NavigationShellDisplayMode

What a NavigationShell's pane is doing right now.

Value
Minimal No pane showing while closed. An open pane overlays the content and closes on a click outside it.
Compact An icon strip (compact_pane_length() wide) while closed; an open pane overlays the content.
Expanded An inline pane beside the content, shrinking to the strip when closed.
enum class NavigationShellSelectionFollowsFocus

Whether a NavigationShell selects the item the arrow keys land on.

Value
Disabled The default: the arrow keys move a cursor, Enter/Space select.
Enabled Whatever item the arrow keys land on is selected at once.
enum class NavEntryKind

What a NavEntry is: an item, a section header or a separator.

Value
Item A selectable, invokable row.
Header A section title showing the entry's text; folded away while the pane is closed compact.
Separator A horizontal rule between groups of items.

Tests

  • tests/test_navigation_shell.cpp