FlightGear next
gui_funcs.cxx
Go to the documentation of this file.
1/**************************************************************************
2 * gui_funcs.cxx
3 *
4 * Based on gui.cxx and renamed on 2002/08/13 by Erik Hofman.
5 *
6 * Written 1998 by Durk Talsma, started Juni, 1998. For the flight gear
7 * project.
8 *
9 * Additional mouse supported added by David Megginson, 1999.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 *
25 * $Id$
26 **************************************************************************/
27
28
29#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
33#ifdef HAVE_WINDOWS_H
34#include <windows.h>
35#endif
36
37#include <simgear/compiler.h>
38
39#include <fstream>
40#include <string>
41#include <cstring>
42#include <sstream>
43
44#include <stdlib.h>
45
46#include <simgear/debug/logstream.hxx>
47#include <simgear/misc/sg_path.hxx>
48#include <simgear/screen/screen-dump.hxx>
49#include <simgear/structure/commands.hxx>
50#include <simgear/structure/event_mgr.hxx>
51#include <simgear/props/props_io.hxx>
52
53#include <Main/globals.hxx>
54#include <Main/fg_props.hxx>
55#include <Main/fg_os.hxx>
56#include <Viewer/renderer.hxx>
57#include <Viewer/viewmgr.hxx>
60#include <GUI/new_gui.hxx>
61
62
63#ifdef _WIN32
64# include <shellapi.h>
65#endif
66
67#if defined(SG_MAC)
68# include <GUI/CocoaHelpers.h> // for cocoaOpenUrl
69#endif
70
71#include "gui.h"
72
73using std::string;
74
76 {"dumpSnapShot", fgDumpSnapShotWrapper},
77 // Help
78 {"helpCb", helpCb},
79
80 // Structure termination
81 {"", NULL}
82};
83
84
85/* ================ General Purpose Functions ================ */
86
87// General Purpose Message Box. Makes sure no more than 5 different
88// messages are displayed at the same time, and none of them are
89// duplicates. (5 is a *lot*, but this will hardly ever be reached
90// and we don't want to miss any, either.)
91void mkDialog (const char *txt)
92{
93 auto gui = globals->get_subsystem<NewGUI>();
94 if (!gui)
95 return;
96 SGPropertyNode *master = gui->getDialogProperties("message");
97 if (!master)
98 return;
99
100 const int maxdialogs = 5;
101 string name;
102 SGPropertyNode *msg = fgGetNode("/sim/gui/dialogs", true);
103 int i;
104 for (i = 0; i < maxdialogs; i++) {
105 std::ostringstream s;
106 s << "message-" << i;
107 name = s.str();
108
109 if (!msg->getNode(name.c_str(), false))
110 break;
111
112 if (!strcmp(txt, msg->getNode(name.c_str())->getStringValue("message").c_str())) {
113 SG_LOG(SG_GENERAL, SG_WARN, "mkDialog(): duplicate of message " << txt);
114 return;
115 }
116 }
117 if (i == maxdialogs)
118 return;
119 msg = msg->getNode(name.c_str(), true);
120 msg->setStringValue("message", txt);
121 msg = msg->getNode("dialog", true);
122 copyProperties(master, msg);
123 msg->setStringValue("name", name.c_str());
124 gui->newDialog(msg);
125 gui->showDialog(name.c_str());
126}
127
128// Message Box to report an error.
129void guiErrorMessage (const char *txt)
130{
131 SG_LOG(SG_GENERAL, SG_ALERT, txt);
132 mkDialog(txt);
133}
134
135// Message Box to report a throwable (usually an exception).
136void guiErrorMessage (const char *txt, const sg_throwable &throwable)
137{
138 string msg = txt;
139 msg += '\n';
140 msg += throwable.getFormattedMessage();
141 if (std::strlen(throwable.getOrigin()) != 0) {
142 msg += "\n (reported by ";
143 msg += throwable.getOrigin();
144 msg += ')';
145 }
146 SG_LOG(SG_GENERAL, SG_ALERT, msg);
147 mkDialog(msg.c_str());
148}
149
150
151
152/* -----------------------------------------------------------------------
153the Gui callback functions
154____________________________________________________________________*/
155
156void helpCb()
157{
158 openBrowser( "Docs/index.html" );
159}
160
161bool openBrowser(const std::string& aAddress)
162{
163 bool ok = true;
164 string address(aAddress);
165
166 // do not resolve addresses with given protocol, i.e. "http://...", "ftp://..."
167 if (address.find("://")==string::npos)
168 {
169 // resolve local file path
170 SGPath path(address);
171 path = globals->resolve_maybe_aircraft_path(address);
172 if (!path.isNull()) {
173 address = "file://" + path.local8BitStr();
174 } else {
175 mkDialog ("Sorry, file not found!");
176 SG_LOG(SG_GENERAL, SG_ALERT, "openBrowser: Cannot find requested file '"
177 << address << "'.");
178 return false;
179 }
180 }
181
182#ifdef SG_MAC
183 cocoaOpenUrl(address);
184#elif defined _WIN32
185
186 // Look for favorite browser
187 char win32_name[1024];
188# ifdef __CYGWIN__
189 cygwin32_conv_to_full_win32_path(address.c_str(),win32_name);
190# else
191 strncpy(win32_name,address.c_str(), 1024);
192# endif
193 ShellExecuteA(NULL, "open", win32_name, NULL, NULL,
194 SW_SHOWNORMAL);
195#else
196 // Linux, BSD, SGI etc
197 string command = globals->get_browser();
198 string::size_type pos;
199 if ((pos = command.find("%u", 0)) != string::npos)
200 command.replace(pos, 2, address);
201 else
202 command += " \"" + address +"\"";
203
204 command += " &";
205 ok = (system( command.c_str() ) == 0);
206#endif
207
208 if( fgGetBool("/sim/gui/show-browser-open-hint", true) )
209 mkDialog("The file is shown in your web browser window.");
210
211 return ok;
212}
213
217
218namespace
219{
220 using namespace flightgear;
221
222 SGPath nextScreenshotPath(const SGPath& screenshotDir)
223 {
224 char filename[60];
225 int count = 0;
226 while (count < 100) { // 100 per second should be more than enough.
227 char time_str[20];
228 time_t calendar_time = time(NULL);
229 struct tm *tmUTC;
230 tmUTC = gmtime(&calendar_time);
231 strftime(time_str, sizeof(time_str), "%Y%m%d%H%M%S", tmUTC);
232
233 if (count)
234 snprintf(filename, 32, "fgfs-%s-%d.png", time_str, count++);
235 else
236 snprintf(filename, 32, "fgfs-%s.png", time_str);
237
238 SGPath p = screenshotDir / filename;
239 if (!p.exists()) {
240 return p;
241 }
242 }
243
244 return SGPath();
245 }
246
247 class GUISnapShotOperation :
249 {
250 public:
251
252 // start new snap shot
253 static bool start()
254 {
255 // allow only one snapshot at a time
256 if (_snapShotOp.valid())
257 return false;
258 _snapShotOp = new GUISnapShotOperation();
259 /* register with graphics context so actual snap shot is done
260 * in the graphics context (thread) */
261 osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
262 WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
263 osg::GraphicsContext* gc = 0;
264 if (guiCamera)
265 gc = guiCamera->getGraphicsContext();
266 if (gc) {
267 gc->add(_snapShotOp.get());
268 } else {
269 wsa->windows[0]->gc->add(_snapShotOp.get());
270 }
271 return true;
272 }
273
274 static void cancel()
275 {
276 _snapShotOp = nullptr;
277 }
278
279 private:
280 // constructor to be executed in main loop's thread
281 GUISnapShotOperation() :
282 flightgear::GraphicsContextOperation(std::string("GUI snap shot")),
283 _master_freeze(fgGetNode("/sim/freeze/master", true)),
284 _freeze(_master_freeze->getBoolValue()),
285 _result(false),
286 _mouse(fgGetMouseCursor())
287 {
288 if (!_freeze)
289 _master_freeze->setBoolValue(true);
290
292
293 SGPath dir = SGPath::fromUtf8(fgGetString("/sim/paths/screenshot-dir"));
294 if (dir.isNull())
295 dir = SGPath::desktop();
296
297 if (!dir.exists() && dir.create_dir( 0755 )) {
298 SG_LOG(SG_GENERAL, SG_ALERT, "Cannot create screenshot directory '"
299 << dir << "'. Trying home directory.");
300 dir = globals->get_fg_home();
301 }
302
303 _path = nextScreenshotPath(dir);
304 _xsize = fgGetInt("/sim/startup/xsize");
305 _ysize = fgGetInt("/sim/startup/ysize");
306
307 FGRenderer *renderer = globals->get_renderer();
308 renderer->resize(_xsize, _ysize);
309 globals->get_event_mgr()->addTask("SnapShotTimer",
310 [this](){ this->timerExpired(); },
311 0.1, false);
312 }
313
314 // to be executed in graphics context (maybe separate thread)
315 void run(osg::GraphicsContext* gc)
316 {
317 std::string ps = _path.local8BitStr();
318 _result = sg_glDumpWindow(ps.c_str(),
319 _xsize,
320 _ysize);
321 }
322
323 // timer method, to be executed in main loop's thread
324 virtual void timerExpired()
325 {
326 if (isFinished())
327 {
328 globals->get_event_mgr()->removeTask("SnapShotTimer");
329
330 fgSetString("/sim/paths/screenshot-last", _path.utf8Str());
331 fgSetBool("/sim/signals/screenshot", _result);
332
333 fgSetMouseCursor(_mouse);
334
335 if ( !_freeze )
336 _master_freeze->setBoolValue(false);
337
338 _snapShotOp = 0;
339 }
340 }
341
342 static osg::ref_ptr<GUISnapShotOperation> _snapShotOp;
343 SGPropertyNode_ptr _master_freeze;
344 bool _freeze;
345 bool _result;
347 int _xsize, _ysize;
348 SGPath _path;
349 };
350
351} // of anonymous namespace
352
353osg::ref_ptr<GUISnapShotOperation> GUISnapShotOperation::_snapShotOp;
354
355// do a screen snap shot
357{
358 // start snap shot operation, while needs to be executed in
359 // graphics context
360 return GUISnapShotOperation::start();
361}
362
364{
365 GUISnapShotOperation::cancel();
366}
367
368// do an entire scenegraph dump
370{
371 char *filename = new char [24];
372 string message;
373 static unsigned short count = 1;
374
375 SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
376
377 bool freeze = master_freeze->getBoolValue();
378 if ( !freeze ) {
379 master_freeze->setBoolValue(true);
380 }
381
382 while (count < 1000) {
383 FILE *fp;
384 snprintf(filename, 24, "fgfs-graph-%03d.osg", count++);
385 if ( (fp = fopen(filename, "r")) == NULL )
386 break;
387 fclose(fp);
388 }
389
390 if ( fgDumpSceneGraphToFile(filename)) {
391 message = "Entire scene graph saved to \"";
392 message += filename;
393 message += "\".";
394 } else {
395 message = "Failed to save to \"";
396 message += filename;
397 message += "\".";
398 }
399
400 mkDialog (message.c_str());
401
402 delete [] filename;
403
404 if ( !freeze ) {
405 master_freeze->setBoolValue(false);
406 }
407}
408
409
410// do an terrain branch dump
412{
413 char *filename = new char [24];
414 string message;
415 static unsigned short count = 1;
416
417 SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
418
419 bool freeze = master_freeze->getBoolValue();
420 if ( !freeze ) {
421 master_freeze->setBoolValue(true);
422 }
423
424 while (count < 1000) {
425 FILE *fp;
426 snprintf(filename, 24, "fgfs-graph-%03d.osg", count++);
427 if ( (fp = fopen(filename, "r")) == NULL )
428 break;
429 fclose(fp);
430 }
431
432 if ( fgDumpTerrainBranchToFile(filename)) {
433 message = "Terrain graph saved to \"";
434 message += filename;
435 message += "\".";
436 } else {
437 message = "Failed to save to \"";
438 message += filename;
439 message += "\".";
440 }
441
442 mkDialog (message.c_str());
443
444 delete [] filename;
445
446 if ( !freeze ) {
447 master_freeze->setBoolValue(false);
448 }
449}
450
452{
453 SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
454
455 bool freeze = master_freeze->getBoolValue();
456 if ( !freeze ) {
457 master_freeze->setBoolValue(true);
458 }
459
460 fgPrintVisibleSceneInfo(globals->get_renderer());
461
462 if ( !freeze ) {
463 master_freeze->setBoolValue(false);
464 }
465}
466
468{
469 bool paused = fgGetBool("/sim/freeze/master", true) || fgGetBool("/sim/freeze/clock", true);
470 SGPropertyNode_ptr args(new SGPropertyNode);
471 args->setStringValue("id", "sim-pause");
472 if (paused && fgGetBool("/sim/view-name-popup")) {
473 args->setStringValue("label", "Simulation is paused");
474 globals->get_commands()->execute("show-message", args, nullptr);
475 } else {
476 globals->get_commands()->execute("clear-message", args, nullptr);
477 }
478}
void cocoaOpenUrl(const std::string &url)
open a URL using the system's web-browser
#define p(x)
#define i(x)
virtual FGRenderer * get_renderer() const
Definition globals.cxx:572
SGEventMgr * get_event_mgr() const
Definition globals.cxx:605
const SGPath & get_fg_home() const
Definition globals.hxx:213
void resize(int width, int height)
Handle a window resize event.
Definition renderer.cxx:625
XML-configured GUI subsystem.
Definition new_gui.hxx:31
virtual SGPropertyNode_ptr getDialogProperties(const std::string &name)
Get dialog property tree's root node.
Definition new_gui.cxx:384
static CameraGroup * getDefault()
Get the default CameraGroup.
An operation that is run once with a particular GraphicsContext current.
WindowVector windows
Vector of all the registered windows.
static WindowSystemAdapter * getWSA()
Get the global WindowSystemAdapter.
SGCommandMgr::command_t command
const char * name
void fgSetMouseCursor(FGMouseCursor::Cursor cursor)
FGMouseCursor::Cursor fgGetMouseCursor()
int fgGetInt(const char *name, int defaultValue)
Get an int value for a property.
Definition fg_props.cxx:532
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
Definition fg_props.cxx:556
FGGlobals * globals
Definition globals.cxx:142
void fgDumpSnapShotWrapper()
void helpCb()
const __fg_gui_fn_t __fg_gui_fn[]
Definition gui_funcs.cxx:75
bool fgDumpSnapShot()
void fgDumpSceneGraph()
void syncPausePopupState()
synchronize /sim/freeze properties with visiblity of the popup-dialog which informs the user
void fgDumpTerrainBranch()
void mkDialog(const char *txt)
Definition gui_funcs.cxx:91
void fgCancelSnapShot()
void guiErrorMessage(const char *txt)
void fgPrintVisibleSceneInfoCommand()
bool openBrowser(const std::string &aAddress)
void fgDumpSnapShotWrapper()
void helpCb()
bool getBoolValue(const char *spec, bool default_)
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
Definition Addon.cxx:53
osg::Camera * getGUICamera(CameraGroup *cgroup)
Get the osg::Camera that draws the GUI, if any, from a camera group.
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
Definition proptest.cpp:25
bool fgSetBool(char const *name, bool val)
Set a bool value for a property.
Definition proptest.cpp:24
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
Definition proptest.cpp:26
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27
bool fgPrintVisibleSceneInfo(FGRenderer *renderer)
bool fgDumpTerrainBranchToFile(const char *filename)
Definition renderer.cxx:886
bool fgDumpSceneGraphToFile(const char *filename)
Definition renderer.cxx:879