]> git.mxchange.org Git - flightgear.git/blob - src/GUI/gui.cxx
source tree reorganization prior to flightgear 0.7
[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  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * $Id$
22  **************************************************************************/
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include <Include/compiler.h>
30
31 #ifdef FG_MATH_EXCEPTION_CLASH
32 #  include <math.h>
33 #endif
34
35 #ifdef HAVE_WINDOWS_H
36 #  include <windows.h>
37 #endif
38
39 #include <GL/glut.h>
40 #include <XGL/xgl.h>
41
42 #if defined(FX) && defined(XMESA)
43 #  include <GL/xmesa.h>
44 #endif
45
46 #include STL_STRING
47
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include <Include/general.hxx>
52 #include <Debug/logstream.hxx>
53 #include <Aircraft/aircraft.hxx>
54 #include <Airports/simple.hxx>
55 #include <Cockpit/panel.hxx>
56 #include <FDM/flight.hxx>
57 #include <Main/options.hxx>
58 #include <Main/fg_init.hxx>
59 #include <Main/views.hxx>
60 #include <Misc/fgpath.hxx>
61 #include <Time/fg_time.hxx>
62
63 #include "gui.h"
64
65 FG_USING_STD(string);
66
67 #ifndef FG_HAVE_NATIVE_SGI_COMPILERS
68 FG_USING_STD(cout);
69 #endif
70
71 puFont guiFnt = 0;
72 fntTexFont *guiFntHandle = 0;
73
74 static puMenuBar    *mainMenuBar = 0;
75 //static puButton     *hideMenuButton = 0;
76
77 static puDialogBox  *dialogBox = 0;
78 static puFrame      *dialogFrame = 0;
79 static puText       *dialogBoxMessage = 0;
80 static puOneShot    *dialogBoxOkButton = 0;
81
82
83 static puDialogBox  *YNdialogBox = 0;
84 static puFrame      *YNdialogFrame = 0;
85 static puText       *YNdialogBoxMessage = 0;
86 static puOneShot    *YNdialogBoxOkButton = 0;
87 static puOneShot    *YNdialogBoxNoButton = 0;
88
89 static char msg_OK[]     = "OK";
90 static char msg_NO[]     = "NO";
91 static char msg_YES[]    = "YES";
92 static char msg_CANCEL[] = "Cancel";
93 static char msg_RESET[]  = "Reset";
94
95 char *gui_msg_OK;     // "OK"
96 char *gui_msg_NO;     // "NO"
97 char *gui_msg_YES;    // "YES"
98 char *gui_msg_CANCEL; // "CANCEL"
99 char *gui_msg_RESET;  // "RESET"
100
101 static char global_dialog_string[256];
102
103 extern void NewAltitude( puObject *cb );
104 extern void NewHeading( puObject *cb );
105 extern void fgAPAdjust( puObject * );
106 extern void fgLatLonFormatToggle( puObject *);
107
108 /* --------------------------------------------------------------------
109 Mouse stuff
110 ---------------------------------------------------------------------*/
111
112 static int _mX = 0;
113 static int  _mY = 0;
114 static int last_buttons = 0 ;
115 static int mouse_active = 0;
116 static int menu_on = 0;
117
118 void guiMotionFunc ( int x, int y )
119 {
120     _mX = x;
121     _mY = y;
122     puMouse ( x, y ) ;
123     glutPostRedisplay () ;
124 }
125
126 void guiMouseFunc(int button, int updown, int x, int y)
127 {
128     _mX = x;
129     _mY = y;
130     if ( updown == PU_DOWN )
131         last_buttons |=  ( 1 << button ) ;
132     else
133         last_buttons &= ~( 1 << button ) ;
134     puMouse (button, updown, x,y);
135     glutPostRedisplay ();
136 }
137
138 int guiGetMouseButton(void)
139 {
140     return last_buttons;
141 }
142
143 void guiGetMouse(int *x, int *y)
144 {
145     *x = _mX;
146     *y = _mY;
147 };
148
149 static inline void TurnCursorOn( void )
150 {
151     mouse_active = ~0;
152 #if defined ( WIN32 ) || defined(__CYGWIN32__)
153     glutSetCursor(GLUT_CURSOR_INHERIT);
154 #endif
155 #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
156     glutWarpPointer( glutGet(GLUT_SCREEN_WIDTH)/2, glutGet(GLUT_SCREEN_HEIGHT)/2);
157 #endif
158 }
159
160 static inline void TurnCursorOff( void )
161 {
162     mouse_active = 0;
163 #if defined ( WIN32 ) || defined(__CYGWIN32__)
164     glutSetCursor(GLUT_CURSOR_NONE);
165 #else  // I guess this is what we want to do ??
166 #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9)
167     glutWarpPointer( glutGet(GLUT_SCREEN_WIDTH), glutGet(GLUT_SCREEN_HEIGHT));
168 #endif
169 #endif
170 }
171
172 void maybeToggleMouse( void )
173 {
174 #ifdef WIN32
175     static int first_time = ~0;
176     static int mouse_changed = 0;
177
178     if ( first_time ) {
179         if(!mouse_active) {
180             mouse_changed = ~mouse_changed;
181             TurnCursorOn();
182         }
183     } else {
184         if( mouse_changed ) {
185             mouse_changed = ~mouse_changed;
186             if(mouse_active) {
187                 TurnCursorOff();
188             }
189         }
190     }
191     first_time = ~first_time;
192 #endif // #ifdef WIN32
193 }
194
195 // Call with FALSE to init and TRUE to restore
196 void BusyCursor( int restore )
197 {
198     static int cursor = 0;
199     if( restore ) {
200         glutSetCursor(cursor);
201     } else {
202         cursor = glutGet( GLUT_WINDOW_CURSOR );
203 #ifdef WIN32
204         TurnCursorOn();
205 #endif
206         glutSetCursor( GLUT_CURSOR_WAIT );
207     }
208 }
209 /* ================ General Purpose Functions ================ */
210
211 // Intercept the Escape Key
212 void ConfirmExitDialog(void)
213 {
214     FG_PUSH_PUI_DIALOG( YNdialogBox );
215 }
216
217 // General Purpose Message Box
218 void mkDialog (const char *txt)
219 {
220     strncpy(global_dialog_string, txt, 256);
221     dialogBoxMessage->setLabel(global_dialog_string);
222     FG_PUSH_PUI_DIALOG( dialogBox );
223 }
224
225 // Repair any damage done to the Panel by other Gui Items
226 void guiFixPanel( void )
227 {
228     int toggle_pause;
229
230     if ( current_options.get_panel_status() ) {
231         FGView *v = &current_view;
232         FGTime *t = FGTime::cur_time_params;
233
234         if( (toggle_pause = !t->getPause()) )
235             t->togglePauseMode();
236
237         // this seems to be the only way to do this :-(
238         // problem is the viewport has been mucked with
239         xglViewport(0, 0 , (GLint)(v->winWidth), (GLint)(v->winHeight) );
240         FGPanel::OurPanel->ReInit(0, 0, 1024, 768);
241
242         if(toggle_pause)
243             t->togglePauseMode();
244     }
245 }
246
247 // Toggle the Menu and Mouse display state
248 void guiToggleMenu(void)
249 {
250     if( menu_on ) {
251         // printf("Hiding Menu\n");
252         mainMenuBar->hide  ();
253 #ifdef WIN32
254         TurnCursorOff();
255 #endif // #ifdef WIN32
256     } else {
257         // printf("Showing Menu\n");
258         mainMenuBar->reveal();
259 #ifdef WIN32
260         TurnCursorOn();
261 #endif // #ifdef WIN32
262     }
263     menu_on = ~menu_on;
264 }
265     
266 /* -----------------------------------------------------------------------
267 the Gui callback functions 
268 ____________________________________________________________________*/
269
270 void reInit(puObject *cb)
271 {
272     BusyCursor(0);
273     fgReInitSubsystems();
274     BusyCursor(1);
275 }
276         
277 // This is the accessor function
278 void guiTogglePanel(puObject *cb)
279 {
280     current_options.toggle_panel();
281 }
282     
283 //void MenuHideMenuCb(puObject *cb)
284 void hideMenuCb (puObject *cb)
285 {
286     guiToggleMenu();
287 }
288
289 void goodBye(puObject *)
290 {
291     // FG_LOG( FG_INPUT, FG_ALERT,
292     //      "Program exiting normally at user request." );
293     cout << "Program exiting normally at user request." << endl;
294
295     //  if(gps_bug)
296     //      fclose(gps_bug);
297
298     exit(-1);
299 }
300
301
302 void goAwayCb (puObject *me)
303 {
304     FG_POP_PUI_DIALOG( dialogBox );
305 }
306
307 void mkDialogInit (void)
308 {
309     //  printf("mkDialogInit\n");
310     int x = (current_options.get_xsize()/2 - 400/2);
311     int y = (current_options.get_ysize()/2 - 100/2);
312     dialogBox = new puDialogBox (x, y); // 150, 50
313     {
314         dialogFrame = new puFrame (0,0,400,100);
315         dialogBoxMessage  =  new puText         (10, 70);
316         dialogBoxMessage  -> setLabel           ("");
317         dialogBoxOkButton =  new puOneShot      (180, 10, 240, 50);
318         dialogBoxOkButton -> setLegend          (gui_msg_OK);
319         dialogBoxOkButton -> makeReturnDefault  (TRUE );
320         dialogBoxOkButton -> setCallback        (goAwayCb);
321     }
322     FG_FINALIZE_PUI_DIALOG( dialogBox );
323 }
324
325 void MayBeGoodBye(puObject *)
326 {
327     ConfirmExitDialog(); 
328 }
329
330 void goAwayYesNoCb(puObject *me)
331 {
332     FG_POP_PUI_DIALOG( YNdialogBox);
333 }
334
335 void ConfirmExitDialogInit(void)
336 {
337     char msg[] = "Really Quit";
338     char *s;
339
340     //  printf("ConfirmExitDialogInit\n");
341     int len = 200 - puGetStringWidth( puGetDefaultLabelFont(), msg )/2;
342
343     int x = (current_options.get_xsize()/2 - 400/2);
344     int y = (current_options.get_ysize()/2 - 100/2);
345         
346     YNdialogBox = new puDialogBox (x, y); // 150, 50
347     //  YNdialogBox = new puDialogBox (150, 50);
348     {
349         YNdialogFrame = new puFrame (0,0,400, 100);
350         
351         YNdialogBoxMessage  =  new puText         (len, 70);
352         YNdialogBoxMessage  -> setDefaultValue    (msg);
353         YNdialogBoxMessage  -> getDefaultValue    (&s);
354         YNdialogBoxMessage  -> setLabel           (s);
355         
356         YNdialogBoxOkButton =  new puOneShot      (100, 10, 160, 50);
357         YNdialogBoxOkButton -> setLegend          (gui_msg_OK);
358         YNdialogBoxOkButton -> setCallback        (goodBye);
359         
360         YNdialogBoxNoButton =  new puOneShot      (240, 10, 300, 50);
361         YNdialogBoxNoButton -> setLegend          (gui_msg_NO);
362         //      YNdialogBoxNoButton -> makeReturnDefault  (TRUE );
363         YNdialogBoxNoButton -> setCallback        (goAwayYesNoCb);
364     }
365     FG_FINALIZE_PUI_DIALOG( YNdialogBox );
366 }
367
368 void notCb (puObject *)
369 {
370     mkDialog ("This function isn't implemented yet");
371 }
372
373 void helpCb (puObject *)
374 {
375     string command;
376         
377 #if defined(FX) && !defined(WIN32)
378 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
379     if ( global_fullscreen ) {
380         global_fullscreen = false;
381         XMesaSetFXmode( XMESA_FX_WINDOW );
382     }
383 #  endif
384 #endif
385         
386 #if !defined(WIN32)
387     string url = "http://www.flightgear.org/Docs/InstallGuide/getstart.html";
388         
389     if ( system("xwininfo -name Netscape > /dev/null 2>&1") == 0 ) {
390         command = "netscape -remote \"openURL(" + url + ")\" &";
391     } else {
392         command = "netscape " + url + " &";
393     }
394 #else
395     command = "webrun.bat";
396 #endif
397         
398     system( command.c_str() );
399     //string text = "Help started in netscape window.";
400
401     //mkDialog (text.c_str());
402     mkDialog ("Help started in netscape window.");
403 }
404
405 /// The beginnings of teleportation :-)
406 //  Needs cleaning up but works
407 //  These statics should disapear when this is a class
408 static puDialogBox     *AptDialog = 0;
409 static puFrame         *AptDialogFrame = 0;
410 static puText          *AptDialogMessage = 0;
411 static puInput         *AptDialogInput = 0;
412
413 static char NewAirportId[16];
414 static char NewAirportLabel[] = "Enter New Airport ID"; 
415
416 static puOneShot       *AptDialogOkButton = 0;
417 static puOneShot       *AptDialogCancelButton = 0;
418 static puOneShot       *AptDialogResetButton = 0;
419
420 void AptDialog_Cancel(puObject *)
421 {
422     FG_POP_PUI_DIALOG( AptDialog );
423 }
424
425 void AptDialog_OK (puObject *)
426 {
427     string AptId;
428     
429     FGTime *t = FGTime::cur_time_params;
430     int PauseMode = t->getPause();
431     if(!PauseMode)
432         t->togglePauseMode();
433
434     char *s;
435     AptDialogInput->getValue(&s);
436     AptId = s;
437     
438     AptDialog_Cancel( NULL );
439     
440     if ( AptId.length() ) {
441         // set initial position from airport id
442         fgAIRPORTS airports;
443         fgAIRPORT a;
444
445         FG_LOG( FG_GENERAL, FG_INFO,
446                 "Attempting to set starting position from airport code "
447                 << s );
448
449         airports.load("apt_simple");
450         if ( airports.search( AptId, &a ) )
451         {
452             current_options.set_airport_id( AptId.c_str() );
453             BusyCursor(0);
454             fgReInitSubsystems();
455             BusyCursor(1);
456         } else {
457             AptId  += " not in database.";
458             mkDialog(AptId.c_str());
459         }
460     }
461     if( PauseMode != t->getPause() )
462         t->togglePauseMode();
463 }
464
465 void AptDialog_Reset(puObject *)
466 {
467     //  strncpy( NewAirportId, current_options.get_airport_id().c_str(), 16 );
468     sprintf( NewAirportId, "%s", current_options.get_airport_id().c_str() );
469     AptDialogInput->setValue ( NewAirportId );
470     AptDialogInput->setCursor( 0 ) ;
471 }
472
473 void NewAirport(puObject *cb)
474 {
475     //  strncpy( NewAirportId, current_options.get_airport_id().c_str(), 16 );
476     sprintf( NewAirportId, "%s", current_options.get_airport_id().c_str() );
477     AptDialogInput->setValue( NewAirportId );
478
479     FG_PUSH_PUI_DIALOG( AptDialog );
480 }
481
482 static void NewAirportInit(void)
483 {
484     sprintf( NewAirportId, "%s", current_options.get_airport_id().c_str() );
485     int len = 150 - puGetStringWidth( puGetDefaultLabelFont(),
486                                       NewAirportLabel ) / 2;
487
488     AptDialog = new puDialogBox (150, 50);
489     {
490         AptDialogFrame   = new puFrame           (0,0,350, 150);
491         AptDialogMessage = new puText            (len, 110);
492         AptDialogMessage ->    setLabel          (NewAirportLabel);
493
494         AptDialogInput   = new puInput           (50, 70, 300, 100);
495         AptDialogInput   ->    setValue          (NewAirportId);
496         AptDialogInput   ->    acceptInput();
497
498         AptDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
499         AptDialogOkButton     ->     setLegend   (gui_msg_OK);
500         AptDialogOkButton     ->     setCallback (AptDialog_OK);
501         AptDialogOkButton     ->     makeReturnDefault(TRUE);
502
503         AptDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
504         AptDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
505         AptDialogCancelButton ->     setCallback (AptDialog_Cancel);
506
507         AptDialogResetButton  =  new puOneShot   (240, 10, 300, 50);
508         AptDialogResetButton  ->     setLegend   (gui_msg_RESET);
509         AptDialogResetButton  ->     setCallback (AptDialog_Reset);
510     }
511     FG_FINALIZE_PUI_DIALOG( AptDialog );
512 }
513
514
515 /* -----------------------------------------------------------------------
516 The menu stuff 
517 ---------------------------------------------------------------------*/
518 char *fileSubmenu               [] = {
519     "Exit", "Close", "---------", "Print", "---------", "Save", "Reset", NULL
520 };
521 puCallback fileSubmenuCb        [] = {
522     MayBeGoodBye, hideMenuCb, NULL, notCb, NULL, notCb, reInit, NULL
523 };
524
525 char *editSubmenu               [] = {
526     "Edit text", NULL
527 };
528 puCallback editSubmenuCb        [] = {
529     notCb, NULL
530 };
531
532 char *viewSubmenu               [] = {
533     "Cockpit View > ", "View >","------------", "Toggle Panel...", NULL
534 };
535 puCallback viewSubmenuCb        [] = {
536     notCb, notCb, NULL, guiTogglePanel, NULL
537 };
538
539 char *aircraftSubmenu           [] = {
540     "Autopilot", "Heading", "Altitude", "Navigation", "Communication", NULL
541 };
542 puCallback aircraftSubmenuCb    [] = {
543     fgAPAdjust, NewHeading, NewAltitude, fgLatLonFormatToggle, notCb, NULL
544 };
545
546 char *environmentSubmenu        [] = {
547     "Airport", "Terrain", "Weather", NULL
548 };
549 puCallback environmentSubmenuCb [] = {
550     NewAirport, notCb, notCb, NULL
551 };
552
553 char *optionsSubmenu            [] = {
554     "Preferences", "Realism & Reliablity...", NULL
555 };
556 puCallback optionsSubmenuCb     [] = {
557     notCb, notCb, NULL
558 };
559
560 char *helpSubmenu               [] = {
561     "About...", "Help", NULL
562 };
563 puCallback helpSubmenuCb        [] = {
564     notCb, helpCb, NULL
565 };
566
567
568 /* -------------------------------------------------------------------------
569 init the gui
570 _____________________________________________________________________*/
571
572
573 void guiInit()
574 {
575     char *mesa_win_state;
576
577     // Initialize PUI
578     puInit();
579     puSetDefaultStyle         ( PUSTYLE_SMALL_BEVELLED ); //PUSTYLE_DEFAULT
580     puSetDefaultColourScheme  (0.8, 0.8, 0.8, 0.4);
581
582     // Initialize our GLOBAL GUI STRINGS
583     gui_msg_OK     = msg_OK;     // "OK"
584     gui_msg_NO     = msg_NO;     // "NO"
585     gui_msg_YES    = msg_YES;    // "YES"
586     gui_msg_CANCEL = msg_CANCEL; // "CANCEL"
587     gui_msg_RESET  = msg_RESET;  // "RESET"
588
589     // Next check home directory
590     FGPath fntpath;
591     char* envp = ::getenv( "FG_FONTS" );
592     if ( envp != NULL ) {
593         fntpath.set( envp );
594     } else {
595         fntpath.set( current_options.get_fg_root() );
596         fntpath.append( "Fonts" );
597     }
598
599     // Install our fast fonts
600     fntpath.append( "typewriter.txf" );
601     guiFntHandle = new fntTexFont ;
602     guiFntHandle -> load ( (char *)fntpath.c_str() ) ;
603     puFont GuiFont ( guiFntHandle, 15 ) ;
604     puSetDefaultFonts( GuiFont, GuiFont ) ;
605     guiFnt = puGetDefaultLabelFont();
606   
607     if ( current_options.get_mouse_pointer() == 0 ) {
608         // no preference specified for mouse pointer, attempt to autodetect...
609         // Determine if we need to render the cursor, or if the windowing
610         // system will do it.  First test if we are rendering with glide.
611         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
612             // Test for the MESA_GLX_FX env variable
613             if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
614                 // test if we are fullscreen mesa/glide
615                 if ( (mesa_win_state[0] == 'f') ||
616                      (mesa_win_state[0] == 'F') ) {
617                     puShowCursor ();
618                 }
619             }
620         }
621         mouse_active = ~mouse_active;
622     } else if ( current_options.get_mouse_pointer() == 1 ) {
623         // don't show pointer
624     } else if ( current_options.get_mouse_pointer() == 2 ) {
625         // force showing pointer
626         puShowCursor();
627         mouse_active = ~mouse_active;
628     }
629
630     // Set up our Dialog Boxes
631     ConfirmExitDialogInit();
632     NewAirportInit();
633     mkDialogInit();
634     
635     // Make the menu bar
636     mainMenuBar = new puMenuBar ();
637     mainMenuBar -> add_submenu ("File", fileSubmenu, fileSubmenuCb);
638     mainMenuBar -> add_submenu ("Edit", editSubmenu, editSubmenuCb);
639     mainMenuBar -> add_submenu ("View", viewSubmenu, viewSubmenuCb);
640     mainMenuBar -> add_submenu ("Aircraft", aircraftSubmenu, aircraftSubmenuCb);
641     mainMenuBar -> add_submenu ("Environment", environmentSubmenu, environmentSubmenuCb);
642     mainMenuBar -> add_submenu ("Options", optionsSubmenu, optionsSubmenuCb);
643     mainMenuBar -> add_submenu ("Help", helpSubmenu, helpSubmenuCb);
644     mainMenuBar-> close ();
645     // Set up menu bar toggle
646     menu_on = ~0;
647 }