Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/gui/windows/GUIMainWindow.cpp
193674 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 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
/****************************************************************************/
14
/// @file GUIMainWindow.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Tue, 29.05.2005
19
///
20
//
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <string>
25
#include <algorithm>
26
#include <utils/foxtools/fxheader.h>
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
35
#include <utils/common/MsgHandler.h>
36
#include <utils/common/StringUtils.h>
37
#include <utils/foxtools/MFXImageHelper.h>
38
#include <utils/foxtools/MFXStaticToolTip.h>
39
#include <utils/gui/images/GUITexturesHelper.h>
40
#include <utils/gui/div/GUIDesigns.h>
41
#include <utils/options/OptionsCont.h>
42
#include "GUIMainWindow.h"
43
#include "GUIGlChildWindow.h"
44
45
46
// ===========================================================================
47
// static member definitions
48
// ===========================================================================
49
GUIMainWindow* GUIMainWindow::myInstance = nullptr;
50
51
// ===========================================================================
52
// member method definitions
53
// ===========================================================================
54
GUIMainWindow::GUIMainWindow(FXApp* app) :
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
64
myStaticTooltipMenu = new MFXStaticToolTip(app);
65
myStaticTooltipView = new MFXStaticToolTip(app);
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
92
GUIMainWindow::~GUIMainWindow() {
93
delete myStaticTooltipMenu;
94
delete myStaticTooltipView;
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
107
void
108
GUIMainWindow::addGLChild(GUIGlChildWindow* child) {
109
myGLWindows.push_back(child);
110
}
111
112
113
void
114
GUIMainWindow::removeGLChild(GUIGlChildWindow* child) {
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
122
void
123
GUIMainWindow::addChild(FXMainWindow* child) {
124
myTrackerLock.lock();
125
myTrackerWindows.push_back(child);
126
myTrackerLock.unlock();
127
}
128
129
130
void
131
GUIMainWindow::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
139
FXDockSite*
140
GUIMainWindow::getTopDock() {
141
return myTopDock;
142
}
143
144
145
std::vector<std::string>
146
GUIMainWindow::getViewIDs() const {
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
155
GUIGlChildWindow*
156
GUIMainWindow::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
166
void
167
GUIMainWindow::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
178
FXFont*
179
GUIMainWindow::getBoldFont() {
180
return myBoldFont;
181
}
182
183
FXFont*
184
GUIMainWindow::getFallbackFont() {
185
return myFallbackFont;
186
}
187
188
const std::vector<GUIGlChildWindow*>&
189
GUIMainWindow::getViews() const {
190
return myGLWindows;
191
}
192
193
194
void
195
GUIMainWindow::updateChildren(int msg) {
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
207
FXGLVisual*
208
GUIMainWindow::getGLVisual() const {
209
return myGLVisual;
210
}
211
212
213
MFXStaticToolTip*
214
GUIMainWindow::getStaticTooltipMenu() const {
215
return myStaticTooltipMenu;
216
}
217
218
219
MFXStaticToolTip*
220
GUIMainWindow::getStaticTooltipView() const {
221
return myStaticTooltipView;
222
}
223
224
225
FXLabel*
226
GUIMainWindow::getCartesianLabel() {
227
return myCartesianCoordinate;
228
}
229
230
231
FXLabel*
232
GUIMainWindow::getGeoLabel() {
233
return myGeoCoordinate;
234
}
235
236
237
FXLabel*
238
GUIMainWindow::getTestLabel() {
239
return myTestCoordinate;
240
}
241
242
243
FXHorizontalFrame*
244
GUIMainWindow::getTestFrame() {
245
return myTestFrame;
246
}
247
248
249
bool
250
GUIMainWindow::isGaming() const {
251
return myAmGaming;
252
}
253
254
255
bool
256
GUIMainWindow::listInternal() const {
257
return myListInternal;
258
}
259
260
261
bool
262
GUIMainWindow::listParking() const {
263
return myListParking;
264
}
265
266
267
bool
268
GUIMainWindow::listTeleporting() const {
269
return myListTeleporting;
270
}
271
272
273
GUIMainWindow*
274
GUIMainWindow::getInstance() {
275
if (myInstance != nullptr) {
276
return myInstance;
277
}
278
throw ProcessError("A GUIMainWindow instance was not yet constructed.");
279
}
280
281
282
GUISUMOAbstractView*
283
GUIMainWindow::getActiveView() const {
284
GUIGlChildWindow* w = dynamic_cast<GUIGlChildWindow*>(myMDIClient->getActiveChild());
285
if (w != nullptr) {
286
return w->getView();
287
}
288
return nullptr;
289
}
290
291
292
void
293
GUIMainWindow::setWindowSizeAndPos() {
294
int windowWidth = getApp()->reg().readIntEntry("SETTINGS", "width", 600);
295
int windowHeight = getApp()->reg().readIntEntry("SETTINGS", "height", 400);
296
const OptionsCont& oc = OptionsCont::getOptions();
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
332
void
333
GUIMainWindow::storeWindowSizeAndPos() {
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
343
void
344
GUIMainWindow::buildLanguageMenu(FXMenuBar* menuBar) {
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)"),
349
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_EN), this, MID_LANGUAGE_EN);
350
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Deutsch", "", TL("Change language to german. (de)"),
351
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_DE), this, MID_LANGUAGE_DE);
352
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Español", "", TL("Change language to spanish. (es)"),
353
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ES), this, MID_LANGUAGE_ES);
354
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Português", "", TL("Change language to portuguese. (pt)"),
355
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_PT), this, MID_LANGUAGE_PT);
356
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Français", "", TL("Change language to french. (fr)"),
357
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_FR), this, MID_LANGUAGE_FR);
358
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Italiano", "", TL("Change language to italian. (it)"),
359
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_IT), this, MID_LANGUAGE_IT);
360
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "简体中文", "", TL("简体中文 (zh)"),
361
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZH), this, MID_LANGUAGE_ZH);
362
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "繁體中文", "", TL("繁體中文 (zh-Hant)"),
363
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZHT), this, MID_LANGUAGE_ZHT);
364
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Türkçe", "", TL("Change language to turkish. (tr)"),
365
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_TR), this, MID_LANGUAGE_TR);
366
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Magyar", "", TL("Change language to hungarian. (hu)"),
367
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_HU), this, MID_LANGUAGE_HU);
368
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "日本語", "", TL("Change language to japanese. (ja)"),
369
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_JA), this, MID_LANGUAGE_JA);
370
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "한국어", "", TL("Change language to korean. (ko)"),
371
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_KO), this, MID_LANGUAGE_KO);
372
}
373
374
375
long
376
GUIMainWindow::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
464
long
465
GUIMainWindow::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
/****************************************************************************/
503
504