Skip to content

CommandBar

Header: winui/ui/menus/CommandBar.hpp. Spec: winui/ui/menus/CommandBar.hpp.

A toolbar of app-bar buttons with an overflow menu behind a More ("...") button.

Primary commands (AppBarButton, AppBarToggleButton, AppBarSeparator, or any Element) sit in a row against the bar's right edge, with optional content on the left. Secondary commands are in the overflow menu. Opening the bar with the More button or set_open() shows the overflow menu and the text of commands whose text goes at the Bottom. The open bar is drawn over whatever lies below it, or above it when it opens upward, and never moves other elements. A click on a command closes the bar, and so does a click outside or Escape unless is_sticky(). With dynamic overflow on (the default), primary commands that do not fit move into the overflow and come back when there is room. The shortcuts of secondary commands fire app-wide while the bar is in the window.

Example:

auto  bar     = std::make_unique<ui::CommandBarControl>();
auto* add     = bar->add_primary(std::make_unique<ui::AppBarButtonControl>("Add", ui::Symbol::Add));
bar->add_primary(std::make_unique<ui::AppBarSeparatorControl>());
bar->add_primary(std::make_unique<ui::AppBarToggleButtonControl>("Shuffle", ui::Symbol::Shuffle));
auto* settings = bar->add_secondary(std::make_unique<ui::AppBarButtonControl>("Settings", ui::Symbol::Setting));
bar->set_content(std::make_unique<ui::TextControl>("Now playing"));
bar->set_default_text_position(ui::CommandBarDefaultTextPosition::Right);
add->on_click([] { /* add an item */ });
settings->on_click([] { /* open settings */ });
window.set_content(std::move(bar));

// Declaratively:
window.set_content(ui::CommandBar{
    .default_text_position = ui::CommandBarDefaultTextPosition::Right,
    .content   = ui::Text{.text = "Now playing", .vertical_alignment = ui::Alignment::Center},
    .primary   = {ui::AppBarButton{.text = "Add", .icon = ui::Symbol::Add},
                  ui::AppBarSeparator{},
                  ui::AppBarToggleButton{.text = "Shuffle", .icon = ui::Symbol::Shuffle}},
    .secondary = {ui::AppBarButton{.text = "Settings", .icon = ui::Symbol::Setting}},
});

ui::CommandBar

A toolbar of app-bar buttons with an overflow menu. Builds a ui::CommandBarControl.

Primary commands sit in the bar, and secondary commands are in the overflow menu behind the More ("...") button. With dynamic overflow on, primary commands that do not fit move into the overflow too. Opening the bar with the More button shows the text and the overflow.

Example:

ui::Property<std::string> status;
window.set_content(ui::CommandBar{
    .default_text_position = ui::CommandBarDefaultTextPosition::Right,
    .on_closed              = [&](ui::PopupCloseReason) { status = "closed"; },
    .content                = ui::Text{ .text = "Now playing", .vertical_alignment = ui::Alignment::Center },
    .primary   = { ui::AppBarButton{ .text = "Add", .icon = ui::Symbol::Add, .on_click = [&] { status = "new"; } },
                   ui::AppBarSeparator{},
                   ui::AppBarToggleButton{ .text = "Shuffle", .icon = ui::Symbol::Shuffle } },
    .secondary = { ui::AppBarButton{ .text = "Settings", .icon = ui::Symbol::Setting } },
});

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

ui::CommandBar{
    .is_open, .sticky, .default_text_position, .overflow_button_visibility,
    .dynamic_overflow_enabled, .closed_display_mode, .background, .style, .margin, .width,
    .height, .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
    .vertical_alignment, .visible, .tool_tip, .enabled, .accessibility, .on_opening,
    .on_opened, .on_closing, .on_closed, .on_pointer_entered, .on_pointer_exited,
    .on_got_focus, .on_lost_focus, .on_key_down, .on_wheel, .control, .content, .primary,
    .secondary
}

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

Field Type Default
is_open ui::TwoWayField<bool> {false} Whether the bar is open, with the text and the overflow menu showing.
sticky ui::Binding<bool> {false} No light dismiss: an outside click or Escape leaves the open bar open.
default_text_position ui::Binding<ui::CommandBarDefaultTextPosition> {ui::CommandBarDefaultTextPosition::Bottom} Text under the icons, to their right, or none.
overflow_button_visibility ui::Binding<ui::AutoVisibility> {ui::AutoVisibility::Auto} Auto shows the More button only when there is something to reveal.
dynamic_overflow_enabled ui::Binding<bool> {true} Primary commands that do not fit move into the overflow menu.
closed_display_mode ui::Binding<ui::AppBarClosedDisplayMode> {ui::AppBarClosedDisplayMode::Compact} Compact (48 DIPs tall), Minimal (24 DIPs, the More button only) or Hidden (0).
background ui::Binding<ui::Paint> The fill behind the bar: a fixed color or a theme resource. Unset is transparent. In Compact mode the open bar draws its own acrylic.
on_opening ui::Action The bar is about to open.
on_opened ui::Action The bar has opened.
on_closing ui::Callback<ui::Decision(const ui::PopupClosingArgs&)> The bar is about to close. Gets the reason: a light dismiss, a command click, the More button, or is_open set to false. Return ui::Cancel to keep it open.
on_closed ui::Callback<void(ui::PopupCloseReason)> The bar has closed, with the reason. This is where a bound is_open learns about 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::CommandBar> Out: the handle that receives the built control.
content ui::Spec Shown at the bar's left.
primary ui::SpecList The commands in the bar: ui::AppBarButton, ui::AppBarToggleButton and ui::AppBarSeparator specs.
secondary ui::SpecList The overflow menu's entries, as app-bar specs.

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

ui::CommandBarControl

Derives from ui::Element, ui::AppBarCommandHost.

A toolbar of app-bar buttons with an overflow menu behind a More ("...") button.

Primary commands (AppBarButton, AppBarToggleButton, AppBarSeparator, or any Element) sit in a row against the bar's right edge, with optional content on the left. Secondary commands are in the overflow menu. Opening the bar with the More button or set_open() shows the overflow menu and the text of commands whose text goes at the Bottom. The open bar is drawn over whatever lies below it, or above it when it opens upward, and never moves other elements. A click on a command closes the bar, and so does a click outside or Escape unless is_sticky(). With dynamic overflow on (the default), primary commands that do not fit move into the overflow and come back when there is room. The shortcuts of secondary commands fire app-wide while the bar is in the window.

Example:

auto  bar     = std::make_unique<ui::CommandBarControl>();
auto* add     = bar->add_primary(std::make_unique<ui::AppBarButtonControl>("Add", ui::Symbol::Add));
bar->add_primary(std::make_unique<ui::AppBarSeparatorControl>());
bar->add_primary(std::make_unique<ui::AppBarToggleButtonControl>("Shuffle", ui::Symbol::Shuffle));
auto* settings = bar->add_secondary(std::make_unique<ui::AppBarButtonControl>("Settings", ui::Symbol::Setting));
bar->set_content(std::make_unique<ui::TextControl>("Now playing"));
bar->set_default_text_position(ui::CommandBarDefaultTextPosition::Right);
add->on_click([] { /* add an item */ });
settings->on_click([] { /* open settings */ });
window.set_content(std::move(bar));

// Declaratively:
window.set_content(ui::CommandBar{
    .default_text_position = ui::CommandBarDefaultTextPosition::Right,
    .content   = ui::Text{.text = "Now playing", .vertical_alignment = ui::Alignment::Center},
    .primary   = {ui::AppBarButton{.text = "Add", .icon = ui::Symbol::Add},
                  ui::AppBarSeparator{},
                  ui::AppBarToggleButton{.text = "Shuffle", .icon = ui::Symbol::Shuffle}},
    .secondary = {ui::AppBarButton{.text = "Settings", .icon = ui::Symbol::Setting}},
});

CommandBarControl

CommandBarControl()

An empty, closed, Compact bar with the More button on Auto.

~CommandBarControl

~CommandBarControl() override

Destroys every command, the content and the overflow.

add_primary

template <typename T>
T* add_primary(std::unique_ptr<T> command)

Appends command to the row. Takes ownership and hands back a non-owning observer (the same convention as StackControl::add()). Updates the layout.

add_secondary

template <typename T>
T* add_secondary(std::unique_ptr<T> command)

Appends command to the overflow menu. Takes ownership and hands back a non-owning observer. Updates the layout.

insert_primary_element

void insert_primary_element(std::size_t index, std::unique_ptr<Element> command)

Inserts a primary command before index (clamped to the end), taking ownership. command must not be null. Updates the layout.

insert_secondary_element

void insert_secondary_element(std::size_t index, std::unique_ptr<Element> command)

Inserts a secondary command before index (clamped to the end), taking ownership. command must not be null. Updates the layout.

remove_primary

void remove_primary(std::size_t index)

Destroys the primary command at index; out of range is ignored. Updates the layout.

remove_secondary

void remove_secondary(std::size_t index)

Destroys the secondary command at index; out of range is ignored. Updates the layout.

primary_count

std::size_t primary_count() const

The number of primary commands, including any moved into the overflow.

secondary_count

std::size_t secondary_count() const

The number of secondary commands.

primary

Element* primary(std::size_t index) const

The primary command at index as a non-owning observer, or nullptr when out of range.

secondary

Element* secondary(std::size_t index) const

The secondary command at index as a non-owning observer, or nullptr when out of range.

set_content

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

Shows content at the bar's left, replacing any previous content; null clears it. Takes ownership and hands back a non-owning observer. Hidden while closed in Minimal/Hidden.

content

Element* content() const

The content as a non-owning observer, or nullptr.

default_text_position

CommandBarDefaultTextPosition default_text_position() const

Where every command puts its text. Bottom (the default) shows the text only while the bar is open, Right always beside the icon, Collapsed never.

set_default_text_position

void set_default_text_position(CommandBarDefaultTextPosition position)

Sets where every command puts its text, and lays out every command again.

is_open

bool is_open() const

Whether the bar is lifted over its surroundings, with the text and the overflow showing. False by default.

set_open

void set_open(bool open)

Opens or closes the bar. Fires on_opening()/on_closing() at once and on_opened()/ on_closed() once the transition has run; no-op when unchanged.

closed_display_mode

AppBarClosedDisplayMode closed_display_mode() const

What the closed bar shows; Compact by default.

set_closed_display_mode

void set_closed_display_mode(AppBarClosedDisplayMode mode)

Sets what the closed bar shows and updates the layout. The closed height is 48, 24 or 0 DIPs.

set_background

void set_background(Paint color)

The fill behind the bar, closed and open: a fixed color or a theme resource. Empty, the default, is transparent. In Compact mode the open bar draws its acrylic over this fill.

open_rect

Rect open_rect() const

Where the open bar is drawn: over the closed bar and whatever lies below it, or above it when it opens upward. It takes no room in the layout, and the bar's bounds() stay those of the closed bar.

opens_up

bool opens_up() const

Whether the open bar went up because there was not enough room below for it and its overflow.

is_sticky

bool is_sticky() const

Whether light dismiss is off, so an outside click or Escape leaves the bar open.

set_sticky

void set_sticky(bool sticky)

False by default. A click on a command still closes a sticky bar.

overflow_button_visibility

AutoVisibility overflow_button_visibility() const

When the More button shows. Auto, the default, shows it only when there is something to reveal: overflow entries or hidden text. With Collapsed, the pointer cannot reach the secondary commands.

set_overflow_button_visibility

void set_overflow_button_visibility(AutoVisibility visibility)

Updates the layout.

is_dynamic_overflow_enabled

bool is_dynamic_overflow_enabled() const

Whether dynamic overflow is on; true by default. When the bar is narrower than its commands, primary commands move into the overflow and move back when there is room. The group with the lowest dynamic_overflow_order() moves first, then the rest from the right.

set_dynamic_overflow_enabled

void set_dynamic_overflow_enabled(bool enabled)

Updates the layout.

is_primary_in_overflow

bool is_primary_in_overflow(std::size_t index) const

Whether the primary command at index has been moved into the overflow by dynamic overflow.

more_button_visible

bool more_button_visible() const

Whether the More button shows, resolving overflow_button_visibility()'s Auto against the current commands, closed mode and text position.

on_opening

void on_opening(Callback<void()> handler)

Fired as is_open() turns true, before the transition. Replaces any previous handler.

on_opened

void on_opened(Callback<void()> handler)

Fired once the opening transition has run.

on_closing

void on_closing(Callback<Decision(const PopupClosingArgs&)> handler)

Fired before is_open() turns false, with why: Programmatic for set_open(false), LightDismiss for a click outside or Escape, Invoked for a command click, CloseButton for the More button. Return ui::Cancel to keep the bar open.

on_closed

void on_closed(Callback<void(PopupCloseReason)> handler)

Fired once the closing transition has run, with the reason on_closing() saw. This is where a bound is_open learns about a light dismiss.

command_invoked

void command_invoked(CommandBarElement& command) override

A command in the bar was clicked, so the bar closes.

toggle_from_more_button

void toggle_from_more_button()

The More button was clicked, or Down/Up pressed on it: toggles the bar, and an opening moves keyboard focus into the overflow.

for_each_child

void for_each_child(ChildVisitor visit) const override

Lists the shown row in drawing order (the content, the primaries left in the bar, the More button), which is what Tab and automation walk. A closed bar in Minimal or Hidden mode leaves out the content and the primaries, and Hidden leaves out the More button too.

sync_native

void sync_native(NativeHost& host) override

Passes native-control hosting on to the content only.

handle_global_shortcut

bool handle_global_shortcut(const KeyEvent& e) override

The shortcuts of the overflow's commands, which fire whether or not the overflow is open.

automation_role

AutomationRole automation_role() const override

Always AutomationRole::ToolBar.

measure_override

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

The closed bar's size, with a height of 48, 24 or 0 DIPs. Also decides which primary commands move into the overflow at the available width.

arrange_override

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

Places the content, the primaries left in the bar and the More button.

render_override

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

Draws the closed bar; the open bar is drawn over the tree by the window's popup layer.

hit_test_children

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

The commands, while the bar is closed.

clear_dirty_override

void clear_dirty_override(DirtyFlags flags) override

Clears flags on this node and every owned child, shown or not: the secondaries, the separator, the open-bar layer and the overflow too.

tick_override

void tick_override(Duration delta) override

Ticks the content and every command, shown or not, and the More button, then runs the open/close transition.

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.

Enumerations

AppBarClosedDisplayMode

enum class AppBarClosedDisplayMode

What a closed CommandBar shows.

Value
Compact the icons, 48 tall
Minimal the More button only, 24 tall
Hidden nothing, 0 tall

Tests

  • tests/test_command_bar.cpp