TitleBar¶
Header: winui/ui/hosting/TitleBar.hpp. Spec: winui/ui/hosting/TitleBar.hpp.
A chrome row with an icon, title and subtitle, optional back and pane-toggle (hamburger) buttons, and three content slots (left header, content, right header).
The bar itself takes no focus. The back and pane-toggle buttons (subtle Buttons) and whatever sits in the slots are each their own Tab stop. Use it either as a row at the top of a page, or as the window's caption in a window with WindowStyle::extend_content_into_title_bar. In a window, the bar follows it: it keeps the right header clear of the space Window::caption_insets() reports for the caption buttons, and dims while Window::active() is false. hit_region() then tells the host which parts drag the window. set_caption_insets() and set_active() override what the window says, for a bar drawn somewhere other than its own window's caption. The bar has no minimize, maximize or close buttons, since the window keeps its own. It doesn't set the window's title from title(), so an app sets both.
Example:
ui::Property<bool> can_go_back{false};
ui::Control<ui::NavigationFrame> frame;
ui::Control<ui::NavigationShell> nav;
window.set_content(ui::VerticalStack{.content = {
ui::TitleBar{
.title = "Contoso Notes",
.subtitle = "Preview",
.icon = ui::IconGlyph{0xE70B},
.back_button_visible = can_go_back,
.pane_toggle_button_visible = true,
.content_alignment = ui::Alignment::Stretch,
.on_back_requested = [&] { frame->go_back(); },
.on_pane_toggle_requested = [&] { nav->set_pane_open(!nav->is_pane_open()); },
.content = ui::TextBox{.placeholder_text = "Search", .max_width = 360.0f},
},
// ... the page below the bar ...
}});
// Run the window with ui::WindowOptions{.style = {.extend_content_into_title_bar = true}} to make
// the bar the caption; without it the bar is an ordinary row under the standard title bar.
ui::TitleBar¶
A horizontal chrome row: icon, title, subtitle, an optional back/pane-toggle button, and three arbitrary content slots. Builds a ui::TitleBarControl.
Example:
using ui::operator""_fr;
ui::Control<ui::NavigationFrame> frame;
window.set_content(ui::Grid{
.rows = {ui::AutoSize, 1_fr},
.content = {
ui::Cell{.row = 0,
.content = ui::TitleBar{
.title = "Contoso Mail",
.subtitle = "Preview",
.icon = ui::symbol_glyph(ui::Symbol::Mail),
.back_button_visible = true,
.on_back_requested = [&] { frame->go_back(); },
.content = ui::AutoSuggestBox{.placeholder_text = "Search", .width = 300.0f},
}},
ui::Cell{.row = 1, .content = ui::NavigationFrame{.control = frame}},
},
});
Every field, in the order a designated initializer names them:
ui::TitleBar{
.title, .subtitle, .icon, .back_button_visible, .back_button_enabled,
.pane_toggle_button_visible, .caption_insets, .active, .content_alignment, .style, .margin,
.width, .height, .min_width, .min_height, .max_width, .max_height, .horizontal_alignment,
.vertical_alignment, .visible, .tool_tip, .enabled, .accessibility, .on_back_requested,
.on_pane_toggle_requested, .on_pointer_entered, .on_pointer_exited, .on_got_focus,
.on_lost_focus, .on_key_down, .on_wheel, .control, .left_header_content, .content,
.right_header_content
}
Fields, in declaration order (designators must follow it):
| Field | Type | Default | |
|---|---|---|---|
title |
ui::Binding<std::string> |
Title: the window's name, after the icon. | |
subtitle |
ui::Binding<std::string> |
Subtitle: secondary text after the title, in the caption style. | |
icon |
ui::Binding<ui::IconSource> |
The icon left of the title: a Symbol, a glyph, a path or a picture; empty shows none. | |
back_button_visible |
ui::Binding<bool> |
{false} |
Show the back button at the far left. |
back_button_enabled |
ui::Binding<bool> |
{true} |
False shows the back button grayed out. |
pane_toggle_button_visible |
ui::Binding<bool> |
{false} |
Show the hamburger button (typically for a NavigationShell). |
caption_insets |
ui::Binding<std::optional<ui::CaptionInsets>> |
The caption space to keep clear of the window's caption buttons. Unset follows the window the bar is in (Window::caption_insets()); a value or a binding wins, for a bar that is not its own window's caption. | |
active |
ui::Binding<std::optional<bool>> |
false dims the bar. Unset follows the window the bar is in (Window::active()); a value or a binding wins. | |
content_alignment |
ui::Binding<ui::Alignment> |
{ui::Alignment::Center} |
Where the content sits between the title and the right header (ui::TitleBarControl::set_content_alignment()). |
on_back_requested |
ui::Callback<void()> |
The back button was clicked. | |
on_pane_toggle_requested |
ui::Callback<void()> |
The pane-toggle button was 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::TitleBar> |
Out: the handle that receives the built control. | |
left_header_content |
ui::Spec |
The left slot, next to the buttons and title. | |
content |
ui::Spec |
Content: the middle slot, placed per content_alignment. |
|
right_header_content |
ui::Spec |
The right slot; kept clear of the caption buttons via caption_insets. |
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¶
Consumes the spec and returns the built ui::TitleBarControl; the caller owns it.
ui::TitleBarControl¶
Derives from ui::Element.
A chrome row with an icon, title and subtitle, optional back and pane-toggle (hamburger) buttons, and three content slots (left header, content, right header).
The bar itself takes no focus. The back and pane-toggle buttons (subtle Buttons) and whatever sits in the slots are each their own Tab stop. Use it either as a row at the top of a page, or as the window's caption in a window with WindowStyle::extend_content_into_title_bar. In a window, the bar follows it: it keeps the right header clear of the space Window::caption_insets() reports for the caption buttons, and dims while Window::active() is false. hit_region() then tells the host which parts drag the window. set_caption_insets() and set_active() override what the window says, for a bar drawn somewhere other than its own window's caption. The bar has no minimize, maximize or close buttons, since the window keeps its own. It doesn't set the window's title from title(), so an app sets both.
Example:
ui::Property<bool> can_go_back{false};
ui::Control<ui::NavigationFrame> frame;
ui::Control<ui::NavigationShell> nav;
window.set_content(ui::VerticalStack{.content = {
ui::TitleBar{
.title = "Contoso Notes",
.subtitle = "Preview",
.icon = ui::IconGlyph{0xE70B},
.back_button_visible = can_go_back,
.pane_toggle_button_visible = true,
.content_alignment = ui::Alignment::Stretch,
.on_back_requested = [&] { frame->go_back(); },
.on_pane_toggle_requested = [&] { nav->set_pane_open(!nav->is_pane_open()); },
.content = ui::TextBox{.placeholder_text = "Search", .max_width = 360.0f},
},
// ... the page below the bar ...
}});
// Run the window with ui::WindowOptions{.style = {.extend_content_into_title_bar = true}} to make
// the bar the caption; without it the bar is an ordinary row under the standard title bar.
TitleBarControl¶
A bar showing title and, beside it in the secondary text color, subtitle. Both buttons start hidden, the slots empty.
title¶
The primary caption text. Empty draws none.
set_title¶
Replaces the title and updates the layout. Does not change the window's title.
subtitle¶
Dimmed secondary text after the title. Empty draws none.
set_subtitle¶
Replaces the subtitle and updates the layout.
icon¶
The icon left of the title: a glyph at 16 DIPs in the title text's color, or a path or picture fitted into the same 16x16 box. Empty (the default) shows none.
set_icon¶
Shows icon; an empty source removes it and the title moves left into the freed space. Updates the layout.
content_alignment¶
Where the content sits in the space between the title and the right header. Center, the default, keeps the content at its own width, centered. Stretch hands it the whole space, which a search box with a max width wants.
set_content_alignment¶
Changes the content slot's alignment and updates the layout.
is_back_button_visible¶
Whether the back button is shown; false by default. A hidden button takes no space, is not a Tab stop and is not hit-tested.
set_back_button_visible¶
Shows or hides the back button and updates the layout.
is_back_button_enabled¶
Whether the back button is enabled; true by default. A disabled back button stays visible but grayed, cannot be clicked, and drags the window when the bar is the caption.
set_back_button_enabled¶
Enables or disables the back button (ButtonControl::set_enabled()); a disabled bar keeps it disabled either way.
on_back_requested¶
Fired on a completed click (or Enter/Space) of the back button. It cannot fire while the button is hidden, since a hidden button is not hit-tested. Replaces any previous handler.
is_pane_toggle_button_visible¶
Whether the pane-toggle button is shown; false by default. Typically paired with a NavigationShell whose own pane button is hidden.
set_pane_toggle_button_visible¶
Shows or hides the pane-toggle button and updates the layout.
on_pane_toggle_requested¶
Fired when the pane-toggle button is clicked. The bar keeps no pane state of its own; the handler opens or closes the pane. Replaces any previous handler.
set_left_header_content¶
The left header: the slot after the buttons and before the icon. Each slot setter takes ownership of an arbitrary Element, replaces (and destroys) what was there, and hands back a non-owning observer, the same shape as ExpanderControl::set_content().
left_header_content¶
The left header, or null when the slot is empty. Owned by the bar.
set_content¶
The content: the middle slot, between the title and the right header, placed per content_alignment(), typically a search box.
content¶
The middle slot's element, or null. Owned by the bar.
set_right_header_content¶
The right header: the slot at the far end, kept clear of the caption buttons by caption_insets(), typically a PersonPicture or a settings button.
right_header_content¶
The right header, or null. Owned by the bar.
caption_insets¶
The caption space the bar keeps free, in DIPs: the value set with set_caption_insets(), otherwise what the window the bar is in reports (Window::caption_insets()), all zero outside a window. All zero is a TitleBar inside the content. Anything else also keeps a 48 DIP strip free at the right for dragging the window.
set_caption_insets¶
The caption space to leave alone, in place of the window's. std::nullopt (the default) follows the window again. A change updates the layout.
active¶
Whether the bar draws as an active window's caption: the value set with set_active(), otherwise Window::active() of the window the bar is in, true outside a window.
set_active¶
false dims the bar (to half opacity) the way a deactivated window's caption is dimmed, whatever the window says; std::nullopt (the default) follows the window again. Redraws only on a change.
hit_region¶
Caption over the bar's own background. The visible back button (while enabled), the pane toggle and both headers take the press; in the content, the enabled focusable controls do and everything else drags, subject to Element::title_bar_drag_region().
for_each_child¶
Lists the back and pane-toggle buttons while they show, then the left header, the content and the right header when present. The icon is decoration, not a child: no tab stop, no popups, no automation node.
automation_role¶
UI Automation's Header control type.
automation_name_fallback¶
The title, when no explicit accessible name is set.
measure_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¶
Position children within the rect arrange() settled on (also in bounds(), window DIPs). Default: nothing, for a leaf.
render_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().
attached¶
The element joined a window's tree: window() is now that window. Called for the root a window takes and for everything inside it, and for a subtree added to a tree already in a window. No-op by default.
detached¶
The element left a window's tree (moved out of it). No-op by default.
enabled_changed¶
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.
Tests¶
tests/test_title_bar.cpp