Menu
Using MenuBar
In this example we will see how easy is to make complex and dynamic menus in U++. Our application looks like this

and code
#include <CtrlLib/CtrlLib.h>
struct App : public TopWindow {
bool numbers_enabled;
void Exit()
{
Close();
}
void EnableNumbers()
{
numbers_enabled = !numbers_enabled;
}
void ShowNumber(int n)
{
PromptOK(AsString(n));
}
void SubMenu(Bar& bar)
{
for(int i = 0; i < 10; i++)
bar.Add(AsString(i), THISBACK1(ShowNumber, i));
}
void Menu(Bar& bar)
{
bar.Add("Enable numbers", THISBACK(EnableNumbers))
.Check(numbers_enabled);
bar.Add(numbers_enabled, "Numbers", THISBACK(SubMenu));
bar.Add("Exit", THISBACK(Exit))
.Key(K_CTRL_E);
}
void MainBar(Bar& bar)
{
bar.Add("Menu", THISBACK(Menu));
}
MenuBar menu;
typedef App CLASSNAME;
App()
{
numbers_enabled = false;
AddFrame(menu);
menu.Set(THISBACK(MainBar));
}
};
GUI_APP_MAIN
{
App().Run();
}
Nothing fancy in main function, we just construct new object of ours App class and call Run function.
In constructor we first set number_enable to false - on start "Numbers" sub menu will be disabled. We then add menu to our App with AddFrame function.
Next line is more tricky
menu.Set(THISBACK(MainBar));
First we construct Callback object with a help of THISBACK macro. MenuBar::Set will first check if the menu object is locked and if it isn't it will clear menu, call our MainBar function with a help of proceeded CallBack object, and then refresh menu.
So in Set function ours MainBar function is been called, and MainBar just adds one menu item in the menu bar "Menu" and the corresponding Callback object. When "Menu" is clicked, first U++ will make pop up menu window and then it will call App::Menu function
void Menu(Bar& bar)
{
bar.Add("Enable numbers", THISBACK(EnableNumbers))
.Check(numbers_enabled);
bar.Add(numbers_enabled, "Numbers", THISBACK(SubMenu));
bar.Add("Exit", THISBACK(Exit))
.Key(K_CTRL_E);
}
This function will dynamically add 3 items in that pop up menu.
First adds "Enable numbers" item and binds this item to EnableNumbers function. Add function returns added menu item object, and then with a help of Check function we say that this menu item is check item and we set it state with numbers_enabled bool parameter.
Second is similar, only we are using overloaded Add with first bool parameter which will set state of that menu item to enabled or disabled.
Similar we add last menu item, but now we call Key(K_CTRL_E) function on returned menu item which set keyboard Ctrl-E shortcut.
Because lots of U++ class function returns reference on current object it is possible to write object.some_function().some_function()...
This approach is used heavily in U++ and it offers very readable, compact and pretty;) code.
Now when we click on "Menu->Numbers" a new pop up menu window will be created and SubMenu function is responsible for filling it
void SubMenu(Bar& bar)
{
for(int i = 0; i < 10; i++)
bar.Add(AsString(i), THISBACK1(ShowNumber, i));
}
This function will add 10 menu items in the new pop up window with names from 0 to 9. AsString are helping here, it is capable to take many things, not just int, and then return textual representation of that thing. We want something interesting and different to happend when we click on different menu items of "Numbers", and to the rescue is coming THISBACK1 macro. With the help of this macro we can callback displayed function and pass it a parameter. So THISBACK1(ShowNumber, 3) will create Callback object, and that object will call ShowNumber(3) when "Menu->Numbers->3" is clicked.
In this example we see how easy is to make dynamic menus in U++, menus that changes and adapts through application lifetime.
menu.cpp
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
struct App : public TopWindow {
bool numbers_enabled;
void Exit()
{
Close();
}
void EnableNumbers()
{
numbers_enabled = !numbers_enabled;
}
void ShowNumber(int n)
{
PromptOK(AsString(n));
}
void SubMenu(Bar& bar)
{
for(int i = 0; i < 10; i++)
bar.Add(AsString(i), THISBACK1(ShowNumber, i));
}
void Menu(Bar& bar)
{
bar.Add("Enable numbers", THISBACK(EnableNumbers))
.Check(numbers_enabled);
bar.Add(numbers_enabled, "Numbers", THISBACK(SubMenu));
bar.Add("Exit", THISBACK(Exit))
.Key(K_CTRL_E);
}
void MainBar(Bar& bar)
{
bar.Add("Menu", THISBACK(Menu));
}
MenuBar menu;
typedef App CLASSNAME;
App()
{
numbers_enabled = false;
AddFrame(menu);
menu.Set(THISBACK(MainBar));
}
};
GUI_APP_MAIN
{
App().Run();
}
|