diff --git a/src/GUI/Makefile.am b/src/GUI/Makefile.am index 6dfeae80c..143216f78 100644 --- a/src/GUI/Makefile.am +++ b/src/GUI/Makefile.am @@ -12,6 +12,7 @@ libGUI_a_SOURCES = \ gui_local.cxx gui_local.hxx \ mouse.cxx \ $(NETWORK_SRCS) \ + prop_picker.cxx prop_picker.hxx \ sgVec3Slider.cxx sgVec3Slider.hxx \ trackball.c trackball.h diff --git a/src/GUI/gui.cxx b/src/GUI/gui.cxx index 8bd6f6c16..bf4afa4b2 100644 --- a/src/GUI/gui.cxx +++ b/src/GUI/gui.cxx @@ -85,6 +85,7 @@ #include "apt_dlg.hxx" #include "net_dlg.hxx" #include "sgVec3Slider.hxx" +#include "prop_picker.hxx" SG_USING_STD(string); @@ -882,12 +883,14 @@ puCallback editSubmenuCb [] = { extern void fgHUDalphaAdjust( puObject * ); char *viewSubmenu [] = { + "Properties", "HUD Alpha", "Pilot Offset", /* "Cockpit View > ", "View >","------------", */ "Toggle Panel...", NULL }; puCallback viewSubmenuCb [] = { + prop_pickerView, fgHUDalphaAdjust, PilotOffsetAdjust, /* notCb, notCb, NULL, */ diff --git a/src/GUI/gui_local.hxx b/src/GUI/gui_local.hxx index 7c386851d..ef329ccaf 100644 --- a/src/GUI/gui_local.hxx +++ b/src/GUI/gui_local.hxx @@ -21,6 +21,7 @@ typedef enum { } MouseMode; extern MouseMode mouse_mode; +extern int gui_menu_on; extern float lastGuiQuat[4]; extern float curGuiQuat[4]; diff --git a/src/GUI/mouse.cxx b/src/GUI/mouse.cxx index 8fdb598c7..140591b4d 100644 --- a/src/GUI/mouse.cxx +++ b/src/GUI/mouse.cxx @@ -199,7 +199,7 @@ void TurnCursorOff( void ) void maybeToggleMouse( void ) { -#if defined(WIN32_CURSOR_TWEAKS) +#if defined(WIN32_CURSOR_TWEAKS_OFF) static int first_time = ~0; static int mouse_changed = 0; @@ -265,7 +265,20 @@ void guiMotionFunc ( int x, int y ) float W, H; double offset; + ww = fgGetInt("/sim/startup/xsize"); + wh = fgGetInt("/sim/startup/ysize"); + if (mouse_mode == MOUSE_POINTER) { + // TURN MENU ON IF MOUSE AT TOP + if( y < 2 ) { + if( !gui_menu_on ) + guiToggleMenu(); + } + // TURN MENU OFF IF MOUSE AT BOTTOM + else if( y > wh-2 ) { + if( gui_menu_on ) + guiToggleMenu(); + } puMouse ( x, y ) ; glutPostRedisplay () ; } else { @@ -275,9 +288,6 @@ void guiMotionFunc ( int x, int y ) // reset left click MOUSE_VIEW toggle feature _mVtoggle = 0; - ww = fgGetInt("/sim/startup/xsize"); - wh = fgGetInt("/sim/startup/ysize"); - switch (mouse_mode) { case MOUSE_YOKE: if( !mouse_joystick_control ) { @@ -490,7 +500,7 @@ void guiMouseFunc(int button, int updown, int x, int y) case MOUSE_YOKE: mouse_mode = MOUSE_VIEW; - fgSetString("/sim/control-mode", "joystick"); + fgSetString("/sim/control-mode", "joystick"); x = fgGetInt("/sim/startup/xsize")/2; y = fgGetInt("/sim/startup/ysize")/2; _mVtoggle = 0; diff --git a/src/GUI/prop_picker.cxx b/src/GUI/prop_picker.cxx new file mode 100755 index 000000000..1024e617d --- /dev/null +++ b/src/GUI/prop_picker.cxx @@ -0,0 +1,575 @@ +/* + + 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 Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + For further information visit http://plib.sourceforge.net + + $Id$ + ******** +*/ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "prop_picker.hxx" +#include
+ +#include + +#define DOTDOTSLASH "../" +#define SLASH "/" + +string name, line, value; + +static puObject *PP_widget = 0; + +// widget location and size... +#define PROPPICK_X 100 +#define PROPPICK_Y 200 +#define PROPPICK_W 500 +#define PROPPICK_H 300 + +static puObject *PE_widget = 0; + +void prop_pickerInit() +{ + if( PP_widget == 0 ) { + fgPropPicker *PP = new fgPropPicker ( PROPPICK_X, PROPPICK_Y, PROPPICK_W, PROPPICK_H, 1, "/", "FG Properties"); + PP_widget = PP; + } +} + +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_pickerRefresh() +{ + if( PP_widget == 0 ) { + prop_pickerInit(); + } + fgPropPicker *me = (fgPropPicker *)PP_widget -> getUserData(); + me -> find_props(); +} + +void prop_editInit(char * name, char * value, char * proppath) +{ + if( PE_widget == 0 ) { + fgPropEdit *PP = new fgPropEdit ( name, value, proppath ); + PE_widget = PP; + } +} + +void prop_editOpen( char * name, char * value, char * proppath ) +{ + if( PE_widget == 0 ) { + prop_editInit( name, value, proppath ); + } + fgPropEdit *me = (fgPropEdit *)PE_widget -> getUserData(); + me -> propname -> setLabel (name); + me -> propinput -> setValue (value); + strcpy(me -> propPath, proppath); + me -> propinput -> acceptInput (); + FG_PUSH_PUI_DIALOG( me ); +} + +// return a human readable form of the value "type" +static string getValueTypeString( const SGPropertyNode *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; +} + +void fgPropPicker::fgPropPickerHandleSlider ( puObject * slider ) +{ + 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 ) ; +} + +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 num_items = list_box->getNumItems () - 1 ; + if ( num_items > 0 ) + { + int index = int ( num_items * val + 0.5 ) + inc ; + if ( index > num_items ) index = num_items ; + if ( index < 0 ) index = 0 ; + + slider -> setValue ( 1.0f - (float)index / num_items ) ; + list_box -> setTopItem ( index ) ; + } +} + + +void fgPropPicker::chop_file ( char *fname ) +{ + /* removes everything back to the last '/' */ + + for ( int i = strlen(fname)-1 ; fname[i] != SLASH[0] && i >= 0 ; i-- ) + fname[i] = '\0' ; +} + + +void fgPropPicker::go_up_one_directory ( char *fname ) +{ + /* removes everything back to the last but one '/' */ + + chop_file ( fname ) ; + + if ( strlen ( fname ) == 0 ) + { + /* Empty string! The only way to go up is to append a "../" */ + + strcpy ( fname, DOTDOTSLASH ) ; + return ; + } + + /* If the last path element is a "../" then we'll have to add another "../" */ + + if ( strcmp ( & fname [ strlen(fname)-3 ], DOTDOTSLASH ) == 0 ) + { + if ( strlen ( fname ) + 4 >= PUSTRING_MAX ) + { + ulSetError ( UL_WARNING, "PUI: fgPropPicker - path is too long, max is %d.", + PUSTRING_MAX ) ; + return ; + } + + strcat ( fname, DOTDOTSLASH ) ; + return ; + } + + /* Otherwise, just delete the last element of the path. */ + + /* Remove the trailing slash - then remove the rest as if it was a file name */ + + fname [ strlen(fname)-1 ] = '\0' ; + chop_file ( fname ) ; +} + + +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 ) + { + 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 ; + } + + printf("select got here 2\n"); + 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 ] ) + { + /* If this is a directory - then descend into it and refresh */ + + if ( strlen ( dst ) + strlen ( src ) + 2 >= PUSTRING_MAX ) + { + ulSetError ( UL_WARNING, + "PUI: fgPropPicker - path is too long, max is %d.", PUSTRING_MAX ) ; + return ; + } + + strcat ( dst, src ) ; /* add path to descend to */ + prop_picker -> find_props () ; + return ; + } + + /* If this is a regular file - then just append it to the string */ + + if ( strlen ( dst ) + strlen ( src ) + 2 >= PUSTRING_MAX ) + { + ulSetError ( UL_WARNING, + "PUI: fgPropPicker - path is too long, max is %d.", PUSTRING_MAX ) ; + return ; + } + prop_editOpen( prop_picker -> names [ selected ], prop_picker -> values [ selected ], dst); + } + else + { + /* + The user clicked on blank screen - maybe we should + refresh just in case some other process created the + file. + */ + + 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 ); +} + +/* + +fgPropPicker::~fgPropPicker () +{ + if ( files ) + { + for ( int i=0; i 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 (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 ); + list_box -> setLabelPlace ( PUPLACE_ABOVE ) ; + list_box -> setStyle ( -PUSTYLE_SMALL_SHADED ) ; + list_box -> setUserData ( this ) ; + list_box -> setCallback ( handle_select ) ; + list_box -> setValue ( 0 ) ; + + 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 ) ; + + 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 ) + { + puArrowButton *down_arrow = new puArrowButton ( w-30, 20+20*arrows, w-10, 40+20*arrows, PUARROW_DOWN ) ; + down_arrow->setUserData ( slider ) ; + down_arrow->setCallback ( fgPropPickerHandleArrow ) ; + + puArrowButton *up_arrow = new puArrowButton ( w-30, h-30-20*arrows, w-10, h-10-20*arrows, PUARROW_UP ) ; + up_arrow->setUserData ( slider ) ; + up_arrow->setCallback ( fgPropPickerHandleArrow ) ; + } + + if ( arrows == 2 ) + { + puArrowButton *down_arrow = new puArrowButton ( w-30, 40, w-10, 60, PUARROW_FASTDOWN ) ; + down_arrow->setUserData ( slider ) ; + down_arrow->setCallback ( fgPropPickerHandleArrow ) ; + + puArrowButton *up_arrow = new puArrowButton ( w-30, h-50, w-10, h-30, PUARROW_FASTUP ) ; + up_arrow->setUserData ( slider ) ; + up_arrow->setCallback ( fgPropPickerHandleArrow ) ; + } + + FG_FINALIZE_PUI_DIALOG( this ); + printf("fgPropPicker - End of Init\n"); +} + + +void fgPropPicker::find_props () +{ + + int pi; + + 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 ; + } + + 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); + + printf("find_props: allocation of node\n"); + num_files = (int)node->nChildren(); + + // take off one for the trailing "null" in each SGProperty list + num_files = num_files -1; + + // instantiate string objects and add [.] and [..] for subdirs + if (strcmp(dir,"/") == 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; + } else { + // add two for the .. and . + num_files = num_files +2; + // make room for .. and . + files = new char* [ num_files+3 ] ; + names = new char* [ num_files+3 ] ; + values = new char* [ num_files+3 ] ; + dflag = new char [ num_files+3 ] ; + line = "."; + files [ 0 ] = new char[ strlen(line.c_str())+2 ]; + 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 ]; + strcpy ( files [ 1 ], line.c_str() ); + names [ 1 ] = new char[ 2 ]; + values[ 1 ] = new char[ 2 ] ; + strcpy ( names [ 1 ], line.c_str() ); + + dflag[ 1 ] = 1; + pi = 2; + }; + + + for (int i = 0; i < (int)node->nChildren()-1; i++) { + SGPropertyNode * child = node->getChild(i); + name = child->getName(); + line = name; + names[ pi ] = new char[ strlen(line.c_str())+2 ] ; + strcpy ( names [ pi ], line.c_str() ) ; + if ( child->nChildren() > 0 ) { + iindex = child->getIndex(); + sprintf(sindex, "%d", iindex); + dflag[ pi ] = 1 ; + files[ pi ] = new char[ strlen(line.c_str())+strlen(sindex)+4 ] ; + strcpy ( files [ pi ], line.c_str() ) ; + strcat ( files [ pi ], "[" ) ; + strcat ( files [ pi ], sindex ) ; + strcat ( files [ pi ], "]/" ) ; + values[ pi ] = new char[ 2 ] ; + } else { + dflag[ pi ] = 0 ; + value = node->getStringValue ( name, "" ); + values[ pi ] = new char[ strlen(value.c_str())+2 ] ; + strcpy ( values [pi], value.c_str() ); + line += " = '" + value + "' " + "("; + line += getValueTypeString( node->getNode( name ) ); + line += ")"; + files[ pi ] = new char[ strlen(line.c_str())+2 ] ; + strcpy ( files [ pi ], line.c_str() ) ; + } + printf("files->%i %s\n",pi, files [pi]); + ++pi; + } + + files [ num_files ] = NULL ; + + printf("files pointer=%i\n", files); + proppath -> setLabel (startDir); + list_box -> newList ( files ) ; + +} + +void fgPropEdit::fgPropEditHandleCancel ( puObject* b ) +{ + fgPropEdit* prop_edit = (fgPropEdit*) b -> getUserData () ; + FG_POP_PUI_DIALOG( prop_edit ); +} + +void fgPropEdit::fgPropEditHandleOK ( puObject* b ) +{ + fgPropEdit* prop_edit = (fgPropEdit*) b -> getUserData () ; + const char* tname; + char* tvalue; + + // use label text for property node to be updated + tname = prop_edit -> propname -> getLabel(); + prop_edit -> propinput -> getValue( &tvalue ); + + SGPropertyNode * node = globals->get_props()->getNode(prop_edit -> propPath); + node->getNode( prop_edit -> propname -> getLabel(), true)->setStringValue(tvalue); + + // update the picker display so it shows new value + prop_pickerRefresh(); + + FG_POP_PUI_DIALOG( prop_edit ); +} + +fgPropEdit::fgPropEdit ( char *name, char *value, char *proppath ) : puDialogBox ( 0, 0 ) + +{ + puFont LegendFont, LabelFont; + puGetDefaultFonts ( &LegendFont, &LabelFont ); + + // 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); + + strcpy (propPath, proppath); + + setUserData( this ); + + propname = new puText (fx+10, fy+90); + propname -> setLabel (name); + + propinput = new puInput (fx+10, fy+50, fx+480, fy+80); + propinput -> setValue (value); + 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 ); +} + + diff --git a/src/GUI/prop_picker.hxx b/src/GUI/prop_picker.hxx new file mode 100755 index 000000000..6f17a46dc --- /dev/null +++ b/src/GUI/prop_picker.hxx @@ -0,0 +1,86 @@ +/* + prop_picker.hxx + +*/ + +#include + +#include +#include "gui.h" + +void prop_pickerInit(); +void prop_pickerView( puObject * ); +void prop_pickerRefresh(); +void prop_editInit(char * name, char * value ); +void prop_editOpen( char * name, char * value ); + +class fgPropPicker ; +class fgPropEdit ; + +class fgPropPicker : public puDialogBox +{ + + static void handle_select ( puObject *b ) ; + static void input_entered ( puObject *b ) ; + static void fgPropPickerHandleSlider ( puObject * slider ); + static void fgPropPickerHandleArrow ( puObject *arrow ); + static void fgPropPickerHandleOk ( puObject* b ); + + char** files ; + char** names ; + char** values ; + char* dflag ; + int num_files ; + int arrow_count ; + char startDir [ PUSTRING_MAX * 2 ] ; + +/* puInput *input ; */ + +protected: + + puFrame *frame ; + puListBox *list_box ; + puSlider *slider ; + puOneShot *cancel_button ; + puOneShot *ok_button ; + + +public: + puText *proppath ; + void find_props () ; + fgPropPicker ( int x, int y, int w, int h, int arrows, + const char *dir, const char *title = "Pick a file" ) ; + + ~fgPropPicker () {;} + + static void go_up_one_directory ( char *fname ) ; + static void chop_file ( char *fname ) ; + +} ; + +class fgPropEdit : public puDialogBox +{ + + static void fgPropEditHandleCancel ( puObject *b ) ; + static void fgPropEditHandleOK ( puObject* b ); + +protected: + + puFrame *frame ; + puOneShot *cancel_button ; + puOneShot *ok_button ; + +public: + puText *propname ; + puInput *propinput ; + char propPath [ PUSTRING_MAX * 2 ] ; + + fgPropEdit ( char *name, char *value, char *proppath ) ; + + ~fgPropEdit () {;} + + static void go_up_one_directory ( char *fname ) ; + static void chop_file ( char *fname ) ; + +} ; + diff --git a/src/GUI/sgVec3Slider.cxx b/src/GUI/sgVec3Slider.cxx index 769ae628b..df752b42b 100644 --- a/src/GUI/sgVec3Slider.cxx +++ b/src/GUI/sgVec3Slider.cxx @@ -13,6 +13,7 @@ */ #include "sgVec3Slider.hxx" +#include
#include class FloatSlider : public puSlider @@ -20,6 +21,7 @@ class FloatSlider : public puSlider protected: float maxValue; + float minValue; float origValue; float Adjust; float MyValue; @@ -30,7 +32,7 @@ protected: char _text[16]; public: FloatSlider ( int x, int y, int sz, float f, const char *title, - float max = 90.0f ); + float max = 100.0f, float min = 0.0f); ~FloatSlider () {;} @@ -41,15 +43,21 @@ public: } float get() { return( MyValue ); } - void set() { MyValue = ((2.0*maxValue) * (TmpValue - 0.5f)) - maxValue; } + + // calc actual "setting" by multiplying the pui fraction by highest value setable + void set() { MyValue = maxValue * TmpValue; } float *getTmp() { return( &TmpValue ); } - void setTmp() { TmpValue += 0.5f; } - // double the range from -max <-> max + // adjust the TmpValue back to 0 to 1 range of pui widget + void setTmp() { TmpValue += 0.0f; } + + // adjust actual "setting" value back to fraction for pui widget void init( float f ) { - Adjust = 0.5f / maxValue; - setValue((f * Adjust) + 0.5f); + if (f > maxValue) f = maxValue; + if (f < minValue) f = minValue; + Adjust = 1.0f / maxValue; + setValue(f * Adjust); adj( this ); } @@ -69,10 +77,92 @@ void FloatSlider::adj( puObject *hs ) } FloatSlider::FloatSlider ( int x, int y, int sz, float f, const char *title, - float max ) : puSlider( x, y, sz, FALSE ) + float max, float min ) : puSlider( x, y, sz, FALSE ) { setUserData( this ); maxValue = max; + minValue = min; + origValue = f; + init(f); + setDelta ( 0.01 ); + setCBMode ( PUSLIDER_DELTA ) ; + setCallback ( adj ) ; + strcpy ( _title, title); + setLabel ( _title ); + setLabelPlace ( PUPLACE_LEFT ); + setLegend(_text); + // setLegendPlace( PUPLACE_RIGHT ); +} + + +class FloatDial : public puDial +{ + +protected: + float maxValue; + float minValue; + float origValue; + float Adjust; + float MyValue; + float TmpValue; + float SaveValue; + char buf[8]; + char _title[32]; + char _text[16]; +public: + FloatDial ( int x, int y, int sz, float f, const char *title, + float max = 180.0f, float min = -180.0f ); + + ~FloatDial () {;} + + static void adj( puObject *); + + void updateText() { + sprintf( _text, "%05.2f", MyValue ); + } + + float get() { return( MyValue ); } + + // calc actual "setting" by multiplying the pui fraction by highest value setable + // in this case we're also turning a 0 to 1 range into a -.05 to +.05 before converting + void set() { MyValue = ((2.0*maxValue) * (TmpValue - 0.5f)) - maxValue; } + + float *getTmp() { return( &TmpValue ); } + + // adjust the TmpValue back to 0 to 1 range of pui widget + void setTmp() { TmpValue += 0.5f; } + + // adjust actual "setting" value back to fraction for pui widget + // double the range from -max <-> max + void init( float f ) { + if (f > maxValue) f = maxValue; + if (f < minValue) f = minValue; + Adjust = 0.5f / maxValue; + setValue((f * Adjust) + 0.5f); + adj( this ); + } + + void reinit() { init( origValue ); } + void cancel() { MyValue = TmpValue; } + void reset () { init( origValue ); } + +}; + +void FloatDial::adj( puObject *hs ) +{ + FloatDial *dial = (FloatDial *)hs->getUserData(); + dial->getValue ( dial->getTmp() ); + dial->setTmp(); + dial->set(); + dial->updateText(); +} + +FloatDial::FloatDial ( int x, int y, int sz, float f, const char *title, + float max, float min ) : puDial( x, y, sz ) +{ + setUserData( this ); + maxValue = max; + minValue = min; origValue = f; init(f); setDelta ( 0.01 ); @@ -96,9 +186,10 @@ class sgVec3Slider : public puDialogBox protected: char Label[64]; - FloatSlider *HS0; - FloatSlider *HS1; + FloatDial *HS0; + FloatDial *HS1; FloatSlider *HS2; + puText *TitleText; puOneShot *OkButton; puOneShot *ResetButton; puOneShot *CancelButton; @@ -114,17 +205,23 @@ public: ~sgVec3Slider () {;} - // ??? + // calc the property Vec with the actual point on sphere void setVec() { Vec3FromHeadingPitchRadius( Vec, - (HS0->get() + 90) * 2, - HS1->get(), - HS2->get() ); + HS0->get(), + HS1->get(), + HS2->get()); } - sgVec3 *getVec() { setVec(); return &Vec; }; + // return the offset vector according to current widget values + sgVec3 *getVec() + { + setVec(); + return &Vec; + }; + // save the Vector before pushing dialog (for cancel button) sgVec3 *getStashVec() { return &SaveVec; } void stashVec() { SaveVec[2] = HS0->get(); @@ -132,13 +229,15 @@ public: SaveVec[0] = HS2->get(); } - FloatSlider *getHS0() { return HS0; } - FloatSlider *getHS1() { return HS1; } + // functions to return pointers to protected pui widget instances + FloatDial *getHS0() { return HS0; } + FloatDial *getHS1() { return HS1; } FloatSlider *getHS2() { return HS2; } static void adjust(puObject *p_obj); }; +// class constructor sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 vec, const char *title, const char *Xtitle, const char *Ytitle, @@ -153,7 +252,6 @@ sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 vec, const char *title, labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ytitle)); labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ztitle)); - int DialogWidth = 300 + fudge + labelW; sgCopyVec3(SaveVec, vec); sgCopyVec3(Vec, vec); @@ -161,44 +259,53 @@ sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 vec, const char *title, int nSliders = 3; int slider_x = 70+fudge; - int slider_y = 55; - int slider_width = 240; + int slider_y = 75; + int slider_width = 270; + int dialer_x = 70+fudge; + int dialer_y = 115; + int dialer_size = 100; int horiz_slider_height = LabelFont.getStringHeight() + LabelFont.getStringDescender() + PUSTR_TGAP + PUSTR_BGAP + 5; + int DialogWidth = slider_width + 20 + fudge + labelW; + int DialogHeight = dialer_size + 115 + nSliders * horiz_slider_height; + // HACKS setUserData( this ); horiz_slider_height += 10; - new puFrame ( 0, 0, - DialogWidth, - 85 + nSliders * horiz_slider_height ); + new puFrame ( 0, 0, DialogWidth, DialogHeight ); setLabelPlace( PUPLACE_DEFAULT /*PUPLACE_CENTERED*/ ); setLabel( Label ); - HS2 = new FloatSlider ( slider_x, slider_y, slider_width, vec[2], Ztitle ); - slider_y += horiz_slider_height; + /* heading */ + HS0 = new FloatDial ( dialer_x, dialer_y, dialer_size, vec[0], Xtitle, 180.0f, -180.0f ); + dialer_x = dialer_x + 170; - HS1 = new FloatSlider ( slider_x, slider_y, slider_width, vec[1], Ytitle ); - slider_y += horiz_slider_height; + /* pitch */ + HS1 = new FloatDial ( dialer_x, dialer_y, dialer_size, vec[1], Ytitle, 89.99f, -89.99f ); - HS0 = new FloatSlider ( slider_x, slider_y, slider_width, vec[0], Xtitle ); + /* radius */ + HS2 = new FloatSlider ( slider_x, slider_y, slider_width, vec[2], Ztitle, 100.0f, 0.0f ); - OkButton = new puOneShot ( 70+fudge, 10, 120+fudge, 50 ); + TitleText = new puText( 130, DialogHeight - 40); + TitleText->setLabel("Pilot Offset"); + + OkButton = new puOneShot ( 70+fudge, 20, 120+fudge, 50 ); OkButton-> setUserData( this ); OkButton-> setLegend ( gui_msg_OK ); OkButton-> makeReturnDefault ( TRUE ); OkButton-> setCallback ( goAway ); - CancelButton = new puOneShot ( 130+fudge, 10, 210+fudge, 50 ); + CancelButton = new puOneShot ( 130+fudge, 20, 210+fudge, 50 ); CancelButton-> setUserData( this ); CancelButton-> setLegend ( gui_msg_CANCEL ); CancelButton-> setCallback ( cancel ); - ResetButton = new puOneShot ( 220+fudge, 10, 280+fudge, 50 ); + ResetButton = new puOneShot ( 220+fudge, 20, 280+fudge, 50 ); ResetButton-> setUserData( this ); ResetButton-> setLegend ( gui_msg_RESET ); ResetButton-> setCallback ( reset ); @@ -206,7 +313,6 @@ sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 vec, const char *title, FG_FINALIZE_PUI_DIALOG( this ); } - void sgVec3Slider::goAway(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); @@ -255,7 +361,11 @@ static puObject *PO_vec = 0; void PilotOffsetInit() { sgVec3 v; - sgSetVec3(v,0.0,0.0,20.0); + sgSetVec3(v, + fgGetFloat("/sim/view[1]/default/pilot-offset/heading-deg"), + fgGetFloat("/sim/view[1]/default/pilot-offset/pitch-deg"), + fgGetFloat("/sim/view[1]/default/pilot-offset/radius-m") + ); PilotOffsetInit(v); } @@ -279,6 +389,7 @@ void PilotOffsetAdjust( puObject * ) FG_PUSH_PUI_DIALOG( me ); } +// external to get pilot offset vector for viewer sgVec3 *PilotOffsetGet() { if( PO_vec == 0 ) { @@ -288,10 +399,37 @@ sgVec3 *PilotOffsetGet() return( me -> getVec() ); } +// external function used to tie to FG properties +float PilotOffsetGetSetting(int opt) +{ + float setting; + if( PO_vec == 0 ) { + PilotOffsetInit(); + } + sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData(); + if( opt == 0 ) setting = me -> getHS0() -> get(); + if( opt == 1 ) setting = me -> getHS1() -> get(); + if( opt == 2 ) setting = me-> getHS2() -> get(); + return( setting ); +} -// Heading == longitude of point on sphere -// Pitch == latitude of point on sphere -// Radius == radius of sphere +// external function used to tie to FG properties +void PilotOffsetSet(int opt, float setting) +{ + if( PO_vec == 0 ) { + PilotOffsetInit(); + } + sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData(); + if( opt == 0 ) me -> getHS0() -> init( setting ); + if( opt == 1 ) me -> getHS1() -> init( setting ); + if( opt == 2 ) me-> getHS2() -> init( setting ); +} + + +// Calculate vector of point on sphere: +// input Heading == longitude of point on sphere +// input Pitch == latitude of point on sphere +// input Radius == radius of sphere #define MIN_VIEW_OFFSET 5.0 void Vec3FromHeadingPitchRadius ( sgVec3 vec3, float heading, float pitch, diff --git a/src/GUI/sgVec3Slider.hxx b/src/GUI/sgVec3Slider.hxx index b6d738ad9..0d694a2e2 100644 --- a/src/GUI/sgVec3Slider.hxx +++ b/src/GUI/sgVec3Slider.hxx @@ -20,5 +20,7 @@ void PilotOffsetAdjust( puObject * ); void Vec3FromHeadingPitchRadius( sgVec3 vec3, float heading, float pitch, float radius ); //void PilotOffsetGet( float *po ); sgVec3 *PilotOffsetGet(); +void PilotOffsetSet( int opt, float setting); +float PilotOffsetGetSetting( int opt ); #endif // _VEC3_SLIDER_H