Skip to content

Breadcrumb

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

A navigation trail (Home > Folder > File) of plain text items, root first.

Every item but the last is a small inline button that raises on_item_click() with its index. The last is the current location. It is not clickable, has no trailing chevron and is never hovered or highlighted by the keyboard. The strip is one tab stop. Left/Right move a highlight among the clickable items, and Enter/Space activates it. The arrow keys alone never navigate. When the trail is wider than the control, the leading items fold into an ellipsis ("…"). Its flyout lists them nearest first, and picking one raises on_item_click() with that item's own index.

The control never changes its own items. A click is a request, and the handler decides what to do, usually cutting the trail back to the clicked item.

Example:

auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
ui::BreadcrumbControl* bar = stack->add(std::make_unique<ui::BreadcrumbControl>(
    std::vector<std::string>{"Home", "Documents", "Design", "Northwind"}));
bar->on_item_click([bar](std::size_t index)
{
    std::vector<std::string> items = bar->items();
    items.resize(index + 1); // navigate up: drop everything after the clicked item
    bar->set_items(std::move(items));
});
window.set_content(std::move(stack));

// Declaratively, reporting the clicked folder:
ui::Property<std::string> location{"Design"};
ui::Control<ui::Breadcrumb> crumbs;
window.set_content(ui::VerticalStack{
    .content = {
        ui::Breadcrumb{
            .items         = {"Home", "Documents", "Design"},
            .on_item_click = [&](std::size_t index) { location = crumbs->items()[index]; },
            .control       = crumbs,
        },
        ui::Text{.text = location},
    },
});

ui::Breadcrumb

A navigation trail (Home > Folder > File). Builds a ui::BreadcrumbControl. The last item is the current location and is plain text. Every earlier item fires .on_item_click when clicked or Enter/Space-activated.

Example:

ui::Control<ui::Breadcrumb> trail;

window.set_content(ui::Breadcrumb{
    .items         = {"Home", "Documents", "Design", "Northwind"},
    .on_item_click = [&](std::size_t index)
    {
        // Navigate up: drop everything after the clicked folder.
        std::vector<std::string> items = trail->items();
        items.resize(index + 1);
        trail->set_items(std::move(items));
    },
    .control = trail,
});

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

ui::Breadcrumb{
    .items, .style, .margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
    .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .enabled, .accessibility,
    .on_item_click, .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<std::string>> The trail, root first; the last entry is the current location. Bind it to a property and assign a shorter trail to go back up.
on_item_click ui::Callback<void(std::size_t)> Called with the index of an activated item. Never fires for the last (current) item.
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::Breadcrumb> 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::BreadcrumbControl; the caller owns it.

ui::BreadcrumbControl

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

A navigation trail (Home > Folder > File) of plain text items, root first.

Every item but the last is a small inline button that raises on_item_click() with its index. The last is the current location. It is not clickable, has no trailing chevron and is never hovered or highlighted by the keyboard. The strip is one tab stop. Left/Right move a highlight among the clickable items, and Enter/Space activates it. The arrow keys alone never navigate. When the trail is wider than the control, the leading items fold into an ellipsis ("…"). Its flyout lists them nearest first, and picking one raises on_item_click() with that item's own index.

The control never changes its own items. A click is a request, and the handler decides what to do, usually cutting the trail back to the clicked item.

Example:

auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
ui::BreadcrumbControl* bar = stack->add(std::make_unique<ui::BreadcrumbControl>(
    std::vector<std::string>{"Home", "Documents", "Design", "Northwind"}));
bar->on_item_click([bar](std::size_t index)
{
    std::vector<std::string> items = bar->items();
    items.resize(index + 1); // navigate up: drop everything after the clicked item
    bar->set_items(std::move(items));
});
window.set_content(std::move(stack));

// Declaratively, reporting the clicked folder:
ui::Property<std::string> location{"Design"};
ui::Control<ui::Breadcrumb> crumbs;
window.set_content(ui::VerticalStack{
    .content = {
        ui::Breadcrumb{
            .items         = {"Home", "Documents", "Design"},
            .on_item_click = [&](std::size_t index) { location = crumbs->items()[index]; },
            .control       = crumbs,
        },
        ui::Text{.text = location},
    },
});

BreadcrumbControl()

An empty trail; it draws nothing and is not focusable.

BreadcrumbControl(std::vector<std::string> items)

A trail of items, root first; the last is the current location.

~BreadcrumbControl() override

Destroys the ellipsis flyout with the control.

BreadcrumbControl(const BreadcrumbControl&) = delete

Non-copyable, like every Element.

operator=

BreadcrumbControl& operator=(const BreadcrumbControl&) = delete

Non-copyable, like every Element.

items

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

The trail, root first (UTF-8); the last entry is the current location.

set_items

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

Replaces the item list and clears the hover, press and keyboard highlight, closing an open flyout. Updates the layout. Safe to call from inside on_item_click().

on_item_click

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

Fires with the index into items() when a clickable item is activated by a click, Enter/Space, or from the ellipsis flyout. Every item but the last is clickable. Replaces any previous handler.

ellipsis_shown

bool ellipsis_shown() const

Whether the leading items are folded into the ellipsis because the trail did not fit its width, as of the last arrange.

first_shown_item

std::size_t first_shown_item() const

Index of the first item drawn after the ellipsis (0 when nothing is folded); items before it live in the flyout.

item_bounds

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

An item's rect in window coordinates as of the last arrange, or nullopt when it is folded into the ellipsis or index is out of range.

ellipsis_bounds

std::optional<Rect> ellipsis_bounds() const

The ellipsis item's rect while it shows; nullopt when nothing is folded.

flyout_open

bool flyout_open() const

Whether the ellipsis flyout listing the folded items is open.

set_flyout_open

void set_flyout_open(bool open)

Opens or closes the ellipsis flyout (a click on the ellipsis toggles it). Opening does nothing while no items are folded or the control is disabled.

focused

bool focused() const

Whether the strip holds keyboard focus.

focusable

bool focusable() const override

Focusable while the control is enabled and has a clickable item, which takes at least two items since the last one is never clickable.

automation_role

AutomationRole automation_role() const override

A Group: the items are plain strings with no automation nodes of their own.

measure_override

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

The whole trail's natural width (items, chevrons) and one row's height; it never wraps.

arrange_override

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

Decides how many leading items fold into the ellipsis so the rest fit final_rect.

render_override

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

Draws the items, chevrons, the ellipsis and the keyboard focus ring. Under a Fluent theme hover and press change only the text color; retro themes also wash the background.

pointer_override

bool pointer_override(const PointerEvent& e) override

Button-style clicks: a press on an item followed by a release anywhere activates it. A click on the ellipsis toggles the flyout.

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

Left/Right move the keyboard highlight and Enter/Space activates it. Up, Down and Escape work in the open flyout.

focus_changed

void focus_changed(bool focused) override

Called by Window. Gaining focus puts the keyboard highlight on the ellipsis if it shows, else on the first shown clickable item. Losing focus clears the highlight. Redraws.

focus_ring_rect

Rect focus_ring_rect(const Theme& theme) const override

Around the focused item, or the ellipsis.

Tests

  • tests/test_breadcrumb.cpp