Skip to content

Toolbar

Header: winui/ui/containers/Toolbar.hpp. Spec: winui/ui/containers/Toolbar.hpp.

A horizontal strip of commands, usually Buttons, with optional separators between groups.

The items are laid out in a row with 4 DIPs of spacing, like a horizontal StackControl. The toolbar itself never takes focus, and each item joins the tab order as in a StackControl. There is no overflow handling, so a toolbar wider than its slot overflows like a StackControl. For a command bar with an overflow menu, use ui::CommandBarControl.

Example:

auto  toolbar = std::make_unique<ui::ToolbarControl>();
auto* cut     = toolbar->add(std::make_unique<ui::ButtonControl>("Cut"));
toolbar->add(std::make_unique<ui::ButtonControl>("Copy"));
toolbar->add_separator();
toolbar->add(std::make_unique<ui::ButtonControl>("Undo"));
cut->on_click([] { /* ... */ });
window.set_content(std::move(toolbar));

// Or declaratively:
window.set_content(ui::Toolbar{
    .content = {
        ui::Button{.text = "Cut", .on_click = [] { /* ... */ }},
        ui::Button{.text = "Copy"},
        ui::Separator{},
        ui::Button{.text = "Undo"},
    },
});

ui::Toolbar

A command strip. Builds a ui::ToolbarControl. Use ui::Separator{} between groups.

Example:

window.set_content(ui::Toolbar{.content = {
    ui::Button{.text = "Open", .on_click = [&] { open_file(); }},
    ui::Separator{},
    ui::Button{.text = "Save", .on_click = [&] { save_document(); }},
}});

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

ui::Toolbar{
    .spacing, .style, .margin, .width, .height, .min_width, .min_height, .max_width,
    .max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip,
    .accessibility, .on_pointer_entered, .on_pointer_exited, .on_got_focus, .on_lost_focus,
    .on_key_down, .on_wheel, .control, .content
}

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

Field Type Default
spacing ui::Binding<float> {4.0f} The gap between adjacent commands, DIPs.
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::Toolbar> Out: the handle that receives the built control.
content ui::SpecList The commands, left to right.

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

build

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

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

ui::Separator

The divider a Toolbar draws between command groups. Builds a ui::SeparatorControl.

Example:

ui::Toolbar{.content = {ui::Button{.text = "Cut"}, ui::Separator{}, ui::Button{.text = "Undo"}}}

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

ui::Separator{
    .style, .margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
    .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .accessibility,
    .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
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::Separator> 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, accessibility every spec carries (conventions).

build

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

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

ui::ToolbarControl

Derives from ui::Element.

A horizontal strip of commands, usually Buttons, with optional separators between groups.

The items are laid out in a row with 4 DIPs of spacing, like a horizontal StackControl. The toolbar itself never takes focus, and each item joins the tab order as in a StackControl. There is no overflow handling, so a toolbar wider than its slot overflows like a StackControl. For a command bar with an overflow menu, use ui::CommandBarControl.

Example:

auto  toolbar = std::make_unique<ui::ToolbarControl>();
auto* cut     = toolbar->add(std::make_unique<ui::ButtonControl>("Cut"));
toolbar->add(std::make_unique<ui::ButtonControl>("Copy"));
toolbar->add_separator();
toolbar->add(std::make_unique<ui::ButtonControl>("Undo"));
cut->on_click([] { /* ... */ });
window.set_content(std::move(toolbar));

// Or declaratively:
window.set_content(ui::Toolbar{
    .content = {
        ui::Button{.text = "Cut", .on_click = [] { /* ... */ }},
        ui::Button{.text = "Copy"},
        ui::Separator{},
        ui::Button{.text = "Undo"},
    },
});

ToolbarControl

ToolbarControl()

An empty toolbar with 4 DIPs between items.

add

template <typename T>
T* add(std::unique_ptr<T> child)

Takes ownership of a child, appends it at the end and returns a non-owning observer to it, like StackControl::add().

add_separator

void add_separator()

Appends a thin vertical divider line that takes no focus, the same element make_separator() returns.

spacing

float spacing() const

The gap between adjacent items in DIPs, 4 by default.

set_spacing

void set_spacing(float spacing)

Changes the gap. Updates layout.

for_each_child

void for_each_child(ChildVisitor visit) const override

Visits the internal StackControl that lays the items out.

automation_children

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

Reports the toolbar's items and separators as its direct children. The internal StackControl that for_each_child() visits never appears in the automation tree.

automation_role

AutomationRole automation_role() const override

Exposed to UI Automation as a toolbar.

make_separator

static std::unique_ptr<Element> make_separator()

Makes the same separator as a standalone ui::SeparatorControl, for adding it yourself. In a declared child list, write ui::Separator{}.

measure_override

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

Implement these instead of measure() and arrange(). The base class has already applied margin, size limits and alignment by the time these run. measure_override() is pure (every concrete Element must size itself); arrange_override() defaults to a no-op since most leaves need nothing beyond having bounds() set, which the base already did.

arrange_override

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

Position children within the rect arrange() settled on (also in bounds(), window DIPs). Default: nothing, for a leaf.

render_override

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

What the control draws, in layout coordinates; render() has already applied the visual layer. A container draws its children through their render(), never their render_override().

class SeparatorControl

Derives from ui::Element.

The divider a Toolbar draws between command groups. It takes no focus, and it is 9 DIPs wide and a control's height. It draws an etched groove, a dark line beside a light one, or a 1 px flat line where the theme draws dividers flat. ui::Separator builds it and ui::ToolbarControl::add_separator() adds it.

SeparatorControl

SeparatorControl() = default

A separator. It has no state.

automation_role

AutomationRole automation_role() const override

Exposed to UI Automation as a separator.

measure_override

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

A fixed width, and the height of a line of body text plus the theme's padding. It doesn't take the available height, which would make an Auto-sized row holding the toolbar grow.

render_override

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

Draws the groove or the flat line, centered across the width.

Tests

  • tests/test_toolbar.cpp