]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
From TomG - support per-aircraft GUI dialogs a little easier.
[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
23 #include <Main/fg_props.hxx>
24
25 #if defined(SG_UNIX) && !defined(SG_MAC) 
26 #include "GL/glx.h"
27 #endif
28
29 #include "FGPUIMenuBar.hxx"
30
31 #if defined(SG_MAC)
32 #include "FGCocoaMenuBar.hxx"
33 #endif
34
35 #include "FGPUIDialog.hxx"
36 #include "FGFontCache.hxx"
37 #include "FGColor.hxx"
38
39 using std::map;
40 using std::string;
41
42 ////////////////////////////////////////////////////////////////////////
43 // Implementation of NewGUI.
44 ////////////////////////////////////////////////////////////////////////
45
46
47
48 NewGUI::NewGUI () :
49   _active_dialog(0)
50 {
51 #if defined(SG_MAC)
52   _menubar.reset(new FGCocoaMenuBar);
53 #else
54   _menubar.reset(new FGPUIMenuBar);
55 #endif
56 }
57
58 NewGUI::~NewGUI ()
59 {
60     _dialog_props.clear();
61     for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
62         delete it->second;
63 }
64
65 void
66 NewGUI::init ()
67 {
68     setStyle();
69     SGPath p(globals->get_fg_root(), "gui/dialogs");
70     readDir(p);
71     const std::string aircraft_dir(fgGetString("/sim/aircraft-dir"));
72     readDir( SGPath(aircraft_dir, "gui/dialogs") );
73     _menubar->init();
74 }
75
76 void
77 NewGUI::reinit ()
78 {
79     reset(true);
80     fgSetBool("/sim/signals/reinit-gui", true);
81 }
82
83 void
84 NewGUI::redraw ()
85 {
86     reset(false);
87 }
88
89 void
90 NewGUI::reset (bool reload)
91 {
92     map<string,FGDialog *>::iterator iter;
93     std::vector<string> dlg;
94     // close all open dialogs and remember them ...
95     for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
96         dlg.push_back(iter->first);
97
98     unsigned int i;
99     for (i = 0; i < dlg.size(); i++)
100         closeDialog(dlg[i]);
101
102     setStyle();
103
104     unbind();
105 #if !defined(SG_MAC)
106     _menubar.reset(new FGPUIMenuBar);
107 #endif
108
109     if (reload) {
110         _dialog_props.clear();
111         init();
112     } else {
113         _menubar->init();
114     }
115
116     bind();
117
118     // open dialogs again
119     for (i = 0; i < dlg.size(); i++)
120         showDialog(dlg[i]);
121 }
122
123 void
124 NewGUI::bind ()
125 {
126     fgTie("/sim/menubar/visibility", this,
127           &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
128 }
129
130 void
131 NewGUI::unbind ()
132 {
133     fgUntie("/sim/menubar/visibility");
134 }
135
136 void
137 NewGUI::update (double delta_time_sec)
138 {
139     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
140     for(/**/; iter != _active_dialogs.end(); iter++)
141         iter->second->update();
142 }
143
144 bool
145 NewGUI::showDialog (const string &name)
146 {
147     if (_dialog_props.find(name) == _dialog_props.end()) {
148         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
149         return false;
150     } else {
151         if(!_active_dialogs[name])
152             _active_dialogs[name] = new FGPUIDialog(_dialog_props[name]);
153         return true;
154     }
155 }
156
157 bool
158 NewGUI::closeActiveDialog ()
159 {
160     if (_active_dialog == 0)
161         return false;
162
163     // Kill any entries in _active_dialogs...  Is there an STL
164     // algorithm to do (delete map entries by value, not key)?  I hate
165     // the STL :) -Andy
166     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
167     for(/**/; iter != _active_dialogs.end(); iter++) {
168         if(iter->second == _active_dialog) {
169             _active_dialogs.erase(iter);
170             // iter is no longer valid
171             break;
172         }
173     }
174
175     delete _active_dialog;
176     _active_dialog = 0;
177     return true;
178 }
179
180 bool
181 NewGUI::closeDialog (const string& name)
182 {
183     if(_active_dialogs.find(name) != _active_dialogs.end()) {
184         if(_active_dialog == _active_dialogs[name])
185             _active_dialog = 0;
186         delete _active_dialogs[name];
187         _active_dialogs.erase(name);
188         return true;
189     }
190     return false; // dialog wasn't open...
191 }
192
193 SGPropertyNode_ptr
194 NewGUI::getDialogProperties (const string &name)
195 {
196     if(_dialog_props.find(name) != _dialog_props.end())
197         return _dialog_props[name];
198
199     SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing");
200     return 0;
201 }
202
203 FGDialog *
204 NewGUI::getDialog (const string &name)
205 {
206     if(_active_dialogs.find(name) != _active_dialogs.end())
207         return _active_dialogs[name];
208
209     SG_LOG(SG_GENERAL, SG_DEBUG, "dialog '" << name << "' missing");
210     return 0;
211 }
212
213 void
214 NewGUI::setActiveDialog (FGDialog * dialog)
215 {
216     _active_dialog = dialog;
217 }
218
219 FGDialog *
220 NewGUI::getActiveDialog ()
221 {
222     return _active_dialog;
223 }
224
225 FGMenuBar *
226 NewGUI::getMenuBar ()
227 {
228     return _menubar.get();
229 }
230
231 bool
232 NewGUI::getMenuBarVisible () const
233 {
234     return _menubar->isVisible();
235 }
236
237 void
238 NewGUI::setMenuBarVisible (bool visible)
239 {
240     if (visible)
241         _menubar->show();
242     else
243         _menubar->hide();
244 }
245
246 void
247 NewGUI::newDialog (SGPropertyNode* props)
248 {
249     const char* cname = props->getStringValue("name");
250     if(!cname) {
251         SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no <name> property");
252         return;
253     }
254     string name = cname;
255     if(_active_dialogs.find(name) == _active_dialogs.end())
256         _dialog_props[name] = props;
257 }
258
259 void
260 NewGUI::readDir (const SGPath& path)
261 {
262     simgear::Dir dir(path);
263     simgear::PathList xmls = dir.children(simgear::Dir::TYPE_FILE, ".xml");
264     
265     for (unsigned int i=0; i<xmls.size(); ++i) {
266       SGPropertyNode * props = new SGPropertyNode;
267       try {
268           readProperties(xmls[i].str(), props);
269       } catch (const sg_exception &) {
270           SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog "
271                  << xmls[i].str());
272           delete props;
273           continue;
274       }
275       SGPropertyNode *nameprop = props->getNode("name");
276       if (!nameprop) {
277           SG_LOG(SG_INPUT, SG_WARN, "dialog " << xmls[i].str()
278              << " has no name; skipping.");
279           delete props;
280           continue;
281       }
282       string name = nameprop->getStringValue();
283       _dialog_props[name] = props;
284     }
285 }
286
287
288 \f
289 ////////////////////////////////////////////////////////////////////////
290 // Style handling.
291 ////////////////////////////////////////////////////////////////////////
292
293 void
294 NewGUI::setStyle (void)
295 {
296     _itt_t it;
297     for (it = _colors.begin(); it != _colors.end(); ++it)
298       delete it->second;
299     _colors.clear();
300
301     // set up the traditional colors as default
302     _colors["background"] = new FGColor(0.8f, 0.8f, 0.9f, 0.85f);
303     _colors["foreground"] = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
304     _colors["highlight"]  = new FGColor(0.7f, 0.7f, 0.7f, 1.0f);
305     _colors["label"]      = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
306     _colors["legend"]     = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
307     _colors["misc"]       = new FGColor(0.0f, 0.0f, 0.0f, 1.0f);
308     _colors["inputfield"] = new FGColor(0.8f, 0.7f, 0.7f, 1.0f);
309
310     //puSetDefaultStyle();
311
312     int which = fgGetInt("/sim/gui/current-style", 0);
313     SGPropertyNode *sim = globals->get_props()->getNode("sim/gui", true);
314     SGPropertyNode *n = sim->getChild("style", which);
315     if (!n)
316         n = sim->getChild("style", 0, true);
317
318     setupFont(n->getNode("fonts/gui", true));
319     n = n->getNode("colors", true);
320
321     for (int i = 0; i < n->nChildren(); i++) {
322         SGPropertyNode *child = n->getChild(i);
323         _colors[child->getName()] = new FGColor(child);
324     }
325
326     FGColor *c = _colors["background"];
327     puSetDefaultColourScheme(c->red(), c->green(), c->blue(), c->alpha());
328 }
329
330
331 void
332 NewGUI::setupFont (SGPropertyNode *node)
333 {
334     _font = globals->get_fontcache()->get(node);
335     puSetDefaultFonts(*_font, *_font);
336     return;
337 }
338
339 // end of new_gui.cxx