Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/gui/windows/GUIMainWindow.cpp
169684 views
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
/****************************************************************************/
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
fdesc.weight = FXFont::Bold;
70
GUIDesignHeight = (int)(fdesc.size / 90.0 * 18) + 5;
71
myBoldFont = new FXFont(app, fdesc);
72
// https://en.wikipedia.org/wiki/Noto_fonts should be widely available
73
myFallbackFont = new FXFont(app, "Noto Sans CJK JP");
74
// build docks
75
myTopDock = new FXDockSite(this, LAYOUT_SIDE_TOP | LAYOUT_FILL_X);
76
myBottomDock = new FXDockSite(this, LAYOUT_SIDE_BOTTOM | LAYOUT_FILL_X);
77
myLeftDock = new FXDockSite(this, LAYOUT_SIDE_LEFT | LAYOUT_FILL_Y);
78
myRightDock = new FXDockSite(this, LAYOUT_SIDE_RIGHT | LAYOUT_FILL_Y);
79
// avoid instance Windows twice
80
if (myInstance != nullptr) {
81
throw ProcessError("MainWindow initialized twice");
82
}
83
myInstance = this;
84
//myGLVisual->setStencilSize(8); // enable stencil buffer
85
}
86
87
88
GUIMainWindow::~GUIMainWindow() {
89
delete myStaticTooltipMenu;
90
delete myStaticTooltipView;
91
delete myBoldFont;
92
delete myFallbackFont;
93
delete myTopDock;
94
delete myBottomDock;
95
delete myLeftDock;
96
delete myRightDock;
97
myInstance = nullptr;
98
}
99
100
101
102
void
103
GUIMainWindow::addGLChild(GUIGlChildWindow* child) {
104
myGLWindows.push_back(child);
105
}
106
107
108
void
109
GUIMainWindow::removeGLChild(GUIGlChildWindow* child) {
110
std::vector<GUIGlChildWindow*>::iterator i = std::find(myGLWindows.begin(), myGLWindows.end(), child);
111
if (i != myGLWindows.end()) {
112
myGLWindows.erase(i);
113
}
114
}
115
116
117
void
118
GUIMainWindow::addChild(FXMainWindow* child) {
119
myTrackerLock.lock();
120
myTrackerWindows.push_back(child);
121
myTrackerLock.unlock();
122
}
123
124
125
void
126
GUIMainWindow::removeChild(FXMainWindow* child) {
127
myTrackerLock.lock();
128
std::vector<FXMainWindow*>::iterator i = std::find(myTrackerWindows.begin(), myTrackerWindows.end(), child);
129
myTrackerWindows.erase(i);
130
myTrackerLock.unlock();
131
}
132
133
134
FXDockSite*
135
GUIMainWindow::getTopDock() {
136
return myTopDock;
137
}
138
139
140
std::vector<std::string>
141
GUIMainWindow::getViewIDs() const {
142
std::vector<std::string> ret;
143
for (GUIGlChildWindow* const window : myGLWindows) {
144
ret.push_back(window->getTitle().text());
145
}
146
return ret;
147
}
148
149
150
GUIGlChildWindow*
151
GUIMainWindow::getViewByID(const std::string& id) const {
152
for (GUIGlChildWindow* const window : myGLWindows) {
153
if (std::string(window->getTitle().text()) == id) {
154
return window;
155
}
156
}
157
return nullptr;
158
}
159
160
161
void
162
GUIMainWindow::removeViewByID(const std::string& id) {
163
for (GUIGlChildWindow* const window : myGLWindows) {
164
if (std::string(window->getTitle().text()) == id) {
165
window->close();
166
removeGLChild(window);
167
return;
168
}
169
}
170
}
171
172
173
FXFont*
174
GUIMainWindow::getBoldFont() {
175
return myBoldFont;
176
}
177
178
FXFont*
179
GUIMainWindow::getFallbackFont() {
180
return myFallbackFont;
181
}
182
183
const std::vector<GUIGlChildWindow*>&
184
GUIMainWindow::getViews() const {
185
return myGLWindows;
186
}
187
188
189
void
190
GUIMainWindow::updateChildren(int msg) {
191
// inform views
192
myMDIClient->forallWindows(this, FXSEL(SEL_COMMAND, msg), nullptr);
193
// inform other windows
194
myTrackerLock.lock();
195
for (int i = 0; i < (int)myTrackerWindows.size(); i++) {
196
myTrackerWindows[i]->handle(this, FXSEL(SEL_COMMAND, msg), nullptr);
197
}
198
myTrackerLock.unlock();
199
}
200
201
202
FXGLVisual*
203
GUIMainWindow::getGLVisual() const {
204
return myGLVisual;
205
}
206
207
208
MFXStaticToolTip*
209
GUIMainWindow::getStaticTooltipMenu() const {
210
return myStaticTooltipMenu;
211
}
212
213
214
MFXStaticToolTip*
215
GUIMainWindow::getStaticTooltipView() const {
216
return myStaticTooltipView;
217
}
218
219
220
FXLabel*
221
GUIMainWindow::getCartesianLabel() {
222
return myCartesianCoordinate;
223
}
224
225
226
FXLabel*
227
GUIMainWindow::getGeoLabel() {
228
return myGeoCoordinate;
229
}
230
231
232
FXLabel*
233
GUIMainWindow::getTestLabel() {
234
return myTestCoordinate;
235
}
236
237
238
FXHorizontalFrame*
239
GUIMainWindow::getTestFrame() {
240
return myTestFrame;
241
}
242
243
244
bool
245
GUIMainWindow::isGaming() const {
246
return myAmGaming;
247
}
248
249
250
bool
251
GUIMainWindow::listInternal() const {
252
return myListInternal;
253
}
254
255
256
bool
257
GUIMainWindow::listParking() const {
258
return myListParking;
259
}
260
261
262
bool
263
GUIMainWindow::listTeleporting() const {
264
return myListTeleporting;
265
}
266
267
268
GUIMainWindow*
269
GUIMainWindow::getInstance() {
270
if (myInstance != nullptr) {
271
return myInstance;
272
}
273
throw ProcessError("A GUIMainWindow instance was not yet constructed.");
274
}
275
276
277
GUISUMOAbstractView*
278
GUIMainWindow::getActiveView() const {
279
GUIGlChildWindow* w = dynamic_cast<GUIGlChildWindow*>(myMDIClient->getActiveChild());
280
if (w != nullptr) {
281
return w->getView();
282
}
283
return nullptr;
284
}
285
286
287
void
288
GUIMainWindow::setWindowSizeAndPos() {
289
int windowWidth = getApp()->reg().readIntEntry("SETTINGS", "width", 600);
290
int windowHeight = getApp()->reg().readIntEntry("SETTINGS", "height", 400);
291
const OptionsCont& oc = OptionsCont::getOptions();
292
if (oc.isSet("window-size")) {
293
std::vector<std::string> windowSize = oc.getStringVector("window-size");
294
if (windowSize.size() != 2) {
295
WRITE_ERROR(TL("option window-size requires INT,INT"));
296
} else {
297
try {
298
windowWidth = StringUtils::toInt(windowSize[0]);
299
windowHeight = StringUtils::toInt(windowSize[1]);
300
} catch (NumberFormatException& e) {
301
WRITE_ERROR("option window-size requires INT,INT " + toString(e.what()));
302
}
303
}
304
}
305
if (oc.isSet("window-size") || getApp()->reg().readIntEntry("SETTINGS", "maximized", 0) == 0 || oc.isSet("window-pos")) {
306
// when restoring previous pos, make sure the window fits fully onto the current screen
307
int x = MAX2(0, MIN2(getApp()->reg().readIntEntry("SETTINGS", "x", 150), getApp()->getRootWindow()->getWidth() - windowWidth));
308
int y = MAX2(50, MIN2(getApp()->reg().readIntEntry("SETTINGS", "y", 150), getApp()->getRootWindow()->getHeight() - windowHeight));
309
if (oc.isSet("window-pos")) {
310
std::vector<std::string> windowPos = oc.getStringVector("window-pos");
311
if (windowPos.size() != 2) {
312
WRITE_ERROR(TL("option window-pos requires INT,INT"));
313
} else {
314
try {
315
x = StringUtils::toInt(windowPos[0]);
316
y = StringUtils::toInt(windowPos[1]);
317
} catch (NumberFormatException& e) {
318
WRITE_ERROR("option window-pos requires INT,INT " + toString(e.what()));
319
}
320
}
321
}
322
move(x, y);
323
resize(windowWidth, windowHeight);
324
}
325
}
326
327
void
328
GUIMainWindow::storeWindowSizeAndPos() {
329
if (!myAmFullScreen) {
330
getApp()->reg().writeIntEntry("SETTINGS", "x", getX());
331
getApp()->reg().writeIntEntry("SETTINGS", "y", getY());
332
getApp()->reg().writeIntEntry("SETTINGS", "width", getWidth());
333
getApp()->reg().writeIntEntry("SETTINGS", "height", getHeight());
334
}
335
}
336
337
338
void
339
GUIMainWindow::buildLanguageMenu(FXMenuBar* menuBar) {
340
myLanguageMenu = new FXMenuPane(this);
341
GUIDesigns::buildFXMenuTitle(menuBar, TL("Langua&ge"), nullptr, myLanguageMenu);
342
343
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "English", "", TL("Change language to english. (en)"),
344
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_EN), this, MID_LANGUAGE_EN);
345
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Deutsch", "", TL("Change language to german. (de)"),
346
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_DE), this, MID_LANGUAGE_DE);
347
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Español", "", TL("Change language to spanish. (es)"),
348
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ES), this, MID_LANGUAGE_ES);
349
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Português", "", TL("Change language to portuguese. (pt)"),
350
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_PT), this, MID_LANGUAGE_PT);
351
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Français", "", TL("Change language to french. (fr)"),
352
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_FR), this, MID_LANGUAGE_FR);
353
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Italiano", "", TL("Change language to italian. (it)"),
354
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_IT), this, MID_LANGUAGE_IT);
355
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "简体中文", "", TL("简体中文 (zh)"),
356
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZH), this, MID_LANGUAGE_ZH);
357
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "繁體中文", "", TL("繁體中文 (zh-Hant)"),
358
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZHT), this, MID_LANGUAGE_ZHT);
359
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Türkçe", "", TL("Change language to turkish. (tr)"),
360
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_TR), this, MID_LANGUAGE_TR);
361
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "Magyar", "", TL("Change language to hungarian. (hu)"),
362
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_HU), this, MID_LANGUAGE_HU);
363
GUIDesigns::buildFXMenuCommandShortcut(myLanguageMenu, "日本語", "", TL("Change language to japanese. (ja)"),
364
GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_JA), this, MID_LANGUAGE_JA);
365
}
366
367
368
long
369
GUIMainWindow::onCmdChangeLanguage(FXObject*, FXSelector sel, void*) {
370
// set language
371
std::string langID;
372
std::string lang;
373
// continue depending of called button
374
switch (FXSELID(sel)) {
375
case MID_LANGUAGE_DE:
376
langID = "de";
377
lang = TL("german");
378
break;
379
case MID_LANGUAGE_ES:
380
langID = "es";
381
lang = TL("spanish");
382
break;
383
case MID_LANGUAGE_PT:
384
langID = "pt";
385
lang = TL("portuguese");
386
break;
387
case MID_LANGUAGE_FR:
388
langID = "fr";
389
lang = TL("french");
390
break;
391
case MID_LANGUAGE_IT:
392
langID = "it";
393
lang = TL("italian");
394
break;
395
case MID_LANGUAGE_ZH:
396
langID = "zh";
397
lang = TL("simplified chinese");
398
break;
399
case MID_LANGUAGE_ZHT:
400
langID = "zh-Hant";
401
lang = TL("traditional chinese");
402
break;
403
case MID_LANGUAGE_TR:
404
langID = "tr";
405
lang = TL("turkish");
406
break;
407
case MID_LANGUAGE_HU:
408
langID = "hu";
409
lang = TL("hungarian");
410
break;
411
case MID_LANGUAGE_JA:
412
langID = "ja";
413
lang = TL("japanese");
414
break;
415
default:
416
langID = "C";
417
lang = TL("english");
418
break;
419
}
420
// check if change language
421
if (langID != gLanguage) {
422
// update language
423
gLanguage = langID;
424
// show info
425
WRITE_MESSAGE(TL("Language changed to ") + lang);
426
// show dialog
427
const std::string header = TL("Restart needed");
428
const std::string body = TL("Changing display language needs restart to take effect.") + std::string("\n") +
429
#ifdef DEBUG
430
#ifdef WIN32
431
TL("For the Debug build you might also need to set the LANG environment variable.") + std::string("\n") +
432
#endif
433
#endif
434
TL("Under development. You can help to improve the translation at:") + std::string("\n") +
435
"https://hosted.weblate.org/projects/eclipse-sumo/";
436
FXMessageBox::information(getApp(), MBOX_OK, header.c_str(), "%s", body.c_str());
437
// update language in registry (common for sumo and netedit)
438
std::string appKey = getApp()->reg().getAppKey().text();
439
if (appKey == "SUMO GUI") {
440
// registry is written again later so we have to modify the "live" version
441
getApp()->reg().writeStringEntry("gui", "language", langID.c_str());
442
} else {
443
FXRegistry reg("SUMO GUI", "sumo-gui");
444
reg.read();
445
reg.writeStringEntry("gui", "language", langID.c_str());
446
reg.write();
447
}
448
}
449
return 1;
450
}
451
452
453
long
454
GUIMainWindow::onUpdChangeLanguage(FXObject* obj, FXSelector, void*) {
455
// get language menu command
456
FXMenuCommand* menuCommand = dynamic_cast<FXMenuCommand*>(obj);
457
if (menuCommand) {
458
// check if change color
459
if ((gLanguage == "C") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_EN))) {
460
menuCommand->setTextColor(GUIDesignTextColorBlue);
461
} else if ((gLanguage == "de") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_DE))) {
462
menuCommand->setTextColor(GUIDesignTextColorBlue);
463
} else if ((gLanguage == "es") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ES))) {
464
menuCommand->setTextColor(GUIDesignTextColorBlue);
465
} else if ((gLanguage == "pt") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_PT))) {
466
menuCommand->setTextColor(GUIDesignTextColorBlue);
467
} else if ((gLanguage == "fr") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_FR))) {
468
menuCommand->setTextColor(GUIDesignTextColorBlue);
469
} else if ((gLanguage == "it") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_IT))) {
470
menuCommand->setTextColor(GUIDesignTextColorBlue);
471
} else if ((gLanguage == "zh") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZH))) {
472
menuCommand->setTextColor(GUIDesignTextColorBlue);
473
} else if ((gLanguage == "zh-Hant") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_ZHT))) {
474
menuCommand->setTextColor(GUIDesignTextColorBlue);
475
} else if ((gLanguage == "tr") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_TR))) {
476
menuCommand->setTextColor(GUIDesignTextColorBlue);
477
} else if ((gLanguage == "hu") && (menuCommand->getIcon() == GUIIconSubSys::getIcon(GUIIcon::LANGUAGE_HU))) {
478
menuCommand->setTextColor(GUIDesignTextColorBlue);
479
} else {
480
menuCommand->setTextColor(GUIDesignTextColorBlack);
481
}
482
}
483
return 1;
484
}
485
486
487
/****************************************************************************/
488
489