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