+++ /dev/null
-/*
-
- Adapted by Jim Wilson, beginning Sept 2001 (FG v 0.79)
-
-**** Insert FlightGear GPL here.
-
- Based on puFilePicker from:
-
- ********
- PLIB - A Suite of Portable Game Libraries
- Copyright (C) 2001 Steve Baker
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library 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
- Library 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.
-
- For further information visit http://plib.sourceforge.net
-
- $Id$
- ********
-*/
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <simgear/compiler.h>
-#include <simgear/props/props.hxx>
-
-#include STL_STRING
-SG_USING_STD(string);
-
-#include <Main/fg_os.hxx>
-#include <Main/globals.hxx>
-#include "new_gui.hxx"
-#include "prop_picker.hxx"
-
-
-static puObject *PP_widget = 0;
-
-#define PROPPICK_X 100
-#define PROPPICK_Y 200
-#define PROPPICK_W 500
-#define PROPPICK_H 300
-
-static puObject *PE_widget = 0;
-
-
-
-// entry point: called from src/GUI/menubar.cxx -- do_properties_dialog() =====
-
-void prop_pickerView( puObject * )
-{
- if( PP_widget == 0 )
- prop_pickerInit();
-
- fgPropPicker *me = (fgPropPicker *)PP_widget -> getUserData();
- // refresh
- me -> find_props();
- FG_PUSH_PUI_DIALOG( me );
-}
-
-
-
-
-// ============================================================================
-
-void prop_pickerInit()
-{
- if (!PP_widget) {
- fgPropPicker *PP = new fgPropPicker ( PROPPICK_X, PROPPICK_Y, PROPPICK_W, PROPPICK_H,
- 1, globals->get_props(), "FG Properties");
- PP_widget = PP;
- }
-}
-
-
-void prop_pickerRefresh()
-{
- if (!PP_widget)
- prop_pickerInit();
-
- fgPropPicker *me = (fgPropPicker *)PP_widget -> getUserData();
- me -> find_props( true );
- me -> clrValue();
-}
-
-
-void prop_editOpen( SGPropertyNode *node )
-{
- assert(node);
- if (!PE_widget)
- PE_widget = new fgPropEdit(node);
-
- fgPropEdit *me = (fgPropEdit *)PE_widget -> getUserData();
- me -> namestring = node->getDisplayName();
- me -> propname -> setLabel (me->namestring.c_str());
- me -> propinput -> setValue (node->getStringValue());
- me -> propinput -> acceptInput ();
- me -> setEditNode(node);
- FG_PUSH_PUI_DIALOG( me );
-}
-
-
-static string getValueTypeString( const SGPropertyNode_ptr node ) {
- string result;
-
- if ( node == NULL )
- 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;
-}
-
-
-// Like strcmp, but for sorting property nodes into a suitable display order.
-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;
-
- // Compare name first, and then index.
- int diff = strcmp(pNode1->getName(), pNode2->getName());
- if (diff)
- return diff;
-
- return pNode1->getIndex() - pNode2->getIndex();
-}
-
-
-
-
-// property picker class ======================================================
-
-void fgPropPicker::fgPropPickerHandleSlider ( puObject * slider )
-{
- puListBox* list_box = (puListBox*) slider -> getUserData ();
-
- float val;
- slider -> getValue ( &val );
- val = 1.0f - val;
- int scroll_range = list_box->getNumItems () - list_box->getNumVisible();
-
- if ( scroll_range > 0 ) {
- int index = int ( scroll_range * val + 0.5 );
- list_box -> setTopItem ( index );
- }
-}
-
-
-void fgPropPicker::fgPropPickerHandleArrow ( puObject *arrow )
-{
- puSlider *slider = (puSlider *) arrow->getUserData ();
- puListBox* list_box = (puListBox*) slider -> getUserData ();
-
- int type = ((puArrowButton *)arrow)->getArrowType();
- int inc = ( type == PUARROW_DOWN ) ? 1 :
- ( type == PUARROW_UP ) ? -1 :
- ( type == PUARROW_FASTDOWN ) ? 10 :
- ( type == PUARROW_FASTUP ) ? -10 : 0;
-
- float val;
- slider -> getValue ( &val );
- val = 1.0f - val;
- int scroll_range = list_box->getNumItems () - list_box->getNumVisible();
-
- if ( scroll_range > 0 ) {
- int index = int ( scroll_range * val + 0.5 );
- index += inc;
- // if ( index > scroll_range ) index = scroll_range;
- // Allow buttons to scroll further than the slider does
- if ( index > ( list_box->getNumItems () - 1 ) )
- index = ( list_box->getNumItems () - 1 );
- if ( index < 0 )
- index = 0;
-
- slider -> setValue ( 1.0f - (float)index / scroll_range );
- list_box -> setTopItem ( index );
- }
-}
-
-
-void fgPropPicker::handle_select ( puObject* list_box )
-{
- fgPropPicker* prop_picker = (fgPropPicker*) list_box -> getUserData ();
- int selected;
- list_box -> getValue ( &selected );
-
- if ( selected >= 0 && selected < prop_picker -> num_files ) {
- const char *src = prop_picker -> files [ selected ];
-
- if (prop_picker->dotFiles && (selected < 2)) {
- if ( strcmp ( src, "." ) == 0 ) {
- /* Do nothing - but better refresh anyway. */
- prop_picker -> find_props ();
- return;
-
- } else if ( strcmp ( src, ".." ) == 0 ) {
- /* Do back up one level - so refresh. */
-
- SGPropertyNode *parent = prop_picker->getCurrent()->getParent();
- if (parent) {
- prop_picker->setCurrent(parent);
- prop_picker -> find_props ();
- }
- return;
- }
- }
-
- // we know we're dealing with a regular entry, so convert
- // it to an index into children[]
- if (prop_picker->dotFiles)
- selected -= 2;
- SGPropertyNode_ptr child = prop_picker->children[selected];
- assert(child != NULL);
-
- // check if it's a directory (had children)
- if ( child->nChildren() ) {
- prop_picker->setCurrent(child);
- prop_picker -> find_props ();
- return;
- }
-
- // it is a regular property
- if (child->getType() == SGPropertyNode::BOOL && (fgGetKeyModifiers() & KEYMOD_CTRL)) {
- child->setBoolValue(!child->getBoolValue());
- prop_pickerRefresh();
- } else
- prop_editOpen(child);
-
- } else {
- // The user clicked on blank screen - maybe we should
- // refresh just in case some other process created the file.
- // Should be obsolete once we observe child add/remove on our top node
- prop_picker -> find_props ();
- }
-}
-
-
-void fgPropPicker::fgPropPickerHandleOk ( puObject* b )
-{
- fgPropPicker* prop_picker = (fgPropPicker*) b -> getUserData ();
-
- // nothing to do, just hide
- FG_POP_PUI_DIALOG( prop_picker );
-}
-
-
-void fgPropPicker::delete_arrays ()
-{
- if ( files ) {
- for ( int i=0; i<num_files; i++ )
- delete[] files[i];
-
- for (int C=0; C<num_children; ++C) {
- if (children[C]->nChildren() == 0)
- children[C]->removeChangeListener(this);
- }
-
- delete[] files;
- delete[] children;
- }
-}
-
-/*
-
-fgPropPicker::~fgPropPicker ()
-{
- delete_arrays();
-
- if ( this == puActiveWidget () )
- puDeactivateWidget ();
-}
-
-*/
-
-
-fgPropPicker::fgPropPicker ( int x, int y, int w, int h, int arrows,
- SGPropertyNode *start, const char *title ) :
- fgPopup ( x,y ),
- curr(start),
- flags(fgGetNode("/sim/gui/dialogs/property-browser/show-flags", true)),
- _gui((NewGUI *)globals->get_subsystem("gui"))
-{
- puFont LegendFont, LabelFont;
- puGetDefaultFonts ( &LegendFont, &LabelFont );
- FGColor txtcol(_gui->getColor("label"));
- txtcol.merge(_gui->getColor("text"));
- txtcol.merge(_gui->getColor("text-label"));
-
- files = NULL;
- num_files = 0;
-
- if ( arrows > 2 )
- arrows = 2;
- if ( arrows < 0 )
- arrows = 0;
- arrow_count = arrows;
-
- frame = new puFrame ( 0, 0, w, h );
-
- setUserData( this );
-
- proppath = new puText (10, h-30);
- proppath -> setLabel (curr->getPath(true));
- proppath -> setColor(PUCOL_LABEL, txtcol.red(), txtcol.green(),
- txtcol.blue(), txtcol.alpha());
-
- slider = new puSlider (w-30,40+20*arrows,h-100-40*arrows,TRUE,20);
- slider->setValue(1.0f);
-
- list_box = new puListBox ( 10, 40, w-40, h-60 );
- list_box -> setLabel ( title );
- list_box -> setLabelPlace ( PUPLACE_ABOVE );
- list_box -> setStyle ( -PUSTYLE_SMALL_SHADED );
- list_box -> setUserData ( this );
- list_box -> setCallback ( handle_select );
- list_box -> setValue ( 0 );
- list_box -> setColor(PUCOL_LABEL, txtcol.red(), txtcol.green(),
- txtcol.blue(), txtcol.alpha());
-
- ok_button = new puOneShot ( 10, 10, (w<170)?(w/2-5):80, 30 );
- ok_button -> setLegend ( "Ok" );
- ok_button -> setUserData ( this );
- ok_button -> setCallback ( fgPropPickerHandleOk );
-
- if ( arrows > 0 ) {
- down_arrow = new puArrowButton ( w-30, 20+20*arrows, w-10, 40+20*arrows, PUARROW_DOWN );
- down_arrow->setUserData ( slider );
- down_arrow->setCallback ( fgPropPickerHandleArrow );
-
- up_arrow = new puArrowButton ( w-30, h-60-20*arrows, w-10, h-40-20*arrows, PUARROW_UP );
- up_arrow->setUserData ( slider );
- up_arrow->setCallback ( fgPropPickerHandleArrow );
- }
-
- // after picker is built, load the list box with data...
- find_props ();
-
- // printf("after Props files[1]=%s\n",files[1]);
- // printf("num items %i", list_box -> getNumItems ());
-
- slider -> setUserData ( list_box );
- slider -> setCallback ( fgPropPickerHandleSlider );
-
- FG_FINALIZE_PUI_DIALOG( this );
-}
-
-
-// Replace list with children of current
-void fgPropPicker::find_props ( bool restore_pos )
-{
- int pi;
- int i;
-
- delete_arrays();
- num_files = (int)curr->nChildren();
-
- // instantiate string objects and add [.] and [..] for subdirs
- if (!curr->getParent()) {
- files = new char* [ num_files+1 ];
- pi = 0;
- dotFiles = false;
-
- } else {
- // add two for the .. and .
- num_files += 2;
- // make room for .. and .
- files = new char* [ num_files+1 ];
-
- stdString line = ".";
- files [ 0 ] = new char[line.size() + 1];
- strcpy ( files [ 0 ], line.c_str() );
-
- line = "..";
- files [ 1 ] = new char[line.size() + 1];
- strcpy ( files [ 1 ], line.c_str() );
-
- 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++) {
- SGPropertyNode * child = children[i];
-
- if ( child->nChildren() > 0 ) {
- stdString name = stdString(child->getDisplayName(true)) + '/';
- files[ pi ] = new char[ name.size() + 1 ];
- strcpy ( files [ pi ], name.c_str() );
-
- } else {
- files[pi] = NULL; // ensure it's NULL before setting intial value
- updateTextForEntry(i);
- child->addChangeListener(this);
- }
-
- ++pi;
- }
-
- files [ num_files ] = NULL;
-
- proppath -> setLabel(curr->getPath(true));
-
- int top = list_box->getTopItem();
- list_box -> newList ( files );
- if (restore_pos)
- list_box->setTopItem(top);
-
- // adjust the size of the slider...
- if (num_files > list_box->getNumVisible()) {
- slider->setSliderFraction((float)list_box->getNumVisible() / num_files);
- if (!restore_pos)
- slider->setValue(1.0f);
-
- slider->reveal();
- up_arrow->reveal();
- down_arrow->reveal();
-
- } else {
- slider->hide();
- up_arrow->hide();
- down_arrow->hide();
- }
-}
-
-
-void fgPropPicker::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 += ')';
-
- // truncate entries to plib pui limit
- if (line.length() >= PUSTRING_MAX)
- line[PUSTRING_MAX-1] = '\0';
-
- if (dotFiles)
- index += 2;
-
- // don't leak everywhere if we're updating
- delete[] files[index];
-
- files[index] = new char[ line.size() + 1 ];
- strcpy ( files [ index ], line.c_str() );
-}
-
-
-void fgPropPicker::valueChanged(SGPropertyNode *nd)
-{
- for (int i = 0; i < num_children; i++)
- if (children[i] == nd) {
- updateTextForEntry(i);
- return;
- }
-}
-
-
-
-
-// property editor class ======================================================
-
-void fgPropEdit::fgPropEditHandleCancel ( puObject* b )
-{
- fgPropEdit* prop_edit = (fgPropEdit*) b -> getUserData ();
- prop_pickerRefresh();
- FG_POP_PUI_DIALOG( prop_edit );
-}
-
-
-void fgPropEdit::fgPropEditHandleOK ( puObject* b )
-{
- fgPropEdit* prop_edit = (fgPropEdit*) b -> getUserData ();
- char* tvalue;
-
- prop_edit -> propinput -> getValue( &tvalue );
- prop_edit->getEditNode()->setStringValue(tvalue);
-
- // update the picker display so it shows new value
- prop_pickerRefresh();
-
- FG_POP_PUI_DIALOG( prop_edit );
-}
-
-
-fgPropEdit::fgPropEdit ( SGPropertyNode *n ) :
- fgPopup ( 0, 0 ),
- node(n),
- _gui((NewGUI *)globals->get_subsystem("gui"))
-{
- assert(n);
-
- puFont LegendFont, LabelFont;
- puGetDefaultFonts ( &LegendFont, &LabelFont );
- FGColor txtcol(_gui->getColor("label"));
- txtcol.merge(_gui->getColor("text"));
- txtcol.merge(_gui->getColor("text-label"));
-
- // locate in relation to picker widget...
- int fx = PROPPICK_X;
- int fy = PROPPICK_Y + PROPPICK_H;
- frame = new puFrame (fx,fy, fx+500, fy+120);
-
- setUserData( this );
-
- namestring = node->getDisplayName();
- propname = new puText (fx+10, fy+90);
- propname -> setLabel(namestring.c_str());
- propname -> setColor(PUCOL_LABEL, txtcol.red(), txtcol.green(),
- txtcol.blue(), txtcol.alpha());
-
- propinput = new puInput (fx+10, fy+50, fx+480, fy+80);
- propinput -> setValue (node->getStringValue());
- propinput -> acceptInput();
-
- ok_button = new puOneShot (fx+10, fy+10, fx+80, fy+30);
- ok_button -> setUserData (this);
- ok_button -> setLegend (gui_msg_OK);
- ok_button -> setCallback (fgPropEditHandleOK);
- ok_button -> makeReturnDefault (TRUE);
-
- cancel_button = new puOneShot (fx+100, fy+10, fx+180, fy+30);
- cancel_button -> setUserData (this);
- cancel_button -> setLegend (gui_msg_CANCEL);
- cancel_button -> setCallback (fgPropEditHandleCancel);
-
- FG_FINALIZE_PUI_DIALOG( this );
-}
-
-