Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GUIMainWindow.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
20//
21/****************************************************************************/
22#include <config.h>
23
24#include <string>
25#include <algorithm>
27// fx3d includes windows.h so we need to guard against macro pollution
28#ifdef WIN32
29#define NOMINMAX
30#endif
31#include <fx3d.h>
32#ifdef WIN32
33#undef NOMINMAX
34#endif
42#include "GUIMainWindow.h"
43#include "GUIGlChildWindow.h"
44
45
46// ===========================================================================
47// static member definitions
48// ===========================================================================
50
51// ===========================================================================
52// member method definitions
53// ===========================================================================
55 FXMainWindow(app, "sumo-gui main window", nullptr, nullptr, DECOR_ALL, 20, 20, 600, 400),
56 myAmFullScreen(false),
57 myTrackerLock(true),
58 myGLVisual(new FXGLVisual(app, VISUAL_DOUBLEBUFFER)),
59 myAmGaming(false),
60 myListInternal(false),
61 myListParking(true),
62 myListTeleporting(false) {
63 // build static tooltips
66 // build bold font
67 FXFontDesc fdesc;
68 app->getNormalFont()->getFontDesc(fdesc);
69 const double uiScale = app->reg().readRealEntry("SETTINGS", "uiscale", 1);
70 fdesc.size = (FXushort)(fdesc.size * uiScale);
71 myNormalFont = new FXFont(app, fdesc);
72 app->setNormalFont(myNormalFont);
73 fdesc.weight = FXFont::Bold;
74 GUIDesignHeight = (int)(fdesc.size / 90.0 * 18) + 5;
75 myBoldFont = new FXFont(app, fdesc);
76 // https://en.wikipedia.org/wiki/Noto_fonts should be widely available
77 myFallbackFont = new FXFont(app, "Noto Sans CJK JP");
78 // build docks
79 myTopDock = new FXDockSite(this, LAYOUT_SIDE_TOP | LAYOUT_FILL_X);
80 myBottomDock = new FXDockSite(this, LAYOUT_SIDE_BOTTOM | LAYOUT_FILL_X);
81 myLeftDock = new FXDockSite(this, LAYOUT_SIDE_LEFT | LAYOUT_FILL_Y);
82 myRightDock = new FXDockSite(this, LAYOUT_SIDE_RIGHT | LAYOUT_FILL_Y);
83 // avoid instance Windows twice
84 if (myInstance != nullptr) {
85 throw ProcessError("MainWindow initialized twice");
86 }
87 myInstance = this;
88 //myGLVisual->setStencilSize(8); // enable stencil buffer
89}
90
91
95 delete myNormalFont;
96 delete myBoldFont;
97 delete myFallbackFont;
98 delete myTopDock;
99 delete myBottomDock;
100 delete myLeftDock;
101 delete myRightDock;
102 myInstance = nullptr;
103}
104
105
106
107void
109 myGLWindows.push_back(child);
110}
111
112
113void
115 std::vector<GUIGlChildWindow*>::iterator i = std::find(myGLWindows.begin(), myGLWindows.end(), child);
116 if (i != myGLWindows.end()) {
117 myGLWindows.erase(i);
118 }
119}
120
121
122void
123GUIMainWindow::addChild(FXMainWindow* child) {
124 myTrackerLock.lock();
125 myTrackerWindows.push_back(child);
126 myTrackerLock.unlock();
127}
128
129
130void
131GUIMainWindow::removeChild(FXMainWindow* child) {
132 myTrackerLock.lock();
133 std::vector<FXMainWindow*>::iterator i = std::find(myTrackerWindows.begin(), myTrackerWindows.end(), child);
134 myTrackerWindows.erase(i);
135 myTrackerLock.unlock();
136}
137
138
139FXDockSite*
143
144
145std::vector<std::string>
147 std::vector<std::string> ret;
148 for (GUIGlChildWindow* const window : myGLWindows) {
149 ret.push_back(window->getTitle().text());
150 }
151 return ret;
152}
153
154
156GUIMainWindow::getViewByID(const std::string& id) const {
157 for (GUIGlChildWindow* const window : myGLWindows) {
158 if (std::string(window->getTitle().text()) == id) {
159 return window;
160 }
161 }
162 return nullptr;
163}
164
165
166void
167GUIMainWindow::removeViewByID(const std::string& id) {
168 for (GUIGlChildWindow* const window : myGLWindows) {
169 if (std::string(window->getTitle().text()) == id) {
170 window->close();
171 removeGLChild(window);
172 return;
173 }
174 }
175}
176
177
178FXFont*
182
183FXFont*
187
188const std::vector<GUIGlChildWindow*>&
190 return myGLWindows;
191}
192
193
194void
196 // inform views
197 myMDIClient->forallWindows(this, FXSEL(SEL_COMMAND, msg), nullptr);
198 // inform other windows
199 myTrackerLock.lock();
200 for (int i = 0; i < (int)myTrackerWindows.size(); i++) {
201 myTrackerWindows[i]->handle(this, FXSEL(SEL_COMMAND, msg), nullptr);
202 }
203 myTrackerLock.unlock();
204}
205
206
207FXGLVisual*
209 return myGLVisual;
210}
211
212
217
218
223
224
225FXLabel*
229
230
231FXLabel*
235
236
237FXLabel*
241
242
243FXHorizontalFrame*
247
248
249bool
251 return myAmGaming;
252}
253
254
255bool
259
260
261bool
263 return myListParking;
264}
265
266
267bool
271
272
275 if (myInstance != nullptr) {
276 return myInstance;
277 }
278 throw ProcessError("A GUIMainWindow instance was not yet constructed.");
279}
280
281
284 GUIGlChildWindow* w = dynamic_cast<GUIGlChildWindow*>(myMDIClient->getActiveChild());
285 if (w != nullptr) {
286 return w->getView();
287 }
288 return nullptr;
289}
290
291
292void
294 int windowWidth = getApp()->reg().readIntEntry("SETTINGS", "width", 600);
295 int windowHeight = getApp()->reg().readIntEntry("SETTINGS", "height", 400);
297 if (oc.isSet("window-size")) {
298 std::vector<std::string> windowSize = oc.getStringVector("window-size");
299 if (windowSize.size() != 2) {
300 WRITE_ERROR(TL("option window-size requires INT,INT"));
301 } else {
302 try {
303 windowWidth = StringUtils::toInt(windowSize[0]);
304 windowHeight = StringUtils::toInt(windowSize[1]);
305 } catch (NumberFormatException& e) {
306 WRITE_ERROR("option window-size requires INT,INT " + toString(e.what()));
307 }
308 }
309 }
310 if (oc.isSet("window-size") || getApp()->reg().readIntEntry("SETTINGS", "maximized", 0) == 0 || oc.isSet("window-pos")) {
311 // when restoring previous pos, make sure the window fits fully onto the current screen
312 int x = MAX2(0, MIN2(getApp()->reg().readIntEntry("SETTINGS", "x", 150), getApp()->getRootWindow()->getWidth() - windowWidth));
313 int y = MAX2(50, MIN2(getApp()->reg().readIntEntry("SETTINGS", "y", 150), getApp()->getRootWindow()->getHeight() - windowHeight));
314 if (oc.isSet("window-pos")) {
315 std::vector<std::string> windowPos = oc.getStringVector("window-pos");
316 if (windowPos.size() != 2) {
317 WRITE_ERROR(TL("option window-pos requires INT,INT"));
318 } else {
319 try {
320 x = StringUtils::toInt(windowPos[0]);
321 y = StringUtils::toInt(windowPos[1]);
322 } catch (NumberFormatException& e) {
323 WRITE_ERROR("option window-pos requires INT,INT " + toString(e.what()));
324 }
325 }
326 }
327 move(x, y);
328 resize(windowWidth, windowHeight);
329 }
330}
331
332void
334 if (!myAmFullScreen) {
335 getApp()->reg().writeIntEntry("SETTINGS", "x", getX());
336 getApp()->reg().writeIntEntry("SETTINGS", "y", getY());
337 getApp()->reg().writeIntEntry("SETTINGS", "width", getWidth());
338 getApp()->reg().writeIntEntry("SETTINGS", "height", getHeight());
339 }
340}
341
342
343void
345 myLanguageMenu = new FXMenuPane(this);
346 GUIDesigns::buildFXMenuTitle(menuBar, TL("Langua&ge"), nullptr, myLanguageMenu);
347
348 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "English", "", TL("Change language to english. (en)"),
350 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Deutsch", "", TL("Change language to german. (de)"),
352 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Español", "", TL("Change language to spanish. (es)"),
354 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Português", "", TL("Change language to portuguese. (pt)"),
356 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Français", "", TL("Change language to french. (fr)"),
358 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Italiano", "", TL("Change language to italian. (it)"),
360 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "简体中文", "", TL("简体中文 (zh)"),
362 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "繁體中文", "", TL("繁體中文 (zh-Hant)"),
364 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Türkçe", "", TL("Change language to turkish. (tr)"),
366 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Magyar", "", TL("Change language to hungarian. (hu)"),
368 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "日本語", "", TL("Change language to japanese. (ja)"),
370 GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "한국어", "", TL("Change language to korean. (ko)"),
372}
373
374
375long
376GUIMainWindow::onCmdChangeLanguage(FXObject*, FXSelector sel, void*) {
377 // set language
378 std::string langID;
379 std::string lang;
380 // continue depending of called button
381 switch (FXSELID(sel)) {
382 case MID_LANGUAGE_DE:
383 langID = "de";
384 lang = TL("german");
385 break;
386 case MID_LANGUAGE_ES:
387 langID = "es";
388 lang = TL("spanish");
389 break;
390 case MID_LANGUAGE_PT:
391 langID = "pt";
392 lang = TL("portuguese");
393 break;
394 case MID_LANGUAGE_FR:
395 langID = "fr";
396 lang = TL("french");
397 break;
398 case MID_LANGUAGE_IT:
399 langID = "it";
400 lang = TL("italian");
401 break;
402 case MID_LANGUAGE_ZH:
403 langID = "zh";
404 lang = TL("simplified chinese");
405 break;
406 case MID_LANGUAGE_ZHT:
407 langID = "zh-Hant";
408 lang = TL("traditional chinese");
409 break;
410 case MID_LANGUAGE_TR:
411 langID = "tr";
412 lang = TL("turkish");
413 break;
414 case MID_LANGUAGE_HU:
415 langID = "hu";
416 lang = TL("hungarian");
417 break;
418 case MID_LANGUAGE_JA:
419 langID = "ja";
420 lang = TL("japanese");
421 break;
422 case MID_LANGUAGE_KO:
423 langID = "ko";
424 lang = TL("korean");
425 break;
426 default:
427 langID = "C";
428 lang = TL("english");
429 break;
430 }
431 // check if change language
432 if (langID != gLanguage) {
433 // update language
434 gLanguage = langID;
435 // show info
436 WRITE_MESSAGE(TL("Language changed to ") + lang);
437 // show dialog
438 const std::string header = TL("Restart needed");
439 const std::string body = TL("Changing display language needs restart to take effect.") + std::string("\n") +
440#ifdef DEBUG
441#ifdef WIN32
442 TL("For the Debug build you might also need to set the LANG environment variable.") + std::string("\n") +
443#endif
444#endif
445 TL("Under development. You can help to improve the translation at:") + std::string("\n") +
446 "https://hosted.weblate.org/projects/eclipse-sumo/";
447 FXMessageBox::information(getApp(), MBOX_OK, header.c_str(), "%s", body.c_str());
448 // update language in registry (common for sumo and netedit)
449 std::string appKey = getApp()->reg().getAppKey().text();
450 if (appKey == "SUMO GUI") {
451 // registry is written again later so we have to modify the "live" version
452 getApp()->reg().writeStringEntry("gui", "language", langID.c_str());
453 } else {
454 FXRegistry reg("SUMO GUI", "sumo-gui");
455 reg.read();
456 reg.writeStringEntry("gui", "language", langID.c_str());
457 reg.write();
458 }
459 }
460 return 1;
461}
462
463
464long
465GUIMainWindow::onUpdChangeLanguage(FXObject* obj, FXSelector, void*) {
466 // get language menu command
467 FXMenuCommand* menuCommand = dynamic_cast<FXMenuCommand*>(obj);
468 if (menuCommand) {
469 // check if change color
470 if ((gLanguage == "C") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_EN))) {
471 menuCommand->setTextColor(GUIDesignTextColorBlue);
472 } else if ((gLanguage == "de") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_DE))) {
473 menuCommand->setTextColor(GUIDesignTextColorBlue);
474 } else if ((gLanguage == "es") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ES))) {
475 menuCommand->setTextColor(GUIDesignTextColorBlue);
476 } else if ((gLanguage == "pt") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_PT))) {
477 menuCommand->setTextColor(GUIDesignTextColorBlue);
478 } else if ((gLanguage == "fr") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_FR))) {
479 menuCommand->setTextColor(GUIDesignTextColorBlue);
480 } else if ((gLanguage == "it") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_IT))) {
481 menuCommand->setTextColor(GUIDesignTextColorBlue);
482 } else if ((gLanguage == "zh") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZH))) {
483 menuCommand->setTextColor(GUIDesignTextColorBlue);
484 } else if ((gLanguage == "zh-Hant") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZHT))) {
485 menuCommand->setTextColor(GUIDesignTextColorBlue);
486 } else if ((gLanguage == "tr") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_TR))) {
487 menuCommand->setTextColor(GUIDesignTextColorBlue);
488 } else if ((gLanguage == "hu") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_HU))) {
489 menuCommand->setTextColor(GUIDesignTextColorBlue);
490 } else if ((gLanguage == "ja") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_JA))) {
491 menuCommand->setTextColor(GUIDesignTextColorBlue);
492 } else if ((gLanguage == "ko") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_KO))) {
493 menuCommand->setTextColor(GUIDesignTextColorBlue);
494 } else {
495 menuCommand->setTextColor(GUIDesignTextColorBlack);
496 }
497 }
498 return 1;
499}
500
501
502/****************************************************************************/
@ MID_LANGUAGE_PT
change language to portuguese
@ MID_LANGUAGE_TR
change language to turkish
@ MID_LANGUAGE_ZHT
change language to chinese (traditional)
@ MID_LANGUAGE_ES
change language to spanish
@ MID_LANGUAGE_HU
change language to hungarian
@ MID_LANGUAGE_IT
change language to italian
@ MID_LANGUAGE_EN
change language to english
@ MID_LANGUAGE_DE
change language to german
@ MID_LANGUAGE_JA
change language to japanese
@ MID_LANGUAGE_ZH
change language to chinese (simplified)
@ MID_LANGUAGE_FR
change language to french
@ MID_LANGUAGE_KO
change language to korean
#define GUIDesignTextColorBlue
blue color (for default text)
Definition GUIDesigns.h:41
#define GUIDesignTextColorBlack
black color (for correct text)
Definition GUIDesigns.h:38
@ LANGUAGE_ZHT
@ LANGUAGE_EN
icons for languages
#define WRITE_MESSAGE(msg)
Definition MsgHandler.h:288
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:304
std::string gLanguage
the language for GUI elements and messages
Definition StdDefs.cpp:38
int GUIDesignHeight
the default height for GUI elements
Definition StdDefs.cpp:40
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static FXMenuTitle * buildFXMenuTitle(FXComposite *p, const std::string &text, FXIcon *icon, FXMenuPane *menuPane)
build menu title
static FXMenuCommand * buildFXMenuCommandShortcut(FXComposite *p, const std::string &text, const std::string &shortcut, const std::string &info, FXIcon *icon, FXObject *tgt, FXSelector sel)
build menu command
GUISUMOAbstractView * getView() const
return GUISUMOAbstractView
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
void setWindowSizeAndPos()
perform initial window positioning and sizing according to user options / previous call
const std::vector< GUIGlChildWindow * > & getViews() const
get views
bool myListParking
information whether the locator should list parking vehicles
static GUIMainWindow * myInstance
the singleton window instance
virtual ~GUIMainWindow()
destructor
FXDockSite * myRightDock
void removeViewByID(const std::string &id)
GUIGlChildWindow * getViewByID(const std::string &id) const
get specific view by ID
std::vector< FXMainWindow * > myTrackerWindows
list of tracker windows
MFXStaticToolTip * getStaticTooltipView() const
get static toolTip for view
FXFont * myFallbackFont
Fallback font for extended characters support.
std::vector< std::string > getViewIDs() const
get view IDs
FXMenuPane * myLanguageMenu
Language menu common to all applications.
GUISUMOAbstractView * getActiveView() const
get the active view or 0
FXLabel * getGeoLabel()
get geo label
bool isGaming() const
return whether the gui is in gaming mode
bool myListTeleporting
information whether the locator should list teleporting vehicles
FXLabel * myCartesianCoordinate
Labels for the current cartesian, geo-coordinate and test coordinates.
MFXStaticToolTip * myStaticTooltipMenu
static toolTip used in menus
FXMDIClient * myMDIClient
The multi view panel.
FXFont * getBoldFont()
get bold front
FXDockSite * myLeftDock
void buildLanguageMenu(FXMenuBar *menuBar)
long onCmdChangeLanguage(FXObject *, FXSelector, void *)
bool listTeleporting() const
return whether to list teleporting vehicles
FXLabel * getTestLabel()
get test label
MFXStaticToolTip * myStaticTooltipView
static toolTip used in view
MFXStaticToolTip * getStaticTooltipMenu() const
get static toolTip for menus
FXFont * myBoldFont
Font used for popup-menu titles.
static GUIMainWindow * getInstance()
get instance
bool listParking() const
return whether to list parking vehicles
FXDockSite * myBottomDock
bool listInternal() const
return whether to list internal structures
FXHorizontalFrame * myTestFrame
void addGLChild(GUIGlChildWindow *child)
Adds a further child window to the list (GUIGlChildWindow)
FXLabel * myTestCoordinate
FXFont * myNormalFont
default Font (after scaling)
FXMutex myTrackerLock
A lock to make the removal and addition of trackers secure.
FXDockSite * myTopDock
dock sites
bool myListInternal
information whether the locator should list internal structures
void storeWindowSizeAndPos()
record window position and size in registry
FXLabel * getCartesianLabel()
get cartesian label
FXGLVisual * getGLVisual() const
get GL Visual
bool myAmFullScreen
FOX need this.
void removeGLChild(GUIGlChildWindow *child)
removes the given child window from the list (GUIGlChildWindow)
FXDockSite * getTopDock()
get top dock
FXHorizontalFrame * getTestFrame()
get test frame
FXLabel * myGeoCoordinate
FXFont * getFallbackFont()
get fallback front
void updateChildren(int msg=MID_SIMSTEP)
update childrens
FXGLVisual * myGLVisual
The gl-visual used.
bool myAmGaming
information whether the gui is currently in gaming mode
void removeChild(FXMainWindow *child)
removes the given child window from the list (FXMainWindow)
GUIMainWindow(FXApp *app)
constructor
std::vector< GUIGlChildWindow * > myGLWindows
list of GLWindows
long onUpdChangeLanguage(FXObject *, FXSelector, void *)
void addChild(FXMainWindow *child)
Adds a further child window to the list (FXMainWindow)
MFXStaticToolTip (based on FXToolTip)
A storage for options typed value containers)
Definition OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...