-
Notifications
You must be signed in to change notification settings - Fork 336
Using Menu
There are examples illustrate the basic usage for creating and displaying a menu.
#include <nana/gui.hpp>
#include <nana/gui/widgets/menu.hpp>
int main()
{
using namespace nana;
//Define a handler for menu item.
auto handler = [](menu::item_proxy& ip) {
msgbox msg("Menu Clicked");
msg<<ip.text();
msg.show();
};
//Define a menu with 2 items
menu m;
m.append("Menu Item 0", handler);
m.append("Menu Item 1", handler);
//Define a form
form fm;
fm.events().mouse_up([&](const arg_mouse& arg){
//When release the mouse right button, display the pop-up menu
//at the position of cursor.
if (mouse::right_button != arg.button)
return;
m.popup_await(fm, arg.pos.x, arg.pos.y);
//or
//m.popup(fm, arg.pos.x, arg.pos.y);
});
fm.show();
exec();
return 0;
}
Another example: using menu as an local variable.
int main()
{
using namespace nana;
form fm;
fm.events().mouse_up([](const arg_mouse& arg){
if (mouse::right_button != arg.button)
return;
auto handler = [](menu::item_proxy& ip) {
msgbox msg("Menu Clicked");
msg << ip.text();
msg.show();
};
menu m;
m.append("Menu Item 0", handler);
m.append("Menu Item 1", handler);
m.popup_await(arg.window_handle, arg.pos.x, arg.pos.y); //Good
//or
//m.popup(arg.window_handle, arg.pos.x, arg.pos.y); //Bad
});
fm.show();
exec();
return 0;
}
In the second example, the menu
is defined as a local variable. If displays the menu by calling menu::popup
, the menu window will be closed immediately, even never see a menu window displayed. Because menu::popup
doesn't block until the menu window gets closed, the menu will be destructed when exits the mouse-up event handler.
There are to ways to create sub menu for an item.
//1, Set an existing menu as a sub menu.
menu popup_menu;
popup_menu.append("Hello");
menu existing_menu;
existing_menu.append("World");
//Sets the existing_menu as a sub menu for popup_menu.
popup_menu.link(0, existing_menu);
//2, Create a sub menu.
menu popup_menu;
popup_menu.append("Hello");
auto sub = popup_menu.create_sub_menu(0);
sub->append("World");
To retrive the sub menu of a certain item, use menu::link
.
auto sub = menu.link(1);
//It returns a pointer to the sub menu of the 2nd item.
The menu sets a shortkey with a character behind the first of &-character in text for an item.
menu.append("File(&F)");
menu.append("&File");
The gap of menu is used to specify the pixels of gap between the menu and its sub menus.
int main()
{
using namespace nana;
menu main_menu;
main_menu.append("Item 0");
main_menu.append("Item 1");
main_menu.gaps({ 3, -2 }); //Sets gaps
menu * submenu = main_menu.create_sub_menu(0);
submenu->append("Item 0");
submenu->append("Item 1");
form fm;
fm.events().mouse_up(menu_popuper(main_menu));
fm.show();
exec();
}
When a renderer is set for a menu, it also affects all sub menus. An example to customize a renderer and make the menu semi-transparent in Windows.
The customized renderer will employ an existing menu renderer,
#include <windows.h> //introduces Win32 APIs
class renderer : public nana::menu::renderer_interface
{
using color_rgb = ::nana::color_rgb;
public:
renderer(const nana::pat::cloneable<renderer_interface>& rd)
: reuse_(rd) //Reuses the current renderer
{}
private:
void background(graph_reference graph, nana::window wd) override
{
graph.rectangle(true, nana::colors::white);
graph.rectangle(false, static_cast<color_rgb>(0x5DC1AC));
//Makes the menu transparent, it only works under Windows with #include <windows.h>
HWND native = reinterpret_cast<HWND>(nana::API::root(wd));
DWORD ex_style = ::GetWindowLong(native, GWL_EXSTYLE);
::SetWindowLong(native, GWL_EXSTYLE, ex_style | 0x00080000 /*WS_EX_LAYERED*/);
using slwa_t = BOOL(WINAPI*)(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
slwa_t slwa = reinterpret_cast<slwa_t>(::GetProcAddress(::GetModuleHandleA("User32.DLL"), "SetLayeredWindowAttributes"));
if (slwa)
slwa(native, 0, 220, 0x00000002/*LWA_ALPHA*/);
}
void item(graph_reference graph, const nana::rectangle& r, const attr & atr) override
{
if (state::active == atr.item_state)
graph.rectangle(r, true, static_cast<color_rgb>(0x9ADCCA));
}
void item_image(graph_reference graph, const nana::point& pos, unsigned image_px, const nana::paint::image& img) override
{
reuse_->item_image(graph, pos, image_px, img);
}
void item_text(graph_reference graph, const nana::point& pos, const std::string& text, unsigned pixels, const attr& atr) override
{
reuse_->item_text(graph, pos, text, pixels, atr);
}
void sub_arrow(graph_reference graph, const nana::point& pos, unsigned pixels, const attr & atr) override
{
reuse_->sub_arrow(graph, pos, pixels, atr);
}
private:
nana::pat::cloneable<renderer_interface> reuse_;
};
int main()
{
using namespace nana;
menu main_menu;
main_menu.append("Item 0");
main_menu.append("Item 1");
main_menu.gaps({ 3, -2 }); //Sets gaps
main_menu.renderer(renderer(main_menu.renderer())); //Reuses the current renderer
main_menu.item_pixels(20);
form fm;
fm.events().mouse_up(menu_popuper(main_menu));
fm.show();
exec();
}