LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUIMainWindow.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 139 210 66.2 %
Date: 2024-05-03 15:29:52 Functions: 22 33 66.7 %

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

Generated by: LCOV version 1.14