Skip to content

ContextMenu

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

A child with a context menu. Built by ui::ContextMenu.

A right-click anywhere on the child, or Shift+F10 or the Menu key while focus is inside it, opens the items as a menu: at the pointer, or for the keyboard over the focused element. A context menu nested deeper wins over this one, and an on_context_requested() handler on an element inside it runs first. With no items it opens nothing.

Example:

auto  host  = std::make_unique<ui::ContextMenuControl>();
auto* label = host->set_child(std::make_unique<ui::TextControl>("Order 1042"));
host->set_items({
    {.text = "Copy", .on_click = [label] { ui::clipboard().set_text(label->text()); }},
    {.text = "Save as...", .on_click = [] { save(); }},
});

ui::ContextMenu

A context menu around any piece of UI. Builds a ui::ContextMenuControl.

A right-click on .content, or Shift+F10 or the Menu key while focus is inside it, opens .items as a menu at the pointer, or over the focused element for the keyboard. The content does not need to be focusable: a right-click on a Text or an Image opens it too. For one menu per row of a list use the view's .item_context_menu instead.

Example:

ui::Property<std::string> note{"Buy milk"};
window.set_content(ui::ContextMenu{
    .items =
        {
            {.text = "Copy", .icon = ui::Symbol::Copy, .on_click = [&] { ui::clipboard().set_text(note.get()); }},
            ui::MenuItem::separator(),
            {.text = "Delete", .icon = ui::Symbol::Delete, .on_click = [&] { note = ""; }},
        },
    .content = ui::Text{.text = note},
});

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

ui::ContextMenu{
    .items, .style, .margin, .width, .height, .min_width, .min_height, .max_width, .max_height,
    .horizontal_alignment, .vertical_alignment, .visible, .tool_tip, .accessibility,
    .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
items ui::Binding<std::vector<ui::MenuItem>> The menu's entries: items, toggles, radio items, separators and submenus.
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::ContextMenu> Out: the handle that receives the built control.
content ui::Spec What the menu belongs to.

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

std::unique_ptr<Element> build()&&

Consumes the spec and returns the built ui::ContextMenuControl; the caller owns it.

ui::ContextMenuControl

Derives from ui::ContentHost.

A child with a context menu. Built by ui::ContextMenu.

A right-click anywhere on the child, or Shift+F10 or the Menu key while focus is inside it, opens the items as a menu: at the pointer, or for the keyboard over the focused element. A context menu nested deeper wins over this one, and an on_context_requested() handler on an element inside it runs first. With no items it opens nothing.

Example:

auto  host  = std::make_unique<ui::ContextMenuControl>();
auto* label = host->set_child(std::make_unique<ui::TextControl>("Order 1042"));
host->set_items({
    {.text = "Copy", .on_click = [label] { ui::clipboard().set_text(label->text()); }},
    {.text = "Save as...", .on_click = [] { save(); }},
});

ContextMenuControl

ContextMenuControl()

No child and no items yet.

~ContextMenuControl

~ContextMenuControl() override

items

const std::vector<MenuItem>& items() const

The menu's entries.

set_items

void set_items(std::vector<MenuItem> items)

Replaces the entries; an open menu closes first.

show_at

void show_at(Point point)

Opens the menu at point (window-client DIPs), as a right-click there does.

is_open

bool is_open() const

Whether the menu is open.

hide

void hide()

Closes the menu.

MenuFlyoutControl& menu() const

The flyout that shows the menu, for its placement and its opened and closed events.

for_each_child

void for_each_child(ChildVisitor visit) const override

The child, and the menu while it shows, so the window finds its popup.

automation_children

void automation_children(std::vector<Element*>& out) const override

The child only: the menu is not part of the page.

raise_context_requested

bool raise_context_requested(std::optional<Point> position) override

Opens the menu after any on_context_requested() handler of this element declined.

clear_dirty_override

void clear_dirty_override(DirtyFlags flags) override

Clears the menu too, which is listed as a child only while it shows.

Tests

  • tests/test_context_menu.cpp