X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FGUI%2Fnew_gui.cxx;h=bb8eb52dba624941d88c664b9c1f198935811ff4;hb=4befe0e6ea6b5f21119364f1175a0b6c8e97395c;hp=b17c0b021d10cd4fd84a5fb0e0ac056be5ea5450;hpb=2a0fcea8a53415407abcf22da5cf029b867becb9;p=flightgear.git diff --git a/src/GUI/new_gui.cxx b/src/GUI/new_gui.cxx index b17c0b021..bb8eb52db 100644 --- a/src/GUI/new_gui.cxx +++ b/src/GUI/new_gui.cxx @@ -1,48 +1,65 @@ // new_gui.cxx: implementation of XML-configurable GUI support. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "new_gui.hxx" + #include #include #include #include -#include - -#include "new_gui.hxx" #include -#include #include #include #include +#include #include +#include #include
-#include "menubar.hxx" -#include "dialog.hxx" +#if defined(SG_UNIX) && !defined(SG_MAC) +#include "GL/glx.h" +#endif + +#include "FGPUIMenuBar.hxx" + +#if defined(SG_MAC) +#include "FGCocoaMenuBar.hxx" +#endif + +#if defined(SG_WINDOWS) +#include "FGWindowsMenuBar.hxx" +#endif -extern puFont FONT_HELVETICA_14; -extern puFont FONT_SANS_12B; +#include "FGPUIDialog.hxx" +#include "FGFontCache.hxx" +#include "FGColor.hxx" +// ignore the word Navaid here, it's a DataCache +#include +using std::map; +using std::string; - //////////////////////////////////////////////////////////////////////// // 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; } @@ -50,15 +67,38 @@ NewGUI::~NewGUI () void NewGUI::init () { + createMenuBarImplementation(); + fgTie("/sim/menubar/visibility", this, + &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible); + setStyle(); - char path1[1024]; - char path2[1024]; - ulMakePath(path1, globals->get_fg_root().c_str(), "gui"); - ulMakePath(path2, path1, "dialogs"); - readDir(path2); + 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 () { @@ -72,55 +112,72 @@ NewGUI::redraw () 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::iterator iter; - vector 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::iterator iter = _active_dialogs.begin(); for(/**/; iter != _active_dialogs.end(); iter++) iter->second->update(); @@ -129,14 +186,18 @@ NewGUI::update (double delta_time_sec) 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 @@ -178,11 +239,27 @@ NewGUI::closeDialog (const string& name) 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 * @@ -210,7 +287,7 @@ NewGUI::getActiveDialog () FGMenuBar * NewGUI::getMenuBar () { - return _menubar; + return _menubar.get(); } bool @@ -228,19 +305,6 @@ NewGUI::setMenuBarVisible (bool visible) _menubar->hide(); } -static bool -test_extension (const char * path, const char * ext) -{ - int pathlen = strlen(path); - int extlen = strlen(ext); - - for (int i = 1; i <= pathlen && i <= extlen; i++) { - if (path[pathlen-i] != ext[extlen-i]) - return false; - } - return true; -} - void NewGUI::newDialog (SGPropertyNode* props) { @@ -250,58 +314,62 @@ NewGUI::newDialog (SGPropertyNode* props) 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 char * path) +NewGUI::readDir (const SGPath& path) { - ulDir * dir = ulOpenDir(path); - - if (dir == 0) { - SG_LOG(SG_GENERAL, SG_ALERT, "Failed to read GUI files from " - << path); - return; + simgear::Dir dir(path); + if( !dir.exists() ) + { + SG_LOG(SG_INPUT, SG_INFO, "directory does not exist: " << path.str()); + return; } - for (ulDirEnt * dirEnt = ulReadDir(dir); - dirEnt != 0; - dirEnt = ulReadDir(dir)) { - - char subpath[1024]; - - ulMakePath(subpath, path, dirEnt->d_name); - - if (!dirEnt->d_isdir && test_extension(subpath, ".xml")) { - SGPropertyNode * props = new SGPropertyNode; - try { - readProperties(subpath, props); - } catch (const sg_exception &) { - SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " - << subpath); - delete props; - continue; - } - SGPropertyNode *nameprop = props->getNode("name"); - if (!nameprop) { - SG_LOG(SG_INPUT, SG_WARN, "dialog " << subpath - << " has no name; skipping."); - delete props; - continue; - } - string name = nameprop->getStringValue(); - if (_dialog_props[name]) - delete (SGPropertyNode *)_dialog_props[name]; - - _dialog_props[name] = props; + flightgear::NavDataCache* cache = flightgear::NavDataCache::instance(); + flightgear::NavDataCache::Transaction txn(cache); + simgear::PathList xmls = dir.children(simgear::Dir::TYPE_FILE, ".xml"); + + 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(xmlPath.str(), props); + } catch (const sg_exception &) { + 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 " << xmlPath << " has no name; skipping."); + continue; + } + + string name = nameprop->getStringValue(); + _dialog_names[name] = xmlPath; + // update cached values + if (!cache->isReadOnly()) { + cache->stampCacheFile(xmlPath); + cache->writeStringProperty(xmlPath.str(), name); } - } - ulCloseDir(dir); -} - - - + } // of directory children iteration + + txn.commit(); +} //////////////////////////////////////////////////////////////////////// // Style handling. //////////////////////////////////////////////////////////////////////// @@ -347,247 +415,9 @@ NewGUI::setStyle (void) void NewGUI::setupFont (SGPropertyNode *node) { - _font = globals->get_fontcache()->get(node); + _font = FGFontCache::instance()->get(node); puSetDefaultFonts(*_font, *_font); return; } - - - -//////////////////////////////////////////////////////////////////////// -// 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; -} - - - - -//////////////////////////////////////////////////////////////////////// -// FGFontCache class. -//////////////////////////////////////////////////////////////////////// - -namespace -{ -struct GuiFont -{ - const char *name; - puFont *font; - struct Predicate - : public std::unary_function - { - 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() -{ - 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(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