]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
Add a new command, "dialog-new", allowing external code (e.g. Nasal
[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 \f
19 ////////////////////////////////////////////////////////////////////////
20 // Implementation of NewGUI.
21 ////////////////////////////////////////////////////////////////////////
22
23
24 NewGUI::NewGUI ()
25     : _menubar(new FGMenuBar),
26       _active_dialog(0)
27 {
28 }
29
30 NewGUI::~NewGUI ()
31 {
32     clear();
33 }
34
35 void
36 NewGUI::init ()
37 {
38     char path1[1024];
39     char path2[1024];
40     ulMakePath(path1, globals->get_fg_root().c_str(), "gui");
41     ulMakePath(path2, path1, "dialogs");
42     readDir(path2);
43     _menubar->init();
44 }
45
46 void
47 NewGUI::reinit ()
48 {
49     unbind();
50     clear();
51     _menubar = new FGMenuBar;
52     init();
53     bind();
54 }
55
56 void
57 NewGUI::bind ()
58 {
59     fgTie("/sim/menubar/visibility", this,
60           &NewGUI::getMenuBarVisible, &NewGUI::setMenuBarVisible);
61 }
62
63 void
64 NewGUI::unbind ()
65 {
66     fgUntie("/sim/menubar/visibility");
67 }
68
69 void
70 NewGUI::update (double delta_time_sec)
71 {
72     // NO OP
73 }
74
75 bool
76 NewGUI::showDialog (const string &name)
77 {
78     if (_dialog_props.find(name) == _dialog_props.end()) {
79         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
80         return false;
81     } else {
82         if(!_active_dialogs[name])
83             _active_dialogs[name] = new FGDialog(_dialog_props[name]);
84         return true;
85     }
86 }
87
88 bool
89 NewGUI::closeActiveDialog ()
90 {
91     if (_active_dialog == 0)
92         return false;
93
94     // Kill any entries in _active_dialogs...  Is there an STL
95     // algorithm to do (delete map entries by value, not key)?  I hate
96     // the STL :) -Andy
97     map<string,FGDialog *>::iterator iter = _active_dialogs.begin();
98     for(/**/; iter != _active_dialogs.end(); iter++)
99         if(iter->second == _active_dialog)
100             _active_dialogs.erase(iter);
101
102     delete _active_dialog;
103     _active_dialog = 0;
104     return true;
105 }
106
107 bool
108 NewGUI::closeDialog (const string& name)
109 {
110     if(_active_dialogs.find(name) != _active_dialogs.end()) {
111         if(_active_dialog == _active_dialogs[name])
112             _active_dialog = 0;
113         delete _active_dialogs[name];
114         _active_dialogs.erase(name);
115         return true;
116     }
117     return false; // dialog wasn't open...
118 }
119
120 void
121 NewGUI::setActiveDialog (FGDialog * dialog)
122 {
123     _active_dialog = dialog;
124 }
125
126 FGDialog *
127 NewGUI::getActiveDialog ()
128 {
129     return _active_dialog;
130 }
131
132 FGMenuBar *
133 NewGUI::getMenuBar ()
134 {
135     return _menubar;
136 }
137
138 bool
139 NewGUI::getMenuBarVisible () const
140 {
141     return _menubar->isVisible();
142 }
143
144 void
145 NewGUI::setMenuBarVisible (bool visible)
146 {
147     if (visible)
148         _menubar->show();
149     else
150         _menubar->hide();
151 }
152
153 void
154 NewGUI::clear ()
155 {
156     delete _menubar;
157     _menubar = 0;
158     _dialog_props.clear();
159 }
160
161 static bool
162 test_extension (const char * path, const char * ext)
163 {
164     int pathlen = strlen(path);
165     int extlen = strlen(ext);
166     
167     for (int i = 1; i <= pathlen && i <= extlen; i++) {
168         if (path[pathlen-i] != ext[extlen-i])
169             return false;
170     }
171     return true;
172 }
173
174 void
175 NewGUI::newDialog (SGPropertyNode* props)
176 {
177     const char* cname = props->getStringValue("name");
178     if(!cname) {
179         SG_LOG(SG_GENERAL, SG_ALERT, "New dialog has no <name> property");
180         return;
181     }
182     string name = props->getStringValue("name");
183     _dialog_props[name] = props;
184 }
185
186 void
187 NewGUI::readDir (const char * path)
188 {
189     ulDir * dir = ulOpenDir(path);
190
191     if (dir == 0) {
192         SG_LOG(SG_GENERAL, SG_ALERT, "Failed to read GUI files from "
193                << path);
194         return;
195     }
196
197     for (ulDirEnt * dirEnt = ulReadDir(dir);
198          dirEnt != 0;
199          dirEnt = ulReadDir(dir)) {
200
201         char subpath[1024];
202
203         ulMakePath(subpath, path, dirEnt->d_name);
204
205         if (!dirEnt->d_isdir && test_extension(subpath, ".xml")) {
206             SGPropertyNode * props = new SGPropertyNode;
207             try {
208                 readProperties(subpath, props);
209             } catch (const sg_exception &ex) {
210                 SG_LOG(SG_INPUT, SG_ALERT, "Error parsing dialog "
211                        << subpath);
212                 delete props;
213                 continue;
214             }
215             if (!props->hasValue("name")) {
216                 SG_LOG(SG_INPUT, SG_WARN, "dialog " << subpath
217                    << " has no name; skipping.");
218                 delete props;
219                 continue;
220             }
221             newDialog(props);
222         }
223     }
224     ulCloseDir(dir);
225 }
226
227 // end of new_gui.cxx