]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
rename VERA_12B font to SANS_12B (as in sans-serif). This is a "Grotesk"
[flightgear.git] / src / GUI / new_gui.cxx
1 // new_gui.cxx: implementation of XML-configurable GUI support.
2
3 #include "new_gui.hxx"
4
5 #include <plib/pu.h>
6 #include <plib/ul.h>
7
8 #include <simgear/compiler.h>
9 #include <simgear/structure/exception.hxx>
10
11 #include <Main/fg_props.hxx>
12
13 #include "menubar.hxx"
14 #include "dialog.hxx"
15
16 SG_USING_STD(map);
17
18 extern puFont FONT_HELVETICA_14;
19 extern puFont FONT_SANS_12B;
20
21
22
23 \f
24 ////////////////////////////////////////////////////////////////////////
25 // Implementation of NewGUI.
26 ////////////////////////////////////////////////////////////////////////
27
28
29
30 NewGUI::NewGUI ()
31     : _font(FONT_HELVETICA_14),
32       _menubar(new FGMenuBar),
33       _active_dialog(0)
34 {
35     // set up the traditional colors as default
36     _colors["background"] = FGColor(0.8f, 0.8f, 0.9f, 0.85f);
37     _colors["foreground"] = FGColor(0.0f, 0.0f, 0.0f, 1.0f);
38     _colors["highlight"]  = FGColor(0.7f, 0.7f, 0.7f, 1.0f);
39     _colors["label"]      = FGColor(0.0f, 0.0f, 0.0f, 1.0f);
40     _colors["legend"]     = FGColor(0.0f, 0.0f, 0.0f, 1.0f);
41     _colors["misc"]       = FGColor(0.0f, 0.0f, 0.0f, 1.0f);
42
43     setStyle();
44 }
45
46 NewGUI::~NewGUI ()
47 {
48     clear();
49 }
50
51 void
52 NewGUI::init ()
53 {
54     char path1[1024];
55     char path2[1024];
56     ulMakePath(path1, globals->get_fg_root().c_str(), "gui");
57     ulMakePath(path2, path1, "dialogs");
58     readDir(path2);
59     _menubar->init();
60 }
61
62 void
63 NewGUI::reinit ()
64 {
65     map<string,FGDialog *>::iterator iter;
66     vector<string> dlg;
67     // close all open dialogs and remember them ...
68     for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); iter++) {
69         dlg.push_back(iter->first);
70         closeDialog(iter->first);
71     }
72
73     unbind();
74     clear();
75     setStyle();
76     _menubar = new FGMenuBar;
77     init();
78     bind();
79
80     // open remembered dialogs again (no nasal generated ones, unfortunately)
81     for (unsigned int i = 0; i < dlg.size(); i++)
82         showDialog(dlg[i]);
83 }
84
85 void
86 NewGUI::bind ()
87 {
88     fgTie("/sim/menubar/visibility", this,
89           &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
90 }
91
92 void
93 NewGUI::unbind ()
94 {
95     fgUntie("/sim/menubar/visibility");
96 }
97
98 void
99 NewGUI::update (double delta_time_sec)
100 {
101     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
102     for(/**/; iter != _active_dialogs.end(); iter++)
103         iter->second->update();
104 }
105
106 bool
107 NewGUI::showDialog (const string &name)
108 {
109     if (_dialog_props.find(name) == _dialog_props.end()) {
110         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
111         return false;
112     } else {
113         if(!_active_dialogs[name])
114             _active_dialogs[name] = new FGDialog(_dialog_props[name]);
115         return true;
116     }
117 }
118
119 bool
120 NewGUI::closeActiveDialog ()
121 {
122     if (_active_dialog == 0)
123         return false;
124
125     // Kill any entries in _active_dialogs...  Is there an STL
126     // algorithm to do (delete map entries by value, not key)?  I hate
127     // the STL :) -Andy
128     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
129     for(/**/; iter != _active_dialogs.end(); iter++) {
130         if(iter->second == _active_dialog) {
131             _active_dialogs.erase(iter);
132             // iter is no longer valid
133             break;
134         }
135     }
136
137     delete _active_dialog;
138     _active_dialog = 0;
139     return true;
140 }
141
142 bool
143 NewGUI::closeDialog (const string& name)
144 {
145     if(_active_dialogs.find(name) != _active_dialogs.end()) {
146         if(_active_dialog == _active_dialogs[name])
147             _active_dialog = 0;
148         delete _active_dialogs[name];
149         _active_dialogs.erase(name);
150         return true;
151     }
152     return false; // dialog wasn't open...
153 }
154
155 void
156 NewGUI::setActiveDialog (FGDialog * dialog)
157 {
158     _active_dialog = dialog;
159 }
160
161 FGDialog *
162 NewGUI::getActiveDialog ()
163 {
164     return _active_dialog;
165 }
166
167 FGMenuBar *
168 NewGUI::getMenuBar ()
169 {
170     return _menubar;
171 }
172
173 bool
174 NewGUI::getMenuBarVisible () const
175 {
176     return _menubar->isVisible();
177 }
178
179 void
180 NewGUI::setMenuBarVisible (bool visible)
181 {
182     if (visible)
183         _menubar->show();
184     else
185         _menubar->hide();
186 }
187
188 void
189 NewGUI::clear ()
190 {
191     delete _menubar;
192     _menubar = 0;
193     _dialog_props.clear();
194 }
195
196 static bool
197 test_extension (const char * path, const char * ext)
198 {
199     int pathlen = strlen(path);
200     int extlen = strlen(ext);
201
202     for (int i = 1; i <= pathlen && i <= extlen; i++) {
203         if (path[pathlen-i] != ext[extlen-i])
204             return false;
205     }
206     return true;
207 }
208
209 void
210 NewGUI::newDialog (SGPropertyNode* props)
211 {
212     const char* cname = props->getStringValue("name");
213     if(!cname) {
214         SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no <name> property");
215         return;
216     }
217     string name = cname;
218     if(!_active_dialogs[name])
219         _dialog_props[name] = props;
220 }
221
222 void
223 NewGUI::readDir (const char * path)
224 {
225     ulDir * dir = ulOpenDir(path);
226
227     if (dir == 0) {
228         SG_LOG(SG_GENERAL, SG_ALERT, "Failed to read GUI files from "
229                << path);
230         return;
231     }
232
233     for (ulDirEnt * dirEnt = ulReadDir(dir);
234          dirEnt != 0;
235          dirEnt = ulReadDir(dir)) {
236
237         char subpath[1024];
238
239         ulMakePath(subpath, path, dirEnt->d_name);
240
241         if (!dirEnt->d_isdir && test_extension(subpath, ".xml")) {
242             SGPropertyNode * props = new SGPropertyNode;
243             try {
244                 readProperties(subpath, props);
245             } catch (const sg_exception &) {
246                 SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog "
247                        << subpath);
248                 delete props;
249                 continue;
250             }
251             SGPropertyNode *nameprop = props->getNode("name");
252             if (!nameprop) {
253                 SG_LOG(SG_INPUT, SG_WARN, "dialog " << subpath
254                    << " has no name; skipping.");
255                 delete props;
256                 continue;
257             }
258             string name = nameprop->getStringValue();
259             if (_dialog_props[name])
260                 delete (SGPropertyNode *)_dialog_props[name];
261
262             _dialog_props[name] = props;
263         }
264     }
265     ulCloseDir(dir);
266 }
267
268
269 \f
270 ////////////////////////////////////////////////////////////////////////
271 // Style handling.
272 ////////////////////////////////////////////////////////////////////////
273
274 void
275 NewGUI::setStyle (void)
276 {
277     setupFont();
278
279     //puSetDefaultStyle();
280
281     SGPropertyNode *n = fgGetNode("/sim/gui/colors");
282     if (!n)
283         return;
284
285     for (int i = 0; i < n->nChildren(); i++) {
286         SGPropertyNode *child = n->getChild(i);
287         _colors[child->getName()] = FGColor(child);
288     }
289
290     FGColor c = _colors["background"];
291     puSetDefaultColourScheme(c.red(), c.green(), c.blue(), c.alpha());
292 }
293
294
295
296
297 static const struct {
298     char *name;
299     puFont *font;
300 } guifonts[] = {
301     "default",      &FONT_HELVETICA_14,
302     "FIXED_8x13",   &PUFONT_8_BY_13,
303     "FIXED_9x15",   &PUFONT_9_BY_15,
304     "TIMES_10",     &PUFONT_TIMES_ROMAN_10,
305     "TIMES_24",     &PUFONT_TIMES_ROMAN_24,
306     "HELVETICA_10", &PUFONT_HELVETICA_10,
307     "HELVETICA_12", &PUFONT_HELVETICA_12,
308     "HELVETICA_14", &FONT_HELVETICA_14,
309     "HELVETICA_18", &PUFONT_HELVETICA_18,
310     "SANS_12B",     &FONT_SANS_12B,
311     0, 0,
312 };
313
314 void
315 NewGUI::setupFont ()
316 {
317     SGPropertyNode *node = fgGetNode("/sim/gui/font", true);
318     string fontname = node->getStringValue("name", "Helvetica.txf");
319     float size = node->getFloatValue("size", 15.0);
320     float slant = node->getFloatValue("slant", 0.0);
321
322     int i;
323     for (i = 0; guifonts[i].name; i++)
324         if (fontname == guifonts[i].name)
325             break;
326     if (guifonts[i].name)
327         _font = *guifonts[i].font;
328     else {
329         SGPath fontpath;
330         char* envp = ::getenv("FG_FONTS");
331         if (envp != NULL) {
332             fontpath.set(envp);
333         } else {
334             fontpath.set(globals->get_fg_root());
335             fontpath.append("Fonts");
336         }
337
338         SGPath path(fontpath);
339         path.append(fontname);
340
341         if (_tex_font.load((char *)path.c_str())) {
342             _font.initialize((fntFont *)&_tex_font, size, slant);
343         } else {
344             _font = *guifonts[0].font;
345             fontname = "default";
346         }
347     }
348     puSetDefaultFonts(_font, _font);
349     fgSetString("/sim/gui/font", fontname.c_str());
350 }
351
352
353
354 \f
355 ////////////////////////////////////////////////////////////////////////
356 // FGColor class.
357 ////////////////////////////////////////////////////////////////////////
358
359 void
360 FGColor::merge(const SGPropertyNode *node)
361 {
362     if (!node)
363         return;
364
365     const SGPropertyNode * n;
366     if ((n = node->getNode("red")))
367         _red = n->getFloatValue();
368     if ((n = node->getNode("green")))
369         _green = n->getFloatValue();
370     if ((n = node->getNode("blue")))
371         _blue = n->getFloatValue();
372     if ((n = node->getNode("alpha")))
373         _alpha = n->getFloatValue();
374 }
375
376 void
377 FGColor::merge(const FGColor& color)
378 {
379     if (color._red >= 0.0)
380         _red = color._red;
381     if (color._green >= 0.0)
382         _green = color._green;
383     if (color._blue >= 0.0)
384         _blue = color._blue;
385     if (color._alpha >= 0.0)
386         _alpha = color._alpha;
387 }
388
389 // end of new_gui.cxx