]> git.mxchange.org Git - flightgear.git/blob - src/GUI/new_gui.cxx
Started a new FGMenuBar class to handle a different XML-configurable
[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 <vector>
9 SG_USING_STD(vector);
10
11 #include <simgear/misc/exception.hxx>
12 #include <Main/fg_props.hxx>
13
14 #include "menubar.hxx"
15
16
17 \f
18 ////////////////////////////////////////////////////////////////////////
19 // Callbacks.
20 ////////////////////////////////////////////////////////////////////////
21
22 /**
23  * Action callback.
24  */
25 static void
26 action_callback (puObject * object)
27 {
28     GUIInfo * info = (GUIInfo *)object->getUserData();
29     NewGUI * gui =
30         (NewGUI *)globals->get_subsystem_mgr()
31           ->get_group(FGSubsystemMgr::INIT)->get_subsystem("gui");
32     gui->setCurrentWidget(info->widget);
33     for (int i = 0; i < info->bindings.size(); i++)
34         info->bindings[i]->fire();
35     gui->setCurrentWidget(0);
36 }
37
38
39 \f
40 ////////////////////////////////////////////////////////////////////////
41 // Implementation of GUIInfo.
42 ////////////////////////////////////////////////////////////////////////
43
44 GUIInfo::GUIInfo (GUIWidget * w)
45     : widget(w)
46 {
47 }
48
49 GUIInfo::~GUIInfo ()
50 {
51     for (int i = 0; i < bindings.size(); i++) {
52         delete bindings[i];
53         bindings[i] = 0;
54     }
55 }
56
57
58 \f
59 ////////////////////////////////////////////////////////////////////////
60 // Implementation of GUIWidget.
61 ////////////////////////////////////////////////////////////////////////
62
63 GUIWidget::GUIWidget (SGPropertyNode_ptr props)
64     : _object(0)
65 {
66     display(props);
67 }
68
69 GUIWidget::~GUIWidget ()
70 {
71     delete _object;
72
73     int i;
74     for (i = 0; i < _info.size(); i++) {
75         delete _info[i];
76         _info[i] = 0;
77     }
78
79     for (i = 0; i < _propertyObjects.size(); i++) {
80         delete _propertyObjects[i];
81         _propertyObjects[i] = 0;
82     }
83 }
84
85 void
86 GUIWidget::updateValue (const char * objectName)
87 {
88     for (int i = 0; i < _propertyObjects.size(); i++) {
89         if (_propertyObjects[i]->name == objectName)
90             _propertyObjects[i]->object
91                 ->setValue(_propertyObjects[i]->node->getStringValue());
92     }
93 }
94
95 void
96 GUIWidget::applyValue (const char * objectName)
97 {
98     for (int i = 0; i < _propertyObjects.size(); i++) {
99         if (_propertyObjects[i]->name == objectName)
100             _propertyObjects[i]->node
101                 ->setStringValue(_propertyObjects[i]
102                                  ->object->getStringValue());
103     }
104 }
105
106 void
107 GUIWidget::updateValues ()
108 {
109     for (int i = 0; i < _propertyObjects.size(); i++) {
110         puObject * object = _propertyObjects[i]->object;
111         SGPropertyNode_ptr node = _propertyObjects[i]->node;
112         object->setValue(node->getStringValue());
113     }
114 }
115
116 void
117 GUIWidget::applyValues ()
118 {
119     for (int i = 0; i < _propertyObjects.size(); i++) {
120         puObject * object = _propertyObjects[i]->object;
121         SGPropertyNode_ptr node = _propertyObjects[i]->node;
122         node->setStringValue(object->getStringValue());
123     }
124 }
125
126 void
127 GUIWidget::display (SGPropertyNode_ptr props)
128 {
129     if (_object != 0) {
130         SG_LOG(SG_GENERAL, SG_ALERT, "This widget is already active");
131         return;
132     }
133
134     _object = makeObject(props, 1024, 768);
135
136     if (_object != 0) {
137         _object->reveal();
138     } else {
139         SG_LOG(SG_GENERAL, SG_ALERT, "Widget "
140                << props->getStringValue("name", "[unnamed]")
141                << " does not contain a proper GUI definition");
142     }
143 }
144
145 puObject *
146 GUIWidget::makeObject (SGPropertyNode * props, int parentWidth, int parentHeight)
147 {
148     int width = props->getIntValue("width", parentWidth);
149     int height = props->getIntValue("height", parentHeight);
150
151     int x = props->getIntValue("x", (parentWidth - width) / 2);
152     int y = props->getIntValue("y", (parentHeight - height) / 2);
153
154     string type = props->getName();
155     if (type == "")
156         type = props->getStringValue("type");
157     if (type == "") {
158         SG_LOG(SG_GENERAL, SG_ALERT, "No type specified for GUI object");
159         return 0;
160     }
161
162     if (type == "dialog") {
163         puPopup * dialog;
164         if (props->getBoolValue("modal", false))
165             dialog = new puDialogBox(x, y);
166         else
167             dialog = new puPopup(x, y);
168         setupGroup(dialog, props, width, height, true);
169         return dialog;
170     } else if (type == "group") {
171         puGroup * group = new puGroup(x, y);
172         setupGroup(group, props, width, height, false);
173         return group;
174     } else if (type == "input") {
175         puInput * input = new puInput(x, y, x + width, y + height);
176         setupObject(input, props);
177         return input;
178     } else if (type == "text") {
179         puText * text = new puText(x, y);
180         setupObject(text, props);
181         return text;
182     } else if (type == "button") {
183         puButton * b;
184         const char * legend = props->getStringValue("legend", "[none]");
185         if (props->getBoolValue("one-shot", true))
186             b = new puOneShot(x, y, legend);
187         else
188             b = new puButton(x, y, legend);
189         setupObject(b, props);
190         return b;
191     } else {
192         return 0;
193     }
194 }
195
196 void
197 GUIWidget::setupObject (puObject * object, SGPropertyNode * props)
198 {
199     if (props->hasValue("legend"))
200         object->setLegend(props->getStringValue("legend"));
201
202     if (props->hasValue("label"))
203         object->setLabel(props->getStringValue("label"));
204
205     if (props->hasValue("property")) {
206         const char * name = props->getStringValue("name");
207         if (name == 0)
208             name = "";
209         const char * propname = props->getStringValue("property");
210         SGPropertyNode_ptr node = fgGetNode(propname, true);
211         object->setValue(node->getStringValue());
212         if (name != 0)
213             _propertyObjects.push_back(new PropertyObject(name, object, node));
214     }
215
216     vector<SGPropertyNode_ptr> nodes = props->getChildren("binding");
217     if (nodes.size() > 0) {
218         GUIInfo * info = new GUIInfo(this);
219
220         for (int i = 0; i < nodes.size(); i++)
221             info->bindings.push_back(new FGBinding(nodes[i]));
222         object->setCallback(action_callback);
223         object->setUserData(info);
224         _info.push_back(info);
225     }
226
227     object->makeReturnDefault(props->getBoolValue("default"));
228 }
229
230 void
231 GUIWidget::setupGroup (puGroup * group, SGPropertyNode * props,
232                     int width, int height, bool makeFrame)
233 {
234     setupObject(group, props);
235
236     if (makeFrame)
237         new puFrame(0, 0, width, height);
238
239     int nChildren = props->nChildren();
240     for (int i = 0; i < nChildren; i++)
241         makeObject(props->getChild(i), width, height);
242     group->close();
243 }
244
245 GUIWidget::PropertyObject::PropertyObject (const char * n,
246                                            puObject * o,
247                                            SGPropertyNode_ptr p)
248     : name(n),
249       object(o),
250       node(p)
251 {
252 }
253
254
255 \f
256 ////////////////////////////////////////////////////////////////////////
257 // Implementation of NewGUI.
258 ////////////////////////////////////////////////////////////////////////
259
260
261 NewGUI::NewGUI ()
262     : _menubar(new FGMenuBar),
263       _current_widget(0)
264 {
265 }
266
267 NewGUI::~NewGUI ()
268 {
269     delete _menubar;
270 }
271
272 void
273 NewGUI::init ()
274 {
275     char path1[1024];
276     char path2[1024];
277     ulMakePath(path1, getenv("FG_ROOT"), "gui");
278     ulMakePath(path2, path1, "dialogs");
279     readDir(path2);
280 #if !defined(FG_OLD_MENUBAR)
281     _menubar->init();
282 #endif
283 }
284
285 void
286 NewGUI::update (double delta_time_sec)
287 {
288     // NO OP
289 }
290
291 void
292 NewGUI::display (const string &name)
293 {
294     if (_widgets.find(name) == _widgets.end())
295         SG_LOG(SG_GENERAL, SG_ALERT, "Dialog " << name << " not defined");
296     else
297         new GUIWidget(_widgets[name]);
298 }
299
300 void
301 NewGUI::setCurrentWidget (GUIWidget * widget)
302 {
303     _current_widget = widget;
304 }
305
306 GUIWidget *
307 NewGUI::getCurrentWidget ()
308 {
309     return _current_widget;
310 }
311
312 FGMenuBar *
313 NewGUI::getMenuBar ()
314 {
315     return _menubar;
316 }
317
318 void
319 NewGUI::readDir (const char * path)
320 {
321     ulDir * dir = ulOpenDir(path);
322
323     if (dir == 0) {
324         SG_LOG(SG_GENERAL, SG_ALERT, "Failed to read GUI files from "
325                << path);
326         return;
327     }
328
329     ulDirEnt * dirEnt = ulReadDir(dir);
330     while (dirEnt != 0) {
331         char subpath[1024];
332
333         ulMakePath(subpath, path, dirEnt->d_name);
334
335         if (dirEnt->d_isdir && dirEnt->d_name[0] != '.') {
336             readDir(subpath);
337         } else {
338             SGPropertyNode_ptr props = new SGPropertyNode;
339             try {
340                 readProperties(subpath, props);
341             } catch (const sg_exception &ex) {
342                 SG_LOG(SG_INPUT, SG_ALERT, "Error parsing GUI file "
343                        << subpath);
344             }
345             if (!props->hasValue("name")) {
346                 SG_LOG(SG_INPUT, SG_WARN, "GUI file " << subpath
347                    << " has no name; skipping.");
348             } else {
349                 string name = props->getStringValue("name");
350                 SG_LOG(SG_INPUT, SG_BULK, "Saving GUI node " << name);
351                 _widgets[name] = props;
352             }
353         }
354         dirEnt = ulReadDir(dir);
355     }
356     ulCloseDir(dir);
357 }
358
359 // end of new_gui.cxx