From ac2c1fcd433df5c61b4a6377b7bab9cbffa92b1b Mon Sep 17 00:00:00 2001 From: mfranz Date: Tue, 6 Dec 2005 17:56:17 +0000 Subject: [PATCH] allow disabling/enabling of menu entries via "enabled" property; Unfortunately, we don't have an easy way to access the puObjects only by knowing the respective XML property node, because the menu structure was built by plib from string lists. That's why we walk the puMenuBar tree and store {property node}->{puObject*} pairs in a map. With this infrastructure in place we can now easily enable/disable entries, but we can also make other changes to menu buttons as we see need. The structure of puMenuBar is described in the pui documentation, so it's less of a hack than it looks. :-) --- src/GUI/menubar.cxx | 101 ++++++++++++++++++++++++++++++++++++++++++++ src/GUI/menubar.hxx | 13 ++++++ 2 files changed, 114 insertions(+) diff --git a/src/GUI/menubar.cxx b/src/GUI/menubar.cxx index c31c34ee3..f500e4342 100644 --- a/src/GUI/menubar.cxx +++ b/src/GUI/menubar.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -302,6 +303,8 @@ FGMenuBar::make_menubar(const SGPropertyNode * props) make_menu(menu_nodes[i]); _menuBar->close(); + make_map(props); + if (_visible) _menuBar->reveal(); else @@ -349,6 +352,104 @@ FGMenuBar::destroy_menubar () SG_LOG(SG_GENERAL, SG_INFO, "Done."); } +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()); +} + +void +FGMenuBar::make_map(const SGPropertyNode * node) +{ + string base = node->getPath(); + + int menu_index = 0; + 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 (!obj->getLegend()) + continue; + + std::ostringstream menu; + menu << base << "/menu[" << menu_index << "]"; + SGPropertyNode *prop = fgGetNode(menu.str().c_str()); + if (!prop) { + SG_LOG(SG_GENERAL, SG_WARN, "menu without node: " << menu.str()); + continue; + } + + // push "menu" entry + _entries[prop->getPath()] = obj; + add_enabled_listener(prop); + + // push "item" entries + puPopupMenu *popup = (puPopupMenu *)obj->getUserData(); + if (!popup) + continue; + + // the entries are for some reason reversed (last first), and we + // don't know yet how many will be usable; so we collect first + vector e; + for (puObject *me = ((puGroup *)popup)->getFirstChild(); + me; me = me->getNextObject()) { + + if (!me->getLegend()) + continue; + + e.push_back(me); + } + + for (unsigned int i = 0; i < e.size(); i++) { + std::ostringstream item; + item << menu.str() << "/item[" << (e.size() - i - 1) << "]"; + prop = fgGetNode(item.str().c_str()); + if (!prop) { + SG_LOG(SG_GENERAL, SG_WARN, "item without node: " << item.str()); + continue; + } + _entries[prop->getPath()] = e[i]; + add_enabled_listener(prop); + } + menu_index++; + } +} + +bool +FGMenuBar::enable_item(const SGPropertyNode * node, bool state) +{ + if (!node || _entries.find(node->getPath()) == _entries.end()) { + SG_LOG(SG_GENERAL, SG_WARN, "Trying to enable/disable " + "non-existent menu item"); + return false; + } + puObject *object = _entries[node->getPath()]; + if (state) + object->activate(); + else + object->greyOut(); + + return true; +} char ** FGMenuBar::make_char_array (int size) diff --git a/src/GUI/menubar.hxx b/src/GUI/menubar.hxx index 6c7217786..0c77c3af8 100644 --- a/src/GUI/menubar.hxx +++ b/src/GUI/menubar.hxx @@ -95,6 +95,11 @@ public: */ void destroy_menubar (); + /** + * Disable/enable menu titles and entries + */ + bool enable_item (const SGPropertyNode * item, bool state); + private: @@ -104,6 +109,12 @@ private: // Make the top-level menubar. void make_menubar (); + // Create a property-path -> puObject map for menu node + void make_map(const SGPropertyNode * node); + + // Add listener that enables/disabled menu entries. + void add_enabled_listener(SGPropertyNode * node); + // Is the menu visible? bool _visible; @@ -121,6 +132,8 @@ private: puCallback * make_callback_array (int size); vector _char_arrays; vector _callback_arrays; + + map _entries; }; #endif // __MENUBAR_HXX -- 2.39.5