/* ** Copyright 2018-2021 Double Precision, Inc. ** See COPYING for distribution information. */ #include "config.h" #include "close_flag.H" #include <x/exception.H> #include <x/destroy_callback.H> #include <x/appid.H> #include <x/w/main_window.H> #include <x/w/gridlayoutmanager.H> #include <x/w/gridfactory.H> #include <x/w/label.H> #include <x/w/text_param_literals.H> #include <x/w/font_literals.H> #include <x/w/container.H> #include <x/w/listlayoutmanager.H> #include <x/w/busy.H> #include <x/threads/run.H> #include <string> #include <iostream> std::string x::appid() noexcept { return "popupmenu2.examples.w.libcxx.com"; } // Temporary holding object for the most recently created context menu popup. class most_recent_popupObj : virtual public x::obj { public: x::w::containerptr created_popup; }; typedef x::ref<most_recent_popupObj> most_recent_popup; x::w::container create_popup_menu(const x::w::element &my_element); // This is the creator lambda, that gets passed to create_mainwindow() below, // factored out for readability. void create_mainwindow(const x::w::main_window &main_window) { auto layout=main_window->gridlayout(); x::w::gridfactory factory=layout->append_row(); auto label=factory->padding(3).create_label({ "liberation sans; point_size=20"_font, "Right click on me, please" }); // Install a context popup callback, but without creating a popup // menu. The callback captures a holding object for the popup menu, // and creates a new popup menu every time it gets called. // // The created menu is show()n and placed in the popup_info holding // object. Unless it gets stashed away in this manner, the popup // menu object itself will go out of scope and get destroyed, so // it's show()ing would be all for nothing. label->install_contextpopup_callback ([popup_info=most_recent_popup::create()] (ONLY IN_THREAD, const x::w::element &my_element, const x::w::callback_trigger_t &trigger, const x::w::busy &mcguffin) { // We'll return immediately from the callback, but // not until we grab a "wait busy" mcguffin, and // and punt it to a new execution thread that // waits a few seconds before creating the new // popup menu and showing it. x::run_lambda ([popup_info, my_element, mcguffin=mcguffin.get_wait_busy_mcguffin()] { sleep(2); popup_info->created_popup= create_popup_menu(my_element); }); }, // Keyboard shortcut {"Ctrl-F3"}); } // New popup menu gets created, and show()n with every context popup click. x::w::container create_popup_menu(const x::w::element &my_element) { x::w::container popup_menu2=my_element->create_popup_menu ([] (const x::w::listlayoutmanager &lm) { lm->append_items({ [](ONLY IN_THREAD, const auto &info) { std::cout << "New" << std::endl; }, "New", [](ONLY IN_THREAD, const auto &info) { std::cout << "Open" << std::endl; }, "Open", [](ONLY IN_THREAD, const auto &info) { std::cout << "Close" << std::endl; }, "Close", }); }); // It's always our job to show() our popup. Nobody else will do it // for us. popup_menu2->show(); return popup_menu2; } void popupmenu2() { x::destroy_callback::base::guard guard; auto close_flag=close_flag_ref::create(); auto main_window=x::w::main_window::create ([&] (const auto &main_window) { create_mainwindow(main_window); }); main_window->on_disconnect([] { _exit(1); }); guard(main_window->connection_mcguffin()); main_window->set_window_title("Click the label for a popup"); main_window->on_delete ([close_flag] (ONLY IN_THREAD, const x::w::busy &ignore) { close_flag->close(); }); main_window->show_all(); close_flag->wait(); } int main(int argc, char **argv) { try { popupmenu2(); } catch (const x::exception &e) { e->caught(); exit(1); } return 0; }
popupmenu2.C
gives an example of creating
a new context popup menu every time. In this manner, the contents of
the context popup menu may reflect the application's current state.
popupmenu2.C
simulates the recommended approach
when creating a context popup menu is a time-consuming task.
popupmenu2.C
's context popup callback
uses its
x::w::busy
parameter to stop input processing,
and start a separate execution thread before the
callback returns.
This allows the internal connection
thread to update the display server, but ignore all
pointer and key clicks.
The new execution thread waits a few seconds, to simulate a time-consuming popup context menu creation, then finally shows the created context popup menu.
install_contextpopup_callback
()'s
optional second parameter specifies a keyboard
x::w::shortcut
for the callback.
The keyboard shortcut invokes the callback, just like the right
pointer button click. The callback's
x::w::callback_trigger_t
parameter indicates why it's invoked.
The keyboard shortcut is active only when its widget is
visible. show
()ing the context popup menu
makes it appear next to the pointer, whether it's on top of the
widget, or not.
Since keyboard shortcuts are global to their windows, all context popup callbacks should have unique keyboard shortcuts.
Prev | Up | Next |
Chapter 25. Context popup menus | Table Of Contents | Chapter 26. Copy/Cut/Paste menu items |