Path: blob/main/src/netedit/dialogs/options/GNEOptionsEditorRow.cpp
193833 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GNEOptionsEditorRow.cpp14/// @author Pablo Alvarez Lopez15/// @date May 202316///17// Row used in GNEOptionsEditor to edit options18/****************************************************************************/19#include <config.h>2021#include <netedit/dialogs/GNEDialog.h>22#include <netedit/GNEApplicationWindow.h>23#include <utils/common/MsgHandler.h>24#include <utils/common/StringTokenizer.h>25#include <utils/foxtools/MFXLabelTooltip.h>26#include <utils/gui/div/GUIDesigns.h>2728#include "GNEOptionsEditorRow.h"29#include "GNEOptionsEditor.h"3031// ===========================================================================32// Defines33// ===========================================================================3435#define MARGIN 436#define MINNAMEWIDTH 2003738// ===========================================================================39// FOX callback mapping40// ===========================================================================4142FXDEFMAP(GNEOptionsEditorRow::OptionRow) OptionRowMap[] = {43FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE, GNEOptionsEditorRow::OptionRow::onCmdSetOption),44FXMAPFUNC(SEL_COMMAND, MID_GNE_RESET, GNEOptionsEditorRow::OptionRow::onCmdResetOption),45};4647FXDEFMAP(GNEOptionsEditorRow::OptionFilename) OptionFilenameMap[] = {48FXMAPFUNC(SEL_COMMAND, MID_GNE_SET_ATTRIBUTE_DIALOG, GNEOptionsEditorRow::OptionFilename::onCmdOpenDialog),49};5051// Object implementation52FXIMPLEMENT_ABSTRACT(GNEOptionsEditorRow::OptionRow, FXHorizontalFrame, OptionRowMap, ARRAYNUMBER(OptionRowMap))53FXIMPLEMENT_ABSTRACT(GNEOptionsEditorRow::OptionFilename, GNEOptionsEditorRow::OptionRow, OptionFilenameMap, ARRAYNUMBER(OptionFilenameMap))5455// ===========================================================================56// method definitions57// ===========================================================================5859// ---------------------------------------------------------------------------60// GNEOptionsEditorRow::OptionRow - methods61// ---------------------------------------------------------------------------6263GNEOptionsEditorRow::OptionRow::OptionRow(GNEOptionsEditor* optionsEditor, FXComposite* parent, const std::string& topic,64const std::string& name, const std::string& description, const std::string& defaultValue, const bool editable) :65FXHorizontalFrame(parent, GUIDesignAuxiliarHorizontalFrame),66myOptionsEditor(optionsEditor),67myTopic(topic),68myName(name),69myDescription(description),70myDefaultValue(defaultValue),71myEditable(editable) {72// build label with name (default width 150)73myNameLabel = new MFXLabelTooltip(this, myOptionsEditor->myDialog->getApplicationWindow()->getStaticTooltipMenu(),74name.c_str(), nullptr, GUIDesignLabelThickedFixed(MINNAMEWIDTH));75// set description as tooltip76myNameLabel->setTipText(description.c_str());77// create content frame78myContentFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarHorizontalFrame);79// Create reset button80myResetButton = GUIDesigns::buildFXButton(this, "", "", TL("Reset value"), GUIIconSubSys::getIcon(GUIIcon::RESET), this, MID_GNE_RESET, GUIDesignButtonIcon);81}828384void85GNEOptionsEditorRow::OptionRow::adjustNameSize() {86const int nameWidth = myNameLabel->getFont()->getTextWidth(myNameLabel->getText().text(), myNameLabel->getText().length() + MARGIN);87if (nameWidth > MINNAMEWIDTH) {88myNameLabel->setWidth(nameWidth);89}90}919293const std::string&94GNEOptionsEditorRow::OptionRow::getTopic() const {95return myTopic;96}979899const std::string100GNEOptionsEditorRow::OptionRow::getNameLower() const {101return StringUtils::to_lower_case(myName);102}103104105const std::string106GNEOptionsEditorRow::OptionRow::getDescriptionLower() const {107return StringUtils::to_lower_case(myDescription);108}109110111void112GNEOptionsEditorRow::OptionRow::updateResetButton() {113if (getValue() != myDefaultValue) {114myResetButton->enable();115} else {116myResetButton->disable();117}118}119120// ---------------------------------------------------------------------------121// GNEOptionsEditorRow::OptionString - methods122// ---------------------------------------------------------------------------123124GNEOptionsEditorRow::OptionString::OptionString(GNEOptionsEditor* optionsEditor, FXComposite* parent,125const std::string& topic, const std::string& name, const std::string& description,126const std::string& defaultValue, const bool editable) :127OptionRow(optionsEditor, parent, topic, name, description, defaultValue, editable) {128myStringTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);129myStringTextField->setText(myOptionsEditor->myOptionsContainer.getString(name).c_str());130if (!editable) {131myStringTextField->disable();132}133updateOption();134}135136137void138GNEOptionsEditorRow::OptionString::updateOption() {139myStringTextField->setText(myOptionsEditor->myOptionsContainer.getString(myName).c_str());140updateResetButton();141}142143144void145GNEOptionsEditorRow::OptionString::restoreOption() {146myStringTextField->setText(myOptionsEditor->myOriginalOptionsContainer.getString(myName).c_str());147onCmdSetOption(nullptr, 0, nullptr);148}149150151long152GNEOptionsEditorRow::OptionString::onCmdSetOption(FXObject*, FXSelector, void*) {153myOptionsEditor->myOptionsContainer.resetWritable();154myOptionsEditor->myOptionsContainer.set(myName, myStringTextField->getText().text());155myOptionsEditor->myOptionsModified = true;156updateResetButton();157return 1;158}159160161long162GNEOptionsEditorRow::OptionString::onCmdResetOption(FXObject*, FXSelector, void*) {163myStringTextField->setText(myDefaultValue.c_str());164updateResetButton();165return 1;166}167168169std::string170GNEOptionsEditorRow::OptionString::getValue() const {171return myStringTextField->getText().text();172}173174175GNEOptionsEditorRow::OptionStringVector::OptionStringVector(GNEOptionsEditor* optionsEditor, FXComposite* parent,176const std::string& topic, const std::string& name, const std::string& description,177const std::string& defaultValue, const bool editable) :178OptionRow(optionsEditor, parent, topic, name, description, defaultValue, editable) {179myStringVectorTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);180if (!editable) {181myStringVectorTextField->disable();182}183updateOption();184}185186187void188GNEOptionsEditorRow::OptionStringVector::updateOption() {189myStringVectorTextField->setText(toString(myOptionsEditor->myOptionsContainer.getStringVector(myName)).c_str());190updateResetButton();191}192193194void195GNEOptionsEditorRow::OptionStringVector::restoreOption() {196myStringVectorTextField->setText(toString(myOptionsEditor->myOriginalOptionsContainer.getStringVector(myName)).c_str());197onCmdSetOption(nullptr, 0, nullptr);198}199200201long202GNEOptionsEditorRow::OptionStringVector::onCmdSetOption(FXObject*, FXSelector, void*) {203myOptionsEditor->myOptionsContainer.resetWritable();204myOptionsEditor->myOptionsContainer.set(myName, myStringVectorTextField->getText().text());205myOptionsEditor->myOptionsModified = true;206updateResetButton();207return 1;208}209210211long212GNEOptionsEditorRow::OptionStringVector::onCmdResetOption(FXObject*, FXSelector, void*) {213myStringVectorTextField->setText(myDefaultValue.c_str());214updateResetButton();215return 1;216}217218219std::string220GNEOptionsEditorRow::OptionStringVector::getValue() const {221return myStringVectorTextField->getText().text();222}223224// ---------------------------------------------------------------------------225// GNEOptionsEditorRow::OptionBool - methods226// ---------------------------------------------------------------------------227228GNEOptionsEditorRow::OptionBool::OptionBool(GNEOptionsEditor* optionsEditor, FXComposite* parent,229const std::string& topic, const std::string& name, const std::string& description,230const std::string& defaultValue, const bool editable) :231OptionRow(optionsEditor, parent, topic, name, description, defaultValue, editable) {232myCheckButton = new FXCheckButton(myContentFrame, "", this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);233if (!editable) {234myCheckButton->disable();235}236updateOption();237}238239240void241GNEOptionsEditorRow::OptionBool::updateOption() {242if (myOptionsEditor->myOptionsContainer.getBool(myName)) {243myCheckButton->setCheck(TRUE);244myCheckButton->setText(TL("true"));245} else {246myCheckButton->setCheck(FALSE);247myCheckButton->setText(TL("false"));248}249updateResetButton();250}251252253void254GNEOptionsEditorRow::OptionBool::restoreOption() {255if (myOptionsEditor->myOriginalOptionsContainer.getBool(myName)) {256myCheckButton->setCheck(TRUE);257myCheckButton->setText(TL("true"));258} else {259myCheckButton->setCheck(FALSE);260myCheckButton->setText(TL("false"));261}262onCmdSetOption(nullptr, 0, nullptr);263}264265266long267GNEOptionsEditorRow::OptionBool::onCmdSetOption(FXObject*, FXSelector, void*) {268myOptionsEditor->myOptionsContainer.resetWritable();269if (myCheckButton->getCheck()) {270myOptionsEditor->myOptionsContainer.set(myName, "true");271myCheckButton->setText(TL("true"));272} else {273myOptionsEditor->myOptionsContainer.set(myName, "false");274myCheckButton->setText(TL("false"));275}276myOptionsEditor->myOptionsModified = true;277// special checks for Debug flags278if ((myName == "gui-testing-debug") && myOptionsEditor->myOptionsContainer.isSet("gui-testing-debug")) {279MsgHandler::enableDebugMessages(myOptionsEditor->myOptionsContainer.getBool("gui-testing-debug"));280}281if ((myName == "gui-testing-debug-gl") && myOptionsEditor->myOptionsContainer.isSet("gui-testing-debug-gl")) {282MsgHandler::enableDebugGLMessages(myOptionsEditor->myOptionsContainer.getBool("gui-testing-debug-gl"));283}284updateResetButton();285return 1;286}287288289long290GNEOptionsEditorRow::OptionBool::onCmdResetOption(FXObject*, FXSelector, void*) {291if (myDefaultValue.empty()) {292myCheckButton->setCheck(FALSE);293myCheckButton->setText(TL("false"));294} else if (StringUtils::toBool(myDefaultValue)) {295myCheckButton->setCheck(TRUE);296myCheckButton->setText(TL("true"));297} else {298myCheckButton->setCheck(FALSE);299myCheckButton->setText(TL("false"));300}301updateResetButton();302return 1;303}304305306std::string307GNEOptionsEditorRow::OptionBool::getValue() const {308return myCheckButton->getCheck() ? "true" : "false";309}310311// ---------------------------------------------------------------------------312// GNEOptionsEditorRow::OptionInt - methods313// ---------------------------------------------------------------------------314315GNEOptionsEditorRow::OptionInt::OptionInt(GNEOptionsEditor* optionsEditor, FXComposite* parent,316const std::string& topic, const std::string& name, const std::string& description,317const std::string& defaultValue, const bool editable) :318OptionRow(optionsEditor, parent, topic, name, description, defaultValue, editable) {319myIntTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextFieldRestricted(TEXTFIELD_INTEGER));320if (!editable) {321myIntTextField->disable();322}323updateOption();324}325326327void328GNEOptionsEditorRow::OptionInt::updateOption() {329myIntTextField->setText(toString(myOptionsEditor->myOptionsContainer.getInt(myName)).c_str());330updateResetButton();331}332333334void335GNEOptionsEditorRow::OptionInt::restoreOption() {336myIntTextField->setText(toString(myOptionsEditor->myOriginalOptionsContainer.getInt(myName)).c_str());337onCmdSetOption(nullptr, 0, nullptr);338}339340341long342GNEOptionsEditorRow::OptionInt::onCmdSetOption(FXObject*, FXSelector, void*) {343if (myIntTextField->getText().empty()) {344myIntTextField->setText(myDefaultValue.c_str());345} else {346myOptionsEditor->myOptionsContainer.resetWritable();347myOptionsEditor->myOptionsContainer.set(myName, myIntTextField->getText().text());348myOptionsEditor->myOptionsModified = true;349}350updateResetButton();351return 1;352}353354355long356GNEOptionsEditorRow::OptionInt::onCmdResetOption(FXObject*, FXSelector, void*) {357myIntTextField->setText(myDefaultValue.c_str());358updateResetButton();359return 1;360}361362363std::string364GNEOptionsEditorRow::OptionInt::getValue() const {365return myIntTextField->getText().text();366}367368// ---------------------------------------------------------------------------369// GNEOptionsEditorRow::OptionIntVector - methods370// ---------------------------------------------------------------------------371372GNEOptionsEditorRow::OptionIntVector::OptionIntVector(GNEOptionsEditor* optionsEditor, FXComposite* parent,373const std::string& topic, const std::string& name, const std::string& description,374const std::string& defaultValue, const bool editable) :375OptionRow(optionsEditor, parent, topic, name, description, defaultValue, editable) {376myIntVectorTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);377myIntVectorTextField->setText(toString(myOptionsEditor->myOptionsContainer.getIntVector(name)).c_str());378if (!editable) {379myIntVectorTextField->disable();380}381updateOption();382}383384385void386GNEOptionsEditorRow::OptionIntVector::updateOption() {387myIntVectorTextField->setText(toString(myOptionsEditor->myOptionsContainer.getIntVector(myName)).c_str());388updateResetButton();389}390391392void393GNEOptionsEditorRow::OptionIntVector::restoreOption() {394myIntVectorTextField->setText(toString(myOptionsEditor->myOriginalOptionsContainer.getIntVector(myName)).c_str());395onCmdSetOption(nullptr, 0, nullptr);396}397398399long400GNEOptionsEditorRow::OptionIntVector::onCmdSetOption(FXObject*, FXSelector, void*) {401try {402// check that int vector can be parsed403const auto intVector = StringTokenizer(myIntVectorTextField->getText().text()).getVector();404for (const auto& intValue : intVector) {405StringUtils::toInt(intValue);406}407myOptionsEditor->myOptionsContainer.resetWritable();408myOptionsEditor->myOptionsContainer.set(myName, myIntVectorTextField->getText().text());409myIntVectorTextField->setTextColor(GUIDesignTextColorBlack);410myOptionsEditor->myOptionsModified = true;411} catch (...) {412myIntVectorTextField->setTextColor(GUIDesignTextColorRed);413}414updateResetButton();415return 1;416}417418419long420GNEOptionsEditorRow::OptionIntVector::onCmdResetOption(FXObject*, FXSelector, void*) {421myIntVectorTextField->setText(myDefaultValue.c_str());422updateResetButton();423return 1;424}425426427std::string428GNEOptionsEditorRow::OptionIntVector::getValue() const {429return myIntVectorTextField->getText().text();430}431432// ---------------------------------------------------------------------------433// GNEOptionsEditorRow::OptionFloat - methods434// ---------------------------------------------------------------------------435436GNEOptionsEditorRow::OptionFloat::OptionFloat(GNEOptionsEditor* optionsEditor, FXComposite* parent,437const std::string& topic, const std::string& name, const std::string& description,438const std::string& defaultValue, const bool editable) :439OptionRow(optionsEditor, parent, topic, name, description, parseFloat(defaultValue), editable) {440myFloatTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextFieldRestricted(TEXTFIELD_REAL));441myFloatTextField->setText(toString(myOptionsEditor->myOptionsContainer.getFloat(name)).c_str());442if (!editable) {443myFloatTextField->disable();444}445updateOption();446}447448449void450GNEOptionsEditorRow::OptionFloat::updateOption() {451myFloatTextField->setText(toString(myOptionsEditor->myOptionsContainer.getFloat(myName)).c_str());452updateResetButton();453}454455456void457GNEOptionsEditorRow::OptionFloat::restoreOption() {458myFloatTextField->setText(toString(myOptionsEditor->myOriginalOptionsContainer.getFloat(myName)).c_str());459onCmdSetOption(nullptr, 0, nullptr);460}461462463long464GNEOptionsEditorRow::OptionFloat::onCmdSetOption(FXObject*, FXSelector, void*) {465// avoid empty values466if (myFloatTextField->getText().empty()) {467myFloatTextField->setText(myDefaultValue.c_str());468} else {469myOptionsEditor->myOptionsContainer.resetWritable();470myOptionsEditor->myOptionsContainer.set(myName, myFloatTextField->getText().text());471myOptionsEditor->myOptionsModified = true;472}473updateResetButton();474return 1;475}476477478long479GNEOptionsEditorRow::OptionFloat::onCmdResetOption(FXObject*, FXSelector, void*) {480myFloatTextField->setText(myDefaultValue.c_str());481updateResetButton();482return 1;483}484485486std::string487GNEOptionsEditorRow::OptionFloat::getValue() const {488return myFloatTextField->getText().text();489}490491492std::string493GNEOptionsEditorRow::OptionFloat::parseFloat(const std::string& value) const {494try {495return toString(StringUtils::toDouble(value));496} catch (...) {497return value;498}499}500501// ---------------------------------------------------------------------------502// GNEOptionsEditorRow::OptionTime - methods503// ---------------------------------------------------------------------------504505GNEOptionsEditorRow::OptionTime::OptionTime(GNEOptionsEditor* optionsEditor, FXComposite* parent,506const std::string& topic, const std::string& name, const std::string& description,507const std::string& defaultValue, const bool editable) :508OptionRow(optionsEditor, parent, topic, name, description, parseTime(defaultValue), editable) {509myTimeTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);510myTimeTextField->setText(toString(myOptionsEditor->myOptionsContainer.getString(name)).c_str());511if (!editable) {512myTimeTextField->disable();513}514updateOption();515}516517518void519GNEOptionsEditorRow::OptionTime::updateOption() {520myTimeTextField->setText(toString(myOptionsEditor->myOptionsContainer.getString(myName)).c_str());521updateResetButton();522}523524525void526GNEOptionsEditorRow::OptionTime::restoreOption() {527myTimeTextField->setText(toString(myOptionsEditor->myOriginalOptionsContainer.getString(myName)).c_str());528onCmdSetOption(nullptr, 0, nullptr);529}530531532long533GNEOptionsEditorRow::OptionTime::onCmdSetOption(FXObject*, FXSelector, void*) {534// avoid empty values535if (myTimeTextField->getText().empty()) {536myTimeTextField->setText(myDefaultValue.c_str());537} else {538myOptionsEditor->myOptionsContainer.resetWritable();539myOptionsEditor->myOptionsContainer.set(myName, myTimeTextField->getText().text());540myOptionsEditor->myOptionsModified = true;541}542updateResetButton();543return 1;544}545546547long548GNEOptionsEditorRow::OptionTime::onCmdResetOption(FXObject*, FXSelector, void*) {549myTimeTextField->setText(myDefaultValue.c_str());550updateResetButton();551return 1;552}553554555std::string556GNEOptionsEditorRow::OptionTime::getValue() const {557return myTimeTextField->getText().text();558}559560561std::string562GNEOptionsEditorRow::OptionTime::parseTime(const std::string& value) const {563try {564return time2string(string2time(value));565} catch (...) {566return value;567}568}569570// ---------------------------------------------------------------------------571// GNEOptionsEditorRow::OptionFilename - methods572// ---------------------------------------------------------------------------573574GNEOptionsEditorRow::OptionFilename::OptionFilename(GNEOptionsEditor* optionsEditor, FXComposite* parent, const std::string& topic,575const std::string& name, const std::string& description, const std::string& defaultValue, const bool editable) :576OptionRow(optionsEditor, parent, topic, name, description, defaultValue, editable) {577myOpenFilenameButton = GUIDesigns::buildFXButton(myContentFrame, "", "", TL("Select filename"),578GUIIconSubSys::getIcon(GUIIcon::OPEN), this, MID_GNE_SET_ATTRIBUTE_DIALOG, GUIDesignButtonIcon);579myFilenameTextField = new FXTextField(myContentFrame, GUIDesignTextFieldNCol, this, MID_GNE_SET_ATTRIBUTE, GUIDesignTextField);580if (!editable) {581myOpenFilenameButton->disable();582myFilenameTextField->disable();583}584updateOption();585}586587588void589GNEOptionsEditorRow::OptionFilename::updateOption() {590myFilenameTextField->setText(myOptionsEditor->myOptionsContainer.getString(myName).c_str());591updateResetButton();592}593594595void596GNEOptionsEditorRow::OptionFilename::restoreOption() {597myFilenameTextField->setText(myOptionsEditor->myOriginalOptionsContainer.getString(myName).c_str());598onCmdSetOption(nullptr, 0, nullptr);599}600601602long603GNEOptionsEditorRow::OptionFilename::onCmdOpenDialog(FXObject*, FXSelector, void*) {604// get open mode605GNEFileDialog::OpenMode openMode = (myName.find("output") != std::string::npos) ? GNEFileDialog::OpenMode::SAVE : GNEFileDialog::OpenMode::LOAD_SINGLE;606// open dialog607const GNEFileDialog XMLFileDialog(myOptionsEditor->myDialog->getApplicationWindow(), myOptionsEditor->myDialog,608TL("XML file"),609SUMOXMLDefinitions::XMLFileExtensions.getStrings(), openMode,610GNEFileDialog::ConfigType::NETEDIT);611// check that file is valid612if (XMLFileDialog.getResult() == GNEDialog::Result::ACCEPT) {613myFilenameTextField->setText(XMLFileDialog.getFilename().c_str(), TRUE);614}615updateResetButton();616return 1;617}618619620long621GNEOptionsEditorRow::OptionFilename::onCmdSetOption(FXObject*, FXSelector, void*) {622if (SUMOXMLDefinitions::isValidFilename(myFilenameTextField->getText().text())) {623myOptionsEditor->myOptionsContainer.resetWritable();624myOptionsEditor->myOptionsContainer.set(myName, myFilenameTextField->getText().text());625myFilenameTextField->setTextColor(GUIDesignTextColorBlack);626myOptionsEditor->myOptionsModified = true;627} else {628myFilenameTextField->setTextColor(GUIDesignTextColorRed);629}630updateResetButton();631return 1;632}633634635long636GNEOptionsEditorRow::OptionFilename::onCmdResetOption(FXObject*, FXSelector, void*) {637myFilenameTextField->setText(myDefaultValue.c_str());638updateResetButton();639return 1;640}641642643GNEOptionsEditorRow::OptionFilename::OptionFilename() {}644645646std::string647GNEOptionsEditorRow::OptionFilename::getValue() const {648return myFilenameTextField->getText().text();649}650651/****************************************************************************/652653654