1 // dialog.cxx: implementation of an XML-configurable dialog box.
3 #include <Input/input.hxx>
9 #include "AirportList.hxx"
11 int fgPopup::checkHit(int button, int updown, int x, int y)
13 int result = puPopup::checkHit(button, updown, x, y);
15 // This is annoying. We would really want a true result from the
16 // superclass to indicate "handled by child object", but all it
17 // tells us is that the pointer is inside the dialog. So do the
18 // intersection test (again) to make sure we don't start a drag
19 // when inside controls. A further weirdness: plib inserts a
20 // "ghost" child which covers the whole control. (?) Skip it.
21 if(!result) return result;
22 puObject* child = getFirstChild();
23 if(child) child = child->getNextObject();
26 child->getAbsolutePosition(&cx, &cy);
27 child->getSize(&cw, &ch);
28 if(x >= cx && x < cx + cw && y >= cy && y < cy + ch)
30 child = child->getNextObject();
33 // Finally, handle the mouse event
34 if(updown == PU_DOWN) {
36 getPosition(&px, &py);
40 } else if(updown == PU_DRAG && _dragging) {
41 setPosition(x + _dX, y + _dY);
49 ////////////////////////////////////////////////////////////////////////
51 ////////////////////////////////////////////////////////////////////////
54 * User data for a GUI object.
58 GUIInfo (FGDialog * d);
62 vector <FGBinding *> bindings;
70 action_callback (puObject * object)
72 GUIInfo * info = (GUIInfo *)object->getUserData();
73 NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
74 gui->setActiveDialog(info->dialog);
75 int nBindings = info->bindings.size();
76 for (int i = 0; i < nBindings; i++) {
77 info->bindings[i]->fire();
78 if (gui->getActiveDialog() == 0)
81 gui->setActiveDialog(0);
86 ////////////////////////////////////////////////////////////////////////
87 // Static helper functions.
88 ////////////////////////////////////////////////////////////////////////
91 * Copy a property value to a PUI object.
94 copy_to_pui (SGPropertyNode * node, puObject * object)
96 switch (node->getType()) {
97 case SGPropertyNode::BOOL:
98 case SGPropertyNode::INT:
99 case SGPropertyNode::LONG:
100 object->setValue(node->getIntValue());
102 case SGPropertyNode::FLOAT:
103 case SGPropertyNode::DOUBLE:
104 object->setValue(node->getFloatValue());
107 object->setValue(node->getStringValue());
114 copy_from_pui (puObject * object, SGPropertyNode * node)
116 switch (node->getType()) {
117 case SGPropertyNode::BOOL:
118 case SGPropertyNode::INT:
119 case SGPropertyNode::LONG:
120 node->setIntValue(object->getIntegerValue());
122 case SGPropertyNode::FLOAT:
123 case SGPropertyNode::DOUBLE:
124 node->setFloatValue(object->getFloatValue());
127 node->setStringValue(object->getStringValue());
134 ////////////////////////////////////////////////////////////////////////
135 // Implementation of GUIInfo.
136 ////////////////////////////////////////////////////////////////////////
138 GUIInfo::GUIInfo (FGDialog * d)
145 for (unsigned int i = 0; i < bindings.size(); i++) {
153 ////////////////////////////////////////////////////////////////////////
154 // Implementation of FGDialog.
155 ////////////////////////////////////////////////////////////////////////
157 FGDialog::FGDialog (SGPropertyNode * props)
163 FGDialog::~FGDialog ()
165 puDeleteObject(_object);
169 // Delete all the arrays we made
170 // and were forced to keep around
171 // because PUI won't do its own
172 // memory management.
173 for (i = 0; i < _char_arrays.size(); i++) {
174 for (int j = 0; _char_arrays[i][j] != 0; j++)
175 free(_char_arrays[i][j]); // added with strdup
176 delete[] _char_arrays[i];
179 // Delete all the info objects we
180 // were forced to keep around because
181 // PUI cannot delete its own user data.
182 for (i = 0; i < _info.size(); i++) {
183 delete (GUIInfo *)_info[i];
187 // Finally, delete the property links.
188 for (i = 0; i < _propertyObjects.size(); i++) {
189 delete _propertyObjects[i];
190 _propertyObjects[i] = 0;
195 FGDialog::updateValue (const char * objectName)
197 for (unsigned int i = 0; i < _propertyObjects.size(); i++) {
198 const string &name = _propertyObjects[i]->name;
199 if (name == objectName)
200 copy_to_pui(_propertyObjects[i]->node,
201 _propertyObjects[i]->object);
206 FGDialog::applyValue (const char * objectName)
208 for (unsigned int i = 0; i < _propertyObjects.size(); i++) {
209 if (_propertyObjects[i]->name == objectName)
210 copy_from_pui(_propertyObjects[i]->object,
211 _propertyObjects[i]->node);
216 FGDialog::updateValues ()
218 for (unsigned int i = 0; i < _propertyObjects.size(); i++)
219 copy_to_pui(_propertyObjects[i]->node, _propertyObjects[i]->object);
223 FGDialog::applyValues ()
225 for (unsigned int i = 0; i < _propertyObjects.size(); i++)
226 copy_from_pui(_propertyObjects[i]->object,
227 _propertyObjects[i]->node);
231 FGDialog::display (SGPropertyNode * props)
234 SG_LOG(SG_GENERAL, SG_ALERT, "This widget is already active");
238 _object = makeObject(props,
239 globals->get_props()->getIntValue("/sim/startup/xsize"),
240 globals->get_props()->getIntValue("/sim/startup/ysize"));
245 SG_LOG(SG_GENERAL, SG_ALERT, "Widget "
246 << props->getStringValue("name", "[unnamed]")
247 << " does not contain a proper GUI definition");
252 FGDialog::makeObject (SGPropertyNode * props, int parentWidth, int parentHeight)
254 int width = props->getIntValue("width", parentWidth);
255 int height = props->getIntValue("height", parentHeight);
257 int x = props->getIntValue("x", (parentWidth - width) / 2);
258 int y = props->getIntValue("y", (parentHeight - height) / 2);
260 string type = props->getName();
264 if (type == "dialog") {
266 if (props->getBoolValue("modal", false))
267 dialog = new puDialogBox(x, y);
269 dialog = new fgPopup(x, y);
270 setupGroup(dialog, props, width, height, true);
272 } else if (type == "group") {
273 puGroup * group = new puGroup(x, y);
274 setupGroup(group, props, width, height, false);
276 } else if (type == "list") {
277 puList * list = new puList(x, y, x + width, y + height);
278 setupObject(list, props);
280 } else if (type == "airport-list") {
281 AirportList * list = new AirportList(x, y, x + width, y + height);
282 setupObject(list, props);
284 } else if (type == "input") {
285 puInput * input = new puInput(x, y, x + width, y + height);
286 setupObject(input, props);
288 } else if (type == "text") {
289 puText * text = new puText(x, y);
290 setupObject(text, props);
292 } else if (type == "checkbox") {
294 b = new puButton(x, y, x + width, y + height, PUBUTTON_CIRCLE);
295 setupObject(b, props);
297 } else if (type == "button") {
299 const char * legend = props->getStringValue("legend", "[none]");
300 if (props->getBoolValue("one-shot", true))
301 b = new puOneShot(x, y, legend);
303 b = new puButton(x, y, legend);
304 setupObject(b, props);
306 } else if (type == "combo") {
307 vector<SGPropertyNode_ptr> value_nodes = props->getChildren("value");
308 char ** entries = make_char_array(value_nodes.size());
309 for (unsigned int i = 0, j = value_nodes.size() - 1;
310 i < value_nodes.size();
312 entries[i] = strdup((char *)value_nodes[i]->getStringValue());
314 new puComboBox(x, y, x + width, y + height, entries,
315 props->getBoolValue("editable", false));
316 setupObject(combo, props);
318 } else if (type == "slider") {
319 bool vertical = props->getBoolValue("vertical", false);
320 puSlider * slider = new puSlider(x, y, (vertical ? height : width));
321 slider->setMinValue(props->getFloatValue("min", 0.0));
322 slider->setMaxValue(props->getFloatValue("max", 1.0));
323 setupObject(slider, props);
325 } else if (type == "dial") {
326 puDial * dial = new puDial(x, y, width);
327 dial->setMinValue(props->getFloatValue("min", 0.0));
328 dial->setMaxValue(props->getFloatValue("max", 1.0));
329 dial->setWrap(props->getBoolValue("wrap", true));
330 setupObject(dial, props);
332 } else if (type == "select") {
333 vector<SGPropertyNode_ptr> value_nodes;
334 SGPropertyNode * selection_node =
335 fgGetNode(props->getChild("selection")->getStringValue(), true);
337 for (int q = 0; q < selection_node->nChildren(); q++)
338 value_nodes.push_back(selection_node->getChild(q));
340 char ** entries = make_char_array(value_nodes.size());
341 for (unsigned int i = 0, j = value_nodes.size() - 1;
342 i < value_nodes.size();
344 entries[i] = strdup((char *)value_nodes[i]->getName());
345 puSelectBox * select =
346 new puSelectBox(x, y, x + width, y + height, entries);
347 setupObject(select, props);
355 FGDialog::setupObject (puObject * object, SGPropertyNode * props)
357 if (props->hasValue("legend"))
358 object->setLegend(props->getStringValue("legend"));
360 if (props->hasValue("label"))
361 object->setLabel(props->getStringValue("label"));
363 if (props->hasValue("property")) {
364 const char * name = props->getStringValue("name");
367 const char * propname = props->getStringValue("property");
368 SGPropertyNode_ptr node = fgGetNode(propname, true);
369 copy_to_pui(node, object);
371 _propertyObjects.push_back(new PropertyObject(name, object, node));
374 vector<SGPropertyNode_ptr> nodes = props->getChildren("binding");
375 if (nodes.size() > 0) {
376 GUIInfo * info = new GUIInfo(this);
378 for (unsigned int i = 0; i < nodes.size(); i++)
379 info->bindings.push_back(new FGBinding(nodes[i]));
380 object->setCallback(action_callback);
381 object->setUserData(info);
382 _info.push_back(info);
385 object->makeReturnDefault(props->getBoolValue("default"));
389 FGDialog::setupGroup (puGroup * group, SGPropertyNode * props,
390 int width, int height, bool makeFrame)
392 setupObject(group, props);
395 new puFrame(0, 0, width, height);
397 int nChildren = props->nChildren();
398 for (int i = 0; i < nChildren; i++)
399 makeObject(props->getChild(i), width, height);
404 FGDialog::make_char_array (int size)
406 char ** list = new char*[size+1];
407 for (int i = 0; i <= size; i++)
409 _char_arrays.push_back(list);
415 ////////////////////////////////////////////////////////////////////////
416 // Implementation of FGDialog::PropertyObject.
417 ////////////////////////////////////////////////////////////////////////
419 FGDialog::PropertyObject::PropertyObject (const char * n,
421 SGPropertyNode_ptr p)