]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
Canvas: Proper fix for OpenVG init handling.
[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     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
146     for(/**/; iter != _active_dialogs.end(); iter++)
147         iter->second->update();
148 }
149
150 bool
151 NewGUI::showDialog (const string &name)
152 {
153     // first, check if it's already shown
154     if (_active_dialogs.find(name) != _active_dialogs.end())
155       return true;
156   
157     // check we know about the dialog by name
158     if (_dialog_names.find(name) == _dialog_names.end()) {
159         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
160         return false;
161     }
162     
163     _active_dialogs[name] = new FGPUIDialog(getDialogProperties(name));
164     return true;
165 }
166
167 bool
168 NewGUI::closeActiveDialog ()
169 {
170     if (_active_dialog == 0)
171         return false;
172
173     // Kill any entries in _active_dialogs...  Is there an STL
174     // algorithm to do (delete map entries by value, not key)?  I hate
175     // the STL :) -Andy
176     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
177     for(/**/; iter != _active_dialogs.end(); iter++) {
178         if(iter->second == _active_dialog) {
179             _active_dialogs.erase(iter);
180             // iter is no longer valid
181             break;
182         }
183     }
184
185     delete _active_dialog;
186     _active_dialog = 0;
187     return true;
188 }
189
190 bool
191 NewGUI::closeDialog (const string& name)
192 {
193     if(_active_dialogs.find(name) != _active_dialogs.end()) {
194         if(_active_dialog == _active_dialogs[name])
195             _active_dialog = 0;
196         delete _active_dialogs[name];
197         _active_dialogs.erase(name);
198         return true;
199     }
200     return false; // dialog wasn't open...
201 }
202
203 SGPropertyNode_ptr
204 NewGUI::getDialogProperties (const string &name)
205 {
206     if (_dialog_names.find(name) == _dialog_names.end()) {
207       SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
208       return NULL;
209     }
210   
211     NameDialogDict::iterator it = _dialog_props.find(name);
212     if (it == _dialog_props.end()) {
213       // load the XML
214       SGPath path = _dialog_names[name];
215       SGPropertyNode_ptr props = new SGPropertyNode;
216       try {
217         readProperties(path.str(), props);
218       } catch (const sg_exception &) {
219         SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << path);
220         return NULL;
221       }
222       
223       it = _dialog_props.insert(it, std::make_pair(name, props));
224     }
225
226     return it->second;
227 }
228
229 FGDialog *
230 NewGUI::getDialog (const string &name)
231 {
232     if(_active_dialogs.find(name) != _active_dialogs.end())
233         return _active_dialogs[name];
234
235     SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing");
236     return 0;
237 }
238
239 void
240 NewGUI::setActiveDialog (FGDialog * dialog)
241 {
242     _active_dialog = dialog;
243 }
244
245 FGDialog *
246 NewGUI::getActiveDialog ()
247 {
248     return _active_dialog;
249 }
250
251 FGMenuBar *
252 NewGUI::getMenuBar ()
253 {
254     return _menubar.get();
255 }
256
257 bool
258 NewGUI::getMenuBarVisible () const
259 {
260     return _menubar->isVisible();
261 }
262
263 void
264 NewGUI::setMenuBarVisible (bool visible)
265 {
266     if (visible)
267         _menubar->show();
268     else
269         _menubar->hide();
270 }
271
272 void
273 NewGUI::newDialog (SGPropertyNode* props)
274 {
275     const char* cname = props->getStringValue("name");
276     if(!cname) {
277         SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no <name> property");
278         return;
279     }
280     string name = cname;
281   
282     if(_active_dialogs.find(name) == _active_dialogs.end()) {
283         _dialog_props[name] = props;
284     // add a dummy path entry, so we believe the dialog exists
285         _dialog_names[name] = SGPath();
286     }
287 }
288
289 void
290 NewGUI::readDir (const SGPath& path)
291 {
292     simgear::Dir dir(path);
293     simgear::PathList xmls = dir.children(simgear::Dir::TYPE_FILE, ".xml");
294     
295     flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
296     BOOST_FOREACH(SGPath xmlPath, xmls) {
297       if (!cache->isCachedFileModified(xmlPath)) {
298         // cached, easy
299         string name = cache->readStringProperty(xmlPath.str());
300         _dialog_names[name] = xmlPath;
301         continue;
302       }
303       
304     // we need to parse the actual XML
305       SGPropertyNode_ptr props = new SGPropertyNode;
306       try {
307         readProperties(xmlPath.str(), props);
308       } catch (const sg_exception &) {
309         SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog " << xmlPath);
310         continue;
311       }
312       
313       SGPropertyNode *nameprop = props->getNode("name");
314       if (!nameprop) {
315         SG_LOG(SG_INPUT, SG_WARN, "dialog " << xmlPath << " has no name; skipping.");
316         continue;
317       }
318       
319       string name = nameprop->getStringValue();
320       _dialog_names[name] = xmlPath;
321     // update cached values
322       cache->stampCacheFile(xmlPath);
323       cache->writeStringProperty(xmlPath.str(), name);
324     } // of directory children iteration
325 }\f
326 ////////////////////////////////////////////////////////////////////////
327 // Style handling.
328 ////////////////////////////////////////////////////////////////////////
329
330 void
331 NewGUI::setStyle (void)
332 {
333     _itt_t it;
334     for (it = _colors.begin(); it != _colors.end(); ++it)
335       delete it->second;
336     _colors.clear();
337
338     // set up the traditional colors as default
339     _colors["background"] = new FGColor(0.8f, 0.8f, 0.9f, 0.85f);
340     _colors["foreground"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
341     _colors["highlight"]  = new FGColor(0.7f, 0.7f, 0.7f, 1.0f);
342     _colors["label"]      = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
343     _colors["legend"]     = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
344     _colors["misc"]       = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
345     _colors["inputfield"] = new FGColor(0.8f, 0.7f, 0.7f, 1.0f);
346
347     //puSetDefaultStyle();
348
349     int which = fgGetInt("/sim/gui/current-style", 0);
350     SGPropertyNode *sim = globals->get_props()->getNode("sim/gui", true);
351     SGPropertyNode *n = sim->getChild("style", which);
352     if (!n)
353         n = sim->getChild("style", 0, true);
354
355     setupFont(n->getNode("fonts/gui", true));
356     n = n->getNode("colors", true);
357
358     for (int i = 0; i < n->nChildren(); i++) {
359         SGPropertyNode *child = n->getChild(i);
360         _colors[child->getName()] = new FGColor(child);
361     }
362
363     FGColor *c = _colors["background"];
364     puSetDefaultColourScheme(c->red(), c->green(), c->blue(), c->alpha());
365 }
366
367
368 void
369 NewGUI::setupFont (SGPropertyNode *node)
370 {
371     _font = globals->get_fontcache()->get(node);
372     puSetDefaultFonts(*_font, *_font);
373     return;
374 }
375
376 // end of new_gui.cxx