X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FGUI%2Fnew_gui.cxx;h=ff9c7ad3c337c370a9ed1d79f66e50589fb83778;hb=5cad5aa7da2476ca8323a61f81dea59676dca085;hp=63f41cba969ed3dc994eedf5b7233f6b6ee30a07;hpb=ea24640f9654883f4fabdb25ddbae9beef71df85;p=flightgear.git diff --git a/src/GUI/new_gui.cxx b/src/GUI/new_gui.cxx index 63f41cba9..ff9c7ad3c 100644 --- a/src/GUI/new_gui.cxx +++ b/src/GUI/new_gui.cxx @@ -1,4 +1,9 @@ // new_gui.cxx: implementation of XML-configurable GUI support. +#include +#include +#include +#include +#include #include "new_gui.hxx" @@ -6,13 +11,18 @@ #include #include -#include +#include +#include + #include
#include "menubar.hxx" #include "dialog.hxx" -SG_USING_STD(map); +extern puFont FONT_HELVETICA_14; +extern puFont FONT_SANS_12B; + + //////////////////////////////////////////////////////////////////////// @@ -20,6 +30,7 @@ SG_USING_STD(map); //////////////////////////////////////////////////////////////////////// + NewGUI::NewGUI () : _menubar(new FGMenuBar), _active_dialog(0) @@ -28,12 +39,16 @@ NewGUI::NewGUI () NewGUI::~NewGUI () { - clear(); + delete _menubar; + _dialog_props.clear(); + for (_itt_t it = _colors.begin(); it != _colors.end(); ++it) + delete it->second; } void NewGUI::init () { + setStyle(); char path1[1024]; char path2[1024]; ulMakePath(path1, globals->get_fg_root().c_str(), "gui"); @@ -45,11 +60,47 @@ NewGUI::init () void NewGUI::reinit () { + reset(true); + fgSetBool("/sim/signals/reinit-gui", true); +} + +void +NewGUI::redraw () +{ + reset(false); +} + +void +NewGUI::reset (bool reload) +{ + map::iterator iter; + vector dlg; + // close all open dialogs and remember them ... + for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter) + dlg.push_back(iter->first); + + unsigned int i; + for (i = 0; i < dlg.size(); i++) + closeDialog(dlg[i]); + + setStyle(); + unbind(); - clear(); + delete _menubar; _menubar = new FGMenuBar; - init(); + + if (reload) { + _dialog_props.clear(); + init(); + } else { + _menubar->init(); + } + bind(); + + // open dialogs again + for (i = 0; i < dlg.size(); i++) + showDialog(dlg[i]); } void @@ -68,7 +119,9 @@ NewGUI::unbind () void NewGUI::update (double delta_time_sec) { - // NO OP + map::iterator iter = _active_dialogs.begin(); + for(/**/; iter != _active_dialogs.end(); iter++) + iter->second->update(); } bool @@ -78,7 +131,8 @@ NewGUI::showDialog (const string &name) SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined"); return false; } else { - new FGDialog(_dialog_props[name]); // it will be deleted by a callback + if(!_active_dialogs[name]) + _active_dialogs[name] = new FGDialog(_dialog_props[name]); return true; } } @@ -86,13 +140,57 @@ NewGUI::showDialog (const string &name) bool NewGUI::closeActiveDialog () { - if (_active_dialog == 0) { + if (_active_dialog == 0) return false; - } else { - delete _active_dialog; - _active_dialog = 0; + + // Kill any entries in _active_dialogs... Is there an STL + // algorithm to do (delete map entries by value, not key)? I hate + // the STL :) -Andy + map::iterator iter = _active_dialogs.begin(); + for(/**/; iter != _active_dialogs.end(); iter++) { + if(iter->second == _active_dialog) { + _active_dialogs.erase(iter); + // iter is no longer valid + break; + } + } + + delete _active_dialog; + _active_dialog = 0; + return true; +} + +bool +NewGUI::closeDialog (const string& name) +{ + if(_active_dialogs.find(name) != _active_dialogs.end()) { + if(_active_dialog == _active_dialogs[name]) + _active_dialog = 0; + delete _active_dialogs[name]; + _active_dialogs.erase(name); return true; } + return false; // dialog wasn't open... +} + +SGPropertyNode_ptr +NewGUI::getDialogProperties (const string &name) +{ + if(_dialog_props.find(name) != _dialog_props.end()) + return _dialog_props[name]; + + SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing"); + return 0; +} + +FGDialog * +NewGUI::getDialog (const string &name) +{ + if(_active_dialogs.find(name) != _active_dialogs.end()) + return _active_dialogs[name]; + + SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing"); + return 0; } void @@ -128,24 +226,12 @@ NewGUI::setMenuBarVisible (bool visible) _menubar->hide(); } -void -NewGUI::clear () -{ - delete _menubar; - _menubar = 0; - - map::iterator it; - for (it = _dialog_props.begin(); it != _dialog_props.end(); it++) - delete it->second; - _dialog_props.clear(); -} - 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; @@ -153,6 +239,19 @@ test_extension (const char * path, const char * ext) return true; } +void +NewGUI::newDialog (SGPropertyNode* props) +{ + const char* cname = props->getStringValue("name"); + if(!cname) { + SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no property"); + return; + } + string name = cname; + if(_active_dialogs.find(name) == _active_dialogs.end()) + _dialog_props[name] = props; +} + void NewGUI::readDir (const char * path) { @@ -176,26 +275,308 @@ NewGUI::readDir (const char * path) SGPropertyNode * props = new SGPropertyNode; try { readProperties(subpath, props); - } catch (const sg_exception &ex) { + } catch (const sg_exception &) { SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << subpath); delete props; continue; } - if (!props->hasValue("name")) { + SGPropertyNode *nameprop = props->getNode("name"); + if (!nameprop) { SG_LOG(SG_INPUT, SG_WARN, "dialog " << subpath << " has no name; skipping."); delete props; continue; } - string name = props->getStringValue("name"); - SG_LOG(SG_INPUT, SG_BULK, "Saving dialog " << name); - if (_dialog_props[name] != 0) - delete _dialog_props[name]; + string name = nameprop->getStringValue(); + if (_dialog_props[name]) + delete (SGPropertyNode *)_dialog_props[name]; + _dialog_props[name] = props; } } ulCloseDir(dir); } + + +//////////////////////////////////////////////////////////////////////// +// Style handling. +//////////////////////////////////////////////////////////////////////// + +void +NewGUI::setStyle (void) +{ + _itt_t it; + for (it = _colors.begin(); it != _colors.end(); ++it) + delete it->second; + _colors.clear(); + + // set up the traditional colors as default + _colors["background"] = new FGColor(0.8f, 0.8f, 0.9f, 0.85f); + _colors["foreground"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f); + _colors["highlight"] = new FGColor(0.7f, 0.7f, 0.7f, 1.0f); + _colors["label"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f); + _colors["legend"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f); + _colors["misc"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f); + _colors["inputfield"] = new FGColor(0.8f, 0.7f, 0.7f, 1.0f); + + //puSetDefaultStyle(); + + int which = fgGetInt("/sim/gui/current-style", 0); + SGPropertyNode *sim = globals->get_props()->getNode("sim/gui", true); + SGPropertyNode *n = sim->getChild("style", which); + if (!n) + n = sim->getChild("style", 0, true); + + setupFont(n->getNode("fonts/gui", true)); + n = n->getNode("colors", true); + + for (int i = 0; i < n->nChildren(); i++) { + SGPropertyNode *child = n->getChild(i); + _colors[child->getName()] = new FGColor(child); + } + + FGColor *c = _colors["background"]; + puSetDefaultColourScheme(c->red(), c->green(), c->blue(), c->alpha()); +} + + +void +NewGUI::setupFont (SGPropertyNode *node) +{ + _font = globals->get_fontcache()->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(name); + FntParams fntParams(fontName, size, slant); + PuFontMap::iterator i = _puFonts.find(fntParams); + if (i != _puFonts.end()) + return i->second; + // fntTexFont s are all preloaded into the _texFonts map + TexFontMap::iterator texi = _texFonts.find(fontName); + fntTexFont* texfont = 0; + puFont* pufont = 0; + if (texi != _texFonts.end()) { + texfont = texi->second; + } else { + 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) { + 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"); + + 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())) + _texFonts[string(dirEntry->d_name)] = f; + else + delete f; + } + } + ulCloseDir(fontdir); + return true; +} + // end of new_gui.cxx