]> git.mxchange.org Git - flightgear.git/blob - src/GUI/dialog.cxx
Fix the nmea and garmin output to a) fake a GSA sentence, b) fix a y2k bug
[flightgear.git] / src / GUI / dialog.cxx
1 // dialog.cxx: implementation of an XML-configurable dialog box.
2
3 #include <Input/input.hxx>
4
5 #include "dialog.hxx"
6 #include "new_gui.hxx"
7
8 #include "puList.hxx"
9 #include "AirportList.hxx"
10
11
12 \f
13 ////////////////////////////////////////////////////////////////////////
14 // Callbacks.
15 ////////////////////////////////////////////////////////////////////////
16
17 /**
18  * User data for a GUI object.
19  */
20 struct GUIInfo
21 {
22     GUIInfo (FGDialog * d);
23     virtual ~GUIInfo ();
24
25     FGDialog * dialog;
26     vector <FGBinding *> bindings;
27 };
28
29
30 /**
31  * Action callback.
32  */
33 static void
34 action_callback (puObject * object)
35 {
36     GUIInfo * info = (GUIInfo *)object->getUserData();
37     NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
38     gui->setActiveDialog(info->dialog);
39     int nBindings = info->bindings.size();
40     for (int i = 0; i < nBindings; i++) {
41         info->bindings[i]->fire();
42         if (gui->getActiveDialog() == 0)
43             break;
44     }
45     gui->setActiveDialog(0);
46 }
47
48
49 \f
50 ////////////////////////////////////////////////////////////////////////
51 // Static helper functions.
52 ////////////////////////////////////////////////////////////////////////
53
54 /**
55  * Copy a property value to a PUI object.
56  */
57 static void
58 copy_to_pui (SGPropertyNode * node, puObject * object)
59 {
60     switch (node->getType()) {
61     case SGPropertyNode::BOOL:
62     case SGPropertyNode::INT:
63     case SGPropertyNode::LONG:
64         object->setValue(node->getIntValue());
65         break;
66     case SGPropertyNode::FLOAT:
67     case SGPropertyNode::DOUBLE:
68         object->setValue(node->getFloatValue());
69         break;
70     default:
71         object->setValue(node->getStringValue());
72         break;
73     }
74 }
75
76
77 static void
78 copy_from_pui (puObject * object, SGPropertyNode * node)
79 {
80     switch (node->getType()) {
81     case SGPropertyNode::BOOL:
82     case SGPropertyNode::INT:
83     case SGPropertyNode::LONG:
84         node->setIntValue(object->getIntegerValue());
85         break;
86     case SGPropertyNode::FLOAT:
87     case SGPropertyNode::DOUBLE:
88         node->setFloatValue(object->getFloatValue());
89         break;
90     default:
91         node->setStringValue(object->getStringValue());
92         break;
93     }
94 }
95
96
97 \f
98 ////////////////////////////////////////////////////////////////////////
99 // Implementation of GUIInfo.
100 ////////////////////////////////////////////////////////////////////////
101
102 GUIInfo::GUIInfo (FGDialog * d)
103     : dialog(d)
104 {
105 }
106
107 GUIInfo::~GUIInfo ()
108 {
109     for (unsigned int i = 0; i < bindings.size(); i++) {
110         delete bindings[i];
111         bindings[i] = 0;
112     }
113 }
114
115
116 \f
117 ////////////////////////////////////////////////////////////////////////
118 // Implementation of FGDialog.
119 ////////////////////////////////////////////////////////////////////////
120
121 FGDialog::FGDialog (SGPropertyNode * props)
122     : _object(0)
123 {
124     display(props);
125 }
126
127 FGDialog::~FGDialog ()
128 {
129     puDeleteObject(_object);
130
131     unsigned int i;
132
133                                 // Delete all the arrays we made
134                                 // and were forced to keep around
135                                 // because PUI won't do its own
136                                 // memory management.
137     for (i = 0; i < _char_arrays.size(); i++) {
138         for (int j = 0; _char_arrays[i][j] != 0; j++)
139             free(_char_arrays[i][j]); // added with strdup
140         delete[] _char_arrays[i];
141     }
142
143                                 // Delete all the info objects we
144                                 // were forced to keep around because
145                                 // PUI cannot delete its own user data.
146     for (i = 0; i < _info.size(); i++) {
147         delete (GUIInfo *)_info[i];
148         _info[i] = 0;
149     }
150
151                                 // Finally, delete the property links.
152     for (i = 0; i < _propertyObjects.size(); i++) {
153         delete _propertyObjects[i];
154         _propertyObjects[i] = 0;
155     }
156 }
157
158 void
159 FGDialog::updateValue (const char * objectName)
160 {
161     for (unsigned int i = 0; i < _propertyObjects.size(); i++) {
162         const string &name = _propertyObjects[i]->name;
163         if (name == objectName)
164             copy_to_pui(_propertyObjects[i]->node,
165                         _propertyObjects[i]->object);
166     }
167 }
168
169 void
170 FGDialog::applyValue (const char * objectName)
171 {
172     for (unsigned int i = 0; i < _propertyObjects.size(); i++) {
173         if (_propertyObjects[i]->name == objectName)
174             copy_from_pui(_propertyObjects[i]->object,
175                           _propertyObjects[i]->node);
176     }
177 }
178
179 void
180 FGDialog::updateValues ()
181 {
182     for (unsigned int i = 0; i < _propertyObjects.size(); i++)
183         copy_to_pui(_propertyObjects[i]->node, _propertyObjects[i]->object);
184 }
185
186 void
187 FGDialog::applyValues ()
188 {
189     for (unsigned int i = 0; i < _propertyObjects.size(); i++)
190         copy_from_pui(_propertyObjects[i]->object,
191                       _propertyObjects[i]->node);
192 }
193
194 void
195 FGDialog::display (SGPropertyNode * props)
196 {
197     if (_object != 0) {
198         SG_LOG(SG_GENERAL, SG_ALERT, "This widget is already active");
199         return;
200     }
201
202     _object = makeObject(props,
203                       globals->get_props()->getIntValue("/sim/startup/xsize"),
204                       globals->get_props()->getIntValue("/sim/startup/ysize"));
205
206     if (_object != 0) {
207         _object->reveal();
208     } else {
209         SG_LOG(SG_GENERAL, SG_ALERT, "Widget "
210                << props->getStringValue("name", "[unnamed]")
211                << " does not contain a proper GUI definition");
212     }
213 }
214
215 puObject *
216 FGDialog::makeObject (SGPropertyNode * props, int parentWidth, int parentHeight)
217 {
218     int width = props->getIntValue("width", parentWidth);
219     int height = props->getIntValue("height", parentHeight);
220
221     int x = props->getIntValue("x", (parentWidth - width) / 2);
222     int y = props->getIntValue("y", (parentHeight - height) / 2);
223
224     string type = props->getName();
225     if (type == "")
226         type = "dialog";
227
228     if (type == "dialog") {
229         puPopup * dialog;
230         if (props->getBoolValue("modal", false))
231             dialog = new puDialogBox(x, y);
232         else
233             dialog = new puPopup(x, y);
234         setupGroup(dialog, props, width, height, true);
235         return dialog;
236     } else if (type == "group") {
237         puGroup * group = new puGroup(x, y);
238         setupGroup(group, props, width, height, false);
239         return group;
240     } else if (type == "list") {
241         puList * list = new puList(x, y, x + width, y + height);
242         setupObject(list, props);
243         return list;
244     } else if (type == "airport-list") {
245         AirportList * list = new AirportList(x, y, x + width, y + height);
246         setupObject(list, props);
247         return list;
248     } else if (type == "input") {
249         puInput * input = new puInput(x, y, x + width, y + height);
250         setupObject(input, props);
251         return input;
252     } else if (type == "text") {
253         puText * text = new puText(x, y);
254         setupObject(text, props);
255         return text;
256     } else if (type == "checkbox") {
257         puButton * b;
258         b = new puButton(x, y, x + width, y + height, PUBUTTON_CIRCLE);
259         setupObject(b, props);
260         return b;
261     } else if (type == "button") {
262         puButton * b;
263         const char * legend = props->getStringValue("legend", "[none]");
264         if (props->getBoolValue("one-shot", true))
265             b = new puOneShot(x, y, legend);
266         else
267             b = new puButton(x, y, legend);
268         setupObject(b, props);
269         return b;
270     } else if (type == "combo") {
271         vector<SGPropertyNode_ptr> value_nodes = props->getChildren("value");
272         char ** entries = make_char_array(value_nodes.size());
273         for (unsigned int i = 0, j = value_nodes.size() - 1;
274              i < value_nodes.size();
275              i++, j--)
276             entries[i] = strdup((char *)value_nodes[i]->getStringValue());
277         puComboBox * combo =
278             new puComboBox(x, y, x + width, y + height, entries,
279                            props->getBoolValue("editable", false));
280         setupObject(combo, props);
281         return combo;
282     } else if (type == "slider") {
283         bool vertical = props->getBoolValue("vertical", false);
284         puSlider * slider = new puSlider(x, y, (vertical ? height : width));
285         slider->setMinValue(props->getFloatValue("min", 0.0));
286         slider->setMaxValue(props->getFloatValue("max", 1.0));
287         setupObject(slider, props);
288         return slider;
289     } else if (type == "dial") {
290         puDial * dial = new puDial(x, y, width);
291         dial->setMinValue(props->getFloatValue("min", 0.0));
292         dial->setMaxValue(props->getFloatValue("max", 1.0));
293         dial->setWrap(props->getBoolValue("wrap", true));
294         setupObject(dial, props);
295         return dial;
296     } else if (type == "select") {
297         vector<SGPropertyNode_ptr> value_nodes;
298         SGPropertyNode * selection_node =
299                 fgGetNode(props->getChild("selection")->getStringValue(), true);
300
301         for (int q = 0; q < selection_node->nChildren(); q++)
302             value_nodes.push_back(selection_node->getChild(q));
303
304         char ** entries = make_char_array(value_nodes.size());
305         for (unsigned int i = 0, j = value_nodes.size() - 1;
306              i < value_nodes.size();
307              i++, j--)
308             entries[i] = strdup((char *)value_nodes[i]->getName());
309         puSelectBox * select =
310             new puSelectBox(x, y, x + width, y + height, entries);
311         setupObject(select, props);
312         return select;
313     } else {
314         return 0;
315     }
316 }
317
318 void
319 FGDialog::setupObject (puObject * object, SGPropertyNode * props)
320 {
321     if (props->hasValue("legend"))
322         object->setLegend(props->getStringValue("legend"));
323
324     if (props->hasValue("label"))
325         object->setLabel(props->getStringValue("label"));
326
327     if (props->hasValue("property")) {
328         const char * name = props->getStringValue("name");
329         if (name == 0)
330             name = "";
331         const char * propname = props->getStringValue("property");
332         SGPropertyNode_ptr node = fgGetNode(propname, true);
333         copy_to_pui(node, object);
334         if (name != 0)
335             _propertyObjects.push_back(new PropertyObject(name, object, node));
336     }
337
338     vector<SGPropertyNode_ptr> nodes = props->getChildren("binding");
339     if (nodes.size() > 0) {
340         GUIInfo * info = new GUIInfo(this);
341
342         for (unsigned int i = 0; i < nodes.size(); i++)
343             info->bindings.push_back(new FGBinding(nodes[i]));
344         object->setCallback(action_callback);
345         object->setUserData(info);
346         _info.push_back(info);
347     }
348
349     object->makeReturnDefault(props->getBoolValue("default"));
350 }
351
352 void
353 FGDialog::setupGroup (puGroup * group, SGPropertyNode * props,
354                     int width, int height, bool makeFrame)
355 {
356     setupObject(group, props);
357
358     if (makeFrame)
359         new puFrame(0, 0, width, height);
360
361     int nChildren = props->nChildren();
362     for (int i = 0; i < nChildren; i++)
363         makeObject(props->getChild(i), width, height);
364     group->close();
365 }
366
367 char **
368 FGDialog::make_char_array (int size)
369 {
370     char ** list = new char*[size+1];
371     for (int i = 0; i <= size; i++)
372         list[i] = 0;
373     _char_arrays.push_back(list);
374     return list;
375 }
376
377
378 \f
379 ////////////////////////////////////////////////////////////////////////
380 // Implementation of FGDialog::PropertyObject.
381 ////////////////////////////////////////////////////////////////////////
382
383 FGDialog::PropertyObject::PropertyObject (const char * n,
384                                            puObject * o,
385                                            SGPropertyNode_ptr p)
386     : name(n),
387       object(o),
388       node(p)
389 {
390 }
391
392
393 // end of dialog.cxx