]> git.mxchange.org Git - flightgear.git/blob - src/GUI/gui.cxx
847c8e0fbe7c62a9c7d8fd401b36fefa8f27e58a
[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 SG_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 <GL/gl.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/sg_path.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/fg_init.hxx>
68 #include <Main/fg_io.hxx>
69 #include <Main/globals.hxx>
70 #include <Main/fg_props.hxx>
71 #include <Main/viewmgr.hxx>
72
73 #ifdef FG_NETWORK_OLK
74 #include <NetworkOLK/network.h>
75 #endif
76    
77 #if defined( WIN32 ) && !defined( __CYGWIN__ ) && !defined(__MINGW32__)
78 #  include <simgear/screen/win32-printer.h>
79 #  include <simgear/screen/GlBitmaps.h>
80 #endif
81
82 #include "gui.h"
83 #include "gui_local.hxx"
84 #include "apt_dlg.hxx"
85 #include "net_dlg.hxx"
86 #include "sgVec3Slider.hxx"
87 #include "prop_picker.hxx"
88
89 SG_USING_STD(string);
90
91 #ifndef SG_HAVE_NATIVE_SGI_COMPILERS
92 SG_USING_STD(cout);
93 #endif
94
95 // main.cxx hack, should come from an include someplace
96 extern void fgInitVisuals( void );
97 extern void fgReshape( int width, int height );
98 extern void fgRenderFrame( void );
99
100 puFont guiFnt = 0;
101 fntTexFont *guiFntHandle = 0;
102 int gui_menu_on = 0;
103 static puMenuBar    *mainMenuBar = 0;
104 //static puButton     *hideMenuButton = 0;
105
106 static puDialogBox  *dialogBox = 0;
107 static puFrame      *dialogFrame = 0;
108 static puText       *dialogBoxMessage = 0;
109 static puOneShot    *dialogBoxOkButton = 0;
110
111
112 static puDialogBox  *YNdialogBox = 0;
113 static puFrame      *YNdialogFrame = 0;
114 static puText       *YNdialogBoxMessage = 0;
115 static puOneShot    *YNdialogBoxOkButton = 0;
116 static puOneShot    *YNdialogBoxNoButton = 0;
117
118 static char msg_OK[]     = "OK";
119 static char msg_NO[]     = "NO";
120 static char msg_YES[]    = "YES";
121 static char msg_CANCEL[] = "Cancel";
122 static char msg_RESET[]  = "Reset";
123
124 char *gui_msg_OK;     // "OK"
125 char *gui_msg_NO;     // "NO"
126 char *gui_msg_YES;    // "YES"
127 char *gui_msg_CANCEL; // "CANCEL"
128 char *gui_msg_RESET;  // "RESET"
129
130 static char global_dialog_string[256];
131
132 // from cockpit.cxx
133 extern void fgLatLonFormatToggle( puObject *);
134
135
136 /* ================ General Purpose Functions ================ */
137
138 // Intercept the Escape Key
139 void ConfirmExitDialog(void)
140 {
141     FG_PUSH_PUI_DIALOG( YNdialogBox );
142 }
143
144 // General Purpose Message Box
145 void mkDialog (const char *txt)
146 {
147     strncpy(global_dialog_string, txt, 256);
148     dialogBoxMessage->setLabel(global_dialog_string);
149     FG_PUSH_PUI_DIALOG( dialogBox );
150 }
151
152 // Message Box to report an error.
153 void guiErrorMessage (const char *txt)
154 {
155     SG_LOG(SG_GENERAL, SG_ALERT, txt);
156     if (dialogBox != 0)
157       mkDialog(txt);
158 }
159
160 // Message Box to report a throwable (usually an exception).
161 void guiErrorMessage (const char *txt, const sg_throwable &throwable)
162 {
163     string msg = txt;
164     msg += '\n';
165     msg += throwable.getFormattedMessage();
166     if (!throwable.getOrigin().empty()) {
167       msg += "\n (reported by ";
168       msg += throwable.getOrigin();
169       msg += ')';
170     }
171     SG_LOG(SG_GENERAL, SG_ALERT, msg);
172     if (dialogBox != 0)
173       mkDialog(msg.c_str());
174 }
175
176 // Toggle the Menu and Mouse display state
177 void guiToggleMenu(void)
178 {
179     if( gui_menu_on ) {
180         // printf("Hiding Menu\n");
181         mainMenuBar->hide  ();
182 #if defined(WIN32_CURSOR_TWEAKS_OFF)
183         if( mouse_mode == MOUSE_POINTER )
184             TurnCursorOff();
185 #endif // WIN32_CURSOR_TWEAKS_OFF
186     } else {
187         // printf("Showing Menu\n");
188         mainMenuBar->reveal();
189 #ifdef WIN32
190         TurnCursorOn();
191 #endif // WIN32
192     }
193     gui_menu_on = ~gui_menu_on;
194 }
195     
196 /* -----------------------------------------------------------------------
197 the Gui callback functions 
198 ____________________________________________________________________*/
199
200
201 // Hier Neu :-) This is my newly added code
202 // Added by David Findlay <nedz@bigpond.com>
203 // on Sunday 3rd of December
204
205 // Start new Save Dialog Box
206 static puDialogBox     *SaveDialog = 0;
207 static puFrame         *SaveDialogFrame = 0;
208 static puText          *SaveDialogMessage = 0;
209 static puInput         *SaveDialogInput = 0;
210
211 static puOneShot       *SaveDialogOkButton = 0;
212 static puOneShot       *SaveDialogCancelButton = 0;
213 // static puOneShot       *SaveDialogResetButton = 0;
214
215 // Default save filename
216 static char saveFile[256] = "fgfs.sav";
217
218 // Cancel Button
219 void SaveDialogCancel(puObject *) {
220     FG_POP_PUI_DIALOG( SaveDialog );
221 }
222
223 // If press OK do this
224 void SaveDialogOk(puObject*) {
225
226     FG_POP_PUI_DIALOG( SaveDialog );
227
228     char *s;
229     SaveDialogInput->getValue(&s);
230
231     ofstream output(s);
232     cout << saveFile << endl;
233     if (output.good() && fgSaveFlight(output)) {
234         output.close();
235         mkDialog("Saved flight");
236         SG_LOG(SG_INPUT, SG_INFO, "Saved flight");
237     } else {
238         mkDialog("Cannot save flight");
239         SG_LOG(SG_INPUT, SG_ALERT, "Cannot save flight");
240     }
241 }
242
243 // Create Dialog
244 static void saveFlight(puObject *cv) {
245     SaveDialog = new puDialogBox (150, 50);
246     {
247         SaveDialogFrame   = new puFrame           (0,0,350, 150);
248         SaveDialogMessage
249             = new puText( (150 - puGetDefaultLabelFont().getStringWidth( "File Name:" ) / 2), 110 );
250         SaveDialogMessage ->    setLabel          ("File Name:");
251
252         SaveDialogInput   = new puInput           (50, 70, 300, 100);
253         SaveDialogInput   ->    setValue          (saveFile);
254         SaveDialogInput   ->    acceptInput();
255
256         SaveDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
257         SaveDialogOkButton     ->     setLegend   (gui_msg_OK);
258         SaveDialogOkButton     ->     setCallback ( SaveDialogOk );
259         SaveDialogOkButton     ->     makeReturnDefault(TRUE);
260
261         SaveDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
262         SaveDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
263         SaveDialogCancelButton ->     setCallback ( SaveDialogCancel );
264     }
265     FG_FINALIZE_PUI_DIALOG( SaveDialog );
266    
267     SaveDialog -> reveal();
268 }
269
270 // Load Dialog Start
271 static puDialogBox     *LoadDialog = 0;
272 static puFrame         *LoadDialogFrame = 0;
273 static puText          *LoadDialogMessage = 0;
274 static puInput         *LoadDialogInput = 0;
275
276 static puOneShot       *LoadDialogOkButton = 0;
277 static puOneShot       *LoadDialogCancelButton = 0;
278 // static puOneShot       *LoadDialogResetButton = 0;
279
280 // Default load filename
281 static char loadFile[256] = "fgfs.sav";
282
283 // Do this if the person click okay
284 void LoadDialogOk(puObject *) {
285
286     FG_POP_PUI_DIALOG( LoadDialog );
287
288     char *l;
289     LoadDialogInput->getValue(&l);
290
291     ifstream input(l);
292     if (input.good() && fgLoadFlight(input)) {
293         input.close();
294         mkDialog("Loaded flight");
295         SG_LOG(SG_INPUT, SG_INFO, "Restored flight");
296     } else {
297         mkDialog("Failed to load flight");
298         SG_LOG(SG_INPUT, SG_ALERT, "Cannot load flight");
299     }
300 }
301
302 // Do this if the person presses cancel
303 void LoadDialogCancel(puObject *) {
304     FG_POP_PUI_DIALOG( LoadDialog );
305 }
306
307 // Create Load Dialog
308 static void loadFlight(puObject *cb)
309 {
310     LoadDialog = new puDialogBox (150, 50);
311     {
312         LoadDialogFrame   = new puFrame           (0,0,350, 150);
313         LoadDialogMessage
314             = new puText( (150 - puGetDefaultLabelFont().getStringWidth( "File Name:" ) / 2), 110 );
315         LoadDialogMessage ->    setLabel          ("File Name:");
316
317         LoadDialogInput   = new puInput           (50, 70, 300, 100);
318         LoadDialogInput   ->    setValue          (loadFile);
319         LoadDialogInput   ->    acceptInput();
320
321         LoadDialogOkButton     =  new puOneShot   (50, 10, 110, 50);
322         LoadDialogOkButton     ->     setLegend   (gui_msg_OK);
323         LoadDialogOkButton     ->     setCallback ( LoadDialogOk );
324         LoadDialogOkButton     ->     makeReturnDefault(TRUE);
325
326         LoadDialogCancelButton =  new puOneShot   (140, 10, 210, 50);
327         LoadDialogCancelButton ->     setLegend   (gui_msg_CANCEL);
328         LoadDialogCancelButton ->     setCallback ( LoadDialogCancel );
329     }
330     FG_FINALIZE_PUI_DIALOG( LoadDialog );
331    
332     LoadDialog -> reveal();
333 }
334
335 // This is the accessor function
336 void guiTogglePanel(puObject *cb)
337 {
338   if (fgGetBool("/sim/panel/visibility"))
339     fgSetBool("/sim/panel/visibility", false);
340   else
341     fgSetBool("/sim/panel/visibility", true);
342
343   fgReshape(fgGetInt("/sim/startup/xsize"),
344             fgGetInt("/sim/startup/ysize"));
345 }
346     
347 //void MenuHideMenuCb(puObject *cb)
348 void hideMenuCb (puObject *cb)
349 {
350     guiToggleMenu();
351 }
352
353 void goodBye(puObject *)
354 {
355     // SG_LOG( SG_INPUT, SG_ALERT,
356     //      "Program exiting normally at user request." );
357     cout << "Program exiting normally at user request." << endl;
358
359 #ifdef FG_NETWORK_OLK    
360     if ( fgGetBool("/sim/networking/network-olk") ) {
361         if ( net_is_registered == 0 ) fgd_send_com( "8", FGFS_host);
362     }
363 #endif
364
365     // close all external I/O connections
366     fgIOShutdownAll();
367
368     exit(0);
369 }
370
371
372 void goAwayCb (puObject *me)
373 {
374     FG_POP_PUI_DIALOG( dialogBox );
375 }
376
377 void mkDialogInit (void)
378 {
379     //  printf("mkDialogInit\n");
380     int x = (fgGetInt("/sim/startup/xsize")/2 - 400/2);
381     int y = (fgGetInt("/sim/startup/ysize")/2 - 100/2);
382     dialogBox = new puDialogBox (x, y); // 150, 50
383     {
384         dialogFrame = new puFrame (0,0,400,100);
385         dialogBoxMessage  =  new puText         (10, 70);
386         dialogBoxMessage  -> setLabel           ("");
387         dialogBoxOkButton =  new puOneShot      (180, 10, 240, 50);
388         dialogBoxOkButton -> setLegend          (gui_msg_OK);
389         dialogBoxOkButton -> makeReturnDefault  (TRUE );
390         dialogBoxOkButton -> setCallback        (goAwayCb);
391     }
392     FG_FINALIZE_PUI_DIALOG( dialogBox );
393 }
394
395 void MayBeGoodBye(puObject *)
396 {
397     ConfirmExitDialog(); 
398 }
399
400 void goAwayYesNoCb(puObject *me)
401 {
402     FG_POP_PUI_DIALOG( YNdialogBox);
403 }
404
405 void ConfirmExitDialogInit(void)
406 {
407     char msg[] = "Really Quit";
408     char *s;
409
410     //  printf("ConfirmExitDialogInit\n");
411     int len = 200 - puGetDefaultLabelFont().getStringWidth ( msg ) / 2;
412
413     int x = (fgGetInt("/sim/startup/xsize")/2 - 400/2);
414     int y = (fgGetInt("/sim/startup/ysize")/2 - 100/2);
415         
416     YNdialogBox = new puDialogBox (x, y); // 150, 50
417     {
418         YNdialogFrame = new puFrame (0,0,400, 100);
419         
420         YNdialogBoxMessage  =  new puText         (len, 70);
421         YNdialogBoxMessage  -> setDefaultValue    (msg);
422         YNdialogBoxMessage  -> getDefaultValue    (&s);
423         YNdialogBoxMessage  -> setLabel           (s);
424         
425         YNdialogBoxOkButton =  new puOneShot      (100, 10, 160, 50);
426         YNdialogBoxOkButton -> setLegend          (gui_msg_OK);
427         YNdialogBoxOkButton -> makeReturnDefault  (TRUE );
428         YNdialogBoxOkButton -> setCallback        (goodBye);
429         
430         YNdialogBoxNoButton =  new puOneShot      (240, 10, 300, 50);
431         YNdialogBoxNoButton -> setLegend          (gui_msg_NO);
432         YNdialogBoxNoButton -> setCallback        (goAwayYesNoCb);
433     }
434     FG_FINALIZE_PUI_DIALOG( YNdialogBox );
435 }
436
437 void notCb (puObject *)
438 {
439     mkDialog ("This function isn't implemented yet");
440 }
441
442 void helpCb (puObject *)
443 {
444     string command;
445         
446 #if defined(FX) && !defined(WIN32)
447 #  if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
448     if ( globals->get_fullscreen() ) {
449         globals->set_fullscreen(false);
450         XMesaSetFXmode( XMESA_FX_WINDOW );
451     }
452 #  endif
453 #endif
454         
455     SGPath path( globals->get_fg_root() );
456     path.append( "Docs/index.html" );
457         
458 #if !defined(WIN32)
459     string help_app = fgGetString("/sim/startup/browser-app");
460
461     if ( system("xwininfo -name Netscape > /dev/null 2>&1") == 0 ) {
462         command = help_app + " -remote \"openURL(" + path.str() + ")\"";
463     } else {
464         command = help_app + " " + path.str();
465     }
466     command += " &";
467 #else // WIN32
468         command = "start ";
469         command += path.str();
470 #endif
471         
472     system( command.c_str() );
473     mkDialog ("Help started in netscape window.");
474 }
475
476 #define TR_HIRES_SNAP
477 #if defined( TR_HIRES_SNAP)
478 #include <simgear/screen/tr.h>
479 extern void trRenderFrame( void );
480 extern void fgUpdateHUD( GLfloat x_start, GLfloat y_start,
481                          GLfloat x_end, GLfloat y_end );
482
483 void fgHiResDump()
484 {
485     FILE *f;
486     string message;
487     bool show_pu_cursor = false;
488     bool show_menu = false;
489     char *filename = new char [24];
490     static int count = 1;
491
492     static const SGPropertyNode *master_freeze
493         = fgGetNode("/sim/freeze/master");
494
495     bool freeze = master_freeze->getBoolValue();
496     if ( !freeze ) {
497         fgSetBool("/sim/freeze/master", true);
498     }
499
500     if(gui_menu_on) {
501         show_menu = true;
502         guiToggleMenu();
503     }
504         
505     if ( !puCursorIsHidden() ) {
506         show_pu_cursor = true;
507         puHideCursor();
508     }
509
510     fgInitVisuals();
511     fgReshape( fgGetInt("/sim/startup/xsize"),
512                fgGetInt("/sim/startup/ysize") );
513
514     // we need two render frames here to clear the menu and cursor
515     // ... not sure why but doing an extra fgRenderFrame() shouldn't
516     // hurt anything
517     fgRenderFrame();
518     fgRenderFrame();
519
520     // Make sure we have SSG projection primed for current view
521     glMatrixMode(GL_MODELVIEW);
522     glLoadIdentity();
523     ssgSetCamera( (sgVec4 *)globals->get_current_view()->get_VIEW() );
524     ssgSetFOV( globals->get_current_view()->get_h_fov(),
525                globals->get_current_view()->get_v_fov() );
526     // ssgSetNearFar( 10.0f, 120000.0f );
527     ssgSetNearFar( 0.5f, 1200000.0f );
528
529         
530     // This ImageSize stuff is a temporary hack
531     // should probably use 128x128 tile size and
532     // support any image size
533
534     // This should be a requester to get multiplier from user
535     int multiplier = 3;
536     int width = fgGetInt("/sim/startup/xsize");
537     int height = fgGetInt("/sim/startup/ysize");
538         
539     /* allocate buffer large enough to store one tile */
540     GLubyte *tile = (GLubyte *)malloc(width * height * 3 * sizeof(GLubyte));
541     if (!tile) {
542         printf("Malloc of tile buffer failed!\n");
543         return;
544     }
545
546     int imageWidth  = multiplier*width;
547     int imageHeight = multiplier*height;
548
549     /* allocate buffer to hold a row of tiles */
550     GLubyte *buffer
551         = (GLubyte *)malloc(imageWidth * height * 3 * sizeof(GLubyte));
552     if (!buffer) {
553         free(tile);
554         printf("Malloc of tile row buffer failed!\n");
555         return;
556     }
557     TRcontext *tr = trNew();
558     trTileSize(tr, width, height, 0);
559     trTileBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, tile);
560     trImageSize(tr, imageWidth, imageHeight);
561     trRowOrder(tr, TR_TOP_TO_BOTTOM);
562     sgFrustum *frustum = ssgGetFrustum();
563     trFrustum(tr,
564               frustum->getLeft(), frustum->getRight(),
565               frustum->getBot(),  frustum->getTop(), 
566               frustum->getNear(), frustum->getFar());
567         
568     /* Prepare ppm output file */
569     while (count < 1000) {
570         snprintf(filename, 24, "fgfs-screen-%03d.ppm", count++);
571         if ( (f = fopen(filename, "r")) == NULL )
572             break;
573         fclose(f);
574     }
575     f = fopen(filename, "wb");
576     if (!f) {
577         printf("Couldn't open image file: %s\n", filename);
578         free(buffer);
579         free(tile);
580         return;
581     }
582     fprintf(f,"P6\n");
583     fprintf(f,"# ppm-file created by %s\n", "trdemo2");
584     fprintf(f,"%i %i\n", imageWidth, imageHeight);
585     fprintf(f,"255\n");
586
587     /* just to be safe... */
588     glPixelStorei(GL_PACK_ALIGNMENT, 1);
589
590     /* Because the HUD and Panel change the ViewPort we will
591      * need to handle some lowlevel stuff ourselves */
592     int ncols = trGet(tr, TR_COLUMNS);
593     int nrows = trGet(tr, TR_ROWS);
594
595     bool do_hud = fgGetBool("/sim/hud/visibility");
596     GLfloat hud_col_step = 640.0 / ncols;
597     GLfloat hud_row_step = 480.0 / nrows;
598         
599     bool do_panel = fgPanelVisible();
600     GLfloat panel_col_step = current_panel->getWidth() / ncols;
601     GLfloat panel_row_step = current_panel->getHeight() / nrows;
602         
603     /* Draw tiles */
604     int more = 1;
605     while (more) {
606         trBeginTile(tr);
607         int curColumn = trGet(tr, TR_CURRENT_COLUMN);
608         int curRow =  trGet(tr, TR_CURRENT_ROW);
609         trRenderFrame();
610         if ( do_hud )
611             fgUpdateHUD( curColumn*hud_col_step,      curRow*hud_row_step,
612                          (curColumn+1)*hud_col_step, (curRow+1)*hud_row_step );
613         if (do_panel)
614             current_panel->update( curColumn*panel_col_step, panel_col_step,
615                                    curRow*panel_row_step,    panel_row_step );
616         more = trEndTile(tr);
617
618         /* save tile into tile row buffer*/
619         int curTileWidth = trGet(tr, TR_CURRENT_TILE_WIDTH);
620         int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
621         int bytesPerTileRow = (width) * 3*sizeof(GLubyte);
622         int xOffset = curColumn * bytesPerTileRow;
623         int bytesPerCurrentTileRow = (curTileWidth) * 3*sizeof(GLubyte);
624         int i;
625         for (i=0;i<height;i++) {
626             memcpy(buffer + i*bytesPerImageRow + xOffset, /* Dest */
627                    tile + i*bytesPerTileRow,              /* Src */
628                    bytesPerCurrentTileRow);               /* Byte count*/
629         }
630
631         if (curColumn == trGet(tr, TR_COLUMNS)-1) {
632             /* write this buffered row of tiles to the file */
633             int curTileHeight = trGet(tr, TR_CURRENT_TILE_HEIGHT);
634             int bytesPerImageRow = imageWidth * 3*sizeof(GLubyte);
635             int i;
636             for (i=0;i<curTileHeight;i++) {
637                 /* Remember, OpenGL images are bottom to top.  Have to reverse. */
638                 GLubyte *rowPtr = buffer + (curTileHeight-1-i) * bytesPerImageRow;
639                 fwrite(rowPtr, 1, imageWidth*3, f);
640             }
641         }
642
643     }
644
645     fgReshape( width, height );
646
647     trDelete(tr);
648
649     fclose(f);
650
651     message = "Snap shot saved to ";
652     message += filename;
653     mkDialog (message.c_str());
654
655     free(tile);
656     free(buffer);
657
658     //  message = "Snap shot saved to ";
659     //  message += filename;
660     //  mkDialog (message.c_str());
661
662     delete [] filename;
663
664     if( show_menu )
665         guiToggleMenu();
666
667     if ( show_pu_cursor ) {
668         puShowCursor();
669     }
670
671     if ( !freeze ) {
672         fgSetBool("/sim/freeze/master", false);
673     }
674 }
675 #endif // #if defined( TR_HIRES_SNAP)
676
677
678 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined(__MINGW32__)
679
680 static void rotateView( double roll, double pitch, double yaw )
681 {
682         // rotate view
683 }
684
685 static GlBitmap *b1 = NULL;
686 extern FGInterface cur_view_fdm;
687 GLubyte *hiResScreenCapture( int multiplier )
688 {
689     float oldfov = fgGetDouble("/sim/current-view/field-of-view");
690     float fov = oldfov / multiplier;
691     FGViewer *v = globals->get_current_view();
692     fgSetDouble("/sim/current-view/field-of-view", fov);
693     fgInitVisuals();
694     int cur_width = fgGetInt("/sim/startup/xsize");
695     int cur_height = fgGetInt("/sim/startup/ysize");
696     if (b1) delete( b1 );
697     // New empty (mostly) bitmap
698     b1 = new GlBitmap( GL_RGB, 1, 1, (unsigned char *)"123" );
699     int x,y;
700     for ( y = 0; y < multiplier; y++ ) {
701         for ( x = 0; x < multiplier; x++ ) {
702             fgReshape( cur_width, cur_height );
703             // pan to tile
704             rotateView( 0, (y*fov)-((multiplier-1)*fov/2), (x*fov)-((multiplier-1)*fov/2) );
705             fgRenderFrame();
706             // restore view
707             GlBitmap b2;
708             b1->copyBitmap( &b2, cur_width*x, cur_height*y );
709         }
710     }
711     fgSetDouble("/sim/current-view/field-of-view", oldfov);
712     return b1->getBitmap();
713 }
714 #endif
715
716
717 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined(__MINGW32__)
718 // win32 print screen function
719 void printScreen ( puObject *obj ) {
720     bool show_pu_cursor = false;
721     TurnCursorOff();
722     if ( !puCursorIsHidden() ) {
723         show_pu_cursor = true;
724         puHideCursor();
725     }
726     // BusyCursor( 0 );
727     mainMenuBar->hide();
728
729     CGlPrinter p( CGlPrinter::PRINT_BITMAP );
730     int cur_width = fgGetInt("/sim/startup/xsize");
731     int cur_height = fgGetInt("/sim/startup/ysize");
732     p.Begin( "FlightGear", cur_width*3, cur_height*3 );
733         p.End( hiResScreenCapture(3) );
734
735     if( gui_menu_on ) {
736         mainMenuBar->reveal();
737     }
738     // BusyCursor(1);
739     if ( show_pu_cursor ) {
740         puShowCursor();
741     }
742     TurnCursorOn();
743 }
744 #endif // #ifdef WIN32
745
746
747 void dumpSnapShot ( puObject *obj ) {
748     fgDumpSnapShot();
749 }
750
751
752 void dumpHiResSnapShot ( puObject *obj ) {
753     fgHiResDump();
754 }
755
756
757 // do a screen snap shot
758 void fgDumpSnapShot () {
759     bool show_pu_cursor = false;
760     char *filename = new char [24];
761     string message;
762     static int count = 1;
763
764     static const SGPropertyNode *master_freeze
765         = fgGetNode("/sim/freeze/master");
766
767     bool freeze = master_freeze->getBoolValue();
768     if ( !freeze ) {
769         fgSetBool("/sim/freeze/master", true);
770     }
771
772     mainMenuBar->hide();
773     TurnCursorOff();
774     if ( !puCursorIsHidden() ) {
775         show_pu_cursor = true;
776         puHideCursor();
777     }
778
779     fgInitVisuals();
780     fgReshape( fgGetInt("/sim/startup/xsize"),
781                fgGetInt("/sim/startup/ysize") );
782
783     // we need two render frames here to clear the menu and cursor
784     // ... not sure why but doing an extra fgRenderFrame() shouldn't
785     // hurt anything
786     fgRenderFrame();
787     fgRenderFrame();
788
789     while (count < 1000) {
790         FILE *fp;
791         snprintf(filename, 24, "fgfs-screen-%03d.ppm", count++);
792         if ( (fp = fopen(filename, "r")) == NULL )
793             break;
794         fclose(fp);
795     }
796
797     if ( sg_glDumpWindow( filename,
798                           fgGetInt("/sim/startup/xsize"), 
799                           fgGetInt("/sim/startup/ysize")) ) {
800         message = "Snap shot saved to ";
801         message += filename;
802     } else {
803         message = "Failed to save to ";
804         message += filename;
805     }
806
807     mkDialog (message.c_str());
808
809     delete [] filename;
810
811     if ( show_pu_cursor ) {
812         puShowCursor();
813     }
814
815     TurnCursorOn();
816     if( gui_menu_on ) {
817         mainMenuBar->reveal();
818     }
819
820     if ( !freeze ) {
821         fgSetBool("/sim/freeze/master", false);
822     }
823 }
824
825 #ifdef FG_NETWORK_OLK
826 static void net_display_toggle( puObject *cb)
827 {
828         net_hud_display = (net_hud_display) ? 0 : 1;
829         printf("Toggle net_hud_display : %d\n", net_hud_display);
830 }
831
832 static void net_register( puObject *cb)
833 {
834         fgd_send_com( "1", FGFS_host );
835         net_is_registered = 0;
836         printf("Registering to deamon\n");
837 }
838
839 static void net_unregister( puObject *cb)
840 {
841         fgd_send_com( "8", FGFS_host );
842         net_is_registered = -1;
843         printf("Unregistering from deamon\n");
844 }
845
846 extern void net_fgd_scan(puObject *cb);
847 #endif // #ifdef FG_NETWORK_OLK
848
849 /* -----------------------------------------------------------------------
850 The menu stuff 
851 ---------------------------------------------------------------------*/
852 char *fileSubmenu               [] = {
853     "Exit", /* "Close", "---------", */
854 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined(__MINGW32__)
855     "Print",
856 #endif
857     "Snap Shot",
858     "Hires Snap Shot",
859     "---------", 
860     "Reset", 
861     "Load flight",
862     "Save flight",
863     NULL
864 };
865 puCallback fileSubmenuCb        [] = {
866     MayBeGoodBye, /* hideMenuCb, NULL, */
867 #if defined( WIN32 ) && !defined( __CYGWIN__) && !defined(__MINGW32__)
868     printScreen, 
869 #endif
870     /* NULL, notCb, */
871     dumpSnapShot,
872     dumpHiResSnapShot,
873     NULL,
874     reInit, 
875     loadFlight,
876     saveFlight,
877     NULL
878 };
879
880 /*
881 char *editSubmenu               [] = {
882     "Edit text", NULL
883 };
884 puCallback editSubmenuCb        [] = {
885     notCb, NULL
886 };
887 */
888
889 extern void fgHUDalphaAdjust( puObject * );
890 char *viewSubmenu               [] = {
891     "Properties",
892     "HUD Alpha",
893     "Pilot Offset",
894     /* "Cockpit View > ", "View >","------------", */
895     "Toggle Panel...", NULL
896 };
897 puCallback viewSubmenuCb        [] = {
898     prop_pickerView,
899     fgHUDalphaAdjust,
900     PilotOffsetAdjust,
901     /* notCb, notCb, NULL, */
902     guiTogglePanel, NULL
903 };
904
905 //  "---------", 
906
907 char *autopilotSubmenu           [] = {
908     "Toggle HUD Format", "Adjust AP Settings",
909     "---------", 
910     "Clear Route", "Skip Current Waypoint", "Add Waypoint",
911     "---------", 
912     "Set Altitude", "Set Heading",
913     NULL
914 };
915
916 puCallback autopilotSubmenuCb    [] = {
917     fgLatLonFormatToggle, fgAPAdjust,
918     NULL,
919     ClearRoute, PopWayPoint, AddWayPoint,
920     NULL,
921     NewAltitude, NewHeading,
922     /* notCb, */ NULL
923 };
924
925 char *environmentSubmenu        [] = {
926     "Goto Airport", /* "Terrain", "Weather", */ NULL
927 };
928 puCallback environmentSubmenuCb [] = {
929     NewAirport, /* notCb, notCb, */ NULL
930 };
931
932 /*
933 char *optionsSubmenu            [] = {
934     "Preferences", "Realism & Reliablity...", NULL
935 };
936 puCallback optionsSubmenuCb     [] = {
937     notCb, notCb, NULL
938 };
939 */
940
941 #ifdef FG_NETWORK_OLK
942 char *networkSubmenu            [] = {
943     "Unregister from FGD ", /* "Send MSG to All", "Send MSG", "Show Pilots", */
944     "Register to FGD",
945     "Scan for Deamons", "Enter Callsign", /* "Display Netinfos", */
946     "Toggle Display", NULL
947 };
948 puCallback networkSubmenuCb     [] = {
949     /* notCb, notCb, notCb, notCb, */ 
950     net_unregister, 
951     net_register, 
952     net_fgd_scan, NewCallSign, 
953     net_display_toggle, NULL
954 };
955 #endif
956
957 char *helpSubmenu               [] = {
958     /* "About...", */ "Help", NULL
959 };
960 puCallback helpSubmenuCb        [] = {
961     /* notCb, */ helpCb, NULL
962 };
963
964
965 /* -------------------------------------------------------------------------
966 init the gui
967 _____________________________________________________________________*/
968
969
970 void guiInit()
971 {
972     char *mesa_win_state;
973
974     // Initialize PUI
975     puInit();
976     puSetDefaultStyle         ( PUSTYLE_SMALL_BEVELLED ); //PUSTYLE_DEFAULT
977     puSetDefaultColourScheme  (0.8, 0.8, 0.8, 0.4);
978
979     // Initialize our GLOBAL GUI STRINGS
980     gui_msg_OK     = msg_OK;     // "OK"
981     gui_msg_NO     = msg_NO;     // "NO"
982     gui_msg_YES    = msg_YES;    // "YES"
983     gui_msg_CANCEL = msg_CANCEL; // "CANCEL"
984     gui_msg_RESET  = msg_RESET;  // "RESET"
985
986     // Next check home directory
987     SGPath fntpath;
988     char* envp = ::getenv( "FG_FONTS" );
989     if ( envp != NULL ) {
990         fntpath.set( envp );
991     } else {
992         fntpath.set( globals->get_fg_root() );
993         fntpath.append( "Fonts" );
994     }
995
996     // Install our fast fonts
997     fntpath.append(fgGetString("/sim/font", "typewriter.txf"));
998     guiFntHandle = new fntTexFont ;
999     guiFntHandle -> load ( (char *)fntpath.c_str() ) ;
1000     puFont GuiFont ( guiFntHandle, 15 ) ;
1001     puSetDefaultFonts( GuiFont, GuiFont ) ;
1002     guiFnt = puGetDefaultLabelFont();
1003   
1004     if (!fgHasNode("/sim/startup/mouse-pointer")) {
1005         // no preference specified for mouse pointer, attempt to autodetect...
1006         // Determine if we need to render the cursor, or if the windowing
1007         // system will do it.  First test if we are rendering with glide.
1008         if ( strstr ( general.get_glRenderer(), "Glide" ) ) {
1009             // Test for the MESA_GLX_FX env variable
1010             if ( (mesa_win_state = getenv( "MESA_GLX_FX" )) != NULL) {
1011                 // test if we are fullscreen mesa/glide
1012                 if ( (mesa_win_state[0] == 'f') ||
1013                      (mesa_win_state[0] == 'F') ) {
1014                     puShowCursor ();
1015                 }
1016             }
1017         }
1018 //        mouse_active = ~mouse_active;
1019     } else if ( !fgGetBool("/sim/startup/mouse-pointer") ) {
1020         // don't show pointer
1021     } else {
1022         // force showing pointer
1023         puShowCursor();
1024 //        mouse_active = ~mouse_active;
1025     }
1026         
1027     // MOUSE_VIEW mode stuff
1028         initMouseQuat();
1029
1030     // Set up our Dialog Boxes
1031     ConfirmExitDialogInit();
1032     NewAirportInit();
1033         
1034 #ifdef FG_NETWORK_OLK
1035     NewNetIdInit();
1036     NewNetFGDInit();
1037 #endif
1038
1039         mkDialogInit();
1040     
1041     // Make the menu bar
1042     mainMenuBar = new puMenuBar ();
1043     mainMenuBar -> add_submenu ("File", fileSubmenu, fileSubmenuCb);
1044     // mainMenuBar -> add_submenu ("Edit", editSubmenu, editSubmenuCb);
1045     mainMenuBar -> add_submenu ("View", viewSubmenu, viewSubmenuCb);
1046     mainMenuBar -> add_submenu ("Environment", environmentSubmenu, environmentSubmenuCb);
1047     mainMenuBar -> add_submenu ("Autopilot", autopilotSubmenu, autopilotSubmenuCb);
1048     // mainMenuBar -> add_submenu ("Options", optionsSubmenu, optionsSubmenuCb);
1049 #ifdef FG_NETWORK_OLK
1050     if ( fgGetBool("/sim/networking/network-olk") ) {
1051         mainMenuBar -> add_submenu ("Network", networkSubmenu, networkSubmenuCb);
1052     }
1053 #endif
1054     mainMenuBar -> add_submenu ("Help", helpSubmenu, helpSubmenuCb);
1055     mainMenuBar-> close ();
1056     // Set up menu bar toggle
1057     gui_menu_on = ~0;
1058
1059     if (!strcmp(fgGetString("/sim/flight-model"), "ada")) {
1060         guiToggleMenu(); // Menu off by default
1061     }
1062 }