X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FGUI%2Fprop_picker.cxx;h=20480755fb1e38e4324cd77158ebff44d34ea830;hb=70cb759ea88526b3fb16dc6221b0a73bc730d641;hp=13724ee6cae8f484e089d1b9c8120416ec9d539b;hpb=0cc3bed841c8b75d6fe48705a3589a8bb500c609;p=flightgear.git diff --git a/src/GUI/prop_picker.cxx b/src/GUI/prop_picker.cxx index 13724ee6c..20480755f 100755 --- a/src/GUI/prop_picker.cxx +++ b/src/GUI/prop_picker.cxx @@ -35,17 +35,23 @@ # include #endif -#include "prop_picker.hxx" +#include +#include + +#include STL_STRING + #include
-#include -#include +#include "prop_picker.hxx" + +SG_USING_STD(string); + +// A local alternative name, for use when a variable called "string" is in scope - e.g. in classes derived from puInput. +typedef string stdString; #define DOTDOTSLASH "../" #define SLASH "/" -string name, line, value; - static puObject *PP_widget = 0; // widget location and size... @@ -84,7 +90,7 @@ void prop_pickerRefresh() me -> find_props(); } -void prop_editInit(char * name, char * value, char * proppath) +void prop_editInit( const char * name, const char * value, char * proppath ) { if( PE_widget == 0 ) { fgPropEdit *PP = new fgPropEdit ( name, value, proppath ); @@ -92,7 +98,7 @@ void prop_editInit(char * name, char * value, char * proppath) } } -void prop_editOpen( char * name, char * value, char * proppath ) +void prop_editOpen( const char * name, const char * value, char * proppath ) { if( PE_widget == 0 ) { prop_editInit( name, value, proppath ); @@ -106,7 +112,7 @@ void prop_editOpen( char * name, char * value, char * proppath ) } // return a human readable form of the value "type" -static string getValueTypeString( const SGPropertyNode *node ) { +static string getValueTypeString( const SGPropertyNode_ptr node ) { string result; if ( node == NULL ) { @@ -137,13 +143,17 @@ static string getValueTypeString( const SGPropertyNode *node ) { void fgPropPicker::fgPropPickerHandleSlider ( puObject * slider ) { + puListBox* list_box = (puListBox*) slider -> getUserData () ; + float val ; slider -> getValue ( &val ) ; val = 1.0f - val ; - - puListBox* list_box = (puListBox*) slider -> getUserData () ; - int index = int ( list_box -> getNumItems () * val ) ; - list_box -> setTopItem ( index ) ; + 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 ) @@ -160,14 +170,18 @@ void fgPropPicker::fgPropPickerHandleArrow ( puObject *arrow ) float val ; slider -> getValue ( &val ) ; val = 1.0f - val ; - int num_items = list_box->getNumItems () - 1 ; - if ( num_items > 0 ) + int scroll_range = list_box->getNumItems () - list_box->getNumVisible() ; + if ( scroll_range > 0 ) { - int index = int ( num_items * val + 0.5 ) + inc ; - if ( index > num_items ) index = num_items ; + 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 / num_items ) ; + slider -> setValue ( 1.0f - (float)index / scroll_range ) ; list_box -> setTopItem ( index ) ; } } @@ -223,7 +237,6 @@ void fgPropPicker::go_up_one_directory ( char *fname ) void fgPropPicker::handle_select ( puObject* list_box ) { fgPropPicker* prop_picker = (fgPropPicker*) list_box -> getUserData () ; - int selected ; list_box -> getValue ( &selected ) ; @@ -232,25 +245,29 @@ void fgPropPicker::handle_select ( puObject* list_box ) char *dst = prop_picker -> startDir ; char *src = prop_picker -> files [ selected ] ; - if ( strcmp ( src, "." ) == 0 ) - { - /* Do nothing - but better refresh anyway. */ - - prop_picker -> find_props () ; - return ; - } - - if ( strcmp ( src, ".." ) == 0 ) - { - /* Do back up one level - so refresh. */ - - go_up_one_directory ( dst ) ; - prop_picker -> find_props () ; - return ; - } + 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. */ + + go_up_one_directory ( dst ) ; + prop_picker -> find_props () ; + return ; + } + } - if ( prop_picker -> dflag [ selected ] ) - { + // 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() ) { /* If this is a directory - then descend into it and refresh */ if ( strlen ( dst ) + strlen ( src ) + 2 >= PUSTRING_MAX ) @@ -273,7 +290,8 @@ void fgPropPicker::handle_select ( puObject* list_box ) "PUI: fgPropPicker - path is too long, max is %d.", PUSTRING_MAX ) ; return ; } - prop_editOpen( prop_picker -> names [ selected ], prop_picker -> values [ selected ], dst); + + prop_editOpen(child->getName(), child->getStringValue(), dst); } else { @@ -282,8 +300,8 @@ void fgPropPicker::handle_select ( puObject* list_box ) refresh just in case some other process created the file. */ - - prop_picker -> find_props () ; + // should be obsolete once we observe child add/remove on our top node + prop_picker -> find_props () ; } } @@ -296,23 +314,30 @@ void fgPropPicker::fgPropPickerHandleOk ( puObject* b ) FG_POP_PUI_DIALOG( prop_picker ); } -/* -fgPropPicker::~fgPropPicker () +void fgPropPicker::delete_arrays () { if ( files ) { for ( int i=0; inChildren() == 0) + children[C]->removeChangeListener(this); + } + delete[] files; - delete[] names; - delete[] values; - delete[] dflag; + delete[] children; } +} + +/* + +fgPropPicker::~fgPropPicker () +{ + delete_arrays(); if ( this == puActiveWidget () ) puDeactivateWidget () ; @@ -327,9 +352,6 @@ fgPropPicker::fgPropPicker ( int x, int y, int w, int h, int arrows, puGetDefaultFonts ( &LegendFont, &LabelFont ); files = NULL ; - dflag = NULL ; - names = NULL ; - values = NULL ; num_files = 0 ; strcpy ( startDir, dir ) ; @@ -346,10 +368,7 @@ fgPropPicker::fgPropPicker ( int x, int y, int w, int h, int arrows, proppath -> setLabel (startDir); slider = new puSlider (w-30,40+20*arrows,h-100-40*arrows,TRUE,20); - slider->setDelta(0.1f); slider->setValue(1.0f); - slider->setSliderFraction (0.2f) ; - slider->setCBMode( PUSLIDER_DELTA ); list_box = new puListBox ( 10, 40, w-40, h-60 ) ; list_box -> setLabel ( title ); @@ -375,17 +394,6 @@ fgPropPicker::fgPropPicker ( int x, int y, int w, int h, int arrows, up_arrow->setCallback ( fgPropPickerHandleArrow ) ; } - if ( arrows == 2 ) - { - down_arrow = new puArrowButton ( w-30, 40, w-10, 60, PUARROW_FASTDOWN ) ; - down_arrow->setUserData ( slider ) ; - down_arrow->setCallback ( fgPropPickerHandleArrow ) ; - - up_arrow = new puArrowButton ( w-30, h-80, w-10, h-60, PUARROW_FASTUP ) ; - up_arrow->setUserData ( slider ) ; - up_arrow->setCallback ( fgPropPickerHandleArrow ) ; - } - // after picker is built, load the list box with data... find_props () ; @@ -396,154 +404,145 @@ fgPropPicker::fgPropPicker ( int x, int y, int w, int h, int arrows, slider -> setCallback ( fgPropPickerHandleSlider ) ; FG_FINALIZE_PUI_DIALOG( this ); - printf("fgPropPicker - End of Init\n"); } -void fgPropPicker::find_props () +// 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; - int pi; + // Compare name first, and then index. + int diff = strcmp(pNode1->getName(), pNode2->getName()); + if (diff) return diff; + return pNode1->getIndex() - pNode2->getIndex(); +} - if ( files != NULL ) - { - for ( int i = 0 ; i < num_files ; i++ ) { - delete files[i] ; - delete names[i] ; - delete values[i] ; - } - delete [] files ; - delete [] names ; - delete [] values ; - delete [] dflag ; - } +// Replace the current list of properties with the children of node "startDir". +void fgPropPicker::find_props () +{ + int pi; + int i; + delete_arrays(); num_files = 0 ; - char dir [ PUSTRING_MAX * 2 ] ; - - int iindex = 0; - char sindex [ 20 ]; - - strcpy ( dir, startDir ) ; - - int i = 0 ; -// printf("dir begin of find_props=%s\n",dir); -// printf("len of dir=%i",strlen(dir)); - SGPropertyNode * node = globals->get_props()->getNode(dir); - - num_files = (int)node->nChildren(); +// printf("dir begin of find_props=%s\n",startDir); +// printf("len of dir=%i",strlen(startDir)); + SGPropertyNode * node = globals->get_props()->getNode(startDir); + num_files = (node) ? (int)node->nChildren() : 0; + // instantiate string objects and add [.] and [..] for subdirs - if (strcmp(dir,"/") == 0) { + if (strcmp(startDir,"/") == 0) { files = new char* [ num_files+1 ] ; - names = new char* [ num_files+1 ] ; - values = new char* [ num_files+1 ] ; - dflag = new char [ num_files+1 ] ; pi = 0; + dotFiles = false; } else { // add two for the .. and . num_files = num_files + 2; // make room for .. and . files = new char* [ num_files+1 ] ; - names = new char* [ num_files+1 ] ; - values = new char* [ num_files+1 ] ; - dflag = new char [ num_files+1 ] ; - line = "."; - files [ 0 ] = new char[ strlen(line.c_str())+2 ]; + + stdString line = "."; + files [ 0 ] = new char[line.size() + 1]; strcpy ( files [ 0 ], line.c_str() ); - names [ 0 ] = new char[ 2 ]; - values[ 0 ] = new char[ 2 ] ; + line = ".."; - dflag[ 0 ] = 1; - files [ 1 ] = new char[ strlen(line.c_str())+2 ]; + files [ 1 ] = new char[line.size() + 1]; strcpy ( files [ 1 ], line.c_str() ); - names [ 1 ] = new char[ strlen(line.c_str())+2 ]; - values[ 1 ] = new char[ 2 ] ; - strcpy ( names [ 1 ], line.c_str() ); - dflag[ 1 ] = 1; pi = 2; + dotFiles = true; }; - for (i = 0; i < (int)node->nChildren(); i++) { - SGPropertyNode * child = node->getChild(i); - name = child->getName(); - if ( node->getChild(name.c_str(), 1) != 0 ) { - iindex = child->getIndex(); - sprintf(sindex, "[%d]", iindex); - name += sindex; - } - line = name; - names[ pi ] = new char[ strlen(line.c_str())+2 ] ; - strcpy ( names [ pi ], line.c_str() ) ; - if ( child->nChildren() > 0 ) { - dflag[ pi ] = 1 ; - files[ pi ] = new char[ strlen(line.c_str())+strlen(sindex)+4 ] ; - strcpy ( files [ pi ], line.c_str() ) ; - strcat ( files [ pi ], "/" ) ; - values[ pi ] = new char[ 2 ] ; - } else { - dflag[ pi ] = 0 ; - value = node->getStringValue ( name.c_str(), "" ); - values[ pi ] = new char[ strlen(value.c_str())+2 ] ; - strcpy ( values [pi], value.c_str() ); - line += " = '" + value + "' " + "("; - line += getValueTypeString( node->getNode( name.c_str() ) ); - line += ")"; - files[ pi ] = new char[ strlen(line.c_str())+2 ] ; - strcpy ( files [ pi ], line.c_str() ) ; - } - // printf("files->%i of %i %s\n",pi, node->nChildren(), files [pi]); - ++pi; - } - - files [ num_files ] = NULL ; - - // leave the . and .. alone... - int ii = ( strcmp(files [0], "." ) == 0 ) ? 2 : 0; - - // Sort the entries. This is a simple N^2 extraction sort. More - // elaborate algorithms aren't necessary for the few dozen - // properties we're going to sort. - for(i=ii; inChildren(); + children = new SGPropertyNode_ptr[num_children]; + for (i = 0; i < num_children; i++) { + children[i] = node->getChild(i); + } + + // Sort the children into display order + 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]; + stdString name = child->getDisplayName(true); + + if ( child->nChildren() > 0 ) { + files[ pi ] = new char[ strlen(name.c_str())+2 ] ; + strcpy ( files [ pi ], name.c_str() ) ; + strcat ( files [ pi ], "/" ) ; + } else { + files[pi] = NULL; // ensure it's NULL before setting intial value + updateTextForEntry(i); + // observe it + child->addChangeListener(this); + } + + ++pi; } } - // printf("files pointer=%i/%i\n", files, num_files); + files [ num_files ] = NULL ; proppath -> setLabel (startDir); list_box -> newList ( files ) ; - // if non-empty list, adjust the size of the slider... - if (num_files > 1) { - if ((11.0f/(num_files-1)) < 1) { - slider->setSliderFraction (11.0f/(num_files-1)) ; - slider->reveal(); - up_arrow->reveal(); - down_arrow->reveal(); - } - else { - slider->setSliderFraction (0.9999f) ; - slider->hide(); - up_arrow->hide(); - down_arrow->hide(); - } + // adjust the size of the slider... + if (num_files > list_box->getNumVisible()) { + slider->setSliderFraction((float)list_box->getNumVisible() / num_files); + 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]; + + // take a copy of the value + stdString value = node->getStringValue(); + + stdString line = node->getDisplayName() + stdString(" = '") + + value + "' " + "("; + line += getValueTypeString( node ); + 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 + if (files[index]) delete[] files[index]; + + files[index] = new char[ strlen(line.c_str())+2 ] ; + strcpy ( files [ index ], line.c_str() ) ; +} + +void fgPropPicker::valueChanged(SGPropertyNode *nd) +{ + for (int C=0; C