]> git.mxchange.org Git - flightgear.git/blob - src/GUI/gui.cxx
09b8562a9d5036c2965cfabd9d7a8b944f85f455
[flightgear.git] / src / GUI / gui.cxx
1 /**************************************************************************
2  * gui.cxx
3  *
4  * Written 1998 by Durk Talsma, started Juni, 1998.  For the flight gear
5  * project.
6  *
7  * Additional mouse supported added by David Megginson, 1999.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of the
12  * License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  **************************************************************************/
25
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #include <simgear/compiler.h>
32
33 #ifdef FG_MATH_EXCEPTION_CLASH
34 #  include <math.h>
35 #endif
36
37 #ifdef HAVE_WINDOWS_H
38 #  include <windows.h>
39 #endif
40
41 #include <GL/glut.h>
42 #include <simgear/xgl/xgl.h>
43
44 #if defined(FX) && defined(XMESA)
45 #  include <GL/xmesa.h>
46 #endif
47
48 #include STL_FSTREAM
49 #include STL_STRING
50
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include <simgear/constants.h>
55 #include <simgear/debug/logstream.hxx>
56 #include <simgear/misc/fgpath.hxx>
57 #include <simgear/screen/screen-dump.hxx>
58
59 #include <Include/general.hxx>
60 #include <Aircraft/aircraft.hxx>
61 #include <Airports/simple.hxx>
62 #include <Autopilot/auto_gui.hxx>
63 #include <Autopilot/newauto.hxx>
64 #include <Cockpit/panel.hxx>
65 #include <Controls/controls.hxx>
66 #include <FDM/flight.hxx>
67 #include <Main/options.hxx>
68 #include <Main/fg_init.hxx>
69 #include <Main/views.hxx>
70 #include <Main/save.hxx>
71 #include <Main/bfi.hxx>
72 #ifdef FG_NETWORK_OLK
73 #include <NetworkOLK/network.h>
74 #endif
75 #include <Time/fg_time.hxx>
76
77 #if defined( WIN32 ) && !defined( __CYGWIN__ )
78 #  include <simgear/screen/win32-printer.h>
79 #  include <simgear/screen/GlBitmaps.h>
80 #endif
81
82 /*
83  * trackball.h
84  * A virtual trackball implementation
85  * Written by Gavin Bell for Silicon Graphics, November 1988.
86  */
87 /*
88  * Pass the x and y coordinates of the last and current positions of
89  * the mouse, scaled so they are from (-1.0 ... 1.0).
90  *
91  * The resulting rotation is returned as a quaternion rotation in the
92  * first paramater.
93  */
94 void
95 trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
96
97 /*
98  * Given two quaternions, add them together to get a third quaternion.
99  * Adding quaternions to get a compound rotation is analagous to adding
100  * translations to get a compound translation.  When incrementally
101  * adding rotations, the first argument here should be the new
102
103   * rotation, the second and third the total rotation (which will be
104  * over-written with the resulting new total rotation).
105  */
106 void
107 add_quats(float *q1, float *q2, float *dest);
108
109 /*
110  * A useful function, builds a rotation matrix in Matrix based on
111  * given quaternion.
112  */
113 void
114 build_rotmatrix(float m[4][4], float q[4]);
115
116 /*
117  * This function computes a quaternion based on an axis (defined by
118  * the given vector) and an angle about which to rotate.  The angle is
119  * expressed in radians.  The result is put into the third argument.
120  */
121 void
122 axis_to_quat(float a[3], float phi, float q[4]);
123
124
125 #include "gui.h"
126
127 FG_USING_STD(string);
128
129 #ifndef FG_HAVE_NATIVE_SGI_COMPILERS
130 FG_USING_STD(cout);
131 #endif
132
133 #if defined(WIN32) || defined(__CYGWIN32__)
134 #define WIN32_CURSOR_TWEAKS
135 #elif (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
136 #define X_CURSOR_TWEAKS
137 #endif
138
139 // hack, should come from an include someplace
140 extern void fgInitVisuals( void );
141 extern void fgReshape( int width, int height );
142 extern void fgRenderFrame( void );
143
144 puFont guiFnt = 0;
145 fntTexFont *guiFntHandle = 0;
146
147 static puMenuBar    *mainMenuBar = 0;
148 //static puButton     *hideMenuButton = 0;
149
150 static puDialogBox  *dialogBox = 0;
151 static puFrame      *dialogFrame = 0;
152 static puText       *dialogBoxMessage = 0;
153 static puOneShot    *dialogBoxOkButton = 0;
154
155
156 static puDialogBox  *YNdialogBox = 0;
157 static puFrame      *YNdialogFrame = 0;
158 static puText       *YNdialogBoxMessage = 0;
159 static puOneShot    *YNdialogBoxOkButton = 0;
160 static puOneShot    *YNdialogBoxNoButton = 0;
161
162 static char msg_OK[]     = "OK";
163 static char msg_NO[]     = "NO";
164 static char msg_YES[]    = "YES";
165 static char msg_CANCEL[] = "Cancel";
166 static char msg_RESET[]  = "Reset";
167
168 char *gui_msg_OK;     // "OK"
169 char *gui_msg_NO;     // "NO"
170 char *gui_msg_YES;    // "YES"
171 char *gui_msg_CANCEL; // "CANCEL"
172 char *gui_msg_RESET;  // "RESET"
173
174 static char global_dialog_string[256];
175
176 // from autopilot.cxx
177 // extern void NewAltitude( puObject *cb );
178 // extern void NewHeading( puObject *cb );
179 // extern void fgAPAdjust( puObject * );
180 // extern void NewTgtAirport( puObject *cb );
181 // bool fgAPTerrainFollowEnabled( void );
182 // bool fgAPAltitudeEnabled( void );
183 // bool fgAPHeadingEnabled( void );
184 // bool fgAPWayPointEnabled( void );
185 // bool fgAPAutoThrottleEnabled( void );
186
187 // from cockpit.cxx
188 extern void fgLatLonFormatToggle( puObject *);
189
190 /* --------------------------------------------------------------------
191 Mouse stuff
192 ---------------------------------------------------------------------*/
193
194 static int _mX = 0;
195 static int _mY = 0;
196 static int _savedX = 0;
197 static int _savedY = 0;
198 static int last_buttons = 0 ;
199 static int mouse_active = 0;
200 static int menu_on = 0;
201 static int mouse_joystick_control = 0;
202
203 //static time_t mouse_off_time;
204 //static int mouse_timed_out;
205
206 // to allow returning to previous view
207 // on second left click in MOUSE_VIEW mode
208 // This has file scope so that it can be reset
209 // if the little rodent is moved  NHV
210 static  int _mVtoggle;
211
212 // we break up the glutGetModifiers return mask
213 // once per loop and stash what we need in these
214 static int glut_active_shift;
215 static int glut_active_ctrl;
216 static int glut_active_alt;
217
218 static float lastquat[4];
219 static float curquat[4];
220 static float _quat0[4];
221 float quat_mat[4][4];
222
223 // uncomment this for view to exactly follow mouse in MOUSE_VIEW mode
224 // else smooth out the view panning to .01 radian per frame
225 // see view_offset smoothing mechanism in main.cxx
226 #define NO_SMOOTH_MOUSE_VIEW
227
228 // uncomment following to
229 #define RESET_VIEW_ON_LEAVING_MOUSE_VIEW
230
231 /* --------------------------------------------------------------------
232 Support for mouse as control yoke (david@megginson.com)
233
234 - right button toggles between pointer and yoke
235 - horizontal drag with no buttons moves ailerons
236 - vertical drag with no buttons moves elevators
237 - horizontal drag with left button moves brakes (left=on)
238 - vertical drag with left button moves throttle (up=more)
239 - horizontal drag with middle button moves rudder
240 - vertical drag with middle button moves trim
241
242 For the *_sensitivity variables, a lower number means more sensitive.
243
244 TODO: figure out how to keep pointer from leaving window in yoke mode.
245 TODO: add thresholds and null zones
246 TODO: sensitivity should be configurable at user option.
247 TODO: allow differential braking (this will be useful if FlightGear
248       ever supports tail-draggers like the DC-3)
249 ---------------------------------------------------------------------*/
250
251 typedef enum {
252     MOUSE_POINTER,
253     MOUSE_YOKE,
254     MOUSE_VIEW
255 } MouseMode;
256
257 MouseMode mouse_mode = MOUSE_POINTER;
258
259 static double aileron_sensitivity = 1.0/500.0;
260 static double elevator_sensitivity = 1.0/500.0;
261 static double brake_sensitivity = 1.0/250.0;
262 static double throttle_sensitivity = 1.0/250.0;
263 static double rudder_sensitivity = 1.0/500.0;
264 static double trim_sensitivity = 1.0/1000.0;
265
266 static inline void Quat0( void ) {
267     curquat[0] = _quat0[0];
268     curquat[1] = _quat0[1];
269     curquat[2] = _quat0[2];
270     curquat[3] = _quat0[3];
271 }
272
273 static inline int left_button( void ) {
274     return( last_buttons & (1 << GLUT_LEFT_BUTTON) );
275 }
276
277 static inline int middle_button( void ) {
278     return( last_buttons & (1 << GLUT_MIDDLE_BUTTON) );
279 }
280
281 static inline int right_button( void ) {
282     return( last_buttons & (1 << GLUT_RIGHT_BUTTON) );
283 }
284
285 static inline void TurnCursorOn( void )
286 {
287     mouse_active = ~0;
288 #if defined(WIN32_CURSOR_TWEAKS)
289     switch (mouse_mode) {
290         case MOUSE_POINTER:
291             glutSetCursor(GLUT_CURSOR_INHERIT);
292             break;
293         case MOUSE_YOKE:
294             glutSetCursor(GLUT_CURSOR_CROSSHAIR);
295             break;
296         case MOUSE_VIEW:
297             glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
298             break;
299     }
300 #endif
301 #if defined(X_CURSOR_TWEAKS)
302     glutWarpPointer( current_view.get_winWidth()/2, current_view.get_winHeight()/2);
303 #endif
304 }
305
306 static inline void TurnCursorOff( void )
307 {
308     mouse_active = 0;
309 #if defined(WIN32_CURSOR_TWEAKS)
310     glutSetCursor(GLUT_CURSOR_NONE);
311 #elif defined(X_CURSOR_TWEAKS)
312     glutWarpPointer( current_view.get_winWidth(), current_view.get_winHeight());
313 #endif
314 }
315
316 void maybeToggleMouse( void )
317 {
318 #if defined(WIN32_CURSOR_TWEAKS)
319     static int first_time = ~0;
320     static int mouse_changed = 0;
321
322     if ( first_time ) {
323         if(!mouse_active) {
324             mouse_changed = ~mouse_changed;
325             TurnCursorOn();
326         }
327     } else {
328         if( mouse_mode != MOUSE_POINTER )
329             return;
330         if( mouse_changed ) {
331             mouse_changed = ~mouse_changed;
332             if(mouse_active) {
333                 TurnCursorOff();
334             }
335         }
336     }
337     first_time = ~first_time;
338 #endif // #ifdef WIN32
339 }
340
341 // Call with FALSE to init and TRUE to restore
342 void BusyCursor( int restore )
343 {
344     static GLenum cursor = (GLenum) 0;
345     if( restore ) {
346         glutSetCursor(cursor);
347     } else {
348         cursor = (GLenum) glutGet( (GLenum) GLUT_WINDOW_CURSOR );
349 #if defined(WIN32_CURSOR_TWEAKS)
350         TurnCursorOn();
351 #endif
352         glutSetCursor( GLUT_CURSOR_WAIT );
353     }
354 }
355
356 int guiGetMouseButton(void)
357 {
358     return last_buttons;
359 }
360
361 void guiGetMouse(int *x, int *y)
362 {
363     *x = _mX;
364     *y = _mY;
365 };
366
367 void guiMotionFunc ( int x, int y )
368 {
369     int ww, wh, need_warp = 0;
370     float W, H;
371     double offset;
372 //  FGTime *t = FGTime::cur_time_params;
373 //  if( mouse_timed_out ) {
374 //      if( t->get_cur_time() > mouse_off_time ) {
375 //          moused_timed_out = 0;
376 //          TurnCursorOn();
377 //          glutPostRedisplay () ;
378 //      }
379 //  }
380
381     if (mouse_mode == MOUSE_POINTER) {
382         puMouse ( x, y ) ;
383         glutPostRedisplay () ;
384     } else {
385         if( x == _mX && y == _mY)
386             return;
387         
388         // reset left click MOUSE_VIEW toggle feature
389         _mVtoggle = 0;
390         
391         ww = current_view.get_winWidth();
392         wh = current_view.get_winHeight();
393         
394         switch (mouse_mode) {
395             case MOUSE_YOKE:
396                 if( !mouse_joystick_control ) {
397                     mouse_joystick_control = 1;
398                     current_options.set_control_mode( fgOPTIONS::FG_MOUSE );
399                 } else {
400                     if ( left_button() ) {
401                         offset = (_mX - x) * brake_sensitivity;
402                         controls.move_brake(FGControls::ALL_WHEELS, offset);
403                         offset = (_mY - y) * throttle_sensitivity;
404                         controls.move_throttle(FGControls::ALL_ENGINES, offset);
405                     } else if ( right_button() ) {
406                         if( ! current_autopilot->get_HeadingEnabled() ) {
407                             offset = (x - _mX) * rudder_sensitivity;
408                             controls.move_rudder(offset);
409                         }
410                         if( ! current_autopilot->get_AltitudeEnabled() ) {
411                             offset = (_mY - y) * trim_sensitivity;
412                             controls.move_elevator_trim(offset);
413                         }
414                     } else {
415                         if( ! current_autopilot->get_HeadingEnabled() ) {
416                             offset = (x - _mX) * aileron_sensitivity;
417                             controls.move_aileron(offset);
418                         }
419                         if( ! current_autopilot->get_AltitudeEnabled() ) {
420                             offset = (_mY - y) * elevator_sensitivity;
421                             controls.move_elevator(offset);
422                         }
423                     }
424                 }
425                 // Keep the mouse in the window.
426                 if (x < 5 || x > ww-5 || y < 5 || y > wh-5) {
427                     x = ww / 2;
428                     y = wh / 2;
429                     need_warp = 1;
430                 }
431                 break;
432                 
433             case MOUSE_VIEW:
434                 if( y <= 0 ) {
435 #define CONTRAINED_MOUSE_VIEW_Y
436 #ifdef CONTRAINED_MOUSE_VIEW_Y
437                     y = 1;
438 #else
439                     y = wh-2;
440 #endif // CONTRAINED_MOUSE_VIEW_Y
441                     need_warp = 1;
442                 } else if( y >= wh-1) {
443 #ifdef CONTRAINED_MOUSE_VIEW_Y
444                     y = wh-2;
445 #else
446                     y = 1;
447 #endif // CONTRAINED_MOUSE_VIEW_Y
448                     need_warp = 1;
449                 }
450                 // wrap MOUSE_VIEW mode cursor x position
451                 if ( x <= 0 ) {
452                     need_warp = 1;
453                     x = ww-2;
454                 } else if ( x >= ww-1 ) {
455                     need_warp = 1;
456                     x = 1;
457                 }
458                 // try to get FG_PI movement in each half of screen
459                 // do spherical pan
460                 W = ww;
461                 H = wh;
462                 if( middle_button() ) {
463                     trackball(lastquat,
464                               (2.0f * _mX - W) / W,
465                               0, //(H - 2.0f * y) / H,         // 3
466                               (2.0f * x - W) / W,
467                               0 //(H - 2.0f * _mY) / H       // 1
468                              );
469                     x = _mX;
470                     y = _mY;
471                     need_warp = 1;
472                 } else {
473                     trackball(lastquat,
474                               0, //(2.0f * _mX - W) / W,  // 0
475                               (H - 2.0f * y) / H,         // 3
476                               0, //(2.0f * x - W) / W,    // 2
477                               (H - 2.0f * _mY) / H        // 1 
478                              );
479                 }
480                 add_quats(lastquat, curquat, curquat);
481                 build_rotmatrix(quat_mat, curquat);
482                 
483                 // do horizontal pan
484                 // this could be done in above quat
485                 // but requires redoing view pipeline
486                 offset = current_view.get_goal_view_offset();
487                 offset += ((_mX - x) * FG_2PI / W );
488                 while (offset < 0.0) {
489                     offset += FG_2PI;
490                 }
491                 while (offset > FG_2PI) {
492                     offset -= FG_2PI;
493                 }
494                 current_view.set_goal_view_offset(offset);
495 #ifdef NO_SMOOTH_MOUSE_VIEW
496                 current_view.set_view_offset(offset);
497 #endif
498                 break;
499             
500             default:
501                 break;
502         }
503     }
504     if( need_warp)
505         glutWarpPointer(x, y);
506     
507     // Record the new mouse position.
508     _mX = x;
509     _mY = y;
510 }
511
512
513 void guiMouseFunc(int button, int updown, int x, int y)
514 {
515     int glutModifiers;
516
517     // private MOUSE_VIEW state variables
518     // to allow alternate left clicks in MOUSE_VIEW mode
519     // to toggle between current offsets and straight ahead
520     // uses _mVtoggle
521     static int _mVx, _mVy, _Vx, _Vy;
522     static float _quat[4];
523     static double _view_offset;
524     
525     // general purpose variables
526     double offset;
527             
528     glutModifiers = glutGetModifiers();
529     glut_active_shift = glutModifiers & GLUT_ACTIVE_SHIFT;
530     glut_active_ctrl  = glutModifiers & GLUT_ACTIVE_CTRL; 
531     glut_active_alt   = glutModifiers & GLUT_ACTIVE_ALT;
532     
533     // Was the left button pressed?
534     if (updown == GLUT_DOWN ) {
535         if( button == GLUT_LEFT_BUTTON)
536         {
537             switch (mouse_mode) {
538                 case MOUSE_POINTER:
539                     break;
540                 case MOUSE_YOKE:
541                     break;
542                 case MOUSE_VIEW:
543                     if(_mVtoggle) {
544                         // resume previous view offsets
545                         _mX = _mVx;
546                         _mY = _mVy;
547                         x = _Vx;
548                         y = _Vy;
549                         curquat[0] = _quat[0];
550                         curquat[1] = _quat[1];
551                         curquat[2] = _quat[2];
552                         curquat[3] = _quat[3];
553                         current_view.set_goal_view_offset(_view_offset);
554 #ifdef NO_SMOOTH_MOUSE_VIEW
555                         current_view.set_view_offset(_view_offset);
556 #endif
557                     } else {
558                         // center view
559                         _mVx = _mX;
560                         _mVy = _mY;
561                         _Vx = x;
562                         _Vy = y;
563                         _quat[0] = curquat[0];
564                         _quat[1] = curquat[1];
565                         _quat[2] = curquat[2];
566                         _quat[3] = curquat[3];
567                         x = current_view.get_winWidth()/2;
568                         y = current_view.get_winHeight()/2;
569                         Quat0();
570                         _view_offset = current_view.get_goal_view_offset();
571                         current_view.set_goal_view_offset(0.0);
572 #ifdef NO_SMOOTH_MOUSE_VIEW
573                         current_view.set_view_offset(0.0);
574 #endif
575                     }
576                     glutWarpPointer( x , y);
577                     build_rotmatrix(quat_mat, curquat);
578                     _mVtoggle = ~_mVtoggle;
579                     break;
580             }
581         }else if ( button == GLUT_RIGHT_BUTTON) {
582             switch (mouse_mode) {
583                 case MOUSE_POINTER:
584                     mouse_mode = MOUSE_YOKE;
585                     mouse_joystick_control = 0;
586                     _savedX = x;
587                     _savedY = y;
588                     // start with zero point in center of screen
589                     _mX = current_view.get_winWidth()/2;
590                     _mY = current_view.get_winHeight()/2;
591                     
592                     // try to have the MOUSE_YOKE position
593                     // reflect the current stick position
594                     offset = controls.get_aileron();
595                     x = _mX - (int)(offset * aileron_sensitivity);
596                     offset = controls.get_elevator();
597                     y = _mY - (int)(offset * elevator_sensitivity);
598                     
599                     glutSetCursor(GLUT_CURSOR_CROSSHAIR);
600                     FG_LOG( FG_INPUT, FG_INFO, "Mouse in yoke mode" );
601                     break;
602                     
603                 case MOUSE_YOKE:
604                     mouse_mode = MOUSE_VIEW;
605                     current_options.set_control_mode( fgOPTIONS::FG_JOYSTICK );
606                     x = current_view.get_winWidth()/2;
607                     y = current_view.get_winHeight()/2;
608                     _mVtoggle = 0;
609                     Quat0();
610                     build_rotmatrix(quat_mat, curquat);
611                     glutSetCursor(GLUT_CURSOR_LEFT_RIGHT);
612                     FG_LOG( FG_INPUT, FG_INFO, "Mouse in view mode" );
613                     break;
614                     
615                 case MOUSE_VIEW:
616                     mouse_mode = MOUSE_POINTER;
617                     x = _savedX;
618                     y = _savedY;
619 #ifdef RESET_VIEW_ON_LEAVING_MOUSE_VIEW
620                     Quat0();
621                     build_rotmatrix(quat_mat, curquat);
622                     current_view.set_goal_view_offset(0.0);
623 #ifdef NO_SMOOTH_MOUSE_VIEW
624                     current_view.set_view_offset(0.0);
625 #endif
626 #endif      // RESET_VIEW_ON_LEAVING_MOUSE_VIEW
627                     glutSetCursor(GLUT_CURSOR_INHERIT);
628                     
629                     if(!menu_on)
630                         TurnCursorOff();
631                     
632                     FG_LOG( FG_INPUT, FG_INFO, "Mouse in pointer mode" );
633                     break;
634             }     
635             glutWarpPointer( x, y );
636         } // END RIGHT BUTTON
637     } // END UPDOWN == GLUT_DOWN
638     
639     // Note which button is pressed.
640     if ( updown == GLUT_DOWN ) {
641         last_buttons |=  ( 1 << button ) ;
642     } else {
643         last_buttons &= ~( 1 << button ) ;
644     }
645     
646     // If we're in pointer mode, let PUI
647     // know what's going on.
648     if (mouse_mode == MOUSE_POINTER) {
649       if (!puMouse (button, updown, x,y)) {
650         current_panel->doMouseAction(button, updown, x, y);
651       }
652     }
653     
654     // Register the new position (if it
655     // hasn't been registered already).
656     _mX = x;
657     _mY = y;
658     
659     glutPostRedisplay ();
660 }
661
662 /* ================ General Purpose Functions ================ */
663
664 // Intercept the Escape Key
665 void ConfirmExitDialog(void)
666 {
667     FG_PUSH_PUI_DIALOG( YNdialogBox );
668 }
669
670 // General Purpose Message Box
671 void mkDialog (const char *txt)
672 {
673     strncpy(global_dialog_string, txt, 256);
674     dialogBoxMessage->setLabel(global_dialog_string);
675     FG_PUSH_PUI_DIALOG( dialogBox );
676 }
677
678 // Repair any damage done to the Panel by other Gui Items
679 void guiFixPanel( void )
680 {
681     int toggle_pause;
682
683     if ( current_options.get_panel_status() ) {
684         // FGView *v = &current_view;
685         FGTime *t = FGTime::cur_time_params;
686
687         if( (toggle_pause = !t->getPause()) )
688             t->togglePauseMode();
689
690         if(toggle_pause)
691             t->togglePauseMode();
692     }
693 }
694
695 // Toggle the Menu and Mouse display state
696 void guiToggleMenu(void)
697 {
698     if( menu_on ) {
699         // printf("Hiding Menu\n");
700         mainMenuBar->hide  ();
701 #if defined(WIN32_CURSOR_TWEAKS)
702         if( mouse_mode == MOUSE_POINTER )
703             TurnCursorOff();
704 #endif // #ifdef WIN32_CURSOR_TWEAKS
705     } else {
706         // printf("Showing Menu\n");
707         mainMenuBar->reveal();
708 #ifdef WIN32
709         TurnCursorOn();
710 #endif // #ifdef WIN32
711     }
712     menu_on = ~menu_on;
713 }
714     
715 /* -----------------------------------------------------------------------
716 the Gui callback functions 
717 ____________________________________________________________________*/
718
719 static void saveFlight(puObject *cv)
720 {
721     BusyCursor(0);
722     ofstream output("fgfs.sav");
723     if (output.good() && fgSaveFlight(output)) {
724       output.close();
725       mkDialog("Saved flight to ./fgfs.sav");
726       FG_LOG(FG_INPUT, FG_INFO, "Saved flight to fgfs.sav");
727     } else {
728       mkDialog("Cannot save flight to ./fgfs.sav");
729       FG_LOG(FG_INPUT, FG_ALERT, "Cannot save flight to fgfs.sav");
730     }
731     BusyCursor(1);
732 }
733
734 static void loadFlight(puObject *cb)
735 {
736     BusyCursor(0);
737     ifstream input("fgfs.sav");
738     if (input.good() && fgLoadFlight(input)) {
739       input.close();
740       mkDialog("Loaded flight from fgfs.sav");
741       FG_LOG(FG_INPUT, FG_INFO, "Restored flight from ./fgfs.sav");
742     } else {
743       mkDialog("Failed to load flight from fgfs.sav");
744       FG_LOG(FG_INPUT, FG_ALERT, "Cannot load flight from ./fgfs.sav");
745     }
746     BusyCursor(1);
747 }
748
749 void reInit(puObject *cb)
750 {
751     BusyCursor(0);
752     Quat0();
753     build_rotmatrix(quat_mat, curquat);
754     fgReInitSubsystems();
755     BusyCursor(1);
756 }
757
758 static void toggleClouds(puObject *cb)
759 {
760     FGBFI::setClouds( !FGBFI::getClouds() );
761 }
762         
763 // This is the accessor function
764 void guiTogglePanel(puObject *cb)
765 {
766     current_options.toggle_panel();
767 }
768     
769 //void MenuHideMenuCb(puObject *cb)
770 void hideMenuCb (puObject *cb)
771 {
772     guiToggleMenu();
773 }
774
775 void goodBye(puObject *)
776 {
777     // FG_LOG( FG_INPUT, FG_ALERT,
778     //      "Program exiting normally at user request." );
779     cout << "Program exiting normally at user request." << endl;
780
781 #ifdef FG_NETWORK_OLK    
782     if ( current_options.get_network_olk() ) {
783         if ( net_is_registered == 0 ) fgd_send_com( "8", FGFS_host);
784     }
785 #endif
786
787     //  if(gps_bug)
788     //      fclose(gps_bug);
789
790     exit(-1);
791 }
792
793
794 void goAwayCb (puObject *me)
795 {
796     FG_POP_PUI_DIALOG( dialogBox );
797 }
798
799 void mkDialogInit (void)
800 {
801     //  printf("mkDialogInit\n");
802     int x = (current_options.get_xsize()/2 - 400/2);
803     int y = (current_options.get_ysize()/2 - 100/2);
804     dialogBox = new puDialogBox (x, y); // 150, 50
805     {
806         dialogFrame = new puFrame (0,0,400,100);
807         dialogBoxMessage  =  new puText         (10, 70);
808         dialogBoxMessage  -> setLabel           ("");
809         dialogBoxOkButton =  new puOneShot      (180, 10, 240, 50);
810         dialogBoxOkButton -> setLegend          (gui_msg_OK);
811         dialogBoxOkButton -> makeReturnDefault  (TRUE );
812         dialogBoxOkButton -> setCallback        (goAwayCb);
813     }
814     FG_FINALIZE_PUI_DIALOG( dialogBox );
815 }
816
817 void MayBeGoodBye(puObject *)
818 {
819     ConfirmExitDialog(); 
820 }
821
822 void goAwayYesNoCb(puObject *me)
823 {
824     FG_POP_PUI_DIALOG( YNdialogBox);
825 }
826
827 void ConfirmExitDialogInit(void)
828 {
829     char msg[] = "Really Quit";
830     char *s;
831
832     //  printf("ConfirmExitDialogInit\n");
833     int len = 200 - puGetStringWidth( puGetDefaultLabelFont(), msg )/2;
834
835     int x = (current_options.get_xsize()/2 - 400/2);
836     int y = (current_options.get_ysize()/2 - 100/2);
837         
838     YNdialogBox = new puDialogBox (x, y); // 150, 50
839     //  YNdialogBox = new puDialogBox (150, 50);
840     {
841         YNdialogFrame = new puFrame (0,0,400, 100);
842         
843         YNdialogBoxMessage  =  new puText         (len, 70);
844         YNdialogBoxMessage  -> setDefaultValue    (msg);
845         YNdialogBoxMessage  -> getDefaultValue    (&s);
846         YNdialogBoxMessage  -> setLabel           (s);
847         
848         YNdialogBoxOkButton =  new puOneShot      (100, 10, 160, 50);
849         YNdialogBoxOkButton -> setLegend          (gui_msg_OK);
850         YNdialogBoxOkButton -> makeReturnDefault  (TRUE );
851         YNdialogBoxOkButton -> setCallback        (goodBye);
852         
853         YNdialogBoxNoButton =  new puOneShot      (240, 10, 300, 50);
854         YNdialogBoxNoButton -> setLegend          (gui_msg_NO);
855         YNdialogBoxNoButton -> setCallback        (goAwayYesNoCb);
856     }
857     FG_FINALIZE_PUI_DIALOG( YNdialogBox );
858 }
859
860 void notCb (puObject *)
861 {
862     mkDialog ("This function isn't implemented yet");
863 }
864
865 void helpCb (puObject *)
866 {
867     string command;
868         
869 #if defined(FX) && !defined(WIN32)
870 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
871     if ( global_fullscreen ) {
872         global_fullscreen = false;
873         XMesaSetFXmode( XMESA_FX_WINDOW );
874     }
875 #  endif
876 #endif
877         
878 #if !defined(WIN32)
879     string url = "http://www.flightgear.org/Docs/InstallGuide/getstart.html";
880         
881     if ( system("xwininfo -name Netscape > /dev/null 2>&1") == 0 ) {
882         command = "netscape -remote \"openURL(" + url + ")\" &";
883     } else {
884         command = "netscape " + url + " &";
885     }
886 #else
887     command = "webrun.bat";
888 #endif
889         
890     system( command.c_str() );
891     //string text = "Help started in netscape window.";
892
893     //mkDialog (text.c_str());
894     mkDialog ("Help started in netscape window.");
895 }
896
897 #if defined( WIN32 ) && !defined( __CYGWIN__)
898
899 static void rotateView( double roll, double pitch, double yaw )
900 {
901         // rotate view
902 }
903
904 static GlBitmap *b1 = NULL;
905 extern FGInterface cur_view_fdm;
906 GLubyte *hiResScreenCapture( int multiplier )
907 {
908         float oldfov = current_options.get_fov();
909         float fov = oldfov / multiplier;
910         FGView *v = &current_view;
911         current_options.set_fov(fov);
912         v->force_update_fov_math();
913     fgInitVisuals();
914     int cur_width = current_view.get_winWidth( );
915     int cur_height = current_view.get_winHeight( );
916         if (b1) delete( b1 );
917         // New empty (mostly) bitmap
918         b1 = new GlBitmap( GL_RGB, 1, 1, (unsigned char *)"123" );
919         int x,y;
920         for ( y = 0; y < multiplier; y++ )
921         {
922                 for ( x = 0; x < multiplier; x++ )
923                 {
924                         fgReshape( cur_width, cur_height );
925                         // pan to tile
926                         rotateView( 0, (y*fov)-((multiplier-1)*fov/2), (x*fov)-((multiplier-1)*fov/2) );
927                         fgRenderFrame();
928                         // restore view
929                         GlBitmap b2;
930                         b1->copyBitmap( &b2, cur_width*x, cur_height*y );
931                 }
932         }
933         current_view.UpdateViewParams(cur_view_fdm);
934         current_options.set_fov(oldfov);
935         v->force_update_fov_math();
936         return b1->getBitmap();
937 }
938 #endif
939
940
941 #if defined( WIN32 ) && !defined( __CYGWIN__)
942 // win32 print screen function
943 void printScreen ( puObject *obj ) {
944     bool show_pu_cursor = false;
945     TurnCursorOff();
946     if ( !puCursorIsHidden() ) {
947         show_pu_cursor = true;
948         puHideCursor();
949     }
950     BusyCursor( 0 );
951     mainMenuBar->hide();
952
953     CGlPrinter p( CGlPrinter::PRINT_BITMAP );
954     int cur_width = current_view.get_winWidth( );
955     int cur_height = current_view.get_winHeight( );
956     p.Begin( "FlightGear", cur_width*3, cur_height*3 );
957         p.End( hiResScreenCapture(3) );
958
959     if( menu_on ) {
960         mainMenuBar->reveal();
961     }
962     BusyCursor(1);
963     if ( show_pu_cursor ) {
964         puShowCursor();
965     }
966     TurnCursorOn();
967 }
968 #endif // #ifdef WIN32
969
970
971 void dumpSnapShot ( puObject *obj ) {
972     fgDumpSnapShot();
973 }
974
975
976 // do a screen snap shot
977 void fgDumpSnapShot () {
978     bool show_pu_cursor = false;
979
980     mainMenuBar->hide();
981     TurnCursorOff();
982     if ( !puCursorIsHidden() ) {
983         show_pu_cursor = true;
984         puHideCursor();
985     }
986
987     fgInitVisuals();
988     fgReshape( current_options.get_xsize(), current_options.get_ysize() );
989
990     // we need two render frames here to clear the menu and cursor
991     // ... not sure why but doing an extra fgFenderFrame() shoulnd't
992     // hurt anything
993     fgRenderFrame();
994     fgRenderFrame();
995
996     my_glDumpWindow( "fgfs-screen.ppm", 
997                      current_options.get_xsize(), 
998                      current_options.get_ysize() );
999     
1000     mkDialog ("Snap shot saved to fgfs-screen.ppm");
1001
1002     if ( show_pu_cursor ) {
1003         puShowCursor();
1004     }
1005
1006     TurnCursorOn();
1007     if( menu_on ) {
1008         mainMenuBar->reveal();
1009     }
1010
1011 }
1012
1013
1014 /// The beginnings of teleportation :-)
1015 //  Needs cleaning up but works
1016 //  These statics should disapear when this is a class
1017 static puDialogBox     *AptDialog = 0;
1018 static puFrame         *AptDialogFrame = 0;
1019 static puText          *AptDialogMessage = 0;
1020 static puInput         *AptDialogInput = 0;
1021
1022 static char NewAirportId[16];
1023 static char NewAirportLabel[] = "Enter New Airport ID"; 
1024
1025 static puOneShot       *AptDialogOkButton = 0;
1026 static puOneShot       *AptDialogCancelButton = 0;
1027 static puOneShot       *AptDialogResetButton = 0;
1028
1029 void AptDialog_Cancel(puObject *)
1030 {
1031     FG_POP_PUI_DIALOG( AptDialog );
1032 }
1033
1034 void AptDialog_OK (puObject *)
1035 {
1036     FGPath path( current_options.get_fg_root() );
1037     path.append( "Airports" );
1038     path.append( "simple.mk4" );
1039     FGAirports airports( path.c_str() );
1040
1041     FGAirport a;
1042     
1043     FGTime *t = FGTime::cur_time_params;
1044     int PauseMode = t->getPause();
1045     if(!PauseMode)
1046         t->togglePauseMode();
1047
1048     char *s;
1049     AptDialogInput->getValue(&s);
1050     string AptId(s);
1051
1052         cout << "AptDialog_OK " << AptId << " " << AptId.length() << endl;
1053     
1054     AptDialog_Cancel( NULL );
1055     
1056     if ( AptId.length() ) {
1057         // set initial position from airport id
1058         FG_LOG( FG_GENERAL, FG_INFO,
1059                 "Attempting to set starting position from airport code "
1060                 << AptId );
1061
1062         if ( airports.search( AptId, &a ) )
1063         {
1064             current_options.set_airport_id( AptId.c_str() );
1065             BusyCursor(0);
1066             fgReInitSubsystems();
1067             BusyCursor(1);
1068         } else {
1069             AptId  += " not in database.";
1070             mkDialog(AptId.c_str());
1071         }
1072     }
1073     if( PauseMode != t->getPause() )
1074         t->togglePauseMode();
1075 }
1076
1077 void AptDialog_Reset(puObject *)
1078 {
1079     //  strncpy( NewAirportId, current_options.get_airport_id().c_str(), 16 );
1080     sprintf( NewAirportId, "%s", current_options.get_airport_id().c_str() );
1081     AptDialogInput->setValue ( NewAirportId );
1082     AptDialogInput->setCursor( 0 ) ;
1083 }
1084
1085 void NewAirport(puObject *cb)
1086 {
1087     //  strncpy( NewAirportId, current_options.get_airport_id().c_str(), 16 );
1088     sprintf( NewAirportId, "%s", current_options.get_airport_id().c_str() );
1089 //      cout << "NewAirport " << NewAirportId << endl;
1090     AptDialogInput->setValue( NewAirportId );
1091
1092     FG_PUSH_PUI_DIALOG( AptDialog );
1093 }
1094
1095 static void NewAirportInit(void)
1096 {
1097     sprintf( NewAirportId, "%s", current_options.get_airport_id().c_str() );
1098     int len = 150 - puGetStringWidth( puGetDefaultLabelFont(),
1099                                       NewAirportLabel ) / 2;
1100
1101     AptDialog = new puDialogBox (150, 50);
1102     {
1103         AptDialogFrame   = new puFrame           (0,0,350, 150);
1104         AptDialogMessage = new puText            (len, 110);
1105         AptDialogMessage ->    setLabel          (NewAirportLabel);
1106
1107         AptDialogInput   = new puInput           (50, 70, 300, 100);
1108         AptDialogInput   ->    setValue          (NewAirportId);
1109         AptDialogInput   ->    acceptInput();
1110
1111         AptDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
1112         AptDialogOkButton     ->     setLegend   (gui_msg_OK);
1113         AptDialogOkButton     ->     setCallback (AptDialog_OK);
1114         AptDialogOkButton     ->     makeReturnDefault(TRUE);
1115
1116         AptDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
1117         AptDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
1118         AptDialogCancelButton ->     setCallback (AptDialog_Cancel);
1119
1120         AptDialogResetButton  =  new puOneShot   (240, 10, 300, 50);
1121         AptDialogResetButton  ->     setLegend   (gui_msg_RESET);
1122         AptDialogResetButton  ->     setCallback (AptDialog_Reset);
1123     }
1124         cout << "NewAirportInit " << NewAirportId << endl;
1125     FG_FINALIZE_PUI_DIALOG( AptDialog );
1126 }
1127
1128 #ifdef FG_NETWORK_OLK
1129
1130 /// The beginnings of networking :-)
1131 //  Needs cleaning up but works
1132 //  These statics should disapear when this is a class
1133 static puDialogBox     *NetIdDialog = 0;
1134 static puFrame         *NetIdDialogFrame = 0;
1135 static puText          *NetIdDialogMessage = 0;
1136 static puInput         *NetIdDialogInput = 0;
1137
1138 static char NewNetId[16];
1139 static char NewNetIdLabel[] = "Enter New Callsign"; 
1140 extern char *fgd_callsign;
1141
1142 static puOneShot       *NetIdDialogOkButton = 0;
1143 static puOneShot       *NetIdDialogCancelButton = 0;
1144
1145 void NetIdDialog_Cancel(puObject *)
1146 {
1147     FG_POP_PUI_DIALOG( NetIdDialog );
1148 }
1149
1150 void NetIdDialog_OK (puObject *)
1151 {
1152     string NetId;
1153     
1154     FGTime *t = FGTime::cur_time_params;
1155     int PauseMode = t->getPause();
1156     if(!PauseMode)
1157         t->togglePauseMode();
1158 /*  
1159    The following needs some cleanup because 
1160    "string options.NetId" and "char *net_callsign" 
1161 */
1162     NetIdDialogInput->getValue(&net_callsign);
1163     NetId = net_callsign;
1164     
1165     NetIdDialog_Cancel( NULL );
1166     current_options.set_net_id( NetId.c_str() );
1167     strcpy( fgd_callsign, net_callsign);
1168 //    strcpy( fgd_callsign, current_options.get_net_id().c_str());
1169 /* Entering a callsign indicates : user wants Net HUD Info */
1170     net_hud_display = 1;
1171
1172     if( PauseMode != t->getPause() )
1173         t->togglePauseMode();
1174 }
1175
1176 void NewCallSign(puObject *cb)
1177 {
1178     sprintf( NewNetId, "%s", current_options.get_net_id().c_str() );
1179 //    sprintf( NewNetId, "%s", fgd_callsign );
1180     NetIdDialogInput->setValue( NewNetId );
1181
1182     FG_PUSH_PUI_DIALOG( NetIdDialog );
1183 }
1184
1185 static void NewNetIdInit(void)
1186 {
1187     sprintf( NewNetId, "%s", current_options.get_net_id().c_str() );
1188 //    sprintf( NewNetId, "%s", fgd_callsign );
1189     int len = 150 - puGetStringWidth( puGetDefaultLabelFont(),
1190                                       NewNetIdLabel ) / 2;
1191
1192     NetIdDialog = new puDialogBox (150, 50);
1193     {
1194         NetIdDialogFrame   = new puFrame           (0,0,350, 150);
1195         NetIdDialogMessage = new puText            (len, 110);
1196         NetIdDialogMessage ->    setLabel          (NewNetIdLabel);
1197
1198         NetIdDialogInput   = new puInput           (50, 70, 300, 100);
1199         NetIdDialogInput   ->    setValue          (NewNetId);
1200         NetIdDialogInput   ->    acceptInput();
1201
1202         NetIdDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
1203         NetIdDialogOkButton     ->     setLegend   (gui_msg_OK);
1204         NetIdDialogOkButton     ->     setCallback (NetIdDialog_OK);
1205         NetIdDialogOkButton     ->     makeReturnDefault(TRUE);
1206
1207         NetIdDialogCancelButton =  new puOneShot   (240, 10, 300, 50);
1208         NetIdDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
1209         NetIdDialogCancelButton ->     setCallback (NetIdDialog_Cancel);
1210
1211     }
1212     FG_FINALIZE_PUI_DIALOG( NetIdDialog );
1213 }
1214
1215 static void net_display_toggle( puObject *cb)
1216 {
1217         net_hud_display = (net_hud_display) ? 0 : 1;
1218         printf("Toggle net_hud_display : %d\n", net_hud_display);
1219 }
1220
1221 static void net_register( puObject *cb)
1222 {
1223         fgd_send_com( "1", FGFS_host );
1224         net_is_registered = 0;
1225         printf("Registering to deamon\n");
1226 }
1227
1228 static void net_unregister( puObject *cb)
1229 {
1230         fgd_send_com( "8", FGFS_host );
1231         net_is_registered = -1;
1232         printf("Unregistering from deamon\n");
1233 }
1234
1235
1236 /*************** Deamon communication **********/
1237
1238 //  These statics should disapear when this is a class
1239 static puDialogBox     *NetFGDDialog = 0;
1240 static puFrame         *NetFGDDialogFrame = 0;
1241 static puText          *NetFGDDialogMessage = 0;
1242 //static puInput         *NetFGDDialogInput = 0;
1243
1244 //static char NewNetId[16];
1245 static char NewNetFGDLabel[] = "Scan for deamon                        "; 
1246 static char NewFGDHost[64] = "olk.mcp.de"; 
1247 static int  NewFGDPortLo = 10000;
1248 static int  NewFGDPortHi = 10001;
1249  
1250 //extern char *fgd_callsign;
1251 extern u_short base_port, end_port;
1252 extern int fgd_ip, verbose, current_port;
1253 extern char *fgd_host;
1254
1255
1256 static puOneShot       *NetFGDDialogOkButton = 0;
1257 static puOneShot       *NetFGDDialogCancelButton = 0;
1258 static puOneShot       *NetFGDDialogScanButton = 0;
1259
1260 static puInput         *NetFGDHostDialogInput = 0;
1261 static puInput         *NetFGDPortLoDialogInput = 0;
1262 static puInput         *NetFGDPortHiDialogInput = 0;
1263
1264 void NetFGDDialog_Cancel(puObject *)
1265 {
1266     FG_POP_PUI_DIALOG( NetFGDDialog );
1267 }
1268
1269 void NetFGDDialog_OK (puObject *)
1270 {
1271     char *NetFGD;    
1272
1273     FGTime *t = FGTime::cur_time_params;
1274     int PauseMode = t->getPause();
1275     if(!PauseMode) t->togglePauseMode();
1276     NetFGDHostDialogInput->getValue( &NetFGD );
1277     strcpy( fgd_host, NetFGD);
1278     NetFGDPortLoDialogInput->getValue( (int *) &base_port );
1279     NetFGDPortHiDialogInput->getValue( (int *) &end_port );
1280     NetFGDDialog_Cancel( NULL );
1281     if( PauseMode != t->getPause() )
1282         t->togglePauseMode();
1283 }
1284
1285 void NetFGDDialog_SCAN (puObject *)
1286 {
1287     char *NetFGD;
1288     int fgd_port;
1289     
1290     FGTime *t = FGTime::cur_time_params;
1291     int PauseMode = t->getPause();
1292     if(!PauseMode) t->togglePauseMode();
1293 //    printf("Vor getvalue %s\n");
1294     NetFGDHostDialogInput->getValue( &NetFGD );
1295 //    printf("Vor strcpy %s\n", (char *) NetFGD);
1296     strcpy( fgd_host, NetFGD);
1297     NetFGDPortLoDialogInput->getValue( (int *) &base_port );
1298     NetFGDPortHiDialogInput->getValue( (int *) &end_port );
1299     printf("FGD: %s  Port-Start: %d Port-End: %d\n", fgd_host, 
1300                  base_port, end_port);
1301     net_resolv_fgd(fgd_host);
1302     printf("Resolve : %d\n", net_r);
1303     if( PauseMode != t->getPause() )  t->togglePauseMode();
1304     if ( net_r == 0 ) {
1305       fgd_port = 10000;
1306       strcpy( fgd_name, "");
1307       for( current_port = base_port; ( current_port <= end_port); current_port++) {
1308           fgd_send_com("0" , FGFS_host);
1309           sprintf( NewNetFGDLabel , "Scanning for deamon Port: %d", current_port); 
1310           printf("FGD: searching %s\n", fgd_name);
1311           if ( strcmp( fgd_name, "") != 0 ) {
1312              sprintf( NewNetFGDLabel , "Found %s at Port: %d", 
1313                                               fgd_name, current_port);
1314              fgd_port = current_port;
1315              current_port = end_port+1;
1316           }
1317       }
1318       current_port = end_port = base_port = fgd_port;
1319     }
1320     NetFGDDialog_Cancel( NULL );
1321 }
1322
1323
1324 void net_fgd_scan(puObject *cb)
1325 {
1326     NewFGDPortLo = base_port;
1327     NewFGDPortHi = end_port;
1328     strcpy( NewFGDHost, fgd_host);
1329     NetFGDPortLoDialogInput->setValue( NewFGDPortLo );
1330     NetFGDPortHiDialogInput->setValue( NewFGDPortHi );
1331     NetFGDHostDialogInput->setValue( NewFGDHost );
1332
1333     FG_PUSH_PUI_DIALOG( NetFGDDialog );
1334 }
1335
1336
1337 static void NewNetFGDInit(void)
1338 {
1339 //    sprintf( NewNetId, "%s", current_options.get_net_id().c_str() );
1340 //    sprintf( NewNetId, "%s", fgd_callsign );
1341     int len = 170 - puGetStringWidth( puGetDefaultLabelFont(),
1342                                       NewNetFGDLabel ) / 2;
1343
1344     NetFGDDialog = new puDialogBox (310, 30);
1345     {
1346         NetFGDDialogFrame   = new puFrame           (0,0,320, 170);
1347         NetFGDDialogMessage = new puText            (len, 140);
1348         NetFGDDialogMessage ->    setLabel          (NewNetFGDLabel);
1349
1350         NetFGDPortLoDialogInput   = new puInput           (50, 70, 127, 100);
1351         NetFGDPortLoDialogInput   ->    setValue          (NewFGDPortLo);
1352         NetFGDPortLoDialogInput   ->    acceptInput();
1353
1354         NetFGDPortHiDialogInput   = new puInput           (199, 70, 275, 100);
1355         NetFGDPortHiDialogInput   ->    setValue          (NewFGDPortHi);
1356         NetFGDPortHiDialogInput   ->    acceptInput();
1357
1358         NetFGDHostDialogInput   = new puInput           (50, 100, 275, 130);
1359         NetFGDHostDialogInput   ->    setValue          (NewFGDHost);
1360         NetFGDHostDialogInput   ->    acceptInput();
1361
1362         NetFGDDialogScanButton     =  new puOneShot   (130, 10, 200, 50);
1363         NetFGDDialogScanButton     ->     setLegend   ("Scan");
1364         NetFGDDialogScanButton     ->     setCallback (NetFGDDialog_SCAN);
1365         NetFGDDialogScanButton     ->     makeReturnDefault(FALSE);
1366
1367         NetFGDDialogOkButton     =  new puOneShot   (50, 10, 120, 50);
1368         NetFGDDialogOkButton     ->     setLegend   (gui_msg_OK);
1369         NetFGDDialogOkButton     ->     setCallback (NetFGDDialog_OK);
1370         NetFGDDialogOkButton     ->     makeReturnDefault(TRUE);
1371
1372         NetFGDDialogCancelButton =  new puOneShot   (210, 10, 280, 50);
1373         NetFGDDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
1374         NetFGDDialogCancelButton ->     setCallback (NetFGDDialog_Cancel);
1375
1376     }
1377     FG_FINALIZE_PUI_DIALOG( NetFGDDialog );
1378 }
1379
1380 /*
1381 static void net_display_toggle( puObject *cb)
1382 {
1383         net_hud_display = (net_hud_display) ? 0 : 1;
1384         printf("Toggle net_hud_display : %d\n", net_hud_display);
1385 }
1386
1387 */
1388
1389 #endif
1390
1391 /***************  End Networking  **************/
1392
1393
1394
1395 /* -----------------------------------------------------------------------
1396 The menu stuff 
1397 ---------------------------------------------------------------------*/
1398 char *fileSubmenu               [] = {
1399     "Exit", /* "Close", "---------", */
1400 #if defined( WIN32 ) && !defined( __CYGWIN__)
1401     "Print",
1402 #endif
1403     "Snap Shot",
1404     "---------", 
1405     "Reset", 
1406     "Load flight",
1407     "Save flight",
1408     NULL
1409 };
1410 puCallback fileSubmenuCb        [] = {
1411     MayBeGoodBye, /* hideMenuCb, NULL, */
1412 #if defined( WIN32 ) && !defined( __CYGWIN__)
1413     printScreen, 
1414 #endif
1415     /* NULL, notCb, */
1416     dumpSnapShot,
1417     NULL,
1418     reInit, 
1419     loadFlight,
1420     saveFlight,
1421     NULL
1422 };
1423
1424 /*
1425 char *editSubmenu               [] = {
1426     "Edit text", NULL
1427 };
1428 puCallback editSubmenuCb        [] = {
1429     notCb, NULL
1430 };
1431 */
1432
1433 extern void fgHUDalphaAdjust( puObject * );
1434 char *viewSubmenu               [] = {
1435     "HUD Alpha",
1436     /* "Cockpit View > ", "View >","------------", */
1437     "Toggle Panel...", NULL
1438 };
1439 puCallback viewSubmenuCb        [] = {
1440     fgHUDalphaAdjust,
1441     /* notCb, notCb, NULL, */
1442     guiTogglePanel, NULL
1443 };
1444
1445 char *aircraftSubmenu           [] = {
1446     "Autopilot", "Heading", "Altitude", "Navigation", "Airport", 
1447     /* "Communication", */ NULL
1448 };
1449 puCallback aircraftSubmenuCb    [] = {
1450     fgAPAdjust, NewHeading, NewAltitude, fgLatLonFormatToggle, NewTgtAirport, 
1451     /* notCb, */ NULL
1452 };
1453
1454 char *environmentSubmenu        [] = {
1455     "Toggle Clouds",
1456     "Goto Airport", /* "Terrain", "Weather", */ NULL
1457 };
1458 puCallback environmentSubmenuCb [] = {
1459     toggleClouds,
1460     NewAirport, /* notCb, notCb, */ NULL
1461 };
1462
1463 /*
1464 char *optionsSubmenu            [] = {
1465     "Preferences", "Realism & Reliablity...", NULL
1466 };
1467 puCallback optionsSubmenuCb     [] = {
1468     notCb, notCb, NULL
1469 };
1470 */
1471
1472 #ifdef FG_NETWORK_OLK
1473 char *networkSubmenu            [] = {
1474     "Unregister from FGD ", /* "Send MSG to All", "Send MSG", "Show Pilots", */
1475     "Register to FGD",
1476     "Scan for Deamons", "Enter Callsign", /* "Display Netinfos", */
1477     "Toggle Display", NULL
1478 };
1479 puCallback networkSubmenuCb     [] = {
1480     /* notCb, notCb, notCb, notCb, */ 
1481     net_unregister, 
1482     net_register, 
1483     net_fgd_scan, NewCallSign, 
1484     net_display_toggle, NULL
1485 };
1486 #endif
1487
1488 char *helpSubmenu               [] = {
1489     /* "About...", */ "Help", NULL
1490 };
1491 puCallback helpSubmenuCb        [] = {
1492     /* notCb, */ helpCb, NULL
1493 };
1494
1495
1496 /* -------------------------------------------------------------------------
1497 init the gui
1498 _____________________________________________________________________*/
1499
1500
1501 void guiInit()
1502 {
1503     char *mesa_win_state;
1504
1505     // Initialize PUI
1506     puInit();
1507     puSetDefaultStyle         ( PUSTYLE_SMALL_BEVELLED ); //PUSTYLE_DEFAULT
1508     puSetDefaultColourScheme  (0.8, 0.8, 0.8, 0.4);
1509
1510     // Initialize our GLOBAL GUI STRINGS
1511     gui_msg_OK     = msg_OK;     // "OK"
1512     gui_msg_NO     = msg_NO;     // "NO"
1513     gui_msg_YES    = msg_YES;    // "YES"
1514     gui_msg_CANCEL = msg_CANCEL; // "CANCEL"
1515     gui_msg_RESET  = msg_RESET;  // "RESET"
1516
1517     // Next check home directory
1518     FGPath fntpath;
1519     char* envp = ::getenv( "FG_FONTS" );
1520     if ( envp != NULL ) {
1521         fntpath.set( envp );
1522     } else {
1523         fntpath.set( current_options.get_fg_root() );
1524         fntpath.append( "Fonts" );
1525     }
1526
1527     // Install our fast fonts
1528     fntpath.append( "typewriter.txf" );
1529     guiFntHandle = new fntTexFont ;
1530     guiFntHandle -> load ( (char *)fntpath.c_str() ) ;
1531     puFont GuiFont ( guiFntHandle, 15 ) ;
1532     puSetDefaultFonts( GuiFont, GuiFont ) ;
1533     guiFnt = puGetDefaultLabelFont();
1534   
1535     if ( current_options.get_mouse_pointer() == 0 ) {
1536         // no preference specified for mouse pointer, attempt to autodetect...
1537         // Determine if we need to render the cursor, or if the windowing
1538         // system will do it.  First test if we are rendering with glide.
1539         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1540             // Test for the MESA_GLX_FX env variable
1541             if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
1542                 // test if we are fullscreen mesa/glide
1543                 if ( (mesa_win_state[0] == 'f') ||
1544                      (mesa_win_state[0] == 'F') ) {
1545                     puShowCursor ();
1546                 }
1547             }
1548         }
1549         mouse_active = ~mouse_active;
1550     } else if ( current_options.get_mouse_pointer() == 1 ) {
1551         // don't show pointer
1552     } else if ( current_options.get_mouse_pointer() == 2 ) {
1553         // force showing pointer
1554         puShowCursor();
1555         mouse_active = ~mouse_active;
1556     }
1557         
1558     // MOUSE_VIEW mode stuff
1559     trackball(_quat0, 0.0, 0.0, 0.0, 0.0);  
1560     Quat0();
1561     build_rotmatrix(quat_mat, curquat);
1562
1563     // Set up our Dialog Boxes
1564     ConfirmExitDialogInit();
1565     NewAirportInit();
1566 #ifdef FG_NETWORK_OLK
1567     NewNetIdInit();
1568     NewNetFGDInit();
1569 #endif
1570     mkDialogInit();
1571     
1572     // Make the menu bar
1573     mainMenuBar = new puMenuBar ();
1574     mainMenuBar -> add_submenu ("File", fileSubmenu, fileSubmenuCb);
1575     // mainMenuBar -> add_submenu ("Edit", editSubmenu, editSubmenuCb);
1576     mainMenuBar -> add_submenu ("View", viewSubmenu, viewSubmenuCb);
1577     mainMenuBar -> add_submenu ("Aircraft", aircraftSubmenu, aircraftSubmenuCb);
1578     mainMenuBar -> add_submenu ("Environment", environmentSubmenu, environmentSubmenuCb);
1579     // mainMenuBar -> add_submenu ("Options", optionsSubmenu, optionsSubmenuCb);
1580 #ifdef FG_NETWORK_OLK
1581     mainMenuBar -> add_submenu ("Network", networkSubmenu, networkSubmenuCb);
1582 #endif
1583     mainMenuBar -> add_submenu ("Help", helpSubmenu, helpSubmenuCb);
1584     mainMenuBar-> close ();
1585     // Set up menu bar toggle
1586     menu_on = ~0;
1587 }
1588
1589
1590
1591 /*
1592  * Trackball code:
1593  *
1594  * Implementation of a virtual trackball.
1595  * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
1596  *   the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
1597  *
1598  * Vector manip code:
1599  *
1600  * Original code from:
1601  * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
1602  *
1603  * Much mucking with by:
1604  * Gavin Bell
1605  */
1606 #if defined(_WIN32) && !defined( __CYGWIN32__ )
1607 #pragma warning (disable:4244)          /* disable bogus conversion warnings */
1608 #endif
1609 #include <math.h>
1610 #include <stdio.h>
1611 //#include "trackball.h"
1612
1613 /*
1614  * This size should really be based on the distance from the center of
1615  * rotation to the point on the object underneath the mouse.  That
1616  * point would then track the mouse as closely as possible.  This is a
1617  * simple example, though, so that is left as an Exercise for the
1618  * Programmer.
1619  */
1620 #define TRACKBALLSIZE  (0.8f)
1621 #define SQRT(x) sqrt(x)
1622
1623 /*
1624  * Local function prototypes (not defined in trackball.h)
1625  */
1626 static float tb_project_to_sphere(float, float, float);
1627 static void normalize_quat(float [4]);
1628
1629 static void
1630 vzero(float *v)
1631 {
1632     v[0] = 0.0;
1633     v[1] = 0.0;
1634     v[2] = 0.0;
1635 }
1636
1637 static void
1638 vset(float *v, float x, float y, float z)
1639 {
1640     v[0] = x;
1641     v[1] = y;
1642     v[2] = z;
1643 }
1644
1645 static void
1646 vsub(const float *src1, const float *src2, float *dst)
1647 {
1648     dst[0] = src1[0] - src2[0];
1649     dst[1] = src1[1] - src2[1];
1650     dst[2] = src1[2] - src2[2];
1651 }
1652
1653 static void
1654 vcopy(const float *v1, float *v2)
1655 {
1656     register int i;
1657     for (i = 0 ; i < 3 ; i++)
1658         v2[i] = v1[i];
1659 }
1660
1661 static void
1662 vcross(const float *v1, const float *v2, float *cross)
1663 {
1664     float temp[3];
1665
1666     temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
1667     temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
1668     temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
1669     vcopy(temp, cross);
1670 }
1671
1672 static float
1673 vlength(const float *v)
1674 {
1675     float tmp = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
1676     return SQRT(tmp);
1677 }
1678
1679 static void
1680 vscale(float *v, float div)
1681 {
1682     v[0] *= div;
1683     v[1] *= div;
1684     v[2] *= div;
1685 }
1686
1687 static void
1688 vnormal(float *v)
1689 {
1690     vscale(v,1.0/vlength(v));
1691 }
1692
1693 static float
1694 vdot(const float *v1, const float *v2)
1695 {
1696     return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
1697 }
1698
1699 static void
1700 vadd(const float *src1, const float *src2, float *dst)
1701 {
1702     dst[0] = src1[0] + src2[0];
1703     dst[1] = src1[1] + src2[1];
1704     dst[2] = src1[2] + src2[2];
1705 }
1706
1707 /*
1708  *  Given an axis and angle, compute quaternion.
1709  */
1710 void
1711 axis_to_quat(float a[3], float phi, float q[4])
1712 {
1713     double sinphi2, cosphi2;
1714     double phi2 = phi/2.0;
1715     sinphi2 = sin(phi2);
1716     cosphi2 = cos(phi2);
1717     vnormal(a);
1718     vcopy(a,q);
1719     vscale(q,sinphi2);
1720     q[3] = cosphi2;
1721 }
1722
1723 /*
1724  * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
1725  * if we are away from the center of the sphere.
1726  */
1727 static float
1728 tb_project_to_sphere(float r, float x, float y)
1729 {
1730     float d, t, z, tmp;
1731
1732     tmp = x*x + y*y;
1733     d = SQRT(tmp);
1734     if (d < r * 0.70710678118654752440) {    /* Inside sphere */
1735         tmp = r*r - d*d;
1736         z = SQRT(tmp);
1737     } else {           /* On hyperbola */
1738         t = r / 1.41421356237309504880;
1739         z = t*t / d;
1740     }
1741     return z;
1742 }
1743
1744 /*
1745  * Quaternions always obey:  a^2 + b^2 + c^2 + d^2 = 1.0
1746  * If they don't add up to 1.0, dividing by their magnitued will
1747  * renormalize them.
1748  *
1749  * Note: See the following for more information on quaternions:
1750  *
1751  * - Shoemake, K., Animating rotation with quaternion curves, Computer
1752  *   Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
1753  * - Pletinckx, D., Quaternion calculus as a basic tool in computer
1754  *   graphics, The Visual Computer 5, 2-13, 1989.
1755  */
1756 static void
1757 normalize_quat(float q[4])
1758 {
1759     int i;
1760     float mag, tmp;
1761
1762     tmp = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
1763     mag = 1.0 / SQRT(tmp);
1764     for (i = 0; i < 4; i++)
1765         q[i] *= mag;
1766 }
1767
1768 /*
1769  * Ok, simulate a track-ball.  Project the points onto the virtual
1770  * trackball, then figure out the axis of rotation, which is the cross
1771  * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
1772  * Note:  This is a deformed trackball-- is a trackball in the center,
1773  * but is deformed into a hyperbolic sheet of rotation away from the
1774  * center.  This particular function was chosen after trying out
1775  * several variations.
1776  *
1777  * It is assumed that the arguments to this routine are in the range
1778  * (-1.0 ... 1.0)
1779  */
1780 void
1781 trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
1782 {
1783     float a[3]; /* Axis of rotation */
1784     float phi;  /* how much to rotate about axis */
1785     float p1[3], p2[3], d[3];
1786     float t;
1787
1788     if (p1x == p2x && p1y == p2y) {
1789         /* Zero rotation */
1790         vzero(q);
1791         q[3] = 1.0;
1792         return;
1793     }
1794
1795     /*
1796      * First, figure out z-coordinates for projection of P1 and P2 to
1797      * deformed sphere
1798      */
1799     vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
1800     vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
1801
1802     /*
1803      *  Now, we want the cross product of P1 and P2
1804      */
1805     vcross(p2,p1,a);
1806
1807     /*
1808      *  Figure out how much to rotate around that axis.
1809      */
1810     vsub(p1,p2,d);
1811     t = vlength(d) / (2.0*TRACKBALLSIZE);
1812
1813     /*
1814      * Avoid problems with out-of-control values...
1815      */
1816     if (t > 1.0) t = 1.0;
1817     if (t < -1.0) t = -1.0;
1818     phi = 2.0 * asin(t);
1819
1820     axis_to_quat(a,phi,q);
1821 }
1822
1823 /*
1824  * Given two rotations, e1 and e2, expressed as quaternion rotations,
1825  * figure out the equivalent single rotation and stuff it into dest.
1826  *
1827  * This routine also normalizes the result every RENORMCOUNT times it is
1828  * called, to keep error from creeping in.
1829  *
1830  * NOTE: This routine is written so that q1 or q2 may be the same
1831  * as dest (or each other).
1832  */
1833
1834 #define RENORMCOUNT 97
1835
1836 void
1837 add_quats(float q1[4], float q2[4], float dest[4])
1838 {
1839     static int count=0;
1840     float t1[4], t2[4], t3[4];
1841     float tf[4];
1842
1843 #if 0
1844 printf("q1 = %f %f %f %f\n", q1[0], q1[1], q1[2], q1[3]);
1845 printf("q2 = %f %f %f %f\n", q2[0], q2[1], q2[2], q2[3]);
1846 #endif
1847
1848     vcopy(q1,t1);
1849     vscale(t1,q2[3]);
1850
1851     vcopy(q2,t2);
1852     vscale(t2,q1[3]);
1853
1854     vcross(q2,q1,t3);
1855     vadd(t1,t2,tf);
1856     vadd(t3,tf,tf);
1857     tf[3] = q1[3] * q2[3] - vdot(q1,q2);
1858
1859 #if 0
1860 printf("tf = %f %f %f %f\n", tf[0], tf[1], tf[2], tf[3]);
1861 #endif
1862
1863     dest[0] = tf[0];
1864     dest[1] = tf[1];
1865     dest[2] = tf[2];
1866     dest[3] = tf[3];
1867
1868     if (++count > RENORMCOUNT) {
1869         count = 0;
1870         normalize_quat(dest);
1871     }
1872 }
1873
1874 /*
1875  * Build a rotation matrix, given a quaternion rotation.
1876  *
1877  */
1878 void
1879 build_rotmatrix(float m[4][4], float q[4])
1880 {
1881 //#define TRANSPOSED_QUAT
1882 #ifndef TRANSPOSED_QUAT
1883     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
1884     m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
1885     m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
1886     m[0][3] = 0.0;
1887
1888     m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
1889     m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
1890     m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
1891     m[1][3] = 0.0;
1892
1893     m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
1894     m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
1895     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
1896     
1897     m[2][3] = 0.0;
1898     m[3][0] = 0.0;
1899     m[3][1] = 0.0;
1900     m[3][2] = 0.0;
1901     m[3][3] = 1.0;
1902 #else //  TRANSPOSED_QUAT
1903     m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
1904     m[0][1] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
1905     m[0][2] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
1906     m[0][3] = 0.0;
1907
1908     m[1][0] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
1909     m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
1910     m[1][2] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
1911     m[1][3] = 0.0;
1912
1913     m[2][0] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
1914     m[2][1] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
1915     m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
1916     m[2][3] = 0.0;
1917     
1918     m[3][0] = 0.0;
1919     m[3][1] = 0.0;
1920     m[3][2] = 0.0;
1921     m[3][3] = 1.0;
1922 #endif // 0
1923 }
1924