diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/MenuCreator.cc | 421 | ||||
-rw-r--r-- | src/MenuCreator.hh | 46 |
2 files changed, 467 insertions, 0 deletions
diff --git a/src/MenuCreator.cc b/src/MenuCreator.cc new file mode 100644 index 0000000..cdec5c7 --- /dev/null +++ b/src/MenuCreator.cc | |||
@@ -0,0 +1,421 @@ | |||
1 | // MenuCreator.cc for Fluxbox | ||
2 | // Copyright (c) 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net) | ||
3 | // and Simon Bowden (rathnor at users.sourceforge.net) | ||
4 | // | ||
5 | // Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | // copy of this software and associated documentation files (the "Software"), | ||
7 | // to deal in the Software without restriction, including without limitation | ||
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | // and/or sell copies of the Software, and to permit persons to whom the | ||
10 | // Software is furnished to do so, subject to the following conditions: | ||
11 | // | ||
12 | // The above copyright notice and this permission notice shall be included in | ||
13 | // all copies or substantial portions of the Software. | ||
14 | // | ||
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | // DEALINGS IN THE SOFTWARE. | ||
22 | |||
23 | // $Id: MenuCreator.cc,v 1.1 2004/05/02 20:59:29 fluxgen Exp $ | ||
24 | |||
25 | #include "MenuCreator.hh" | ||
26 | |||
27 | #include "Screen.hh" | ||
28 | #include "CommandParser.hh" | ||
29 | #include "fluxbox.hh" | ||
30 | #include "CommandParser.hh" | ||
31 | #include "Window.hh" | ||
32 | #include "I18n.hh" | ||
33 | |||
34 | #include "FbMenu.hh" | ||
35 | #include "IconMenu.hh" | ||
36 | #include "WorkspaceMenu.hh" | ||
37 | #include "LayerMenu.hh" | ||
38 | #include "SendToMenu.hh" | ||
39 | |||
40 | #include "FbMenuParser.hh" | ||
41 | #include "StyleMenuItem.hh" | ||
42 | |||
43 | #include "FbTk/MultiButtonMenuItem.hh" | ||
44 | #include "FbTk/RefCount.hh" | ||
45 | #include "FbTk/MacroCommand.hh" | ||
46 | #include "FbTk/SimpleCommand.hh" | ||
47 | #include "FbTk/StringUtil.hh" | ||
48 | #include "FbTk/Directory.hh" | ||
49 | |||
50 | #include <iostream> | ||
51 | using namespace std; | ||
52 | |||
53 | template <> | ||
54 | void LayerMenuItem<FluxboxWindow>::click(int button, int time) { | ||
55 | m_object->moveToLayer(m_layernum); | ||
56 | } | ||
57 | |||
58 | static FbTk::Menu *createStyleMenu(FbTk::Menu &parent, const std::string &label, | ||
59 | const std::string &directory) { | ||
60 | // perform shell style ~ home directory expansion | ||
61 | string stylesdir(FbTk::StringUtil::expandFilename(directory)); | ||
62 | |||
63 | if (!FbTk::Directory::isDirectory(stylesdir)) | ||
64 | return 0; | ||
65 | |||
66 | FbTk::Directory dir(stylesdir.c_str()); | ||
67 | |||
68 | // create a vector of all the filenames in the directory | ||
69 | // add sort it | ||
70 | std::vector<std::string> filelist(dir.entries()); | ||
71 | for (size_t file_index = 0; file_index < dir.entries(); ++file_index) | ||
72 | filelist[file_index] = dir.readFilename(); | ||
73 | |||
74 | std::sort(filelist.begin(), filelist.end(), less<string>()); | ||
75 | |||
76 | // for each file in directory add filename and path to menu | ||
77 | for (size_t file_index = 0; file_index < dir.entries(); file_index++) { | ||
78 | std::string style(stylesdir + '/' + filelist[file_index]); | ||
79 | // add to menu only if the file is a regular file, and not a | ||
80 | // .file or a backup~ file | ||
81 | if ((FbTk::Directory::isRegularFile(style) && | ||
82 | (filelist[file_index][0] != '.') && | ||
83 | (style[style.length() - 1] != '~')) || | ||
84 | FbTk::Directory::isRegularFile(style + "/theme.cfg")) | ||
85 | parent.insert(new StyleMenuItem(filelist[file_index], style)); | ||
86 | } | ||
87 | // update menu graphics | ||
88 | parent.update(); | ||
89 | Fluxbox::instance()->saveMenuFilename(stylesdir.c_str()); | ||
90 | } | ||
91 | |||
92 | static void translateMenuItem(Parser &parse, | ||
93 | const std::string &str_key, | ||
94 | const std::string &str_label, | ||
95 | const std::string &str_cmd, | ||
96 | FbTk::Menu &menu); | ||
97 | |||
98 | |||
99 | static void parseMenu(Parser &pars, FbTk::Menu &menu) { | ||
100 | Parser::Item item, item2, item3; | ||
101 | while (!pars.eof()) { | ||
102 | pars>>item>>item2>>item3; | ||
103 | if (item.second == "end") | ||
104 | return; | ||
105 | translateMenuItem(pars, | ||
106 | item.second, | ||
107 | item2.second, | ||
108 | item3.second, | ||
109 | menu); | ||
110 | |||
111 | } | ||
112 | } | ||
113 | |||
114 | static void translateMenuItem(Parser &parse, | ||
115 | const std::string &str_key, | ||
116 | const std::string &str_label, | ||
117 | const std::string &str_cmd, | ||
118 | FbTk::Menu &menu) { | ||
119 | |||
120 | const int screen_number = menu.screenNumber(); | ||
121 | static I18n &i18n = *I18n::instance(); | ||
122 | using namespace FBNLS; | ||
123 | |||
124 | #define SCREENNLS(a, b) i18n.getMessage(ScreenSet, a, b) | ||
125 | |||
126 | if (str_key == "end") { | ||
127 | return; | ||
128 | } else if (str_key == "nop") { | ||
129 | menu.insert(str_label.c_str()); | ||
130 | } else if (str_key == "icons") { | ||
131 | FbTk::Menu *submenu = MenuCreator::createMenuType("iconmenu", menu.screenNumber()); | ||
132 | if (submenu == 0) | ||
133 | return; | ||
134 | if (str_label.empty()) | ||
135 | menu.insert(i18n.getMessage(IconSet, IconIcons, "Icons")); | ||
136 | else | ||
137 | menu.insert(str_label.c_str(), submenu); | ||
138 | } else if (str_key == "exit") { // exit | ||
139 | FbTk::RefCount<FbTk::Command> exit_cmd(CommandParser::instance().parseLine("exit")); | ||
140 | if (str_label.empty()) | ||
141 | menu.insert(SCREENNLS(ScreenExit, "Exit"), exit_cmd); | ||
142 | else | ||
143 | menu.insert(str_label.c_str(), exit_cmd); | ||
144 | } else if (str_key == "exec") { | ||
145 | // execute and hide menu | ||
146 | using namespace FbTk; | ||
147 | RefCount<Command> exec_cmd(CommandParser::instance().parseLine("exec " + str_cmd)); | ||
148 | RefCount<Command> hide_menu(new SimpleCommand<FbTk::Menu>(menu, | ||
149 | &Menu::hide)); | ||
150 | MacroCommand *exec_and_hide = new FbTk::MacroCommand(); | ||
151 | exec_and_hide->add(hide_menu); | ||
152 | exec_and_hide->add(exec_cmd); | ||
153 | RefCount<Command> exec_and_hide_cmd(exec_and_hide); | ||
154 | menu.insert(str_label.c_str(), exec_and_hide_cmd); | ||
155 | } | ||
156 | else if (str_key == "style") { // style | ||
157 | menu.insert(new StyleMenuItem(str_label, str_cmd)); | ||
158 | } else if (str_key == "config") { | ||
159 | BScreen *screen = Fluxbox::instance()->findScreen(screen_number); | ||
160 | if (screen != 0) | ||
161 | menu.insert(str_label.c_str(), &screen->configMenu()); | ||
162 | } // end of config | ||
163 | else if (str_key == "include") { // include | ||
164 | string newfile = FbTk::StringUtil::expandFilename(str_label); | ||
165 | // inject this file into the current menu | ||
166 | MenuCreator::createFromFile(newfile, menu); | ||
167 | Fluxbox::instance()->saveMenuFilename(newfile.c_str()); | ||
168 | } // end of include | ||
169 | else if (str_key == "submenu") { | ||
170 | |||
171 | FbTk::Menu *submenu = MenuCreator::createMenu("", screen_number); | ||
172 | if (submenu == 0) | ||
173 | return; | ||
174 | |||
175 | if (str_cmd.size()) | ||
176 | submenu->setLabel(str_cmd.c_str()); | ||
177 | else | ||
178 | submenu->setLabel(str_label.c_str()); | ||
179 | |||
180 | parseMenu(parse, *submenu); | ||
181 | submenu->update(); | ||
182 | menu.insert(str_label.c_str(), submenu); | ||
183 | // save to screen list so we can delete it later | ||
184 | BScreen *screen = Fluxbox::instance()->findScreen(screen_number); | ||
185 | if (screen != 0) | ||
186 | screen->saveMenu(*submenu); | ||
187 | |||
188 | } // end of submenu | ||
189 | else if (str_key == "restart") { | ||
190 | FbTk::RefCount<FbTk::Command> restart_fb(CommandParser::instance(). | ||
191 | parseLine("restart")); | ||
192 | if (str_label.empty()) | ||
193 | menu.insert(SCREENNLS(ScreenRestart, "Restart"), restart_fb); | ||
194 | else | ||
195 | menu.insert(str_label.c_str(), restart_fb); | ||
196 | } // end of restart | ||
197 | else if (str_key == "reconfig") { // reconf | ||
198 | // | ||
199 | //!! TODO: NLS | ||
200 | // | ||
201 | FbTk::RefCount<FbTk::Command> | ||
202 | reconfig_fb_cmd(CommandParser::instance(). | ||
203 | parseLine("reconfigure")); | ||
204 | menu.insert(str_label.c_str(), reconfig_fb_cmd); | ||
205 | |||
206 | } else if (str_key == "stylesdir" || str_key == "stylesmenu") { | ||
207 | createStyleMenu(menu, str_label, | ||
208 | str_key == "stylesmenu" ? str_cmd : str_label); | ||
209 | } // end of stylesdir | ||
210 | else if (str_key == "workspaces") { | ||
211 | BScreen *screen = Fluxbox::instance()->findScreen(screen_number); | ||
212 | if (screen != 0) { | ||
213 | screen->getWorkspacemenu().setInternalMenu(); | ||
214 | menu.insert(str_label.c_str(), &screen->getWorkspacemenu()); | ||
215 | } | ||
216 | } else if (str_key == "separator") { | ||
217 | menu.insert("---"); //!! TODO: this will be better in the future | ||
218 | } else { // ok, if we didn't find any special menu item we try with command parser | ||
219 | // we need to attach command with arguments so command parser can parse it | ||
220 | string line = str_key + " " + str_cmd; | ||
221 | FbTk::RefCount<FbTk::Command> command(CommandParser::instance().parseLine(line)); | ||
222 | if (*command != 0) | ||
223 | menu.insert(str_label.c_str(), command); | ||
224 | } | ||
225 | #undef SCREENNLS | ||
226 | |||
227 | } | ||
228 | |||
229 | |||
230 | static void parseWindowMenu(Parser &parse, FbTk::Menu &menu, FluxboxWindow &win) { | ||
231 | |||
232 | Parser::Item item, item2, item3; | ||
233 | while (!parse.eof()) { | ||
234 | parse>>item>>item2>>item3; | ||
235 | if (MenuCreator::createWindowMenuItem(item.second, item2.second, menu, win)) | ||
236 | continue; | ||
237 | |||
238 | if (item.second == "end") { | ||
239 | return; | ||
240 | } else if (item.second == "submenu") { | ||
241 | FbTk::Menu *submenu = MenuCreator::createMenu(item2.second, menu.screenNumber()); | ||
242 | parseWindowMenu(parse, *submenu, win); | ||
243 | submenu->update(); | ||
244 | menu.insert(item2.second.c_str(), submenu); | ||
245 | |||
246 | } else { // try non window menu specific stuff | ||
247 | translateMenuItem(parse, item.second, item2.second, item3.second, menu); | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | |||
252 | FbTk::Menu *MenuCreator::createMenu(const std::string &label, int screen_number) { | ||
253 | BScreen *screen = Fluxbox::instance()->findScreen(screen_number); | ||
254 | if (screen == 0) | ||
255 | return 0; | ||
256 | |||
257 | FbTk::Menu *menu = new FbMenu(screen->menuTheme(), | ||
258 | screen->imageControl(), | ||
259 | *screen->layerManager(). | ||
260 | getLayer(Fluxbox::instance()->getMenuLayer())); | ||
261 | if (!label.empty()) | ||
262 | menu->setLabel(label.c_str()); | ||
263 | |||
264 | return menu; | ||
265 | } | ||
266 | |||
267 | bool getStart(FbMenuParser &parser, std::string &label) { | ||
268 | Parser::Item item, item2, item3; | ||
269 | while (!parser.eof()) { | ||
270 | // get first begin line | ||
271 | parser>>item>>item2>>item3; | ||
272 | if (item.second == "begin") { | ||
273 | break; | ||
274 | } | ||
275 | } | ||
276 | if (parser.eof()) | ||
277 | return false; | ||
278 | label = item2.second; | ||
279 | return true; | ||
280 | } | ||
281 | |||
282 | FbTk::Menu *MenuCreator::createFromFile(const std::string &filename, int screen_number) { | ||
283 | FbMenuParser parser(filename); | ||
284 | if (!parser.isLoaded()) | ||
285 | return 0; | ||
286 | |||
287 | std::string label; | ||
288 | if (!getStart(parser, label)) | ||
289 | return 0; | ||
290 | |||
291 | FbTk::Menu *menu = createMenu(label, screen_number); | ||
292 | if (menu != 0) | ||
293 | parseMenu(parser, *menu); | ||
294 | |||
295 | return menu; | ||
296 | } | ||
297 | |||
298 | |||
299 | void MenuCreator::createFromFile(const std::string &filename, | ||
300 | FbTk::Menu &inject_into) { | ||
301 | |||
302 | std::string real_filename = FbTk::StringUtil::expandFilename(filename); | ||
303 | FbMenuParser parser(real_filename); | ||
304 | if (!parser.isLoaded()) | ||
305 | return; | ||
306 | |||
307 | std::string label; | ||
308 | if (!getStart(parser, label)) | ||
309 | return; | ||
310 | |||
311 | parseMenu(parser, inject_into); | ||
312 | } | ||
313 | |||
314 | |||
315 | void MenuCreator::createFromFile(const std::string &filename, | ||
316 | FbTk::Menu &inject_into, | ||
317 | FluxboxWindow &win) { | ||
318 | std::string real_filename = FbTk::StringUtil::expandFilename(filename); | ||
319 | FbMenuParser parser(real_filename); | ||
320 | if (!parser.isLoaded()) | ||
321 | return; | ||
322 | |||
323 | std::string label; | ||
324 | |||
325 | if (!getStart(parser, label)) | ||
326 | return; | ||
327 | |||
328 | parseWindowMenu(parser, inject_into, win); | ||
329 | } | ||
330 | |||
331 | |||
332 | FbTk::Menu *MenuCreator::createMenuType(const std::string &type, int screen_num) { | ||
333 | BScreen *screen = Fluxbox::instance()->findScreen(screen_num); | ||
334 | if (screen == 0) | ||
335 | return 0; | ||
336 | if (type == "iconmenu") { | ||
337 | return new IconMenu(*screen); | ||
338 | } else if (type == "workspacemenu") { | ||
339 | return new WorkspaceMenu(*screen); | ||
340 | } | ||
341 | |||
342 | } | ||
343 | |||
344 | bool MenuCreator::createWindowMenuItem(const std::string &type, | ||
345 | const std::string &label, | ||
346 | FbTk::Menu &menu, | ||
347 | FluxboxWindow &win) { | ||
348 | static I18n &i18n = *I18n::instance(); | ||
349 | typedef FbTk::RefCount<FbTk::Command> RefCmd; | ||
350 | typedef FbTk::SimpleCommand<FluxboxWindow> WindowCmd; | ||
351 | using namespace FBNLS; | ||
352 | |||
353 | #define WINDOWNLS(a, b) std::string real_label = label; if (label.empty()) real_label = i18n.getMessage(FBNLS::WindowmenuSet, a, b) | ||
354 | |||
355 | if (type == "shade") { | ||
356 | WINDOWNLS(WindowmenuShade, "Shade"); | ||
357 | RefCmd shade_cmd(new WindowCmd(win, &FluxboxWindow::shade)); | ||
358 | menu.insert(real_label.c_str(), shade_cmd); | ||
359 | } else if (type == "maximize") { | ||
360 | WINDOWNLS(WindowmenuMaximize, "Maximize"); | ||
361 | RefCmd maximize_cmd(new WindowCmd(win, &FluxboxWindow::maximizeFull)); | ||
362 | RefCmd maximize_vert_cmd(new WindowCmd(win, &FluxboxWindow::maximizeVertical)); | ||
363 | RefCmd maximize_horiz_cmd(new WindowCmd(win, &FluxboxWindow::maximizeHorizontal)); | ||
364 | FbTk::MultiButtonMenuItem *maximize_item = new FbTk::MultiButtonMenuItem(3, real_label.c_str()); | ||
365 | // create maximize item with: | ||
366 | // button1: Maximize normal | ||
367 | // button2: Maximize Vertical | ||
368 | // button3: Maximize Horizontal | ||
369 | maximize_item->setCommand(1, maximize_cmd); | ||
370 | maximize_item->setCommand(2, maximize_vert_cmd); | ||
371 | maximize_item->setCommand(3, maximize_horiz_cmd); | ||
372 | menu.insert(maximize_item); | ||
373 | } else if (type == "iconify") { | ||
374 | WINDOWNLS(WindowmenuIconify, "Iconify"); | ||
375 | RefCmd iconify_cmd(new WindowCmd(win, &FluxboxWindow::iconify)); | ||
376 | menu.insert(real_label.c_str(), iconify_cmd); | ||
377 | } else if (type == "close") { | ||
378 | WINDOWNLS(WindowmenuClose, "Close"); | ||
379 | RefCmd close_cmd(new WindowCmd(win, &FluxboxWindow::close)); | ||
380 | menu.insert(real_label.c_str(), close_cmd); | ||
381 | } else if (type == "lower") { | ||
382 | WINDOWNLS(WindowmenuLower, "Lower"); | ||
383 | RefCmd lower_cmd(new WindowCmd(win, &FluxboxWindow::lower)); | ||
384 | menu.insert(real_label.c_str(), lower_cmd); | ||
385 | } else if (type == "raise") { | ||
386 | WINDOWNLS(WindowmenuRaise, "Raise"); | ||
387 | RefCmd raise_cmd(new WindowCmd(win, &FluxboxWindow::raise)); | ||
388 | menu.insert(real_label.c_str(), raise_cmd); | ||
389 | } else if (type == "stick") { | ||
390 | WINDOWNLS(WindowmenuStick, "Stick"); | ||
391 | RefCmd stick_cmd(new WindowCmd(win, &FluxboxWindow::stick)); | ||
392 | menu.insert(real_label.c_str(), stick_cmd); | ||
393 | } else if (type == "extramenus") { | ||
394 | FluxboxWindow::ExtraMenus::iterator it = win.extraMenus().begin(); | ||
395 | FluxboxWindow::ExtraMenus::iterator it_end = win.extraMenus().end(); | ||
396 | for (; it != it_end; ++it) { | ||
397 | it->second->disableTitle(); | ||
398 | menu.insert(it->first, it->second); | ||
399 | } | ||
400 | |||
401 | } else if (type == "sendto") { | ||
402 | WINDOWNLS(WindowmenuSendTo, "Send To ..."); | ||
403 | menu.insert(real_label.c_str(), new SendToMenu(win)); | ||
404 | } else if (type == "layer") { | ||
405 | WINDOWNLS(WindowmenuLayer, "Layer ..."); | ||
406 | BScreen *screen = Fluxbox::instance()->findScreen(menu.screenNumber()); | ||
407 | if (screen == 0) | ||
408 | return false; | ||
409 | menu.insert(real_label.c_str(), | ||
410 | new LayerMenu<FluxboxWindow>(screen->menuTheme(), | ||
411 | screen->imageControl(), | ||
412 | *screen->layerManager().getLayer(Fluxbox::instance()->getMenuLayer()), | ||
413 | &win, | ||
414 | false)); | ||
415 | |||
416 | } else | ||
417 | return false; | ||
418 | #undef WINDOWNLS | ||
419 | |||
420 | return true; | ||
421 | } | ||
diff --git a/src/MenuCreator.hh b/src/MenuCreator.hh new file mode 100644 index 0000000..d9625f3 --- /dev/null +++ b/src/MenuCreator.hh | |||
@@ -0,0 +1,46 @@ | |||
1 | // MenuCreator.hh for Fluxbox | ||
2 | // Copyright (c) 2004 Henrik Kinnunen (fluxgen at users.sourceforge.net) | ||
3 | // and Simon Bowden (rathnor at users.sourceforge.net) | ||
4 | // | ||
5 | // Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | // copy of this software and associated documentation files (the "Software"), | ||
7 | // to deal in the Software without restriction, including without limitation | ||
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | // and/or sell copies of the Software, and to permit persons to whom the | ||
10 | // Software is furnished to do so, subject to the following conditions: | ||
11 | // | ||
12 | // The above copyright notice and this permission notice shall be included in | ||
13 | // all copies or substantial portions of the Software. | ||
14 | // | ||
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | // DEALINGS IN THE SOFTWARE. | ||
22 | |||
23 | #ifndef MENUCREATOR_HH | ||
24 | #define MENUCREATOR_HH | ||
25 | |||
26 | #include <string> | ||
27 | |||
28 | namespace FbTk { | ||
29 | class Menu; | ||
30 | } | ||
31 | |||
32 | class FluxboxWindow; | ||
33 | |||
34 | class MenuCreator { | ||
35 | public: | ||
36 | static FbTk::Menu *createMenu(const std::string &label, int screen_num); | ||
37 | static FbTk::Menu *createFromFile(const std::string &filename, int screen_num); | ||
38 | static FbTk::Menu *createMenuType(const std::string &label, int screen_num); | ||
39 | static void createFromFile(const std::string &filename, FbTk::Menu &inject_into); | ||
40 | static void createFromFile(const std::string &filename, FbTk::Menu &inject_into, | ||
41 | FluxboxWindow &win); | ||
42 | static bool createWindowMenuItem(const std::string &type, const std::string &label, | ||
43 | FbTk::Menu &inject_into, FluxboxWindow &win); | ||
44 | }; | ||
45 | |||
46 | #endif // MENUCREATOR_HH | ||