Popup¶
Header: winui/ui/dialogs/Popup.hpp. Spec: winui/ui/dialogs/Popup.hpp.
Floats one child above the tree, at an offset from where the Popup sits.
The Popup itself takes no space in layout and draws no background, border or shadow. While it is open, the window measures the child at its natural size and places its top-left corner at the Popup's position plus the offsets. A child running past the window edge is clipped and stays where it is. Light dismiss is off by default, so the popup stays open until set_open(false) and clicks outside reach the page. With light dismiss on, a click outside or Escape closes it, and it holds keyboard focus while open and gives it back on close. In a spec tree it is built by ui::Popup, usually with is_open bound to a Property.
Example:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
ui::ButtonControl* show = stack->add(std::make_unique<ui::ButtonControl>("Show popup"));
ui::PopupControl* popup = stack->add(std::make_unique<ui::PopupControl>());
ui::ButtonControl* close = popup->set_child(std::make_unique<ui::ButtonControl>("Close"));
popup->set_horizontal_offset(200.0f);
popup->set_light_dismiss(true);
popup->set_child_transitions({ui::PopupTransition{}});
show->on_click([popup] { popup->set_open(true); });
close->on_click([popup] { popup->set_open(false); });
popup->on_closed([] { /* closed by the button, a click outside or Escape */ });
window.set_content(std::move(stack));
// Declaratively, with the open state in a Property:
ui::Property<bool> open{false};
std::unique_ptr<ui::Element> node = ui::build(ui::Popup{
.is_open = open, // two-way: a light dismiss writes false into `open`
.light_dismiss = true,
.content = ui::Text{.text = "Simple Popup"},
}); // add `node` to any panel
ui::Popup¶
One child floated above the tree at an offset from where the popup sits, with no chrome of its own. Builds a ui::PopupControl, which takes no room in layout.
Example:
ui::Property<bool> open{false};
window.set_content(ui::VerticalStack{ .content = {
ui::Button{ .text = "Show Popup", .on_click = [&] { open = true; } },
ui::Popup{ .is_open = open,
.horizontal_offset = 200,
.light_dismiss = true,
.content = ui::Text{ .text = "Simple Popup" } },
}});
Every field, in the order a designated initializer names them:
ui::Popup{
.is_open, .horizontal_offset, .vertical_offset, .light_dismiss, .child_transitions, .style,
.margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
.horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .accessibility,
.on_opened, .on_closed, .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 | |
|---|---|---|---|
is_open |
ui::TwoWayField<bool> |
{false} |
Whether the child is showing. |
horizontal_offset |
ui::Binding<float> |
{0.0f} |
The child's horizontal offset from the popup's own position, in DIPs. |
vertical_offset |
ui::Binding<float> |
{0.0f} |
The child's vertical offset from the popup's own position, in DIPs. |
light_dismiss |
ui::Binding<bool> |
{false} |
Whether an outside click or Escape closes it. |
child_transitions |
ui::Binding<ui::TransitionList> |
The transitions the child plays (ui::PopupControl::set_child_transitions()). A PopupTransition animates the child opening and closing. | |
on_opened |
ui::Action |
Raised once the child is showing. | |
on_closed |
ui::Action |
Raised however it closed, including a click outside or Escape. A two-way bound is_open has been written by then. |
|
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::Popup> |
Out: the handle that receives the built control. | |
content |
ui::Spec |
The floated content; it draws its own background, if any. |
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¶
Consumes the spec and returns the built ui::PopupControl; the caller owns it.
ui::PopupControl¶
Derives from ui::Element.
Floats one child above the tree, at an offset from where the Popup sits.
The Popup itself takes no space in layout and draws no background, border or shadow. While it is open, the window measures the child at its natural size and places its top-left corner at the Popup's position plus the offsets. A child running past the window edge is clipped and stays where it is. Light dismiss is off by default, so the popup stays open until set_open(false) and clicks outside reach the page. With light dismiss on, a click outside or Escape closes it, and it holds keyboard focus while open and gives it back on close. In a spec tree it is built by ui::Popup, usually with is_open bound to a Property.
Example:
auto stack = std::make_unique<ui::StackControl>(ui::Orientation::Vertical);
ui::ButtonControl* show = stack->add(std::make_unique<ui::ButtonControl>("Show popup"));
ui::PopupControl* popup = stack->add(std::make_unique<ui::PopupControl>());
ui::ButtonControl* close = popup->set_child(std::make_unique<ui::ButtonControl>("Close"));
popup->set_horizontal_offset(200.0f);
popup->set_light_dismiss(true);
popup->set_child_transitions({ui::PopupTransition{}});
show->on_click([popup] { popup->set_open(true); });
close->on_click([popup] { popup->set_open(false); });
popup->on_closed([] { /* closed by the button, a click outside or Escape */ });
window.set_content(std::move(stack));
// Declaratively, with the open state in a Property:
ui::Property<bool> open{false};
std::unique_ptr<ui::Element> node = ui::build(ui::Popup{
.is_open = open, // two-way: a light dismiss writes false into `open`
.light_dismiss = true,
.content = ui::Text{.text = "Simple Popup"},
}); // add `node` to any panel
PopupControl¶
A closed popup with no child, zero offsets and light dismiss off. Not hit-test visible: it draws nothing where it sits, so a press there goes to what is under it.
set_child¶
Takes ownership of the floated child and returns a non-owning observer to it. The child is not part of the main tree. The window lays it out and draws it while the popup is open.
child¶
The floated child (non-owning), or nullptr.
is_open¶
Whether the popup is open. Opening raises on_opened. Closing raises on_closed, whether by set_open(), a click outside or Escape. Setting the value it already has raises nothing.
set_open¶
Opens or closes the popup. With child transitions, the child stays on screen after closing until its close transition has played (see closing()).
horizontal_offset¶
The child's offset from the Popup's own position, in DIPs. 0 by default.
set_horizontal_offset¶
Sets the horizontal offset. The child moves on the next layout.
vertical_offset¶
The child's vertical offset from the Popup's position, in DIPs; 0 by default.
set_vertical_offset¶
Sets the vertical offset. The child moves on the next layout.
light_dismiss¶
Whether light dismiss is on; false by default. On, a click outside the child or Escape closes the popup, and it holds keyboard focus while open.
set_light_dismiss¶
Turns light dismiss on or off. Takes effect at once, on an open popup too.
on_opened¶
Fired after the popup opens. Replaces any previous handler.
on_closed¶
Fired after the popup closes, whether by set_open(false), a click outside or Escape. Reset state bound to is_open() here. Replaces any previous handler.
child_transitions¶
The transitions the child plays; empty by default. A PopupTransition slides the child in from its offset and fades it in on open, and fades it out on close. A ContentTransition also plays both ways, and an EntranceTransition on open only.
set_child_transitions¶
Sets the child's transitions. Applies from the next open or close.
closing¶
Whether the child is still on screen after closing, playing its close transition.
automation_role¶
Screen readers see the Popup as an empty group where it sits. They see the child only while the popup is open.
measure_override¶
Always zero: the Popup takes no space in layout.
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().
clear_dirty_override¶
This element's own part of clear_dirty(): clear any part it owns but leaves out of for_each_child() (a parked page, a hidden button), through that part's clear_dirty(). Default: nothing.
tick_override¶
This element's own part of tick(): a clock of its own (ToolTip's hover delay, an animation's phase, a caret blink). Runs after the visual layer has advanced and before the children are ticked, which tick() does by itself. Tick only parts that for_each_child() does not list here. Default: nothing.
Tests¶
tests/test_popup.cpp