From daa973f1bc7efdcc96adf58fdba7248969af3ad1 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sat, 19 Nov 2011 22:04:35 +0000 Subject: [PATCH] And make FGMenuBar abstract too, sinking the current implementation into FGPUIMenubar --- src/GUI/CMakeLists.txt | 2 + src/GUI/FGPUIMenuBar.cxx | 376 +++++++++++++++++++++++++++++++++++++++ src/GUI/FGPUIMenuBar.hxx | 138 ++++++++++++++ src/GUI/menubar.cxx | 362 ------------------------------------- src/GUI/menubar.hxx | 99 +---------- src/GUI/new_gui.cxx | 10 +- src/GUI/new_gui.hxx | 2 +- 7 files changed, 527 insertions(+), 462 deletions(-) create mode 100644 src/GUI/FGPUIMenuBar.cxx create mode 100644 src/GUI/FGPUIMenuBar.hxx diff --git a/src/GUI/CMakeLists.txt b/src/GUI/CMakeLists.txt index 6fd3f4704..030416ef0 100644 --- a/src/GUI/CMakeLists.txt +++ b/src/GUI/CMakeLists.txt @@ -13,6 +13,7 @@ set(SOURCES layout-props.cxx layout.cxx menubar.cxx + FGPUIMenuBar.cxx new_gui.cxx property_list.cxx FGFontCache.cxx @@ -29,6 +30,7 @@ set(HEADERS gui.h layout.hxx menubar.hxx + FGPUIMenuBar.hxx new_gui.hxx property_list.hxx FGFontCache.hxx diff --git a/src/GUI/FGPUIMenuBar.cxx b/src/GUI/FGPUIMenuBar.cxx new file mode 100644 index 000000000..a7d8ba0eb --- /dev/null +++ b/src/GUI/FGPUIMenuBar.cxx @@ -0,0 +1,376 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include
+#include
+ +#include "new_gui.hxx" +#include "FGPUIMenuBar.hxx" + +using std::vector; +using std::string; +using std::map; +//////////////////////////////////////////////////////////////////////// +// FIXME!! +// +// Deprecated wrappers for old menu commands. +// +// DO NOT ADD TO THESE. THEY WILL BE DELETED SOON! +// +// These are defined in gui_funcs.cxx. They should be replaced with +// user-configured dialogs and new commands where necessary. +//////////////////////////////////////////////////////////////////////// + +#if defined(TR_HIRES_SNAP) +extern void dumpHiResSnapShot (); +static bool +do_hires_snapshot_dialog (const SGPropertyNode * arg) +{ + dumpHiResSnapShot(); + return true; +} +#endif // TR_HIRES_SNAP + +static struct { + const char * name; + SGCommandMgr::command_t command; +} deprecated_dialogs [] = { +#if defined(TR_HIRES_SNAP) + { "old-hires-snapshot-dialog", do_hires_snapshot_dialog }, +#endif + { 0, 0 } +}; + +static void +add_deprecated_dialogs () +{ + SG_LOG(SG_GENERAL, SG_INFO, "Initializing old dialog commands:"); + for (int i = 0; deprecated_dialogs[i].name != 0; i++) { + SG_LOG(SG_GENERAL, SG_INFO, " " << deprecated_dialogs[i].name); + globals->get_commands()->addCommand(deprecated_dialogs[i].name, + deprecated_dialogs[i].command); + } +} + + + +//////////////////////////////////////////////////////////////////////// +// Static functions. +//////////////////////////////////////////////////////////////////////// + + +static void +menu_callback (puObject * object) +{ + NewGUI * gui = (NewGUI *)globals->get_subsystem("gui"); + FGPUIMenuBar* mb = static_cast(gui->getMenuBar()); + mb->fireItem(object); +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of FGPUIMenuBar. +//////////////////////////////////////////////////////////////////////// + + +FGPUIMenuBar::FGPUIMenuBar () + : _visible(false), + _menuBar(0) +{ +} + +FGPUIMenuBar::~FGPUIMenuBar () +{ + destroy_menubar(); +} + +void +FGPUIMenuBar::init () +{ + delete _menuBar; // FIXME: check if PUI owns the pointer + make_menubar(); + // FIXME: temporary commands to get at + // old, hard-coded dialogs. + add_deprecated_dialogs(); +} + +void +FGPUIMenuBar::show () +{ + if (_menuBar != 0) + _menuBar->reveal(); + _visible = true; +} + +void +FGPUIMenuBar::hide () +{ + if (_menuBar != 0) + _menuBar->hide(); + _visible = false; +} + +bool +FGPUIMenuBar::isVisible () const +{ + return _visible; +} + +void +FGPUIMenuBar::fireItem (puObject * item) +{ + const char * name = item->getLegend(); + vector &bindings = _bindings[name]; + int nBindings = bindings.size(); + + for (int i = 0; i < nBindings; i++) + bindings[i]->fire(); +} + +void +FGPUIMenuBar::make_menu (SGPropertyNode * node) +{ + const char * name = strdup(node->getStringValue("label")); + vector item_nodes = node->getChildren("item"); + + int array_size = item_nodes.size(); + + char ** items = make_char_array(array_size); + puCallback * callbacks = make_callback_array(array_size); + + for (unsigned int i = 0, j = item_nodes.size() - 1; + i < item_nodes.size(); + i++, j--) { + + // Set up the PUI entries for this item + items[j] = strdup((char *)item_nodes[i]->getStringValue("label")); + callbacks[j] = menu_callback; + + // Load all the bindings for this item + vector bindings = item_nodes[i]->getChildren("binding"); + SGPropertyNode * dest = fgGetNode("/sim/bindings/menu", true); + + for (unsigned int k = 0; k < bindings.size(); k++) { + unsigned int m = 0; + SGPropertyNode_ptr binding; + while (dest->getChild("binding", m)) + m++; + + binding = dest->getChild("binding", m, true); + copyProperties(bindings[k], binding); + _bindings[items[j]].push_back(new SGBinding(binding, globals->get_props())); + } + } + + _menuBar->add_submenu(name, items, callbacks); +} + +void +FGPUIMenuBar::make_menubar () +{ + SGPropertyNode *targetpath; + + targetpath = fgGetNode("/sim/menubar/default",true); + // fgLoadProps("gui/menubar.xml", targetpath); + + /* NOTE: there is no check to see whether there's any usable data at all + * + * This would also have the advantage of being able to create some kind of + * 'fallback' menu - just in case that either menubar.xml is empty OR that + * its XML data is not valid, that way we would avoid displaying an + * unusable menubar without any functionality - if we decided to add another + * char * element to the commands structure in + * $FG_SRC/src/Main/fgcommands.cxx + * we could additionally save each function's (short) description and use + * this as label for the fallback PUI menubar item labels - as a workaround + * one might simply use the internal fgcommands and put them into the + * fallback menu, so that the user is at least able to re-init the menu + * loading - just in case there was some malformed XML in it + * (it happend to me ...) + */ + + make_menubar(targetpath); +} + +/* WARNING: We aren't yet doing any validation of what's found - but since + * this isn't done with menubar.xml either, it should not really matter + * right now. Although one should later on consider to validate the + * contents, whether they are representing a 'legal' menubar structure. + */ +void +FGPUIMenuBar::make_menubar(SGPropertyNode * props) +{ + // Just in case. + destroy_menubar(); + _menuBar = new puMenuBar; + + vector menu_nodes = props->getChildren("menu"); + for (unsigned int i = 0; i < menu_nodes.size(); i++) + make_menu(menu_nodes[i]); + + _menuBar->close(); + make_object_map(props); + + if (_visible) + _menuBar->reveal(); + else + _menuBar->hide(); +} + +void +FGPUIMenuBar::destroy_menubar () +{ + if ( _menuBar == 0 ) + return; + + hide(); + puDeleteObject(_menuBar); + + unsigned int i; + + // Delete all the character arrays + // we were forced to keep around for + // plib. + SG_LOG(SG_GENERAL, SG_BULK, "Deleting char arrays"); + for (i = 0; i < _char_arrays.size(); i++) { + for (int j = 0; _char_arrays[i][j] != 0; j++) + free(_char_arrays[i][j]); // added with strdup + delete[] _char_arrays[i]; + } + + // Delete all the callback arrays + // we were forced to keep around for + // plib. + SG_LOG(SG_GENERAL, SG_BULK, "Deleting callback arrays"); + for (i = 0; i < _callback_arrays.size(); i++) + delete[] _callback_arrays[i]; + + // Delete all those bindings + SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings"); + map >::iterator it; + for (it = _bindings.begin(); it != _bindings.end(); it++) { + SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings for " << it->first); + for ( i = 0; i < it->second.size(); i++ ) + delete it->second[i]; + } + + SG_LOG(SG_GENERAL, SG_BULK, "Done."); +} + +void +FGPUIMenuBar::make_object_map(SGPropertyNode * node) +{ + unsigned int menu_index = 0; + vector menus = node->getChildren("menu"); + for (puObject *obj = ((puGroup *)_menuBar)->getFirstChild(); + obj; obj = obj->getNextObject()) { + + // skip puPopupMenus. They are also children of _menuBar, + // but we access them via getUserData() (see below) + if (!(obj->getType() & PUCLASS_ONESHOT)) + continue; + + if (menu_index >= menus.size()) { + SG_LOG(SG_GENERAL, SG_WARN, "'menu' object without node: " + << node->getPath() << "/menu[" << menu_index << ']'); + return; + } + + SGPropertyNode *menu = menus.at(menu_index); + _objects[menu->getPath()] = obj; + add_enabled_listener(menu); + + puGroup *popup = (puGroup *)obj->getUserData(); + if (!popup) + continue; + + // the entries are for some reason reversed (last first), and we + // don't know yet how many there will be; so we collect first + vector e; + for (puObject *me = popup->getFirstChild(); me; me = me->getNextObject()) + e.push_back(me); + + vector items = menu->getChildren("item"); + for (unsigned int i = 0; i < e.size(); i++) { + if (i >= items.size()) { + SG_LOG(SG_GENERAL, SG_WARN, "'item' object without node: " + << menu->getPath() << "/item[" << i << ']'); + break; + } + SGPropertyNode *item = items.at(e.size() - i - 1); + _objects[item->getPath()] = e[i]; + add_enabled_listener(item); + } + menu_index++; + } +} + +struct EnabledListener : SGPropertyChangeListener { + void valueChanged(SGPropertyNode *node) { + NewGUI * gui = (NewGUI *)globals->get_subsystem("gui"); + if (!gui) + return; + FGPUIMenuBar* menubar = static_cast(gui->getMenuBar()); + if (menubar) + menubar->enable_item(node->getParent(), node->getBoolValue()); + } +}; + +void +FGPUIMenuBar::add_enabled_listener(SGPropertyNode * node) +{ + if (!node->hasValue("enabled")) + node->setBoolValue("enabled", true); + + enable_item(node, node->getBoolValue("enabled")); + node->getNode("enabled")->addChangeListener(new EnabledListener()); +} + +bool +FGPUIMenuBar::enable_item(const SGPropertyNode * node, bool state) +{ + string path = node->getPath(); + if (_objects.find(path) == _objects.end()) { + SG_LOG(SG_GENERAL, SG_ALERT, "Trying to enable/disable " + "non-existent menu item for node `" << path << '\''); + return false; + } + puObject *object = _objects[path]; + if (state) + object->activate(); + else + object->greyOut(); + + return true; +} + +char ** +FGPUIMenuBar::make_char_array (int size) +{ + char ** list = new char*[size+1]; + for (int i = 0; i <= size; i++) + list[i] = 0; + _char_arrays.push_back(list); + return list; +} + +puCallback * +FGPUIMenuBar::make_callback_array (int size) +{ + puCallback * list = new puCallback[size+1]; + for (int i = 0; i <= size; i++) + list[i] = 0; + _callback_arrays.push_back(list); + return list; +} + +// end of menubar.cxx diff --git a/src/GUI/FGPUIMenuBar.hxx b/src/GUI/FGPUIMenuBar.hxx new file mode 100644 index 000000000..fa21c05b3 --- /dev/null +++ b/src/GUI/FGPUIMenuBar.hxx @@ -0,0 +1,138 @@ +// menubar.hxx - XML-configured menu bar. + +#ifndef FG_PUI_MENUBAR_HXX +#define FG_PUI_MENUBAR_HXX 1 + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include + +#include +#include + +// forward decls, avoid pulling in PLIB headers here +class puMenuBar; +class puObject; +class SGPropertyNode; +class SGBinding; + +typedef void (*puCallback)(class puObject *) ; + +/** + * XML-configured PUI menu bar. + * + * This class creates a menu bar from a tree of XML properties. These + * properties are not part of the main FlightGear property tree, but + * are read from a separate file ($FG_ROOT/gui/menubar.xml). + * + * WARNING: because PUI provides no easy way to attach user data to a + * menu item, all menu item strings must be unique; otherwise, this + * class will always use the first binding with any given name. + */ +class FGPUIMenuBar : public FGMenuBar +{ +public: + + /** + * Constructor. + */ + FGPUIMenuBar (); + + + /** + * Destructor. + */ + virtual ~FGPUIMenuBar (); + + + /** + * Initialize the menu bar from $FG_ROOT/gui/menubar.xml + */ + virtual void init (); + + /** + * Make the menu bar visible. + */ + virtual void show (); + + + /** + * Make the menu bar invisible. + */ + virtual void hide (); + + + /** + * Test whether the menu bar is visible. + */ + virtual bool isVisible () const; + + + /** + * IGNORE THIS METHOD!!! + * + * This is necessary only because plib does not provide any easy + * way to attach user data to a menu item. FlightGear should not + * have to know about PUI internals, but this method allows the + * callback to pass the menu item one-shot on to the current menu. + */ + virtual void fireItem (puObject * item); + + + /** + * create a menubar based on a PropertyList within the PropertyTree + */ + void make_menubar (SGPropertyNode * props); + + + /** + * destroy a menubar based on a PropertyList within the PropertyTree + */ + void destroy_menubar (); + + + /** + * Disable/enable menu titles and entries + */ + bool enable_item (const SGPropertyNode * item, bool state); + + +private: + + // Make a single menu. + void make_menu (SGPropertyNode * node); + + // Make the top-level menubar. + void make_menubar (); + + // Create a property-path -> puObject map for menu node + void make_object_map(SGPropertyNode * node); + + // Add listener that enables/disables menu entries. + void add_enabled_listener(SGPropertyNode * node); + + // Is the menu visible? + bool _visible; + + // The top-level menubar itself. + puMenuBar * _menuBar; + + // A map of bindings for the menubar. + std::map > _bindings; + + // These are hoops that we have to jump through because PUI doesn't + // do memory management for lists. We have to allocate the arrays, + // hang onto pointers, and then delete them when the menubar is + // freed. + char ** make_char_array (int size); + puCallback * make_callback_array (int size); + std::vector _char_arrays; + std::vector _callback_arrays; + + // A map for {menu node path}->puObject translation. + std::map _objects; +}; + +#endif // __MENUBAR_HXX diff --git a/src/GUI/menubar.cxx b/src/GUI/menubar.cxx index b21b9ce64..4295f808b 100644 --- a/src/GUI/menubar.cxx +++ b/src/GUI/menubar.cxx @@ -2,373 +2,11 @@ # include #endif -#include -#include -#include -#include -#include -#include -#include
- -#include "new_gui.hxx" #include "menubar.hxx" -using std::vector; -using std::string; -using std::map; -//////////////////////////////////////////////////////////////////////// -// FIXME!! -// -// Deprecated wrappers for old menu commands. -// -// DO NOT ADD TO THESE. THEY WILL BE DELETED SOON! -// -// These are defined in gui_funcs.cxx. They should be replaced with -// user-configured dialogs and new commands where necessary. -//////////////////////////////////////////////////////////////////////// - -#if defined(TR_HIRES_SNAP) -extern void dumpHiResSnapShot (); -static bool -do_hires_snapshot_dialog (const SGPropertyNode * arg) -{ - dumpHiResSnapShot(); - return true; -} -#endif // TR_HIRES_SNAP - -static struct { - const char * name; - SGCommandMgr::command_t command; -} deprecated_dialogs [] = { -#if defined(TR_HIRES_SNAP) - { "old-hires-snapshot-dialog", do_hires_snapshot_dialog }, -#endif - { 0, 0 } -}; - -static void -add_deprecated_dialogs () -{ - SG_LOG(SG_GENERAL, SG_INFO, "Initializing old dialog commands:"); - for (int i = 0; deprecated_dialogs[i].name != 0; i++) { - SG_LOG(SG_GENERAL, SG_INFO, " " << deprecated_dialogs[i].name); - globals->get_commands()->addCommand(deprecated_dialogs[i].name, - deprecated_dialogs[i].command); - } -} - - - -//////////////////////////////////////////////////////////////////////// -// Static functions. -//////////////////////////////////////////////////////////////////////// - - -static void -menu_callback (puObject * object) -{ - NewGUI * gui = (NewGUI *)globals->get_subsystem("gui"); - gui->getMenuBar()->fireItem(object); -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of FGMenuBar. -//////////////////////////////////////////////////////////////////////// - - -FGMenuBar::FGMenuBar () - : _visible(false), - _menuBar(0) -{ -} - FGMenuBar::~FGMenuBar () { - destroy_menubar(); -} - -void -FGMenuBar::init () -{ - delete _menuBar; // FIXME: check if PUI owns the pointer - make_menubar(); - // FIXME: temporary commands to get at - // old, hard-coded dialogs. - add_deprecated_dialogs(); -} - -void -FGMenuBar::show () -{ - if (_menuBar != 0) - _menuBar->reveal(); - _visible = true; -} - -void -FGMenuBar::hide () -{ - if (_menuBar != 0) - _menuBar->hide(); - _visible = false; -} - -bool -FGMenuBar::isVisible () const -{ - return _visible; -} - -void -FGMenuBar::fireItem (puObject * item) -{ - const char * name = item->getLegend(); - vector &bindings = _bindings[name]; - int nBindings = bindings.size(); - - for (int i = 0; i < nBindings; i++) - bindings[i]->fire(); -} - -void -FGMenuBar::make_menu (SGPropertyNode * node) -{ - const char * name = strdup(node->getStringValue("label")); - vector item_nodes = node->getChildren("item"); - - int array_size = item_nodes.size(); - - char ** items = make_char_array(array_size); - puCallback * callbacks = make_callback_array(array_size); - - for (unsigned int i = 0, j = item_nodes.size() - 1; - i < item_nodes.size(); - i++, j--) { - - // Set up the PUI entries for this item - items[j] = strdup((char *)item_nodes[i]->getStringValue("label")); - callbacks[j] = menu_callback; - - // Load all the bindings for this item - vector bindings = item_nodes[i]->getChildren("binding"); - SGPropertyNode * dest = fgGetNode("/sim/bindings/menu", true); - - for (unsigned int k = 0; k < bindings.size(); k++) { - unsigned int m = 0; - SGPropertyNode_ptr binding; - while (dest->getChild("binding", m)) - m++; - - binding = dest->getChild("binding", m, true); - copyProperties(bindings[k], binding); - _bindings[items[j]].push_back(new SGBinding(binding, globals->get_props())); - } - } - - _menuBar->add_submenu(name, items, callbacks); -} - -void -FGMenuBar::make_menubar () -{ - SGPropertyNode *targetpath; - - targetpath = fgGetNode("/sim/menubar/default",true); - // fgLoadProps("gui/menubar.xml", targetpath); - - /* NOTE: there is no check to see whether there's any usable data at all - * - * This would also have the advantage of being able to create some kind of - * 'fallback' menu - just in case that either menubar.xml is empty OR that - * its XML data is not valid, that way we would avoid displaying an - * unusable menubar without any functionality - if we decided to add another - * char * element to the commands structure in - * $FG_SRC/src/Main/fgcommands.cxx - * we could additionally save each function's (short) description and use - * this as label for the fallback PUI menubar item labels - as a workaround - * one might simply use the internal fgcommands and put them into the - * fallback menu, so that the user is at least able to re-init the menu - * loading - just in case there was some malformed XML in it - * (it happend to me ...) - */ - - make_menubar(targetpath); -} - -/* WARNING: We aren't yet doing any validation of what's found - but since - * this isn't done with menubar.xml either, it should not really matter - * right now. Although one should later on consider to validate the - * contents, whether they are representing a 'legal' menubar structure. - */ -void -FGMenuBar::make_menubar(SGPropertyNode * props) -{ - // Just in case. - destroy_menubar(); - _menuBar = new puMenuBar; - - vector menu_nodes = props->getChildren("menu"); - for (unsigned int i = 0; i < menu_nodes.size(); i++) - make_menu(menu_nodes[i]); - - _menuBar->close(); - make_object_map(props); - - if (_visible) - _menuBar->reveal(); - else - _menuBar->hide(); -} - -void -FGMenuBar::destroy_menubar () -{ - if ( _menuBar == 0 ) - return; - - hide(); - puDeleteObject(_menuBar); - - unsigned int i; - - // Delete all the character arrays - // we were forced to keep around for - // plib. - SG_LOG(SG_GENERAL, SG_BULK, "Deleting char arrays"); - for (i = 0; i < _char_arrays.size(); i++) { - for (int j = 0; _char_arrays[i][j] != 0; j++) - free(_char_arrays[i][j]); // added with strdup - delete[] _char_arrays[i]; - } - - // Delete all the callback arrays - // we were forced to keep around for - // plib. - SG_LOG(SG_GENERAL, SG_BULK, "Deleting callback arrays"); - for (i = 0; i < _callback_arrays.size(); i++) - delete[] _callback_arrays[i]; - - // Delete all those bindings - SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings"); - map >::iterator it; - for (it = _bindings.begin(); it != _bindings.end(); it++) { - SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings for " << it->first); - for ( i = 0; i < it->second.size(); i++ ) - delete it->second[i]; - } - - SG_LOG(SG_GENERAL, SG_BULK, "Done."); -} - -void -FGMenuBar::make_object_map(SGPropertyNode * node) -{ - unsigned int menu_index = 0; - vector menus = node->getChildren("menu"); - for (puObject *obj = ((puGroup *)_menuBar)->getFirstChild(); - obj; obj = obj->getNextObject()) { - - // skip puPopupMenus. They are also children of _menuBar, - // but we access them via getUserData() (see below) - if (!(obj->getType() & PUCLASS_ONESHOT)) - continue; - - if (menu_index >= menus.size()) { - SG_LOG(SG_GENERAL, SG_WARN, "'menu' object without node: " - << node->getPath() << "/menu[" << menu_index << ']'); - return; - } - - SGPropertyNode *menu = menus.at(menu_index); - _objects[menu->getPath()] = obj; - add_enabled_listener(menu); - - puGroup *popup = (puGroup *)obj->getUserData(); - if (!popup) - continue; - - // the entries are for some reason reversed (last first), and we - // don't know yet how many there will be; so we collect first - vector e; - for (puObject *me = popup->getFirstChild(); me; me = me->getNextObject()) - e.push_back(me); - - vector items = menu->getChildren("item"); - for (unsigned int i = 0; i < e.size(); i++) { - if (i >= items.size()) { - SG_LOG(SG_GENERAL, SG_WARN, "'item' object without node: " - << menu->getPath() << "/item[" << i << ']'); - break; - } - SGPropertyNode *item = items.at(e.size() - i - 1); - _objects[item->getPath()] = e[i]; - add_enabled_listener(item); - } - menu_index++; - } -} - -struct EnabledListener : SGPropertyChangeListener { - void valueChanged(SGPropertyNode *node) { - NewGUI * gui = (NewGUI *)globals->get_subsystem("gui"); - if (!gui) - return; - FGMenuBar *menubar = gui->getMenuBar(); - if (menubar) - menubar->enable_item(node->getParent(), node->getBoolValue()); - } -}; - -void -FGMenuBar::add_enabled_listener(SGPropertyNode * node) -{ - if (!node->hasValue("enabled")) - node->setBoolValue("enabled", true); - - enable_item(node, node->getBoolValue("enabled")); - node->getNode("enabled")->addChangeListener(new EnabledListener()); -} - -bool -FGMenuBar::enable_item(const SGPropertyNode * node, bool state) -{ - string path = node->getPath(); - if (_objects.find(path) == _objects.end()) { - SG_LOG(SG_GENERAL, SG_ALERT, "Trying to enable/disable " - "non-existent menu item for node `" << path << '\''); - return false; - } - puObject *object = _objects[path]; - if (state) - object->activate(); - else - object->greyOut(); - - return true; -} - -char ** -FGMenuBar::make_char_array (int size) -{ - char ** list = new char*[size+1]; - for (int i = 0; i <= size; i++) - list[i] = 0; - _char_arrays.push_back(list); - return list; -} - -puCallback * -FGMenuBar::make_callback_array (int size) -{ - puCallback * list = new puCallback[size+1]; - for (int i = 0; i <= size; i++) - list[i] = 0; - _callback_arrays.push_back(list); - return list; } // end of menubar.cxx diff --git a/src/GUI/menubar.hxx b/src/GUI/menubar.hxx index 79e0af814..fa3f43ca5 100644 --- a/src/GUI/menubar.hxx +++ b/src/GUI/menubar.hxx @@ -3,42 +3,19 @@ #ifndef __MENUBAR_HXX #define __MENUBAR_HXX 1 -#ifndef __cplusplus -# error This library requires C++ -#endif - -#include
- -#include - -#include -#include - -class puMenuBar; -class puObject; -class SGBinding; - /** - * XML-configured PUI menu bar. + * XML-configured menu bar interface * * This class creates a menu bar from a tree of XML properties. These * properties are not part of the main FlightGear property tree, but * are read from a separate file ($FG_ROOT/gui/menubar.xml). - * - * WARNING: because PUI provides no easy way to attach user data to a - * menu item, all menu item strings must be unique; otherwise, this - * class will always use the first binding with any given name. + */ class FGMenuBar { public: - /** - * Constructor. - */ - FGMenuBar (); - /** * Destructor. @@ -49,89 +26,25 @@ public: /** * Initialize the menu bar from $FG_ROOT/gui/menubar.xml */ - virtual void init (); + virtual void init () = 0; /** * Make the menu bar visible. */ - virtual void show (); + virtual void show () = 0; /** * Make the menu bar invisible. */ - virtual void hide (); + virtual void hide () = 0; /** * Test whether the menu bar is visible. */ - virtual bool isVisible () const; - - - /** - * IGNORE THIS METHOD!!! - * - * This is necessary only because plib does not provide any easy - * way to attach user data to a menu item. FlightGear should not - * have to know about PUI internals, but this method allows the - * callback to pass the menu item one-shot on to the current menu. - */ - virtual void fireItem (puObject * item); - - - /** - * create a menubar based on a PropertyList within the PropertyTree - */ - void make_menubar (SGPropertyNode * props); - - - /** - * destroy a menubar based on a PropertyList within the PropertyTree - */ - void destroy_menubar (); - - - /** - * Disable/enable menu titles and entries - */ - bool enable_item (const SGPropertyNode * item, bool state); - - -private: - - // Make a single menu. - void make_menu (SGPropertyNode * node); - - // Make the top-level menubar. - void make_menubar (); - - // Create a property-path -> puObject map for menu node - void make_object_map(SGPropertyNode * node); - - // Add listener that enables/disables menu entries. - void add_enabled_listener(SGPropertyNode * node); - - // Is the menu visible? - bool _visible; - - // The top-level menubar itself. - puMenuBar * _menuBar; - - // A map of bindings for the menubar. - std::map > _bindings; - - // These are hoops that we have to jump through because PUI doesn't - // do memory management for lists. We have to allocate the arrays, - // hang onto pointers, and then delete them when the menubar is - // freed. - char ** make_char_array (int size); - puCallback * make_callback_array (int size); - std::vector _char_arrays; - std::vector _callback_arrays; + virtual bool isVisible () const = 0; - // A map for {menu node path}->puObject translation. - std::map _objects; }; #endif // __MENUBAR_HXX diff --git a/src/GUI/new_gui.cxx b/src/GUI/new_gui.cxx index a374b2912..f9d7941c2 100644 --- a/src/GUI/new_gui.cxx +++ b/src/GUI/new_gui.cxx @@ -26,7 +26,7 @@ #include "GL/glx.h" #endif -#include "menubar.hxx" +#include "FGPUIMenuBar.hxx" #include "FGPUIDialog.hxx" #include "FGFontCache.hxx" #include "FGColor.hxx" @@ -41,14 +41,13 @@ using std::string; NewGUI::NewGUI () - : _menubar(new FGMenuBar), + : _menubar(new FGPUIMenuBar), _active_dialog(0) { } NewGUI::~NewGUI () { - delete _menubar; _dialog_props.clear(); for (_itt_t it = _colors.begin(); it != _colors.end(); ++it) delete it->second; @@ -92,8 +91,7 @@ NewGUI::reset (bool reload) setStyle(); unbind(); - delete _menubar; - _menubar = new FGMenuBar; + _menubar.reset(new FGPUIMenuBar); if (reload) { _dialog_props.clear(); @@ -214,7 +212,7 @@ NewGUI::getActiveDialog () FGMenuBar * NewGUI::getMenuBar () { - return _menubar; + return _menubar.get(); } bool diff --git a/src/GUI/new_gui.hxx b/src/GUI/new_gui.hxx index 3f69cab95..08a01b27f 100644 --- a/src/GUI/new_gui.hxx +++ b/src/GUI/new_gui.hxx @@ -219,7 +219,7 @@ private: // Read all the configuration files in a directory. void readDir (const SGPath& path); - FGMenuBar * _menubar; + std::auto_ptr _menubar; FGDialog * _active_dialog; std::map _active_dialogs; std::map _dialog_props; -- 2.39.5