SplitButton¶
Header: winui/ui/input/SplitButton.hpp. Spec: winui/ui/input/SplitButton.hpp.
A button with a second, chevron part that opens a flyout.
The primary part raises on_click() and runs the command; the 35 DIP secondary part at the right (or Alt+Down / F4) opens the flyout below the button. As for every flyout anchor, the flyout owns the split button: make it the flyout's anchor and the flyout wires itself in through set_flyout(). The declarative form is ui::SplitButton, usually as a ui::Flyout's .anchor.
Example:
ui::Property<ui::Color> current{ui::colors::Black};
ui::Property<ui::Color> ink{ui::colors::Black};
window.set_content(ui::Flyout{
.anchor = ui::SplitButton{ .text = "Choose color",
.on_click = [&] { ink = current.get(); } },
.content = ui::HorizontalStack{ .spacing = 4, .content = {
ui::Button{ .text = "Red", .on_click = [&] { current = ui::Color::from_argb(0xFFFF0000); } },
ui::Button{ .text = "Blue", .on_click = [&] { current = ui::Color::from_argb(0xFF0000FF); } },
}},
});
// Imperatively:
auto flyout = std::make_unique<ui::FlyoutControl>();
auto* split = flyout->set_anchor(std::make_unique<ui::SplitButtonControl>("Choose color"));
flyout->set_content(std::make_unique<ui::TextControl>("Pick a color"));
split->on_click([&] { ink = current.get(); });
ui::SplitButton¶
A button with a second part that opens a flyout. Builds a ui::SplitButtonControl.
The primary part raises .on_click and runs .command; the secondary part (the chevron) opens the flyout the split button is the .anchor of, below it and left-aligned.
Example:
ui::Property<std::string> current{"Red"};
ui::Property<std::string> ink{"Black"};
window.set_content(ui::Flyout{
.anchor = ui::SplitButton{.text = "Choose color",
.on_click = [&] { ink = current.get(); }},
.content = ui::VerticalStack{.content = {
ui::Button{.text = "Red", .on_click = [&] { current = "Red"; }},
ui::Button{.text = "Blue", .on_click = [&] { current = "Blue"; }},
}},
});
Every field, in the order a designated initializer names them:
ui::SplitButton{
.text, .padding, .style, .margin, .width, .height, .min_width, .min_height, .max_width,
.max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .enabled,
.accessibility, .command, .command_parameter, .on_click, .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 | |
|---|---|---|---|
text |
ui::Binding<std::string> |
The primary part's label, ignored while .content is set. |
|
padding |
ui::Binding<std::optional<ui::Thickness>> |
Padding around the primary part's content; nullopt keeps the theme's button padding. | |
command |
ui::CommandRef |
Run after .on_click; while it is disabled the primary part is too (the secondary part still opens the flyout). |
|
command_parameter |
std::string |
Handed to .command when it runs. |
|
on_click |
ui::Action |
A click on the primary part. The chevron raises nothing, it opens the flyout. | |
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::SplitButton> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The primary part's content, instead of .text. |
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::SplitButtonControl; the caller owns it.
ui::ToggleSplitButton¶
A split button whose primary part also toggles checked. Builds a ui::ToggleSplitButtonControl.
The chevron opens the flyout it is the .anchor of, as ui::SplitButton's does. .checked is two-way with a Property<bool> or a Property<std::optional<bool>>: the button shows the property and a click on the primary part writes it back, before .on_checked_changed runs.
Example:
ui::Property<bool> bullets{false};
window.set_content(ui::MenuFlyout{
.items = {{.text = "Bullets"}, {.text = "Numbers"}},
.anchor = ui::ToggleSplitButton{
.text = "List",
.checked = bullets,
},
});
Every field, in the order a designated initializer names them:
ui::ToggleSplitButton{
.text, .checked, .padding, .style, .margin, .width, .height, .min_width, .min_height,
.max_width, .max_height, .horizontal_alignment, .vertical_alignment, .visible, .tool_tip,
.enabled, .accessibility, .command, .command_parameter, .on_click, .on_checked_changed,
.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 | |
|---|---|---|---|
text |
ui::Binding<std::string> |
The primary part's label, ignored while .content is set. |
|
checked |
ui::CheckedField |
{false} |
Whether the button is checked; std::nullopt shows unchecked, since the button has no third state. Seeding it raises no .on_checked_changed. Two-way with a Property<bool> or a Property<std::optional<bool>>. See ui::CheckedField. |
padding |
ui::Binding<std::optional<ui::Thickness>> |
Padding around the primary part's content; nullopt keeps the theme's button padding. | |
command |
ui::CommandRef |
As ui::SplitButton's: run after .on_click; the primary part disabled while it is. |
|
command_parameter |
std::string |
Handed to .command when it runs. |
|
on_click |
ui::Action |
A click on the primary part. | |
on_checked_changed |
ui::Callback<void(bool)> |
The checked state changed: a click on the primary part, UI Automation's Toggle, or a bound value. | |
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::ToggleSplitButton> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The primary part's content, instead of .text. |
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::ToggleSplitButtonControl; the caller owns it.
ui::SplitButtonControl¶
Derives from ui::Element, ui::InvokeProvider, ui::ExpandCollapseProvider.
A button with a second, chevron part that opens a flyout.
The primary part raises on_click() and runs the command; the 35 DIP secondary part at the right (or Alt+Down / F4) opens the flyout below the button. As for every flyout anchor, the flyout owns the split button: make it the flyout's anchor and the flyout wires itself in through set_flyout(). The declarative form is ui::SplitButton, usually as a ui::Flyout's .anchor.
Example:
ui::Property<ui::Color> current{ui::colors::Black};
ui::Property<ui::Color> ink{ui::colors::Black};
window.set_content(ui::Flyout{
.anchor = ui::SplitButton{ .text = "Choose color",
.on_click = [&] { ink = current.get(); } },
.content = ui::HorizontalStack{ .spacing = 4, .content = {
ui::Button{ .text = "Red", .on_click = [&] { current = ui::Color::from_argb(0xFFFF0000); } },
ui::Button{ .text = "Blue", .on_click = [&] { current = ui::Color::from_argb(0xFF0000FF); } },
}},
});
// Imperatively:
auto flyout = std::make_unique<ui::FlyoutControl>();
auto* split = flyout->set_anchor(std::make_unique<ui::SplitButtonControl>("Choose color"));
flyout->set_content(std::make_unique<ui::TextControl>("Pick a color"));
split->on_click([&] { ink = current.get(); });
SplitButtonControl¶
An empty split button: no text or content, no flyout.
SplitButtonControl¶
A split button whose primary part shows text.
~SplitButtonControl¶
text¶
The primary part's text, used while there is no content().
set_text¶
Changes the text, which is also the accessible name when none is set. The button is measured again and redrawn.
set_content¶
The primary part's content, in place of text(). Returns the observer.
content¶
The primary part's content (owned by the button), or null.
set_padding¶
Padding around the primary part's content; nullopt keeps the theme's button padding.
primary_enabled¶
Whether the primary part takes a click: enabled, and the command (if any) is too.
on_click¶
The primary part was clicked (or Space/Enter released on the control).
set_command¶
A command and its parameter, run after on_click. The primary part is disabled while the command is, following it as it changes, and without a tooltip of its own the button shows the command's description. A destroyed command leaves the button as if it had none.
command¶
The command set_command() installed, or null.
tool_tip¶
The tooltip set on the button, else its command's description.
set_flyout¶
The flyout the chevron opens. Set for you when the split button becomes a flyout's anchor.
flyout¶
The flyout the chevron part opens (non-owning; it owns this button), or null.
is_flyout_open¶
Whether the flyout is showing.
open_flyout¶
Shows the flyout below the button, left edges lined up.
close_flyout¶
Hides the flyout if it is open.
checked¶
A toggle split button's checked state; always false for a plain SplitButton.
primary_rect¶
The primary part, without the divider, from the last arrange.
secondary_rect¶
The chevron part, 35 DIPs wide at the right, from the last arrange.
chevron¶
The chevron (an AnimatedIcon).
focused¶
Whether the control has keyboard focus.
focusable¶
One tab stop for both parts, while enabled.
automation_role¶
A SplitButton.
automation_name_fallback¶
The text, when no accessible name is set.
visual_state¶
The visual state the button is drawn in, derived from hover, press, key and flyout state.
measure_override¶
The primary part (content or text plus padding, at least 35 DIPs wide), the 1 DIP divider and the 35 DIP chevron part side by side.
arrange_override¶
Splits final_rect into the two parts and arranges the content in the primary one.
render_override¶
Draws each part in its own state's colors, the divider, the content and the chevron.
pointer_override¶
Tracks hover and press per part; a click on the primary part clicks, on the chevron opens.
tick_override¶
Ticks the content and the chevron's animation.
on_click_primary¶
Raises on_click, then runs the command. ToggleSplitButtonControl toggles first.
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.
key_override¶
Space/Enter click the primary part on key up; Alt+Down and F4 open the flyout.
focus_changed¶
Called by the Window as focus arrives or leaves; redraws.
focus_ring_corner_radius¶
The ring follows the button's corner radius.
automation_providers¶
Lists what a client can do with this node: set out's field for each pattern this control implements now to this, through the provider interface it inherits privately (ui/Automation.hpp). A pattern that only applies in some states is an if. out arrives empty, and nothing is listed by default.
Example:
class Chip final : public ui::Element, private ui::InvokeProvider
{
protected:
void automation_providers(ui::AutomationProviders& out) override
{
out.invoke = this;
}
private:
bool invoke() override
{
on_click_();
return true;
}
ui::Callback<void()> on_click_;
};
class ToggleSplitButtonControl¶
Derives from ui::SplitButtonControl, ui::ToggleProvider.
A SplitButton whose primary part also toggles checked(). Checked, both parts draw in the accent colors. The declarative form is ui::ToggleSplitButton.
Example:
ui::Property<bool> bullets{false};
ui::Property<int> bullet_style{0};
window.set_content(ui::Flyout{
.anchor = ui::ToggleSplitButton{ .text = "Bullets",
.checked = bullets }, // two-way
.content = ui::VerticalStack{ .content = {
ui::Button{ .text = "Round", .on_click = [&] { bullet_style = 0; } },
ui::Button{ .text = "Square", .on_click = [&] { bullet_style = 1; } },
}},
});
ToggleSplitButtonControl¶
Unchecked, with no text.
ToggleSplitButtonControl¶
Unchecked, the primary part showing text.
checked¶
Whether the button is checked.
set_checked¶
Sets the checked state; fires on_checked_changed() only when the value changes.
on_checked_changed¶
Fires with the new state after a click or set_checked() changes it.
on_click_primary¶
Toggles, then raises the base's on_click and runs the command.
Enumerations¶
SplitButtonState¶
The visual state a SplitButton draws in. A checked ToggleSplitButton draws the same states in the accent colors.
| Value | |
|---|---|
Normal |
At rest. |
Disabled |
is_enabled() is false. |
FlyoutOpen |
The flyout is open: both parts drawn pressed. |
TouchPressed |
Space or Enter held: both parts pressed. |
PrimaryPointerOver |
The pointer is over the primary part. |
PrimaryPressed |
The primary part is pressed. |
SecondaryPointerOver |
The pointer is over the chevron part. |
SecondaryPressed |
The chevron part is pressed. |
Tests¶
tests/test_split_button.cpp