1 // dialog.cxx: implementation of an XML-configurable dialog box.
3 #include <Input/input.hxx>
9 #include "AirportList.hxx"
13 ////////////////////////////////////////////////////////////////////////
15 ////////////////////////////////////////////////////////////////////////
18 * User data for a GUI object.
22 GUIInfo (FGDialog * d);
26 vector <FGBinding *> bindings;
34 action_callback (puObject * object)
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)
45 gui->setActiveDialog(0);
50 ////////////////////////////////////////////////////////////////////////
51 // Static helper functions.
52 ////////////////////////////////////////////////////////////////////////
55 * Copy a property value to a PUI object.
58 copy_to_pui (SGPropertyNode * node, puObject * object)
60 switch (node->getType()) {
61 case SGPropertyNode::BOOL:
62 case SGPropertyNode::INT:
63 case SGPropertyNode::LONG:
64 object->setValue(node->getIntValue());
66 case SGPropertyNode::FLOAT:
67 case SGPropertyNode::DOUBLE:
68 object->setValue(node->getFloatValue());
71 object->setValue(node->getStringValue());
78 copy_from_pui (puObject * object, SGPropertyNode * node)
80 switch (node->getType()) {
81 case SGPropertyNode::BOOL:
82 case SGPropertyNode::INT:
83 case SGPropertyNode::LONG:
84 node->setIntValue(object->getIntegerValue());
86 case SGPropertyNode::FLOAT:
87 case SGPropertyNode::DOUBLE:
88 node->setFloatValue(object->getFloatValue());
91 node->setStringValue(object->getStringValue());
98 ////////////////////////////////////////////////////////////////////////
99 // Implementation of GUIInfo.
100 ////////////////////////////////////////////////////////////////////////
102 GUIInfo::GUIInfo (FGDialog * d)
109 for (unsigned int i = 0; i < bindings.size(); i++) {
117 ////////////////////////////////////////////////////////////////////////
118 // Implementation of FGDialog.
119 ////////////////////////////////////////////////////////////////////////
121 FGDialog::FGDialog (SGPropertyNode * props)
127 FGDialog::~FGDialog ()
129 puDeleteObject(_object);
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];
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];
151 // Finally, delete the property links.
152 for (i = 0; i < _propertyObjects.size(); i++) {
153 delete _propertyObjects[i];
154 _propertyObjects[i] = 0;
159 FGDialog::updateValue (const char * objectName)
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);
170 FGDialog::applyValue (const char * objectName)
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);
180 FGDialog::updateValues ()
182 for (unsigned int i = 0; i < _propertyObjects.size(); i++)
183 copy_to_pui(_propertyObjects[i]->node, _propertyObjects[i]->object);
187 FGDialog::applyValues ()
189 for (unsigned int i = 0; i < _propertyObjects.size(); i++)
190 copy_from_pui(_propertyObjects[i]->object,
191 _propertyObjects[i]->node);
195 FGDialog::display (SGPropertyNode * props)
198 SG_LOG(SG_GENERAL, SG_ALERT, "This widget is already active");
202 _object = makeObject(props,
203 globals->get_props()->getIntValue("/sim/startup/xsize"),
204 globals->get_props()->getIntValue("/sim/startup/ysize"));
209 SG_LOG(SG_GENERAL, SG_ALERT, "Widget "
210 << props->getStringValue("name", "[unnamed]")
211 << " does not contain a proper GUI definition");
216 FGDialog::makeObject (SGPropertyNode * props, int parentWidth, int parentHeight)
218 int width = props->getIntValue("width", parentWidth);
219 int height = props->getIntValue("height", parentHeight);
221 int x = props->getIntValue("x", (parentWidth - width) / 2);
222 int y = props->getIntValue("y", (parentHeight - height) / 2);
224 string type = props->getName();
228 if (type == "dialog") {
230 if (props->getBoolValue("modal", false))
231 dialog = new puDialogBox(x, y);
233 dialog = new puPopup(x, y);
234 setupGroup(dialog, props, width, height, true);
236 } else if (type == "group") {
237 puGroup * group = new puGroup(x, y);
238 setupGroup(group, props, width, height, false);
240 } else if (type == "list") {
241 puList * list = new puList(x, y, x + width, y + height);
242 setupObject(list, props);
244 } else if (type == "airport-list") {
245 AirportList * list = new AirportList(x, y, x + width, y + height);
246 setupObject(list, props);
248 } else if (type == "input") {
249 puInput * input = new puInput(x, y, x + width, y + height);
250 setupObject(input, props);
252 } else if (type == "text") {
253 puText * text = new puText(x, y);
254 setupObject(text, props);
256 } else if (type == "checkbox") {
258 b = new puButton(x, y, x + width, y + height, PUBUTTON_CIRCLE);
259 setupObject(b, props);
261 } else if (type == "button") {
263 const char * legend = props->getStringValue("legend", "[none]");
264 if (props->getBoolValue("one-shot", true))
265 b = new puOneShot(x, y, legend);
267 b = new puButton(x, y, legend);
268 setupObject(b, props);
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();
276 entries[i] = strdup((char *)value_nodes[i]->getStringValue());
278 new puComboBox(x, y, x + width, y + height, entries,
279 props->getBoolValue("editable", false));
280 setupObject(combo, props);
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);
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);
296 } else if (type == "select") {
297 vector<SGPropertyNode_ptr> value_nodes;
298 SGPropertyNode * selection_node =
299 fgGetNode(props->getChild("selection")->getStringValue(), true);
301 for (int q = 0; q < selection_node->nChildren(); q++)
302 value_nodes.push_back(selection_node->getChild(q));
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();
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);
319 FGDialog::setupObject (puObject * object, SGPropertyNode * props)
321 if (props->hasValue("legend"))
322 object->setLegend(props->getStringValue("legend"));
324 if (props->hasValue("label"))
325 object->setLabel(props->getStringValue("label"));
327 if (props->hasValue("property")) {
328 const char * name = props->getStringValue("name");
331 const char * propname = props->getStringValue("property");
332 SGPropertyNode_ptr node = fgGetNode(propname, true);
333 copy_to_pui(node, object);
335 _propertyObjects.push_back(new PropertyObject(name, object, node));
338 vector<SGPropertyNode_ptr> nodes = props->getChildren("binding");
339 if (nodes.size() > 0) {
340 GUIInfo * info = new GUIInfo(this);
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);
349 object->makeReturnDefault(props->getBoolValue("default"));
353 FGDialog::setupGroup (puGroup * group, SGPropertyNode * props,
354 int width, int height, bool makeFrame)
356 setupObject(group, props);
359 new puFrame(0, 0, width, height);
361 int nChildren = props->nChildren();
362 for (int i = 0; i < nChildren; i++)
363 makeObject(props->getChild(i), width, height);
368 FGDialog::make_char_array (int size)
370 char ** list = new char*[size+1];
371 for (int i = 0; i <= size; i++)
373 _char_arrays.push_back(list);
379 ////////////////////////////////////////////////////////////////////////
380 // Implementation of FGDialog::PropertyObject.
381 ////////////////////////////////////////////////////////////////////////
383 FGDialog::PropertyObject::PropertyObject (const char * n,
385 SGPropertyNode_ptr p)