1
0
Fork 0

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.  :-)
This commit is contained in:
mfranz 2005-12-06 17:56:17 +00:00
parent 435d874e35
commit ac2c1fcd43
2 changed files with 114 additions and 0 deletions

View file

@ -4,6 +4,7 @@
#include <string.h>
#include <iostream>
#include <sstream>
#include <plib/pu.h>
#include <simgear/debug/logstream.hxx>
@ -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<puObject *> 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)

View file

@ -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 <enabled> 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 **> _char_arrays;
vector<puCallback *> _callback_arrays;
map<string, puObject *> _entries;
};
#endif // __MENUBAR_HXX