]> git.mxchange.org Git - flightgear.git/commitdiff
new property browser widget
authormfranz <mfranz>
Mon, 22 May 2006 14:34:20 +0000 (14:34 +0000)
committermfranz <mfranz>
Mon, 22 May 2006 14:34:20 +0000 (14:34 +0000)
src/GUI/property_list.cxx [new file with mode: 0644]
src/GUI/property_list.hxx [new file with mode: 0644]

diff --git a/src/GUI/property_list.cxx b/src/GUI/property_list.cxx
new file mode 100644 (file)
index 0000000..a1f5962
--- /dev/null
@@ -0,0 +1,302 @@
+// Implementation of the <property-list> widget.
+//
+// Copyright (C) 2001  Steve BAKER
+// Copyright (C) 2001  Jim WILSON
+// Copyright (C) 2006  Melchior FRANZ
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include STL_STRING
+SG_USING_STD(string);
+typedef string stdString;      // puObject has a "string" member
+
+#include <Main/fg_os.hxx>      // fgGetKeyModifiers()
+#include <Main/fg_props.hxx>
+
+#include "property_list.hxx"
+
+
+static int nodeNameCompare(const void *ppNode1, const void *ppNode2)
+{
+    const SGPropertyNode_ptr pNode1 = *(const SGPropertyNode_ptr *)ppNode1;
+    const SGPropertyNode_ptr pNode2 = *(const SGPropertyNode_ptr *)ppNode2;
+
+    int diff = strcmp(pNode1->getName(), pNode2->getName());
+    return diff ? diff : pNode1->getIndex() - pNode2->getIndex();
+}
+
+
+static string getValueTypeString(const SGPropertyNode *node)
+{
+    string result;
+
+    if (!node)
+        return "unknown";
+
+    SGPropertyNode::Type type = node->getType();
+    if (type == SGPropertyNode::UNSPECIFIED)
+        result = "unspecified";
+    else if (type == SGPropertyNode::NONE)
+        result = "none";
+    else if (type == SGPropertyNode::BOOL)
+        result = "bool";
+    else if (type == SGPropertyNode::INT)
+        result = "int";
+    else if (type == SGPropertyNode::LONG)
+        result = "long";
+    else if (type == SGPropertyNode::FLOAT)
+        result = "float";
+    else if (type == SGPropertyNode::DOUBLE)
+        result = "double";
+    else if (type == SGPropertyNode::STRING)
+        result = "string";
+
+    return result;
+}
+
+
+
+
+PropertyList::PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *start) :
+    puList(minx, miny, maxx, maxy, short(0), 20),
+    _curr(start),
+    _flags(fgGetNode("/sim/gui/dialogs/property-browser/show-flags", true)),
+    _return(0),
+    _entries(0),
+    _num_entries(0)
+
+{
+    _list_box->setUserData(this);
+    _list_box->setCallback(handle_select);
+    _list_box->setValue(0);
+    update();
+}
+
+
+PropertyList::~PropertyList()
+{
+    delete_arrays();
+}
+
+
+void PropertyList::delete_arrays()
+{
+    if (!_entries)
+        return;
+
+    for (int i = 0; i < _num_entries; i++)
+        delete[] _entries[i];
+
+    for (int j = 0; j < _num_children; j++) {
+        if (!_children[j]->nChildren())
+            _children[j]->removeChangeListener(this);
+    }
+
+    delete[] _entries;
+    delete[] _children;
+    _entries = 0;
+    _children = 0;
+}
+
+
+void PropertyList::handle_select(puObject *list_box)
+{
+    PropertyList *prop_list = (PropertyList *)list_box->getUserData();
+    int selected = list_box->getIntegerValue();
+    bool mod_ctrl = fgGetKeyModifiers() & KEYMOD_CTRL;
+
+    if (selected >= 0 && selected < prop_list->_num_entries) {
+        const char *src = prop_list->_entries[selected];
+
+        if (prop_list->dotFiles && (selected < 2)) {
+            if (!strcmp(src, ".")) {
+                if (mod_ctrl)
+                    prop_list->toggleFlags();
+
+                prop_list->update();
+                return;
+
+            } else if (!strcmp(src, "..")) {
+                SGPropertyNode *parent = prop_list->getCurrent()->getParent();
+                if (parent) {
+                    if (mod_ctrl)
+                        for (; parent->getParent(); parent = parent->getParent())
+                            ;
+                    prop_list->setCurrent(parent);
+                }
+                return;
+            }
+        }
+
+        // we know we're dealing with a regular entry, so convert
+        // it to an index into children[]
+        if (prop_list->dotFiles)
+            selected -= 2;
+
+        SGPropertyNode_ptr child = prop_list->_children[selected];
+        assert(child);
+
+        // check if it's a directory
+        if (child->nChildren()) {
+            prop_list->setCurrent(child);
+            return;
+        }
+
+        // it is a regular property
+        if (child->getType() == SGPropertyNode::BOOL && mod_ctrl) {
+            child->setBoolValue(!child->getBoolValue());
+            prop_list->update();
+        } else
+            prop_list->publish(child);
+
+    } else {
+        // the user clicked on blank screen
+        prop_list->update();
+    }
+}
+
+
+void PropertyList::update(bool restore_pos)
+{
+    int pi;
+    int i;
+
+    delete_arrays();
+    _num_entries = (int)_curr->nChildren();
+
+    // instantiate string objects and add [.] and [..] for subdirs
+    if (!_curr->getParent()) {
+        _entries = new char*[_num_entries + 1];
+        pi = 0;
+        dotFiles = false;
+
+    } else {
+        _num_entries += 2;    // for . and ..
+        _entries = new char*[_num_entries + 1];
+
+        _entries[0] = new char[2];
+        strcpy(_entries[0], ".");
+
+        _entries[1] = new char[3];
+        strcpy(_entries[1], "..");
+
+        pi = 2;
+        dotFiles = true;
+    }
+
+    _num_children = _curr->nChildren();
+    _children = new SGPropertyNode_ptr[_num_children];
+    for (i = 0; i < _num_children; i++)
+        _children[i] = _curr->getChild(i);
+
+    qsort(_children, _num_children, sizeof(_children[0]), nodeNameCompare);
+
+    // Make lists of the children's names, values, etc.
+    for (i = 0; i < _num_children; i++, pi++) {
+        SGPropertyNode *child = _children[i];
+
+        if (child->nChildren() > 0) {
+            stdString name = stdString(child->getDisplayName(true)) + '/';
+            _entries[pi] = new char[name.size() + 1];
+            strcpy(_entries[pi], name.c_str());
+
+        } else {
+            _entries[pi] = 0;       // ensure it's 0 before setting intial value
+            updateTextForEntry(i);
+            child->addChangeListener(this);
+        }
+    }
+
+    _entries[_num_entries] = 0;
+
+    int top = getTopItem();
+    newList(_entries);
+    if (restore_pos)
+        setTopItem(top);
+}
+
+
+void PropertyList::updateTextForEntry(int index)
+{
+    assert((index >= 0) && (index < _num_children));
+    SGPropertyNode_ptr node = _children[index];
+
+    stdString name = node->getDisplayName(true);
+    stdString type = getValueTypeString(node);
+    stdString value = node->getStringValue();
+
+    stdString line = name + " = '" + value + "' (" + type;
+
+    if (_flags->getBoolValue()) {
+        stdString ext;
+        if (!node->getAttribute(SGPropertyNode::READ))
+            ext += 'r';
+        if (!node->getAttribute(SGPropertyNode::WRITE))
+            ext += 'w';
+        if (node->getAttribute(SGPropertyNode::TRACE_READ))
+            ext += 'R';
+        if (node->getAttribute(SGPropertyNode::TRACE_WRITE))
+            ext += 'W';
+        if (node->getAttribute(SGPropertyNode::ARCHIVE))
+            ext += 'A';
+        if (node->getAttribute(SGPropertyNode::USERARCHIVE))
+            ext += 'U';
+        if (node->isTied())
+            ext += 'T';
+        if (ext.size())
+            line += ", " + ext;
+    }
+
+    line += ')';
+
+    if (line.size() >= PUSTRING_MAX)
+        line.resize(PUSTRING_MAX - 1);
+
+    if (dotFiles)
+        index += 2;
+
+    delete[] _entries[index];
+    _entries[index] = new char[line.size() + 1];
+    strcpy(_entries[index], line.c_str());
+}
+
+
+void PropertyList::valueChanged(SGPropertyNode *nd)
+{
+    for (int i = 0; i < _num_children; i++)
+        if (_children[i] == nd) {
+            updateTextForEntry(i);
+            return;
+        }
+}
+
+
+void PropertyList::setValue(const char *s)
+{
+    SGPropertyNode *p = fgGetNode(s, false);
+    if (p)
+        setCurrent(p);
+}
+
+
diff --git a/src/GUI/property_list.hxx b/src/GUI/property_list.hxx
new file mode 100644 (file)
index 0000000..7d0792e
--- /dev/null
@@ -0,0 +1,74 @@
+// Implementation of the <property-list> widget.
+//
+// Copyright (C) 2001  Steve BAKER
+// Copyright (C) 2001  Jim WILSON
+// Copyright (C) 2006  Melchior FRANZ
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#ifndef _PROPERTY_LIST_HXX
+#define _PROPERTY_LIST_HXX
+
+
+#include <plib/pu.h>
+#include <simgear/props/props.hxx>
+
+#include "puList.hxx"
+
+
+class PropertyList : public puList, public SGPropertyChangeListener {
+public:
+    PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *);
+    ~PropertyList();
+
+    void update (bool restore_slider_pos = false);
+    void setCurrent(SGPropertyNode *p) { _curr = p; update(); publish(p); }
+    SGPropertyNode *getCurrent() const { return _curr; }
+    void publish(SGPropertyNode *p) { _return = p; invokeCallback(); }
+    void toggleFlags() { _flags->setBoolValue(!_flags->getBoolValue()); }
+
+    // overridden plib pui methods
+    virtual char *getStringValue(void) { return (char *)(_return ? _return->getPath(true) : ""); }
+    virtual void setValue(const char *);
+
+    // listener method
+    virtual void valueChanged(SGPropertyNode *node);
+
+private:
+    // update the text string in the puList using the given node and
+    // updating the requested offset. The value of dotFiles is taken
+    // into account before the index is applied, i.e this should be
+    // an index into 'children'
+    void updateTextForEntry(int index);
+    void delete_arrays();
+    static void handle_select(puObject *b);
+
+    SGPropertyNode_ptr _curr;
+    SGPropertyNode_ptr _flags;
+    SGPropertyNode_ptr _return;
+
+    char **_entries;
+    int _num_entries;
+
+    SGPropertyNode_ptr *_children;
+    int _num_children;
+
+    bool dotFiles;      // . and .. pseudo-dirs currently shown?
+};
+
+
+#endif // _PROP_PICKER_HXX