#include <simgear/misc/sg_dir.hxx>
#include <boost/algorithm/string/case_conv.hpp>
+#include <boost/foreach.hpp>
#include <Main/fg_props.hxx>
#include "GL/glx.h"
#endif
-#include "menubar.hxx"
-#include "dialog.hxx"
+#include "FGPUIMenuBar.hxx"
-extern puFont FONT_HELVETICA_14;
-extern puFont FONT_SANS_12B;
+#if defined(SG_MAC)
+#include "FGCocoaMenuBar.hxx"
+#endif
+
+#if defined(SG_WINDOWS)
+#include "FGWindowsMenuBar.hxx"
+#endif
+#include "FGPUIDialog.hxx"
+#include "FGFontCache.hxx"
+#include "FGColor.hxx"
+// ignore the word Navaid here, it's a DataCache
+#include <Navaids/NavDataCache.hxx>
+
+using std::map;
+using std::string;
-\f
////////////////////////////////////////////////////////////////////////
// Implementation of NewGUI.
////////////////////////////////////////////////////////////////////////
-NewGUI::NewGUI ()
- : _menubar(new FGMenuBar),
- _active_dialog(0)
+NewGUI::NewGUI () :
+ _active_dialog(0)
{
}
NewGUI::~NewGUI ()
{
- delete _menubar;
- _dialog_props.clear();
for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
delete it->second;
}
void
NewGUI::init ()
{
+ createMenuBarImplementation();
+ fgTie("/sim/menubar/visibility", this,
+ &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
+
setStyle();
SGPath p(globals->get_fg_root(), "gui/dialogs");
readDir(p);
+
+ SGPath aircraftDialogDir(string(fgGetString("/sim/aircraft-dir")), "gui/dialogs");
+ if (aircraftDialogDir.exists()) {
+ readDir(aircraftDialogDir);
+ }
+
+ // Fix for http://code.google.com/p/flightgear-bugs/issues/detail?id=947
+ fgGetNode("sim/menubar")->setAttribute(SGPropertyNode::PRESERVE, true);
_menubar->init();
}
+void
+NewGUI::shutdown()
+{
+ DialogDict::iterator it = _active_dialogs.begin();
+ for (; it != _active_dialogs.end(); ++it) {
+ delete it->second;
+ }
+ _active_dialogs.clear();
+
+ fgUntie("/sim/menubar/visibility");
+ _menubar.reset();
+ _dialog_props.clear();
+}
+
void
NewGUI::reinit ()
{
reset(false);
}
+void
+NewGUI::createMenuBarImplementation()
+{
+#if defined(SG_MAC)
+ if (fgGetBool("/sim/menubar/native", true)) {
+ _menubar.reset(new FGCocoaMenuBar);
+ }
+#endif
+#if defined(SG_WINDOWS)
+ if (fgGetBool("/sim/menubar/native", true)) {
+ // Windows-native menubar disabled for the moment, fall-through
+ // to PUI version
+ // _menubar.reset(new FGWindowsMenuBar);
+ }
+#endif
+ if (!_menubar.get()) {
+ _menubar.reset(new FGPUIMenuBar);
+ }
+}
+
void
NewGUI::reset (bool reload)
{
- map<string,FGDialog *>::iterator iter;
- vector<string> dlg;
+ DialogDict::iterator iter;
+ string_list openDialogs;
// close all open dialogs and remember them ...
for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
- dlg.push_back(iter->first);
+ openDialogs.push_back(iter->first);
- unsigned int i;
- for (i = 0; i < dlg.size(); i++)
- closeDialog(dlg[i]);
+ BOOST_FOREACH(string d, openDialogs)
+ closeDialog(d);
setStyle();
unbind();
- delete _menubar;
- _menubar = new FGMenuBar;
if (reload) {
_dialog_props.clear();
+ _dialog_names.clear();
init();
} else {
+ createMenuBarImplementation();
_menubar->init();
}
bind();
// open dialogs again
- for (i = 0; i < dlg.size(); i++)
- showDialog(dlg[i]);
+ BOOST_FOREACH(string d, openDialogs)
+ showDialog(d);
}
void
NewGUI::bind ()
{
- fgTie("/sim/menubar/visibility", this,
- &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
}
void
NewGUI::unbind ()
{
- fgUntie("/sim/menubar/visibility");
}
void
NewGUI::update (double delta_time_sec)
{
+ SG_UNUSED(delta_time_sec);
map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
for(/**/; iter != _active_dialogs.end(); iter++)
iter->second->update();
bool
NewGUI::showDialog (const string &name)
{
- if (_dialog_props.find(name) == _dialog_props.end()) {
+ // first, check if it's already shown
+ if (_active_dialogs.find(name) != _active_dialogs.end())
+ return true;
+
+ // check we know about the dialog by name
+ if (_dialog_names.find(name) == _dialog_names.end()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
return false;
- } else {
- if(!_active_dialogs[name])
- _active_dialogs[name] = new FGDialog(_dialog_props[name]);
- return true;
}
+
+ _active_dialogs[name] = new FGPUIDialog(getDialogProperties(name));
+ return true;
}
bool
SGPropertyNode_ptr
NewGUI::getDialogProperties (const string &name)
{
- if(_dialog_props.find(name) != _dialog_props.end())
- return _dialog_props[name];
+ if (_dialog_names.find(name) == _dialog_names.end()) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
+ return NULL;
+ }
+
+ NameDialogDict::iterator it = _dialog_props.find(name);
+ if (it == _dialog_props.end()) {
+ // load the XML
+ SGPath path = _dialog_names[name];
+ SGPropertyNode_ptr props = new SGPropertyNode;
+ try {
+ readProperties(path.str(), props);
+ } catch (const sg_exception &) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << path);
+ return NULL;
+ }
+
+ it = _dialog_props.insert(it, std::make_pair(name, props));
+ }
- SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing");
- return 0;
+ return it->second;
}
FGDialog *
FGMenuBar *
NewGUI::getMenuBar ()
{
- return _menubar;
+ return _menubar.get();
}
bool
return;
}
string name = cname;
- if(_active_dialogs.find(name) == _active_dialogs.end())
+
+ if(_active_dialogs.find(name) == _active_dialogs.end()) {
_dialog_props[name] = props;
+ // add a dummy path entry, so we believe the dialog exists
+ _dialog_names[name] = SGPath();
+ }
}
void
NewGUI::readDir (const SGPath& path)
{
simgear::Dir dir(path);
+ if( !dir.exists() )
+ {
+ SG_LOG(SG_INPUT, SG_INFO, "directory does not exist: " << path.str());
+ return;
+ }
+
+ flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+ flightgear::NavDataCache::Transaction txn(cache);
simgear::PathList xmls = dir.children(simgear::Dir::TYPE_FILE, ".xml");
- for (unsigned int i=0; i<xmls.size(); ++i) {
- SGPropertyNode * props = new SGPropertyNode;
+ BOOST_FOREACH(SGPath xmlPath, xmls) {
+ if (!cache->isCachedFileModified(xmlPath)) {
+ // cached, easy
+ string name = cache->readStringProperty(xmlPath.str());
+ _dialog_names[name] = xmlPath;
+ continue;
+ }
+
+ // we need to parse the actual XML
+ SGPropertyNode_ptr props = new SGPropertyNode;
try {
- readProperties(xmls[i].str(), props);
+ readProperties(xmlPath.str(), props);
} catch (const sg_exception &) {
- SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog "
- << xmls[i].str());
- delete props;
- continue;
+ SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << xmlPath);
+ continue;
}
+
SGPropertyNode *nameprop = props->getNode("name");
if (!nameprop) {
- SG_LOG(SG_INPUT, SG_WARN, "dialog " << xmls[i].str()
- << " has no name; skipping.");
- delete props;
- continue;
+ SG_LOG(SG_INPUT, SG_WARN, "dialog " << xmlPath << " has no name; skipping.");
+ continue;
}
+
string name = nameprop->getStringValue();
- _dialog_props[name] = props;
- }
-}
-
-
-\f
+ _dialog_names[name] = xmlPath;
+ // update cached values
+ if (!cache->isReadOnly()) {
+ cache->stampCacheFile(xmlPath);
+ cache->writeStringProperty(xmlPath.str(), name);
+ }
+ } // of directory children iteration
+
+ txn.commit();
+}\f
////////////////////////////////////////////////////////////////////////
// Style handling.
////////////////////////////////////////////////////////////////////////
void
NewGUI::setupFont (SGPropertyNode *node)
{
- _font = globals->get_fontcache()->get(node);
+ _font = FGFontCache::instance()->get(node);
puSetDefaultFonts(*_font, *_font);
return;
}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// FGColor class.
-////////////////////////////////////////////////////////////////////////
-
-void
-FGColor::print() const {
- std::cerr << "red=" << _red << ", green=" << _green
- << ", blue=" << _blue << ", alpha=" << _alpha << std::endl;
-}
-
-bool
-FGColor::merge(const SGPropertyNode *node)
-{
- if (!node)
- return false;
-
- bool dirty = false;
- const SGPropertyNode * n;
- if ((n = node->getNode("red")))
- _red = n->getFloatValue(), dirty = true;
- if ((n = node->getNode("green")))
- _green = n->getFloatValue(), dirty = true;
- if ((n = node->getNode("blue")))
- _blue = n->getFloatValue(), dirty = true;
- if ((n = node->getNode("alpha")))
- _alpha = n->getFloatValue(), dirty = true;
- return dirty;
-}
-
-bool
-FGColor::merge(const FGColor *color)
-{
- bool dirty = false;
- if (color && color->_red >= 0.0)
- _red = color->_red, dirty = true;
- if (color && color->_green >= 0.0)
- _green = color->_green, dirty = true;
- if (color && color->_blue >= 0.0)
- _blue = color->_blue, dirty = true;
- if (color && color->_alpha >= 0.0)
- _alpha = color->_alpha, dirty = true;
- return dirty;
-}
-
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// FGFontCache class.
-////////////////////////////////////////////////////////////////////////
-
-namespace
-{
-struct GuiFont
-{
- const char *name;
- puFont *font;
- struct Predicate
- : public std::unary_function<const GuiFont, bool>
- {
- Predicate(const char* name_) : name(name_) {}
- bool operator() (const GuiFont& f1) const
- {
- return std::strcmp(f1.name, name) == 0;
- }
- const char* name;
- };
-};
-
-const GuiFont guifonts[] = {
- { "default", &FONT_HELVETICA_14 },
- { "FIXED_8x13", &PUFONT_8_BY_13 },
- { "FIXED_9x15", &PUFONT_9_BY_15 },
- { "TIMES_10", &PUFONT_TIMES_ROMAN_10 },
- { "TIMES_24", &PUFONT_TIMES_ROMAN_24 },
- { "HELVETICA_10", &PUFONT_HELVETICA_10 },
- { "HELVETICA_12", &PUFONT_HELVETICA_12 },
- { "HELVETICA_14", &FONT_HELVETICA_14 },
- { "HELVETICA_18", &PUFONT_HELVETICA_18 },
- { "SANS_12B", &FONT_SANS_12B }
-};
-
-const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
-}
-
-FGFontCache::FGFontCache() :
- _initialized(false)
-{
-}
-
-FGFontCache::~FGFontCache()
-{
-#if defined(SG_UNIX) && !defined(SG_MAC)
- // Ugly workaround for a crash on exit with multiple screens configured
- if (!glXGetCurrentContext())
- return;
-#endif
- PuFontMap::iterator it, end = _puFonts.end();
- for (it = _puFonts.begin(); it != end; ++it)
- delete it->second;
-}
-
-inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1,
- const FntParams& f2) const
-{
- int comp = f1.name.compare(f2.name);
- if (comp < 0)
- return true;
- else if (comp > 0)
- return false;
- if (f1.size < f2.size)
- return true;
- else if (f1.size > f2.size)
- return false;
- return f1.slant < f2.slant;
-}
-
-struct FGFontCache::fnt *
-FGFontCache::getfnt(const char *name, float size, float slant)
-{
- string fontName = boost::to_lower_copy(string(name));
- FntParams fntParams(fontName, size, slant);
- PuFontMap::iterator i = _puFonts.find(fntParams);
- if (i != _puFonts.end()) {
- // found in the puFonts map, all done
- return i->second;
- }
-
- // fntTexFont s are all preloaded into the _texFonts map
- TexFontMap::iterator texi = _texFonts.find(fontName);
- fntTexFont* texfont = NULL;
- puFont* pufont = NULL;
- if (texi != _texFonts.end()) {
- texfont = texi->second;
- } else {
- // check the built-in PUI fonts (in guifonts array)
- const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
- GuiFont::Predicate(name));
- if (guifont != guifontsEnd) {
- pufont = guifont->font;
- }
- }
-
- fnt* f = new fnt;
- if (pufont) {
- f->pufont = pufont;
- } else if (texfont) {
- f->texfont = texfont;
- f->pufont = new puFont;
- f->pufont->initialize(static_cast<fntFont *>(f->texfont), size, slant);
- } else {
- f->pufont = guifonts[0].font;
- }
- _puFonts[fntParams] = f;
- return f;
-}
-
-puFont *
-FGFontCache::get(const char *name, float size, float slant)
-{
- return getfnt(name, size, slant)->pufont;
-}
-
-fntTexFont *
-FGFontCache::getTexFont(const char *name, float size, float slant)
-{
- return getfnt(name, size, slant)->texfont;
-}
-
-puFont *
-FGFontCache::get(SGPropertyNode *node)
-{
- if (!node)
- return get("Helvetica.txf", 15.0, 0.0);
-
- const char *name = node->getStringValue("name", "Helvetica.txf");
- float size = node->getFloatValue("size", 15.0);
- float slant = node->getFloatValue("slant", 0.0);
-
- return get(name, size, slant);
-}
-
-void FGFontCache::init()
-{
- if (_initialized) {
- return;
- }
-
- char *envp = ::getenv("FG_FONTS");
- if (envp != NULL) {
- _path.set(envp);
- } else {
- _path.set(globals->get_fg_root());
- _path.append("Fonts");
- }
- _initialized = true;
-}
-
-SGPath
-FGFontCache::getfntpath(const char *name)
-{
- init();
- SGPath path(_path);
- if (name && std::string(name) != "") {
- path.append(name);
- if (path.exists())
- return path;
- }
-
- path = SGPath(_path);
- path.append("Helvetica.txf");
- SG_LOG(SG_GENERAL, SG_WARN, "Unknown font name '" << name << "', defaulting to Helvetica");
- return path;
-}
-
-bool FGFontCache::initializeFonts()
-{
- static string fontext("txf");
- init();
- ulDir* fontdir = ulOpenDir(_path.c_str());
- if (!fontdir)
- return false;
- const ulDirEnt *dirEntry;
- while ((dirEntry = ulReadDir(fontdir)) != 0) {
- SGPath path(_path);
- path.append(dirEntry->d_name);
- if (path.extension() == fontext) {
- fntTexFont* f = new fntTexFont;
- if (f->load((char *)path.c_str())) {
- // convert font names in the map to lowercase for matching
- string fontName = boost::to_lower_copy(string(dirEntry->d_name));
- _texFonts[fontName] = f;
- } else
- delete f;
- }
- }
- ulCloseDir(fontdir);
- return true;
-}
-
// end of new_gui.cxx