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