1
0
Fork 0
flightgear/src/GUI/prop_picker.cxx

593 lines
16 KiB
C++
Raw Normal View History

/*
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.
2006-02-21 01:16:04 +00:00
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>
Patch from Julian Foad: When the scroll bar slider is dragged, the list scrolls only far enough to see all items; only the arrow buttons can scroll it so far that the last item goes to the top of the view. Fix scroll bar proportional size: was wrong when the list was only a little longer than the visible area. Minor fixes such as "delete files[i];" -> "delete[] files[i];" (where the item being deleted is an array of characters) and removal of global variables. Smooth scrolling when dragging the slider: one item at a time, rather than one tenth of the list at a time. Fix a bug that would have occurred if instantiated with arrows=2. Sort properties primarily by name and then by numerical index order, rather than a simple ASCII string order. E.g. "js[1]", "js[2]", "js[10]" rather than "js[1]", "js[10]", "js[2]". Avoid crashing if the selected property path does not exist; display an empty list instead. This cannot happen when the property picker is working properly, but did happen due to missing indices prior to this patch, and could happen if the user is allowed to type a pathname, as in the http and telnet interfaces. Fix truncation of strings to PUSTRING_MAX: was wrong when string length was exactly 80. Fix: move the scroll bar to the top each time a new list is displayed. It was left at its previous position, while the top of the new list was displayed, not corresponding to the slider. Use getDisplayName instead of duplicated code: gives a better decision on whether to display the index, and avoids invalid property paths being generated which would previously crash find_props(). Replace unnecessary node lookups by name with direct access: tidier and more efficient. E.g. "getValueTypeString (node->getNode(name.c_str()))" -> "getValueTypeString (child)".
2002-09-07 12:35:06 +00:00
#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 );
}
Patch from Julian Foad: When the scroll bar slider is dragged, the list scrolls only far enough to see all items; only the arrow buttons can scroll it so far that the last item goes to the top of the view. Fix scroll bar proportional size: was wrong when the list was only a little longer than the visible area. Minor fixes such as "delete files[i];" -> "delete[] files[i];" (where the item being deleted is an array of characters) and removal of global variables. Smooth scrolling when dragging the slider: one item at a time, rather than one tenth of the list at a time. Fix a bug that would have occurred if instantiated with arrows=2. Sort properties primarily by name and then by numerical index order, rather than a simple ASCII string order. E.g. "js[1]", "js[2]", "js[10]" rather than "js[1]", "js[10]", "js[2]". Avoid crashing if the selected property path does not exist; display an empty list instead. This cannot happen when the property picker is working properly, but did happen due to missing indices prior to this patch, and could happen if the user is allowed to type a pathname, as in the http and telnet interfaces. Fix truncation of strings to PUSTRING_MAX: was wrong when string length was exactly 80. Fix: move the scroll bar to the top each time a new list is displayed. It was left at its previous position, while the top of the new list was displayed, not corresponding to the slider. Use getDisplayName instead of duplicated code: gives a better decision on whether to display the index, and avoids invalid property paths being generated which would previously crash find_props(). Replace unnecessary node lookups by name with direct access: tidier and more efficient. E.g. "getValueTypeString (node->getNode(name.c_str()))" -> "getValueTypeString (child)".
2002-09-07 12:35:06 +00:00
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;
}
Patch from Julian Foad: When the scroll bar slider is dragged, the list scrolls only far enough to see all items; only the arrow buttons can scroll it so far that the last item goes to the top of the view. Fix scroll bar proportional size: was wrong when the list was only a little longer than the visible area. Minor fixes such as "delete files[i];" -> "delete[] files[i];" (where the item being deleted is an array of characters) and removal of global variables. Smooth scrolling when dragging the slider: one item at a time, rather than one tenth of the list at a time. Fix a bug that would have occurred if instantiated with arrows=2. Sort properties primarily by name and then by numerical index order, rather than a simple ASCII string order. E.g. "js[1]", "js[2]", "js[10]" rather than "js[1]", "js[10]", "js[2]". Avoid crashing if the selected property path does not exist; display an empty list instead. This cannot happen when the property picker is working properly, but did happen due to missing indices prior to this patch, and could happen if the user is allowed to type a pathname, as in the http and telnet interfaces. Fix truncation of strings to PUSTRING_MAX: was wrong when string length was exactly 80. Fix: move the scroll bar to the top each time a new list is displayed. It was left at its previous position, while the top of the new list was displayed, not corresponding to the slider. Use getDisplayName instead of duplicated code: gives a better decision on whether to display the index, and avoids invalid property paths being generated which would previously crash find_props(). Replace unnecessary node lookups by name with direct access: tidier and more efficient. E.g. "getValueTypeString (node->getNode(name.c_str()))" -> "getValueTypeString (child)".
2002-09-07 12:35:06 +00:00
}
/*
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 )
Patch from Julian Foad: When the scroll bar slider is dragged, the list scrolls only far enough to see all items; only the arrow buttons can scroll it so far that the last item goes to the top of the view. Fix scroll bar proportional size: was wrong when the list was only a little longer than the visible area. Minor fixes such as "delete files[i];" -> "delete[] files[i];" (where the item being deleted is an array of characters) and removal of global variables. Smooth scrolling when dragging the slider: one item at a time, rather than one tenth of the list at a time. Fix a bug that would have occurred if instantiated with arrows=2. Sort properties primarily by name and then by numerical index order, rather than a simple ASCII string order. E.g. "js[1]", "js[2]", "js[10]" rather than "js[1]", "js[10]", "js[2]". Avoid crashing if the selected property path does not exist; display an empty list instead. This cannot happen when the property picker is working properly, but did happen due to missing indices prior to this patch, and could happen if the user is allowed to type a pathname, as in the http and telnet interfaces. Fix truncation of strings to PUSTRING_MAX: was wrong when string length was exactly 80. Fix: move the scroll bar to the top each time a new list is displayed. It was left at its previous position, while the top of the new list was displayed, not corresponding to the slider. Use getDisplayName instead of duplicated code: gives a better decision on whether to display the index, and avoids invalid property paths being generated which would previously crash find_props(). Replace unnecessary node lookups by name with direct access: tidier and more efficient. E.g. "getValueTypeString (node->getNode(name.c_str()))" -> "getValueTypeString (child)".
2002-09-07 12:35:06 +00:00
{
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;
Patch from Julian Foad: When the scroll bar slider is dragged, the list scrolls only far enough to see all items; only the arrow buttons can scroll it so far that the last item goes to the top of the view. Fix scroll bar proportional size: was wrong when the list was only a little longer than the visible area. Minor fixes such as "delete files[i];" -> "delete[] files[i];" (where the item being deleted is an array of characters) and removal of global variables. Smooth scrolling when dragging the slider: one item at a time, rather than one tenth of the list at a time. Fix a bug that would have occurred if instantiated with arrows=2. Sort properties primarily by name and then by numerical index order, rather than a simple ASCII string order. E.g. "js[1]", "js[2]", "js[10]" rather than "js[1]", "js[10]", "js[2]". Avoid crashing if the selected property path does not exist; display an empty list instead. This cannot happen when the property picker is working properly, but did happen due to missing indices prior to this patch, and could happen if the user is allowed to type a pathname, as in the http and telnet interfaces. Fix truncation of strings to PUSTRING_MAX: was wrong when string length was exactly 80. Fix: move the scroll bar to the top each time a new list is displayed. It was left at its previous position, while the top of the new list was displayed, not corresponding to the slider. Use getDisplayName instead of duplicated code: gives a better decision on whether to display the index, and avoids invalid property paths being generated which would previously crash find_props(). Replace unnecessary node lookups by name with direct access: tidier and more efficient. E.g. "getValueTypeString (node->getNode(name.c_str()))" -> "getValueTypeString (child)".
2002-09-07 12:35:06 +00:00
}
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;
Patch from Julian Foad: When the scroll bar slider is dragged, the list scrolls only far enough to see all items; only the arrow buttons can scroll it so far that the last item goes to the top of the view. Fix scroll bar proportional size: was wrong when the list was only a little longer than the visible area. Minor fixes such as "delete files[i];" -> "delete[] files[i];" (where the item being deleted is an array of characters) and removal of global variables. Smooth scrolling when dragging the slider: one item at a time, rather than one tenth of the list at a time. Fix a bug that would have occurred if instantiated with arrows=2. Sort properties primarily by name and then by numerical index order, rather than a simple ASCII string order. E.g. "js[1]", "js[2]", "js[10]" rather than "js[1]", "js[10]", "js[2]". Avoid crashing if the selected property path does not exist; display an empty list instead. This cannot happen when the property picker is working properly, but did happen due to missing indices prior to this patch, and could happen if the user is allowed to type a pathname, as in the http and telnet interfaces. Fix truncation of strings to PUSTRING_MAX: was wrong when string length was exactly 80. Fix: move the scroll bar to the top each time a new list is displayed. It was left at its previous position, while the top of the new list was displayed, not corresponding to the slider. Use getDisplayName instead of duplicated code: gives a better decision on whether to display the index, and avoids invalid property paths being generated which would previously crash find_props(). Replace unnecessary node lookups by name with direct access: tidier and more efficient. E.g. "getValueTypeString (node->getNode(name.c_str()))" -> "getValueTypeString (child)".
2002-09-07 12:35:06 +00:00
}
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 );
}