]> git.mxchange.org Git - flightgear.git/blob - src/GUI/sgVec3Slider.cxx
Patch from Andy Ross to sort properties in browser.
[flightgear.git] / src / GUI / sgVec3Slider.cxx
1 /**
2  *      sgVec3Slider.cxx
3  *
4  *      Simple PUI wrapper around sgVec3 class
5  *
6  *      Created by: Norman Vine [NHV]
7  *         nhv@yahoo.com, nhv@cape.com
8  *
9  *      Revision History
10  *      ---------------- 
11  *  Started 12:53 01/28/2001
12  *
13  */
14
15 #include "sgVec3Slider.hxx"
16 #include <Main/fg_props.hxx>
17 #include <simgear/sg_inlines.h>
18
19 class FloatSlider : public puSlider
20 {
21
22 protected:
23         float maxValue;
24         float minValue;
25         float origValue;
26         float Adjust;
27         float MyValue;
28         float TmpValue;
29         float SaveValue;
30         char buf[8];
31         char _title[32];
32         char _text[16];
33 public:
34         FloatSlider ( int x, int y, int sz, float f, const char *title,
35                                   float max = 100.0f, float min = 0.0f);
36
37         ~FloatSlider () {;}
38                 
39         static void adj( puObject *);
40
41         void updateText() {
42                 sprintf( _text, "%05.2f", MyValue );
43         }
44
45         float get() { return( MyValue ); }
46
47         // calc actual "setting" by multiplying the pui fraction by highest value setable
48         void  set() { MyValue = maxValue * TmpValue; }
49
50         float *getTmp() { return( &TmpValue ); }
51
52         // adjust the TmpValue back to 0 to 1 range of pui widget
53         void   setTmp() { TmpValue += 0.0f; }
54
55         // adjust actual "setting" value back to fraction for pui widget
56         void init( float f ) {
57                 if (f > maxValue) f = maxValue;
58                 if (f < minValue) f = minValue;
59                 Adjust   = 1.0f / maxValue;
60                 setValue(f * Adjust);
61                 adj( this );
62         }
63
64         void reinit() { init( origValue ); }
65         void cancel() { MyValue = TmpValue; }
66         void reset () { init( origValue ); }
67
68 };
69
70 void FloatSlider::adj( puObject *hs )
71 {
72         FloatSlider *slider = (FloatSlider *)hs->getUserData();
73         slider->getValue ( slider->getTmp() );
74         slider->setTmp();
75         slider->set();
76         slider->updateText();
77 }
78
79 FloatSlider::FloatSlider ( int x, int y, int sz, float f, const char *title,
80                                                    float max, float min ) :  puSlider( x, y, sz, FALSE )
81 {
82         setUserData( this );
83         maxValue = max;
84         minValue = min;
85         origValue = f;
86         init(f);
87         setDelta    ( 0.01 );
88         setCBMode   ( PUSLIDER_DELTA ) ;
89         setCallback ( adj ) ;
90         strcpy      ( _title, title);
91         setLabel    ( _title );
92         setLabelPlace ( PUPLACE_LEFT  );
93         setLegend(_text);
94         // setLegendPlace( PUPLACE_RIGHT );
95 }
96
97
98 class FloatDial : public puDial
99 {
100
101 protected:
102         float maxValue;
103         float minValue;
104         float origValue;
105         float Adjust;
106         float MyValue;
107         float TmpValue;
108         float SaveValue;
109         char buf[8];
110         char _title[32];
111         char _text[16];
112 public:
113         FloatDial ( int x, int y, int sz, float f, const char *title,
114                                   float max = 180.0f, float min = -180.0f );
115
116         ~FloatDial () {;}
117                 
118         static void adj( puObject *);
119
120         void updateText() {
121                 sprintf( _text, "%05.2f", MyValue );
122         }
123
124         float get() { return( MyValue ); }
125
126         // calc actual "setting" by multiplying the pui fraction by highest value setable
127         // in this case we're also turning a 0 to 1 range into a -.05 to +.05 before converting
128         void  set() { MyValue = ((2.0*maxValue) * (TmpValue - 0.5f)) - maxValue; }
129
130         float *getTmp() { return( &TmpValue ); }
131
132         // adjust the TmpValue back to 0 to 1 range of pui widget
133         void   setTmp() { TmpValue += 0.5f; }
134
135         // adjust actual "setting" value back to fraction for pui widget
136         // double the range from -max <-> max
137         void init( float f ) {
138                 if (f > maxValue) f = maxValue;
139                 if (f < minValue) f = minValue;
140                 Adjust   = 0.5f / maxValue;
141                 setValue((f * Adjust) + 0.5f);
142                 adj( this );
143         }
144
145         void reinit() { init( origValue ); }
146         void cancel() { MyValue = TmpValue; }
147         void reset () { init( origValue ); }
148
149 };
150
151 void FloatDial::adj( puObject *hs )
152 {
153         FloatDial *dial = (FloatDial *)hs->getUserData();
154         dial->getValue ( dial->getTmp() );
155         dial->setTmp();
156         dial->set();
157         dial->updateText();
158 }
159
160 FloatDial::FloatDial ( int x, int y, int sz, float f, const char *title,
161                                                    float max, float min ) :  puDial( x, y, sz )
162 {
163         setUserData( this );
164         maxValue = max;
165         minValue = min;
166         origValue = f;
167         init(f);
168         setDelta    ( 0.01 );
169         setCBMode   ( PUSLIDER_DELTA ) ;
170         setCallback ( adj ) ;
171         strcpy      ( _title, title);
172         setLabel    ( _title );
173         setLabelPlace ( PUPLACE_LEFT  );
174         setLegend(_text);
175         // setLegendPlace( PUPLACE_RIGHT );
176 }
177
178
179 /***********************************************/
180
181 class sgVec3Slider : public puDialogBox
182 {
183         static void goAway(puObject *p_obj);
184         static void reset(puObject *p_obj);
185         static void cancel(puObject *p_obj);
186
187 protected:
188         char Label[64];
189         FloatDial *HS0;
190         FloatDial *HS1;
191         FloatSlider *HS2;
192         puText *TitleText;
193         puOneShot *OkButton;
194         puOneShot *ResetButton;
195         puOneShot *CancelButton;
196         sgVec3 Vec, SaveVec;
197         
198 public:
199
200         sgVec3Slider ( int x, int y, sgVec3 vec,
201                                    const char *title = "Vector Adjuster",
202                                    const char *Xtitle = "Heading",
203                                    const char *Ytitle = "Pitch",
204                                    const char *Ztitle = "Radius" );
205
206         ~sgVec3Slider () {;}
207
208         // calc the property Vec with the actual point on sphere
209         void setVec()
210         {
211                 Vec3FromHeadingPitchRadius( Vec,
212                                                 HS0->get(),
213                                                 HS1->get(),
214                                                 HS2->get());
215         }
216
217         // return the offset vector according to current widget values
218         sgVec3 *getVec()
219         { 
220                 setVec();
221                 return &Vec;
222         };
223
224         // save the Vector before pushing dialog (for cancel button)
225         sgVec3 *getStashVec() { return &SaveVec; }
226         void stashVec() { 
227                 SaveVec[2] = HS0->get();
228                 SaveVec[1] = HS1->get();
229                 SaveVec[0] = HS2->get();
230         }
231
232         // functions to return pointers to protected pui widget instances
233         FloatDial *getHS0() { return HS0; }
234         FloatDial *getHS1() { return HS1; }
235         FloatSlider *getHS2() { return HS2; }
236
237         static void adjust(puObject *p_obj);
238 };
239
240 // class constructor
241 sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 vec, const char *title,
242                              const char *Xtitle,
243                              const char *Ytitle,
244                              const char *Ztitle ): puDialogBox ( x, y )
245 {
246         puFont LegendFont, LabelFont;
247         puGetDefaultFonts ( &LegendFont, &LabelFont );
248
249         int fudge = 20;
250
251         int labelW = LabelFont.getStringWidth(Xtitle);
252         labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ytitle));
253         labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ztitle));
254                 
255
256         sgCopyVec3(SaveVec, vec);
257         sgCopyVec3(Vec, vec);
258         strcpy( Label, title );
259
260         int nSliders = 3;
261         int slider_x = 70+fudge;
262         int slider_y = 75;
263         int slider_width = 270;
264         int dialer_x = 70+fudge;
265         int dialer_y = 115;
266         int dialer_size = 100;
267
268         int horiz_slider_height = LabelFont.getStringHeight()
269             + LabelFont.getStringDescender()
270             + PUSTR_TGAP + PUSTR_BGAP + 5;
271
272         int DialogWidth = slider_width + 20 + fudge + labelW;
273         int DialogHeight = dialer_size + 115 + nSliders * horiz_slider_height;
274         
275         // HACKS
276         setUserData( this );
277         horiz_slider_height += 10;
278
279         new puFrame ( 0, 0, DialogWidth, DialogHeight );
280
281         setLabelPlace( PUPLACE_DEFAULT /*PUPLACE_CENTERED*/ );
282         setLabel( Label );
283
284         /* heading */
285         HS0 = new FloatDial (  dialer_x, dialer_y, dialer_size, vec[0], Xtitle, 180.0f, -180.0f );
286         dialer_x = dialer_x + 170;
287
288         /* pitch */
289         HS1 = new FloatDial (  dialer_x, dialer_y, dialer_size, vec[1], Ytitle, 89.99f, -89.99f );
290
291         /* radius */
292         HS2 = new FloatSlider (  slider_x, slider_y, slider_width, vec[2], Ztitle, 100.0f, 0.0f );
293
294         TitleText = new puText( 130, DialogHeight - 40);
295         TitleText->setLabel("Pilot Offset");
296
297         OkButton = new puOneShot ( 70+fudge, 20, 120+fudge, 50 );
298         OkButton-> setUserData( this );
299         OkButton-> setLegend ( gui_msg_OK );
300         OkButton-> makeReturnDefault ( TRUE );
301         OkButton-> setCallback ( goAway );
302
303         CancelButton = new puOneShot ( 130+fudge, 20, 210+fudge, 50 );
304         CancelButton-> setUserData( this );
305         CancelButton-> setLegend ( gui_msg_CANCEL );
306         CancelButton-> setCallback ( cancel );
307
308         ResetButton = new puOneShot ( 220+fudge, 20, 280+fudge, 50 );
309         ResetButton-> setUserData( this );
310         ResetButton-> setLegend ( gui_msg_RESET );
311         ResetButton-> setCallback ( reset );
312
313         FG_FINALIZE_PUI_DIALOG( this );
314 }
315
316 void sgVec3Slider::goAway(puObject *p_obj)
317 {
318         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
319         FG_POP_PUI_DIALOG( me );
320 };
321
322 void sgVec3Slider::reset(puObject *p_obj)
323 {
324         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
325         me->HS0->reinit();
326         me->HS1->reinit();
327         me->HS2->reinit();
328 };
329
330 void sgVec3Slider::cancel(puObject *p_obj)
331 {
332         sgVec3 vec;
333         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
334         sgVec3 *pvec = me -> getStashVec();
335         sgCopyVec3( vec, *pvec );
336         me->HS0->init(vec[2]);
337         me->HS1->init(vec[1]);
338         me->HS2->init(vec[0]);
339         me->setVec();
340         FG_POP_PUI_DIALOG( me );
341 };
342
343 void sgVec3Slider::adjust(puObject *p_obj)
344 {
345         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
346         me -> getHS0() -> adj((puObject *)me -> getHS0());
347         me -> getHS1() -> adj((puObject *)me -> getHS1());
348         me -> getHS2() -> adj((puObject *)me -> getHS2());
349         me -> setVec();
350 };
351
352 void sgVec3SliderAdjust( puObject *p_obj )
353 {
354         sgVec3Slider *me = (sgVec3Slider *)p_obj -> getUserData();
355         me -> adjust( me );
356         FG_PUSH_PUI_DIALOG( me );
357 }
358
359 // These are globals for now
360 static puObject *PO_vec = 0;
361
362 void PilotOffsetInit() {
363         sgVec3 v;
364         sgSetVec3(v,
365                fgGetFloat("/sim/view[1]/default/pilot-offset/heading-deg"),
366                fgGetFloat("/sim/view[1]/default/pilot-offset/pitch-deg"),
367                fgGetFloat("/sim/view[1]/default/pilot-offset/radius-m")
368         );
369
370         PilotOffsetInit(v);
371 }
372
373 void PilotOffsetInit( sgVec3 vec )
374 {
375         // Only one of these things for now
376         if( PO_vec == 0 ) {
377                 /* make change so this gets done once for each vector */
378                 fgSetFloat("/sim/view[1]/current/pilot-offset/heading-deg",fgGetFloat("/sim/view[1]/default/pilot-offset/heading-deg"));
379                 fgSetFloat("/sim/view[1]/current/pilot-offset/pitch-deg",fgGetFloat("/sim/view[1]/default/pilot-offset/pitch-deg"));
380                 fgSetFloat("/sim/view[1]/current/pilot-offset/radius-m",fgGetFloat("/sim/view[1]/default/pilot-offset/radius-m"));
381                 sgVec3Slider *PO = new sgVec3Slider ( 200, 200, vec, "Pilot Offset" );
382                 PO_vec = PO;
383                 // Bindings for Pilot Offset
384                 fgTie("/sim/view[1]/current/pilot-offset/heading-deg", getPilotOffsetHeadingDeg, setPilotOffsetHeadingDeg);
385                 fgTie("/sim/view[1]/current/pilot-offset/pitch-deg", getPilotOffsetPitchDeg, setPilotOffsetPitchDeg);
386                 fgTie("/sim/view[1]/current/pilot-offset/radius-m", getPilotOffsetRadiusM, setPilotOffsetRadiusM);
387         }
388 }
389
390 void PilotOffsetAdjust( puObject * )
391 {
392         if( PO_vec == 0 ) {
393                 PilotOffsetInit();
394         }
395         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
396         me -> stashVec();
397         me -> adjust( me );
398         FG_PUSH_PUI_DIALOG( me );
399 }
400
401 // external to get pilot offset vector for viewer
402 sgVec3 *PilotOffsetGet()
403 {
404         if( PO_vec == 0 ) {
405                 PilotOffsetInit();
406         }
407         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
408         return( me -> getVec() );
409 }
410
411 // external function used to tie to FG properties
412 float PilotOffsetGetSetting(int opt)
413 {
414         float setting;
415         if( PO_vec == 0 ) {
416                 PilotOffsetInit();
417         }
418         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
419         if( opt == 0 ) setting = me -> getHS0() -> get();
420         if( opt == 1 ) setting = me -> getHS1() -> get();
421         if( opt == 2 ) setting = me->  getHS2() -> get();
422         return( setting );
423 }
424
425 // external function used to tie to FG properties
426 void PilotOffsetSet(int opt, float setting)
427 {
428         if( PO_vec == 0 ) {
429                 PilotOffsetInit();
430         }
431         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
432         if( opt == 0 ) me -> getHS0() -> init( setting );
433         if( opt == 1 ) me -> getHS1() -> init( setting );
434         if( opt == 2 ) me->  getHS2() -> init( setting );
435 }
436
437
438 // Calculate vector of point on sphere:
439 // input Heading == longitude of point on sphere
440 // input Pitch   == latitude of point on sphere
441 // input Radius  == radius of sphere
442
443 #define MIN_VIEW_OFFSET 5.0
444 void Vec3FromHeadingPitchRadius ( sgVec3 vec3, float heading, float pitch,
445 float radius )
446 {
447   double ch, sh, cp, sp;
448
449   if ( heading == SG_ZERO )
450   {
451     ch = SGD_ONE ;
452     sh = SGD_ZERO ;
453   }
454   else
455   {
456     sh = sin( (double)( heading * SG_DEGREES_TO_RADIANS )) ;
457     ch = cos( (double)( heading * SG_DEGREES_TO_RADIANS )) ;
458   }
459
460   if ( pitch == SG_ZERO )
461   {
462     cp = SGD_ONE ;
463     sp = SGD_ZERO ;
464   }
465   else
466   {
467     sp = sin( (double)( pitch * SG_DEGREES_TO_RADIANS )) ;
468     cp = cos( (double)( pitch * SG_DEGREES_TO_RADIANS )) ;
469   }
470
471   if ( radius < MIN_VIEW_OFFSET )
472           radius = MIN_VIEW_OFFSET ;
473
474   vec3[2] = (SGfloat)( ch * cp ) * radius ; // X
475   vec3[1] = (SGfloat)( sh * cp ) * radius ; // Y
476   vec3[0] = (SGfloat)(  sp ) * radius ; // Z
477 }