]> git.mxchange.org Git - flightgear.git/blobdiff - src/GUI/dialog.cxx
Merge branch 'durk/atcdcl-cond'
[flightgear.git] / src / GUI / dialog.cxx
index 9c82d8813668dad04774798505954b2da011bee4..95fe5f04c1fad5f40f56783fb492facf157f66b0 100644 (file)
@@ -4,7 +4,7 @@
 #  include "config.h"
 #endif
 
-#include <Input/input.hxx>
+#include <simgear/structure/SGBinding.hxx>
 #include <Scripting/NasalSys.hxx>
 #include <Main/fg_os.hxx>
 
@@ -355,8 +355,41 @@ void fgPopup::applySize(puObject *object)
     object->setSize(w, h);
 }
 
-\f
 ////////////////////////////////////////////////////////////////////////
+
+void FGDialog::ConditionalObject::update(FGDialog* aDlg)
+{
+  if (_name == "visible") {
+    bool wasVis = _pu->isVisible();
+    bool newVis = test();
+    
+    if (newVis == wasVis) {
+      return;
+    }
+    
+    if (newVis) { // puObject needs a setVisible. Oh well.
+    _pu->reveal();
+    } else {
+      _pu->hide();
+    }
+  } else if (_name == "enable") {
+    bool wasEnabled = _pu->isActive();
+    bool newEnable = test();
+    
+    if (wasEnabled == newEnable) {
+      return;
+    }
+    
+    if (newEnable) {
+      _pu->activate();
+    } else {
+      _pu->greyOut();
+    }
+  }
+  
+  aDlg->setNeedsLayout();
+}
+\f////////////////////////////////////////////////////////////////////////
 // Callbacks.
 ////////////////////////////////////////////////////////////////////////
 
@@ -390,6 +423,7 @@ action_callback (puObject *object)
 static void
 copy_to_pui (SGPropertyNode *node, puObject *object)
 {
+    using namespace simgear;
     GUIInfo *info = (GUIInfo *)object->getUserData();
     if (!info) {
         SG_LOG(SG_GENERAL, SG_ALERT, "dialog: widget without GUIInfo!");
@@ -409,13 +443,13 @@ copy_to_pui (SGPropertyNode *node, puObject *object)
     }
 
     switch (node->getType()) {
-    case SGPropertyNode::BOOL:
-    case SGPropertyNode::INT:
-    case SGPropertyNode::LONG:
+    case props::BOOL:
+    case props::INT:
+    case props::LONG:
         object->setValue(node->getIntValue());
         break;
-    case SGPropertyNode::FLOAT:
-    case SGPropertyNode::DOUBLE:
+    case props::FLOAT:
+    case props::DOUBLE:
         object->setValue(node->getFloatValue());
         break;
     default:
@@ -429,18 +463,19 @@ copy_to_pui (SGPropertyNode *node, puObject *object)
 static void
 copy_from_pui (puObject *object, SGPropertyNode *node)
 {
+    using namespace simgear;
     // puText objects are immutable, so should not be copied out
     if (object->getType() & PUCLASS_TEXT)
         return;
 
     switch (node->getType()) {
-    case SGPropertyNode::BOOL:
-    case SGPropertyNode::INT:
-    case SGPropertyNode::LONG:
+    case props::BOOL:
+    case props::INT:
+    case props::LONG:
         node->setIntValue(object->getIntegerValue());
         break;
-    case SGPropertyNode::FLOAT:
-    case SGPropertyNode::DOUBLE:
+    case props::FLOAT:
+    case props::DOUBLE:
         node->setFloatValue(object->getFloatValue());
         break;
     default:
@@ -460,9 +495,11 @@ copy_from_pui (puObject *object, SGPropertyNode *node)
 FGDialog::FGDialog (SGPropertyNode *props) :
     _object(0),
     _gui((NewGUI *)globals->get_subsystem("gui")),
-    _props(props)
+    _props(props),
+    _needsRelayout(false)
 {
     _module = string("__dlg:") + props->getStringValue("name", "[unnamed]");
+        
     SGPropertyNode *nasal = props->getNode("nasal");
     if (nasal) {
         _nasal_close = nasal->getNode("close");
@@ -516,18 +553,24 @@ FGDialog::updateValues (const char *objectName)
     if (objectName && !objectName[0])
         objectName = 0;
 
-    for (unsigned int i = 0; i < _propertyObjects.size(); i++) {
-        const string &name = _propertyObjects[i]->name;
-        if (objectName && name != objectName)
-            continue;
-
-        puObject *obj = _propertyObjects[i]->object;
-        if ((obj->getType() & PUCLASS_LIST) && (dynamic_cast<GUI_ID *>(obj)->id & FGCLASS_LIST)) {
-            fgList *pl = static_cast<fgList *>(obj);
-            pl->update();
-        } else
-            copy_to_pui(_propertyObjects[i]->node, obj);
+  for (unsigned int i = 0; i < _propertyObjects.size(); i++) {
+    const string &name = _propertyObjects[i]->name;
+    if (objectName && name != objectName) {
+      continue;
+    }
+    
+    puObject *widget = _propertyObjects[i]->object;
+    int widgetType = widget->getType();
+    if ((widgetType & PUCLASS_LIST) && (dynamic_cast<GUI_ID *>(widget)->id & FGCLASS_LIST)) {
+      fgList *pl = static_cast<fgList*>(widget);
+      pl->update();
+    } else if (widgetType & PUCLASS_COMBOBOX) {
+      fgComboBox* combo = static_cast<fgComboBox*>(widget);
+      combo->update();
+    } else {
+      copy_to_pui(_propertyObjects[i]->node, widget);
     }
+  } // of property objects iteration
 }
 
 void
@@ -556,6 +599,14 @@ FGDialog::update ()
 
         copy_to_pui(_liveObjects[i]->node, obj);
     }
+    
+  for (unsigned int j=0; j < _conditionalObjects.size(); ++j) {
+    _conditionalObjects[j]->update(this);
+  }
+  
+  if (_needsRelayout) {
+    relayout();
+  }
 }
 
 void
@@ -851,6 +902,18 @@ FGDialog::setupObject (puObject *object, SGPropertyNode *props)
        object->setLabelFont(*_font);
     }
 
+    if (props->hasChild("visible")) {
+      ConditionalObject* cnd = new ConditionalObject("visible", object);
+      cnd->setCondition(sgReadCondition(globals->get_props(), props->getChild("visible")));
+      _conditionalObjects.push_back(cnd);
+    }
+
+    if (props->hasChild("enable")) {
+      ConditionalObject* cnd = new ConditionalObject("enable", object);
+      cnd->setCondition(sgReadCondition(globals->get_props(), props->getChild("enable")));
+      _conditionalObjects.push_back(cnd);
+    }
+
     string type = props->getName();
     if (type == "input" && props->getBoolValue("live"))
         object->setDownCallback(action_callback);
@@ -1070,8 +1133,97 @@ FGDialog::getKeyCode(const char *str)
     return key;
 }
 
+void\fFGDialog::relayout()
+{
+  _needsRelayout = false;
+  
+  int screenw = globals->get_props()->getIntValue("/sim/startup/xsize");
+  int screenh = globals->get_props()->getIntValue("/sim/startup/ysize");
+
+  bool userx = _props->hasValue("x");
+  bool usery = _props->hasValue("y");
+  bool userw = _props->hasValue("width");
+  bool userh = _props->hasValue("height");
+
+  // Let the layout widget work in the same property subtree.
+  LayoutWidget wid(_props);
+  wid.setDefaultFont(_font, int(_font->getPointSize()));
+
+  int pw = 0, ph = 0;
+  int px, py, savex, savey;
+  if (!userw || !userh) {
+    wid.calcPrefSize(&pw, &ph);
+  }
+  
+  pw = _props->getIntValue("width", pw);
+  ph = _props->getIntValue("height", ph);
+  px = savex = _props->getIntValue("x", (screenw - pw) / 2);
+  py = savey = _props->getIntValue("y", (screenh - ph) / 2);
+
+  // Negative x/y coordinates are interpreted as distance from the top/right
+  // corner rather than bottom/left.
+  if (userx && px < 0)
+    px = screenw - pw + px;
+  if (usery && py < 0)
+    py = screenh - ph + py;
+
+  // Define "x", "y", "width" and/or "height" in the property tree if they
+  // are not specified in the configuration file.
+  wid.layout(px, py, pw, ph);
+
+  applySize(_object);
+  
+  // Remove automatically generated properties, so the layout looks
+  // the same next time around, or restore x and y to preserve negative coords.
+  if (userx)
+      _props->setIntValue("x", savex);
+  else
+      _props->removeChild("x");
+
+  if (usery)
+      _props->setIntValue("y", savey);
+  else
+      _props->removeChild("y");
+
+  if (!userw) _props->removeChild("width");
+  if (!userh) _props->removeChild("height");
+}
+
+void
+FGDialog::applySize(puObject *object)
+{
+  // compound plib widgets use setUserData() for internal purposes, so refuse
+  // to descend into anything that has other bits set than the following
+  const int validUserData = PUCLASS_VALUE|PUCLASS_OBJECT|PUCLASS_GROUP|PUCLASS_INTERFACE
+          |PUCLASS_FRAME|PUCLASS_TEXT|PUCLASS_BUTTON|PUCLASS_ONESHOT|PUCLASS_INPUT
+          |PUCLASS_ARROW|PUCLASS_DIAL|PUCLASS_POPUP;
+
+  int type = object->getType();
+  if ((type & PUCLASS_GROUP) && !(type & ~validUserData)) {
+    puObject* c = ((puGroup *)object)->getFirstChild();
+    for (; c != NULL; c = c->getNextObject()) {
+      applySize(c);
+    } // of child iteration
+  } // of group object case
+  
+  GUIInfo *info = (GUIInfo *)object->getUserData();
+  if (!info)
+    return;
+
+  SGPropertyNode *n = info->node;
+  if (!n) {
+    SG_LOG(SG_GENERAL, SG_ALERT, "FGDialog::applySize: no props");
+    return;
+  }
+  
+  int x = n->getIntValue("x");
+  int y = n->getIntValue("y");
+  int w = n->getIntValue("width", 4);
+  int h = n->getIntValue("height", 4);
+  object->setPosition(x, y);
+  object->setSize(w, h);
+}
 
-\f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of FGDialog::PropertyObject.
 ////////////////////////////////////////////////////////////////////////
@@ -1113,12 +1265,26 @@ fgValueList::~fgValueList()
 void
 fgValueList::make_list()
 {
-    vector<SGPropertyNode_ptr> value_nodes = _props->getChildren("value");
-    _list = new char *[value_nodes.size() + 1];
-    unsigned int i;
-    for (i = 0; i < value_nodes.size(); i++)
-        _list[i] = strdup((char *)value_nodes[i]->getStringValue());
-    _list[i] = 0;
+  SGPropertyNode_ptr values = _props;
+  const char* vname = "value";
+  
+  if (_props->hasChild("properties")) {
+    // dynamic values, read from a property's children
+    const char* path = _props->getStringValue("properties");
+    values = fgGetNode(path, true);
+  }
+  
+  if (_props->hasChild("property-name")) {
+    vname = _props->getStringValue("property-name");
+  }
+  
+  vector<SGPropertyNode_ptr> value_nodes = values->getChildren(vname);
+  _list = new char *[value_nodes.size() + 1];
+  unsigned int i;
+  for (i = 0; i < value_nodes.size(); i++) {
+    _list[i] = strdup((char *)value_nodes[i]->getStringValue());
+  }
+  _list[i] = 0;
 }
 
 void
@@ -1141,4 +1307,10 @@ fgList::update()
     setTopItem(top);
 }
 
+void fgComboBox::update()
+{
+  fgValueList::update();
+  newList(_list);
+}
+
 // end of dialog.cxx