From: mfranz Date: Mon, 22 May 2006 14:34:20 +0000 (+0000) Subject: new property browser widget X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=3610680095a229d8dec3b2b7dd4557633af8744a;p=flightgear.git new property browser widget --- diff --git a/src/GUI/property_list.cxx b/src/GUI/property_list.cxx new file mode 100644 index 000000000..a1f59624e --- /dev/null +++ b/src/GUI/property_list.cxx @@ -0,0 +1,302 @@ +// Implementation of the 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 +#endif + +#include + +#include STL_STRING +SG_USING_STD(string); +typedef string stdString; // puObject has a "string" member + +#include
// fgGetKeyModifiers() +#include
+ +#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 index 000000000..7d0792eda --- /dev/null +++ b/src/GUI/property_list.hxx @@ -0,0 +1,74 @@ +// Implementation of the 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 +#include + +#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