DropdownButton¶
Header: winui/ui/input/DropdownButton.hpp. Spec: winui/ui/input/DropdownButton.hpp.
A Button with a trailing chevron that says a click opens a menu or flyout.
It adds no behavior of its own to Button: the flyout is whichever FlyoutBase (a MenuFlyout, a Flyout) has it as its anchor, and a click opens that flyout as it would for any button. It adds a 12x12 animated chevron 8 DIPs right of the content, which dips on a press, and the ExpandCollapse automation pattern, expanded while the flyout is open. All of Button's API (text, content, style, on_click, command) applies.
Example:
// Declarative: the flyout owns its anchor.
window.set_content(ui::MenuFlyout{
.items = {{.text = "Send"}, {.text = "Reply"}, {.text = "Reply All", .on_click = [] { /* ... */ }}},
.placement = ui::PopupPlacement::Below,
.placement_alignment = ui::PopupPlacementAlignment::Leading,
.anchor = ui::DropdownButton{.text = "Email"},
});
// Imperative: the same tree built by hand.
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto* menu = stack->add(std::make_unique<ui::MenuFlyoutControl>());
menu->set_items({{.text = "Send"}, {.text = "Reply"}, {.text = "Reply All"}});
menu->set_placement(ui::PopupPlacement::Below);
menu->set_placement_alignment(ui::PopupPlacementAlignment::Leading);
ui::DropdownButtonControl* email = menu->set_anchor(std::make_unique<ui::DropdownButtonControl>("Email"));
ui::DropdownButton¶
A button with a chevron that says it opens a flyout. Builds a ui::DropdownButtonControl.
The button does not hold the flyout itself: it is the .anchor of a ui::MenuFlyout or ui::Flyout, and a click opens that.
Example:
window.set_content(ui::MenuFlyout{
.items = {{.text = "Send"}, {.text = "Reply"}, {.text = "Reply All"}},
.placement = ui::PopupPlacement::Below,
.placement_alignment = ui::PopupPlacementAlignment::Leading,
.anchor = ui::DropdownButton{.text = "Email"},
});
Every field, in the order a designated initializer names them:
ui::DropdownButton{
.text, .variant, .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 label before the chevron, ignored while .content is set. |
|
variant |
ui::Binding<ui::ButtonVariant> |
{ui::ButtonVariant::Neutral} |
The button look, as ui::Button's. |
padding |
ui::Binding<std::optional<ui::Thickness>> |
Padding around the label or content; nullopt keeps the theme's button padding. | |
command |
ui::CommandRef |
As ui::Button's: run after .on_click, and the button enabled only while it is. |
|
command_parameter |
std::string |
Handed to .command when it runs. |
|
on_click |
ui::Action |
A click; .command runs after 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::DropdownButton> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
Arbitrary content (an icon, say) before the chevron, 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::DropdownButtonControl; the caller owns it.
ui::DropdownButtonControl¶
Derives from ui::ButtonControl, ui::ExpandCollapseProvider.
A Button with a trailing chevron that says a click opens a menu or flyout.
It adds no behavior of its own to Button: the flyout is whichever FlyoutBase (a MenuFlyout, a Flyout) has it as its anchor, and a click opens that flyout as it would for any button. It adds a 12x12 animated chevron 8 DIPs right of the content, which dips on a press, and the ExpandCollapse automation pattern, expanded while the flyout is open. All of Button's API (text, content, style, on_click, command) applies.
Example:
// Declarative: the flyout owns its anchor.
window.set_content(ui::MenuFlyout{
.items = {{.text = "Send"}, {.text = "Reply"}, {.text = "Reply All", .on_click = [] { /* ... */ }}},
.placement = ui::PopupPlacement::Below,
.placement_alignment = ui::PopupPlacementAlignment::Leading,
.anchor = ui::DropdownButton{.text = "Email"},
});
// Imperative: the same tree built by hand.
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
auto* menu = stack->add(std::make_unique<ui::MenuFlyoutControl>());
menu->set_items({{.text = "Send"}, {.text = "Reply"}, {.text = "Reply All"}});
menu->set_placement(ui::PopupPlacement::Below);
menu->set_placement_alignment(ui::PopupPlacementAlignment::Leading);
ui::DropdownButtonControl* email = menu->set_anchor(std::make_unique<ui::DropdownButtonControl>("Email"));
DropdownButtonControl¶
A button with no text; give it content through Button's setters.
DropdownButtonControl¶
A button labeled text, with the chevron after it.
~DropdownButtonControl¶
is_flyout_open¶
Whether the flyout the button opens is showing. False when no flyout has this button as its anchor.
chevron¶
The chevron (an AnimatedIcon), for an app that wants another source. Owned by the button. Its state ("Normal", "PointerOver" or "Pressed") follows the button's.
parallel_measure_safe¶
The same answer as ButtonControl's, since the chevron measures only its glyph.
measure_override¶
Button's size, at least as tall as the chevron plus the padding.
arrange_override¶
Places the content as Button does and the chevron at the right edge of the padded area, centered vertically.
render_override¶
Draws the button, then the chevron in the theme's secondary text color at rest and its tertiary one under the pointer and while pressed. Disabled, on an Accent button and in themes without the Fluent palette, the chevron takes the label's color.
pointer_override¶
Button's pointer handling, then moves the chevron to the new visual state.
tick_override¶
Advances Button's animations and the chevron's, catching state changes without an event (set_enabled(), focus loss).
key_override¶
Button's keys (Enter or Space click on key up), then moves the chevron to the new state.
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_;
};
Tests¶
tests/test_split_button.cpp