]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
Fix windows build
[flightgear.git] / src / GUI / new_gui.cxx
1 // new_gui.cxx: implementation of XML-configurable GUI support.
2
3 #ifdef HAVE_CONFIG_H
4 #  include <config.h>
5 #endif
6
7 #include "new_gui.hxx"
8
9 #include <algorithm>
10 #include <iostream>
11 #include <cstring>
12 #include <sys/types.h>
13
14 #include <plib/pu.h>
15
16 #include <simgear/compiler.h>
17 #include <simgear/structure/exception.hxx>
18 #include <simgear/props/props_io.hxx>
19 #include <simgear/misc/sg_dir.hxx>
20
21 #include <boost/algorithm/string/case_conv.hpp>
22 #include <boost/foreach.hpp>
23
24 #include <Main/fg_props.hxx>
25
26 #if defined(SG_UNIX) && !defined(SG_MAC) 
27 #include "GL/glx.h"
28 #endif
29
30 #include "FGPUIMenuBar.hxx"
31
32 #if defined(SG_MAC)
33 #include "FGCocoaMenuBar.hxx"
34 #endif
35
36 #include "FGPUIDialog.hxx"
37 #include "FGFontCache.hxx"
38 #include "FGColor.hxx"
39
40 // ignore the word Navaid here, it's a DataCache
41 #include <Navaids/NavDataCache.hxx>
42
43 using std::map;
44 using std::string;
45
46 ////////////////////////////////////////////////////////////////////////
47 // Implementation of NewGUI.
48 ////////////////////////////////////////////////////////////////////////
49
50
51
52 NewGUI::NewGUI () :
53   _active_dialog(0)
54 {
55 #if defined(SG_MAC)
56     if (fgGetBool("/sim/menubar/native", true)) {
57         _menubar.reset(new FGCocoaMenuBar);
58         return;
59     }
60 #endif
61   _menubar.reset(new FGPUIMenuBar);
62 }
63
64 NewGUI::~NewGUI ()
65 {
66     _dialog_props.clear();
67     for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
68         delete it->second;
69 }
70
71 void
72 NewGUI::init ()
73 {
74     setStyle();
75     SGPath p(globals->get_fg_root(), "gui/dialogs");
76     readDir(p);
77     const std::string aircraft_dir(fgGetString("/sim/aircraft-dir"));
78     readDir( SGPath(aircraft_dir, "gui/dialogs") );
79     _menubar->init();
80 }
81
82 void
83 NewGUI::reinit ()
84 {
85     reset(true);
86     fgSetBool("/sim/signals/reinit-gui", true);
87 }
88
89 void
90 NewGUI::redraw ()
91 {
92     reset(false);
93 }
94
95 void
96 NewGUI::reset (bool reload)
97 {
98     map<string,FGDialog *>::iterator iter;
99     string_list openDialogs;
100     // close all open dialogs and remember them ...
101     for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
102         openDialogs.push_back(iter->first);
103
104     BOOST_FOREACH(string d, openDialogs)
105         closeDialog(d);
106
107     setStyle();
108
109     unbind();
110 #if !defined(SG_MAC)
111     _menubar.reset(new FGPUIMenuBar);
112 #endif
113
114     if (reload) {
115         _dialog_props.clear();
116         _dialog_names.clear();
117         init();
118     } else {
119         _menubar->init();
120     }
121
122     bind();
123
124     // open dialogs again
125     BOOST_FOREACH(string d, openDialogs)
126         showDialog(d);
127 }
128
129 void
130 NewGUI::bind ()
131 {
132     fgTie("/sim/menubar/visibility", this,
133           &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
134 }
135
136 void
137 NewGUI::unbind ()
138 {
139     fgUntie("/sim/menubar/visibility");
140 }
141
142 void
143 NewGUI::update (double delta_time_sec)
144 {
145     SG_UNUSED(delta_time_sec);
146     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
147     for(/**/; iter != _active_dialogs.end(); iter++)
148         iter->second->update();
149 }
150
151 bool
152 NewGUI::showDialog (const string &name)
153 {
154     // first, check if it's already shown
155     if (_active_dialogs.find(name) != _active_dialogs.end())
156       return true;
157   
158     // check we know about the dialog by name
159     if (_dialog_names.find(name) == _dialog_names.end()) {
160         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
161         return false;
162     }
163     
164     _active_dialogs[name] = new FGPUIDialog(getDialogProperties(name));
165     return true;
166 }
167
168 bool
169 NewGUI::closeActiveDialog ()
170 {
171     if (_active_dialog == 0)
172         return false;
173
174     // Kill any entries in _active_dialogs...  Is there an STL
175     // algorithm to do (delete map entries by value, not key)?  I hate
176     // the STL :) -Andy
177     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
178     for(/**/; iter != _active_dialogs.end(); iter++) {
179         if(iter->second == _active_dialog) {
180             _active_dialogs.erase(iter);
181             // iter is no longer valid
182             break;
183         }
184     }
185
186     delete _active_dialog;
187     _active_dialog = 0;
188     return true;
189 }
190
191 bool
192 NewGUI::closeDialog (const string& name)
193 {
194     if(_active_dialogs.find(name) != _active_dialogs.end()) {
195         if(_active_dialog == _active_dialogs[name])
196             _active_dialog = 0;
197         delete _active_dialogs[name];
198         _active_dialogs.erase(name);
199         return true;
200     }
201     return false; // dialog wasn't open...
202 }
203
204 SGPropertyNode_ptr
205 NewGUI::getDialogProperties (const string &name)
206 {
207     if (_dialog_names.find(name) == _dialog_names.end()) {
208       SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
209       return NULL;
210     }
211   
212     NameDialogDict::iterator it = _dialog_props.find(name);
213     if (it == _dialog_props.end()) {
214       // load the XML
215       SGPath path = _dialog_names[name];
216       SGPropertyNode_ptr props = new SGPropertyNode;
217       try {
218         readProperties(path.str(), props);
219       } catch (const sg_exception &) {
220         SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << path);
221         return NULL;
222       }
223       
224       it = _dialog_props.insert(it, std::make_pair(name, props));
225     }
226
227     return it->second;
228 }
229
230 FGDialog *
231 NewGUI::getDialog (const string &name)
232 {
233     if(_active_dialogs.find(name) != _active_dialogs.end())
234         return _active_dialogs[name];
235
236     SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing");
237     return 0;
238 }
239
240 void
241 NewGUI::setActiveDialog (FGDialog * dialog)
242 {
243     _active_dialog = dialog;
244 }
245
246 FGDialog *
247 NewGUI::getActiveDialog ()
248 {
249     return _active_dialog;
250 }
251
252 FGMenuBar *
253 NewGUI::getMenuBar ()
254 {
255     return _menubar.get();
256 }
257
258 bool
259 NewGUI::getMenuBarVisible () const
260 {
261     return _menubar->isVisible();
262 }
263
264 void
265 NewGUI::setMenuBarVisible (bool visible)
266 {
267     if (visible)
268         _menubar->show();
269     else
270         _menubar->hide();
271 }
272
273 void
274 NewGUI::newDialog (SGPropertyNode* props)
275 {
276     const char* cname = props->getStringValue("name");
277     if(!cname) {
278         SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no <name> property");
279         return;
280     }
281     string name = cname;
282   
283     if(_active_dialogs.find(name) == _active_dialogs.end()) {
284         _dialog_props[name] = props;
285     // add a dummy path entry, so we believe the dialog exists
286         _dialog_names[name] = SGPath();
287     }
288 }
289
290 void
291 NewGUI::readDir (const SGPath& path)
292 {
293     flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
294     flightgear::NavDataCache::Transaction txn(cache);
295     simgear::Dir dir(path);
296     simgear::PathList xmls = dir.children(simgear::Dir::TYPE_FILE, ".xml");
297     
298     BOOST_FOREACH(SGPath xmlPath, xmls) {
299       if (!cache->isCachedFileModified(xmlPath)) {
300         // cached, easy
301         string name = cache->readStringProperty(xmlPath.str());
302         _dialog_names[name] = xmlPath;
303         continue;
304       }
305       
306     // we need to parse the actual XML
307       SGPropertyNode_ptr props = new SGPropertyNode;
308       try {
309         readProperties(xmlPath.str(), props);
310       } catch (const sg_exception &) {
311         SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << xmlPath);
312         continue;
313       }
314       
315       SGPropertyNode *nameprop = props->getNode("name");
316       if (!nameprop) {
317         SG_LOG(SG_INPUT, SG_WARN, "dialog " << xmlPath << " has no name; skipping.");
318         continue;
319       }
320       
321       string name = nameprop->getStringValue();
322       _dialog_names[name] = xmlPath;
323     // update cached values
324       cache->stampCacheFile(xmlPath);
325       cache->writeStringProperty(xmlPath.str(), name);
326     } // of directory children iteration
327   
328     txn.commit();
329 }\f
330 ////////////////////////////////////////////////////////////////////////
331 // Style handling.
332 ////////////////////////////////////////////////////////////////////////
333
334 void
335 NewGUI::setStyle (void)
336 {
337     _itt_t it;
338     for (it = _colors.begin(); it != _colors.end(); ++it)
339       delete it->second;
340     _colors.clear();
341
342     // set up the traditional colors as default
343     _colors["background"] = new FGColor(0.8f, 0.8f, 0.9f, 0.85f);
344     _colors["foreground"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
345     _colors["highlight"]  = new FGColor(0.7f, 0.7f, 0.7f, 1.0f);
346     _colors["label"]      = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
347     _colors["legend"]     = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
348     _colors["misc"]       = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
349     _colors["inputfield"] = new FGColor(0.8f, 0.7f, 0.7f, 1.0f);
350
351     //puSetDefaultStyle();
352
353     int which = fgGetInt("/sim/gui/current-style", 0);
354     SGPropertyNode *sim = globals->get_props()->getNode("sim/gui", true);
355     SGPropertyNode *n = sim->getChild("style", which);
356     if (!n)
357         n = sim->getChild("style", 0, true);
358
359     setupFont(n->getNode("fonts/gui", true));
360     n = n->getNode("colors", true);
361
362     for (int i = 0; i < n->nChildren(); i++) {
363         SGPropertyNode *child = n->getChild(i);
364         _colors[child->getName()] = new FGColor(child);
365     }
366
367     FGColor *c = _colors["background"];
368     puSetDefaultColourScheme(c->red(), c->green(), c->blue(), c->alpha());
369 }
370
371
372 void
373 NewGUI::setupFont (SGPropertyNode *node)
374 {
375     _font = globals->get_fontcache()->get(node);
376     puSetDefaultFonts(*_font, *_font);
377     return;
378 }
379
380 // end of new_gui.cxx