Path: blob/main/src/netedit/frames/GNEAttributesEditorRow.cpp
193769 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 GNEAttributesEditorRow.cpp14/// @author Pablo Alvarez Lopez15/// @date Nov 202416///17// Row used for edit attributes in GNEAttributesEditorType18/****************************************************************************/1920#include <netedit/dialogs/GNEVClassesDialog.h>21#include <netedit/dialogs/GNEColorDialog.h>22#include <netedit/frames/common/GNEInspectorFrame.h>23#include <netedit/GNEApplicationWindow.h>24#include <netedit/GNEInternalTest.h>25#include <netedit/GNENet.h>26#include <netedit/GNETagProperties.h>27#include <netedit/GNEViewNet.h>28#include <netedit/GNEViewParent.h>29#include <utils/common/Translation.h>30#include <utils/foxtools/MFXLabelTooltip.h>31#include <utils/foxtools/MFXTextFieldIcon.h>32#include <utils/gui/div/GUIDesigns.h>33#include <utils/gui/images/POIIcons.h>34#include <utils/gui/images/VClassIcons.h>3536#include "GNEAttributesEditorRow.h"3738// ===========================================================================39// FOX callback mapping40// ===========================================================================4142FXDEFMAP(GNEAttributesEditorRow) GNEAttributeRowMap[] = {43FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_SETATTRIBUTE, GNEAttributesEditorRow::onCmdSetAttribute),44FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_TOGGLEENABLEATTRIBUTE, GNEAttributesEditorRow::onCmdToggleEnableAttribute),45FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_COLOR, GNEAttributesEditorRow::onCmdOpenColorDialog),46FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_ALLOW, GNEAttributesEditorRow::onCmdOpenVClassDialog),47FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_FILE, GNEAttributesEditorRow::onCmdOpenFileDialog),48FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_REPARENT, GNEAttributesEditorRow::onCmdReparent),49FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_INSPECTPARENT, GNEAttributesEditorRow::onCmdInspectParent),50FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_MOVELANEUP, GNEAttributesEditorRow::onCmdMoveLaneUp),51FXMAPFUNC(SEL_COMMAND, MID_GNE_ATTRIBUTESEDITORROW_MOVELANEDOWN, GNEAttributesEditorRow::onCmdMoveLaneDown)52};5354// Object implementation55FXIMPLEMENT(GNEAttributesEditorRow, FXHorizontalFrame, GNEAttributeRowMap, ARRAYNUMBER(GNEAttributeRowMap))5657// ===========================================================================58// method definitions59// ===========================================================================6061GNEAttributesEditorRow::GNEAttributesEditorRow(GNEAttributesEditorType* attributeTable) :62FXHorizontalFrame(attributeTable->getCollapsableFrame(), GUIDesignAuxiliarHorizontalFrame),63myAttributeTable(attributeTable) {64// get static tooltip menu65const auto tooltipMenu = attributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu();66// Create left label67myAttributeLabel = new MFXLabelTooltip(this, tooltipMenu, "Label", nullptr, GUIDesignLabelThickedFixed(100));68myAttributeLabel->hide();69// create lef boolean checkBox for enable/disable attributes70myAttributeToggleEnableCheckButton = new FXCheckButton(this, "Enable/Disable attribute checkBox", this,71MID_GNE_ATTRIBUTESEDITORROW_TOGGLEENABLEATTRIBUTE, GUIDesignCheckButtonAttribute);72myAttributeToggleEnableCheckButton->hide();73// create left button parent74myAttributeButton = new MFXButtonTooltip(this, tooltipMenu, "button", nullptr, this,75MID_GNE_ATTRIBUTESEDITORROW_REPARENT, GUIDesignButtonAttribute);76// create right text field for string attributes77myValueTextField = new MFXTextFieldIcon(this, tooltipMenu, GUIIcon::EMPTY, this, MID_GNE_ATTRIBUTESEDITORROW_SETATTRIBUTE, GUIDesignTextField);78myValueTextField->hide();79// create right combo box for discrete attributes80myValueComboBox = new MFXComboBoxIcon(this, tooltipMenu, true, GUIDesignComboBoxVisibleItems, this,81MID_GNE_ATTRIBUTESEDITORROW_SETATTRIBUTE, GUIDesignComboBoxAttribute);82myValueComboBox->hide();83// Create right check button84myValueCheckButton = new FXCheckButton(this, "check button", this, MID_GNE_ATTRIBUTESEDITORROW_SETATTRIBUTE, GUIDesignCheckButton);85myValueCheckButton->hide();86// create right move lane up button87myValueLaneUpButton = new MFXButtonTooltip(this, tooltipMenu, "", GUIIconSubSys::getIcon(GUIIcon::ARROW_UP), this,88MID_GNE_ATTRIBUTESEDITORROW_MOVELANEUP, GUIDesignButtonIcon);89myValueLaneUpButton->hide();90// set tip texts91myValueLaneUpButton->setTipText(TL("Move element up one lane"));92myValueLaneUpButton->setHelpText(TL("Move element up one lane"));93// create right move lane down button94myValueLaneDownButton = new MFXButtonTooltip(this, tooltipMenu, "", GUIIconSubSys::getIcon(GUIIcon::ARROW_DOWN), this,95MID_GNE_ATTRIBUTESEDITORROW_MOVELANEDOWN, GUIDesignButtonIcon);96myValueLaneDownButton->hide();97// set tip texts98myValueLaneDownButton->setTipText(TL("Move element down one lane"));99myValueLaneDownButton->setHelpText(TL("Move element down one lane"));100// start hidden101hide();102}103104105bool106GNEAttributesEditorRow::showAttributeRow(GNEAttributesEditorType* attributeTable, const GNEAttributeProperties* attrProperty, const bool forceDisable) {107// update parent table108myAttributeTable = attributeTable;109if (myAttributeTable->myEditedACs.empty()) {110return false;111} else {112reparent(myAttributeTable->getCollapsableFrame());113}114myAttrProperty = attrProperty;115const auto attribute = myAttrProperty->getAttr();116const auto tagPropertyParent = attrProperty->getTagPropertyParent();117const auto firstEditedAC = myAttributeTable->myEditedACs.front();118// check if we're editing multiple ACs119const auto multipleEditedACs = (myAttributeTable->myEditedACs.size() > 1);120// declare flag for show attribute enabled121const bool attributeEnabled = isAttributeEnabled(attrProperty);122// check if this attribute is computed123const bool computedAttribute = multipleEditedACs ? false : firstEditedAC->isAttributeComputed(attribute);124// get string value depending if attribute is enabled125const std::string value = getAttributeValue(attributeEnabled);126// get parent if we're editing single vTypes127GNEAttributeCarrier* ACParent = nullptr;128if (!multipleEditedACs && attrProperty->isVType()) {129const auto& ACs = myAttributeTable->myFrameParent->getViewNet()->getNet()->getAttributeCarriers();130// parent can be either type or distribution131if (attribute == SUMO_ATTR_TYPE) {132ACParent = ACs->retrieveDemandElement(SUMO_TAG_VTYPE, firstEditedAC->getAttribute(SUMO_ATTR_TYPE), false);133}134if (ACParent == nullptr) {135ACParent = ACs->retrieveDemandElement(SUMO_TAG_VTYPE_DISTRIBUTION, firstEditedAC->getAttribute(SUMO_ATTR_TYPE), false);136}137}138// hide editing for unique attributes in case of multi-selection139if (multipleEditedACs && attrProperty->isUnique()) {140return hideAttributeRow();141}142// front element has their own button, and doesn't use the UndoList143if (attribute == GNE_ATTR_FRONTELEMENT) {144return hideAttributeRow();145}146// if we have a disabled flow attribute, don't show row147if (attrProperty->isFlow() && !attributeEnabled) {148return hideAttributeRow();149}150// expected and joins depend of triggered151if (tagPropertyParent->isVehicleStop() && !attributeEnabled) {152if (attribute == SUMO_ATTR_EXPECTED) {153return hideAttributeRow();154} else if (attribute == SUMO_ATTR_EXPECTED_CONTAINERS) {155return hideAttributeRow();156} else if (attribute == SUMO_ATTR_JOIN) {157return hideAttributeRow();158}159}160// don't show stop offset exception if stopOffset is zero161if ((attribute == GNE_ATTR_STOPOEXCEPTION) && !attributeEnabled) {162return hideAttributeRow();163}164// show elements depending of attribute properties165if (attrProperty->isActivatable()) {166showAttributeToggleEnable(attrProperty, attributeEnabled);167} else if (attrProperty->isFileOpen() || attrProperty->isFileSave()) {168showAttributeFile(attrProperty, attributeEnabled);169} else if (attribute == GNE_ATTR_PARENT) {170showAttributeReparent(attributeEnabled);171} else if ((attribute == SUMO_ATTR_TYPE) && tagPropertyParent->hasTypeParent()) {172showAttributeInspectParent(attrProperty, attributeEnabled);173} else if (attrProperty->isVClass() && (attribute != SUMO_ATTR_DISALLOW)) {174showAttributeVClass(attrProperty, attributeEnabled);175} else if (attribute == SUMO_ATTR_COLOR) {176showAttributeColor(attrProperty, attributeEnabled);177} else if (attribute == GNE_ATTR_PARAMETERS) {178hideAllAttributeElements();179} else {180showAttributeLabel(attrProperty);181}182// continue depending of type of attribute183if (attrProperty->isBool()) {184showValueCheckButton(value, attributeEnabled, computedAttribute);185} else if (attrProperty->isDiscrete() || attrProperty->isVType()) {186showValueComboBox(attrProperty, value, attributeEnabled, computedAttribute);187} else {188showValueString(value, attributeEnabled, computedAttribute);189}190// check if show move lane buttons191if (!multipleEditedACs && !tagPropertyParent->isNetworkElement() && (attribute == SUMO_ATTR_LANE)) {192showMoveLaneButtons(value);193myValueLaneUpButton->show();194myValueLaneDownButton->show();195} else {196myValueLaneUpButton->hide();197myValueLaneDownButton->hide();198}199// enable depending of supermode200enableElements(attrProperty, forceDisable);201// Show row202show();203return true;204}205206207bool208GNEAttributesEditorRow::hideAttributeRow() {209hide();210return false;211}212213214void215GNEAttributesEditorRow::disable() {216// disable all elements217myAttributeToggleEnableCheckButton->disable();218myAttributeButton->disable();219myValueTextField->disable();220myValueComboBox->disable();221myValueCheckButton->disable();222myValueLaneUpButton->disable();223myValueLaneDownButton->disable();224}225226227const GNEAttributeProperties*228GNEAttributesEditorRow::getAttrProperty() const {229return myAttrProperty;230}231232233std::string234GNEAttributesEditorRow::getCurrentValue() const {235if (myValueCheckButton->shown()) {236return (myValueCheckButton->getCheck() == TRUE) ? "true" : "false";237} else if (myValueComboBox->shown()) {238return myValueComboBox->getText().text();239} else if (myValueTextField->shown()) {240return myValueTextField->getText().text();241} else {242return "";243}244}245246247bool248GNEAttributesEditorRow::isValueValid() const {249if (myValueCheckButton->shown()) {250return true;251} else if (myValueComboBox->shown()) {252return (myValueComboBox->getTextColor() != GUIDesignTextColorRed) &&253(myValueComboBox->getBackColor() != GUIDesignBackgroundColorRed);254} else if (myValueTextField->shown()) {255return (myValueTextField->getTextColor() != GUIDesignTextColorRed) &&256(myValueTextField->getBackColor() != GUIDesignBackgroundColorRed);257} else {258return true;259}260}261262263bool264GNEAttributesEditorRow::isAttributeRowShown() const {265return shown();266}267268269SumoXMLAttr270GNEAttributesEditorRow::fillSumoBaseObject(CommonXMLStructure::SumoBaseObject* baseObject, const bool insertDefaultValues) const {271const auto attribute = myAttrProperty->getAttr();272// check if this is the default value273const bool usingDefaultValue = isValueValid() && (myAttrProperty->getDefaultStringValue() == getCurrentValue());274// first check if insert default values275if (!insertDefaultValues && usingDefaultValue) {276return SUMO_ATTR_NOTHING;277}278// now check if attribute is activatable AND is enabled279if (myAttrProperty->isActivatable() && (myAttributeToggleEnableCheckButton->getCheck() == FALSE)) {280return SUMO_ATTR_NOTHING;281}282// continue depending of type283if (myAttrProperty->isBool()) {284baseObject->addBoolAttribute(attribute, myValueCheckButton->getCheck() == TRUE);285} else if (myAttrProperty->isDiscrete()) {286if ((myValueComboBox->getTextColor() == GUIDesignTextColorRed) ||287(myValueComboBox->getBackColor() == GUIDesignBackgroundColorRed)) {288return attribute;289} else {290baseObject->addStringAttribute(attribute, myValueComboBox->getText().text());291}292} else if ((myValueTextField->getTextColor() == GUIDesignTextColorRed) ||293(myValueTextField->getBackColor() == GUIDesignBackgroundColorRed)) {294return attribute;295} else if (myAttrProperty->isInt()) {296// int value297if (GNEAttributeCarrier::canParse<int>(myValueTextField->getText().text())) {298const auto intValue = GNEAttributeCarrier::parse<int>(myValueTextField->getText().text());299if (myAttrProperty->isPositive() && (intValue < 0)) {300return attribute;301} else {302baseObject->addIntAttribute(attribute, intValue);303}304} else if (myAttrProperty->hasDefaultValue() && (myValueTextField->getText().text() == myAttrProperty->getDefaultStringValue())) {305baseObject->addIntAttribute(attribute, myAttrProperty->getDefaultIntValue());306} else if (myAttrProperty->hasDefaultValue() && myValueTextField->getText().empty()) {307baseObject->addIntAttribute(attribute, myAttrProperty->getDefaultIntValue());308} else {309return attribute;310}311} else if (myAttrProperty->isFloat()) {312// double value313if (myAttrProperty->isList()) {314if (GNEAttributeCarrier::canParse<std::vector<double> >(myValueTextField->getText().text())) {315const auto doubleListValue = GNEAttributeCarrier::parse<std::vector<double> >(myValueTextField->getText().text());316// check every double317for (const auto doubleValue : doubleListValue) {318if (myAttrProperty->isPositive() && (doubleValue < 0)) {319return attribute;320} else if (myAttrProperty->isFloat() && ((doubleValue < 0) || (doubleValue > 1))) {321return attribute;322}323}324baseObject->addDoubleListAttribute(attribute, doubleListValue);325} else {326return attribute;327}328} else if (GNEAttributeCarrier::canParse<double>(myValueTextField->getText().text())) {329const auto doubleValue = GNEAttributeCarrier::parse<double>(myValueTextField->getText().text());330// check using default value for certain default values (for example, length = -1)331if (!usingDefaultValue && myAttrProperty->isPositive() && (doubleValue < 0)) {332return attribute;333} else if (!usingDefaultValue && myAttrProperty->isProbability() && ((doubleValue < 0) || (doubleValue > 1))) {334return attribute;335} else {336baseObject->addDoubleAttribute(attribute, doubleValue);337}338} else if (myAttrProperty->hasDefaultValue() && (myValueTextField->getText().text() == myAttrProperty->getDefaultStringValue())) {339baseObject->addDoubleAttribute(attribute, myAttrProperty->getDefaultDoubleValue());340} else if (myAttrProperty->hasDefaultValue() && myValueTextField->getText().empty()) {341baseObject->addDoubleAttribute(attribute, myAttrProperty->getDefaultDoubleValue());342} else {343return attribute;344}345} else if (myAttrProperty->isSUMOTime()) {346// time value347if (GNEAttributeCarrier::canParse<SUMOTime>(myValueTextField->getText().text())) {348const auto timeValue = GNEAttributeCarrier::parse<SUMOTime>(myValueTextField->getText().text());349if (timeValue < 0) {350return attribute;351} else {352baseObject->addTimeAttribute(attribute, timeValue);353}354} else if (myAttrProperty->hasDefaultValue() && (myValueTextField->getText().text() == myAttrProperty->getDefaultStringValue())) {355baseObject->addTimeAttribute(attribute, myAttrProperty->getDefaultTimeValue());356} else if (myAttrProperty->hasDefaultValue() && myValueTextField->getText().empty()) {357baseObject->addTimeAttribute(attribute, myAttrProperty->getDefaultTimeValue());358} else {359return attribute;360}361} else if (myAttrProperty->isPosition()) {362// position value363if (myAttrProperty->isList()) {364if (GNEAttributeCarrier::canParse<PositionVector>(myValueTextField->getText().text())) {365baseObject->addPositionVectorAttribute(attribute, GNEAttributeCarrier::parse<PositionVector>(myValueTextField->getText().text()));366} else {367return attribute;368}369} else if (GNEAttributeCarrier::canParse<Position>(myValueTextField->getText().text())) {370baseObject->addPositionAttribute(attribute, GNEAttributeCarrier::parse<Position>(myValueTextField->getText().text()));371} else if (myAttrProperty->hasDefaultValue() && (myValueTextField->getText().text() == myAttrProperty->getDefaultStringValue())) {372baseObject->addPositionAttribute(attribute, myAttrProperty->getDefaultPositionValue());373} else if (myAttrProperty->hasDefaultValue() && myValueTextField->getText().empty()) {374baseObject->addPositionAttribute(attribute, myAttrProperty->getDefaultPositionValue());375} else {376return attribute;377}378} else if (myAttrProperty->isColor()) {379// color value380if (GNEAttributeCarrier::canParse<RGBColor>(myValueTextField->getText().text())) {381baseObject->addColorAttribute(attribute, GNEAttributeCarrier::parse<RGBColor>(myValueTextField->getText().text()));382} else if (myAttrProperty->hasDefaultValue() && (myValueTextField->getText().text() == myAttrProperty->getDefaultStringValue())) {383baseObject->addColorAttribute(attribute, myAttrProperty->getDefaultColorValue());384} else if (myAttrProperty->hasDefaultValue() && myValueTextField->getText().empty()) {385baseObject->addColorAttribute(attribute, myAttrProperty->getDefaultColorValue());386} else {387return attribute;388}389} else if (myAttrProperty->isList()) {390baseObject->addStringListAttribute(attribute, GNEAttributeCarrier::parse<std::vector<std::string> >(myValueTextField->getText().text()));391} else if (attribute == GNE_ATTR_PARAMETERS) {392baseObject->addParameters(myValueTextField->getText().text());393} else {394baseObject->addStringAttribute(attribute, myValueTextField->getText().text());395}396// all ok, then return nothing397return SUMO_ATTR_NOTHING;398}399400401long402GNEAttributesEditorRow::onCmdOpenColorDialog(FXObject*, FXSelector, void*) {403auto GNEApp = myAttributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows();404RGBColor color = RGBColor::BLACK;405// If previous attribute wasn't correct, set black as default color406if (GNEAttributeCarrier::canParse<RGBColor>(myValueTextField->getText().text())) {407color = GNEAttributeCarrier::parse<RGBColor>(myValueTextField->getText().text());408} else if (myAttrProperty->hasDefaultValue()) {409color = myAttrProperty->getDefaultColorValue();410}411// declare colorDialog412const auto colorDialog = new GNEColorDialog(GNEApp, color);413// continue depending of result414if (colorDialog->getResult() == GNEDialog::Result::ACCEPT) {415myValueTextField->setText(toString(colorDialog->getColor()).c_str(), TRUE);416}417return 1;418}419420421long422GNEAttributesEditorRow::onCmdOpenVClassDialog(FXObject*, FXSelector, void*) {423auto GNEApp = myAttributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows();424// declare allowVClassesDialog425const auto allowVClassesDialog = new GNEVClassesDialog(GNEApp, myAttrProperty->getAttr(), myValueTextField->getText().text());426// continue depending of result427if (allowVClassesDialog->getResult() == GNEDialog::Result::ACCEPT) {428myValueTextField->setText(allowVClassesDialog->getModifiedVClasses().c_str(), TRUE);429}430return 1;431}432433434long435GNEAttributesEditorRow::onCmdOpenFileDialog(FXObject*, FXSelector, void*) {436// open dialog437const GNEFileDialog fileDialog(myAttributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows(),438myAttrProperty->getAttrStr(),439myAttrProperty->getFilenameExtensions(),440myAttrProperty->isFileSave() ? GNEFileDialog::OpenMode::SAVE : GNEFileDialog::OpenMode::LOAD_SINGLE,441GNEFileDialog::ConfigType::NETEDIT);442// update text field443if (fileDialog.getResult() == GNEDialog::Result::ACCEPT) {444myValueTextField->setText(fileDialog.getFilename().c_str(), TRUE);445}446return 1;447}448449450long451GNEAttributesEditorRow::onCmdReparent(FXObject*, FXSelector, void*) {452myAttributeTable->enableReparent();453return 1;454}455456457long458GNEAttributesEditorRow::onCmdInspectParent(FXObject*, FXSelector, void*) {459myAttributeTable->inspectParent();460return 1;461}462463464long465GNEAttributesEditorRow::onCmdMoveLaneUp(FXObject*, FXSelector, void*) {466myAttributeTable->moveLaneUp();467return 1;468}469470471long472GNEAttributesEditorRow::onCmdMoveLaneDown(FXObject*, FXSelector, void*) {473myAttributeTable->moveLaneDown();474return 1;475}476477478long479GNEAttributesEditorRow::onCmdSetAttribute(FXObject* obj, FXSelector, void*) {480if (myAttributeTable->myEditedACs.empty()) {481return 0;482}483const auto& editedAC = myAttributeTable->myEditedACs.front();484const auto attribute = myAttrProperty->getAttr();485// continue depending of clicked object486if (obj == myValueCheckButton) {487// Set true o false depending of the checkBox488if (myValueCheckButton->getCheck()) {489myValueCheckButton->setText("true");490} else {491myValueCheckButton->setText("false");492}493myAttributeTable->setAttribute(attribute, myValueCheckButton->getText().text());494} else if (obj == myValueComboBox) {495const std::string newValue = myValueComboBox->getText().text();496// check if the new comboBox value is valid497if (editedAC->isValid(attribute, newValue)) {498myValueComboBox->setTextColor(GUIDesignTextColorBlack);499myValueComboBox->setBackColor(GUIDesignBackgroundColorWhite);500myValueComboBox->killFocus();501myAttributeTable->setAttribute(attribute, newValue);502} else {503// edit colors504myValueComboBox->setTextColor(GUIDesignTextColorRed);505if (newValue.empty()) {506myValueComboBox->setBackColor(GUIDesignBackgroundColorRed);507}508}509} else if (obj == myValueTextField) {510// first check if set default value511if (myValueTextField->getText().empty() && myAttrProperty->hasDefaultValue() && !myAttrProperty->isVClass()) {512// update text field without notify513myValueTextField->setText(myAttrProperty->getDefaultStringValue().c_str(), FALSE);514}515// if we're editing an angle, check if filter between [0,360]516if ((attribute == SUMO_ATTR_ANGLE) && GNEAttributeCarrier::canParse<double>(myValueTextField->getText().text())) {517// filter anglea and update text field without notify518const double angle = fmod(GNEAttributeCarrier::parse<double>(myValueTextField->getText().text()), 360);519myValueTextField->setText(toString(angle).c_str(), FALSE);520}521// if we're editing a position or a shape, strip whitespace after comma522if ((attribute == SUMO_ATTR_POSITION) || (attribute == SUMO_ATTR_SHAPE)) {523std::string shape(myValueTextField->getText().text());524while (shape.find(", ") != std::string::npos) {525shape = StringUtils::replace(shape, ", ", ",");526}527myValueTextField->setText(toString(shape).c_str(), FALSE);528}529// if we're editing a int, strip decimal value530if (myAttrProperty->isInt() && GNEAttributeCarrier::canParse<double>(myValueTextField->getText().text())) {531double doubleValue = GNEAttributeCarrier::parse<double>(myValueTextField->getText().text());532if ((doubleValue - (int)doubleValue) == 0) {533myValueTextField->setText(toString((int)doubleValue).c_str(), FALSE);534}535}536// after apply all filters, obtain value537const std::string newValue = myValueTextField->getText().text();538// check if the new textField value is valid539if (editedAC->isValid(attribute, newValue)) {540myValueTextField->setTextColor(GUIDesignTextColorBlack);541myValueTextField->setBackColor(GUIDesignBackgroundColorWhite);542myValueTextField->killFocus();543if (myAttributeTable->isEditorTypeEditor() || newValue.empty() || (attribute != SUMO_ATTR_ID)) {544myAttributeTable->setAttribute(attribute, newValue);545}546} else {547// edit colors548myValueTextField->setTextColor(GUIDesignTextColorRed);549if (newValue.empty()) {550myValueTextField->setBackColor(GUIDesignBackgroundColorRed);551}552}553}554return 1;555}556557558long559GNEAttributesEditorRow::onCmdToggleEnableAttribute(FXObject*, FXSelector, void*) {560myAttributeTable->toggleEnableAttribute(myAttrProperty->getAttr(), myAttributeToggleEnableCheckButton->getCheck() == TRUE);561return 0;562}563564565GNEAttributesEditorRow::GNEAttributesEditorRow() :566myAttributeTable(nullptr) {567}568569570const std::string571GNEAttributesEditorRow::getAttributeValue(const bool enabled) const {572const auto attribute = myAttrProperty->getAttr();573// if we're in creator mode, generate ID574if ((attribute == SUMO_ATTR_ID) && (myAttributeTable->myEditorType == GNEAttributesEditorType::EditorType::CREATOR)) {575const auto& ACs = myAttributeTable->getFrameParent()->getViewNet()->getNet()->getAttributeCarriers();576const auto parentTag = myAttrProperty->getTagPropertyParent()->getTag();577if (myAttrProperty->getTagPropertyParent()->getTag() == SUMO_TAG_EDGE) {578return ACs->generateEdgeID();579} else if (myAttrProperty->getTagPropertyParent()->isAdditionalElement()) {580return ACs->generateAdditionalID(parentTag);581} else if (myAttrProperty->getTagPropertyParent()->isDemandElement()) {582return ACs->generateDemandElementID(parentTag);583} else if (myAttrProperty->getTagPropertyParent()->isMeanData()) {584return ACs->generateMeanDataID(parentTag);585} else if (parentTag == SUMO_TAG_TYPE) {586return ACs->generateEdgeTypeID();587} else if (parentTag == SUMO_TAG_DATASET) {588return ACs->generateDataSetID();589}590}591if (enabled) {592// Declare a set of occurring values and insert attribute's values of item (note: We use a set to avoid repeated values)593std::set<std::string> values;594// iterate over edited attributes and insert every value in set595for (const auto& editedAC : myAttributeTable->myEditedACs) {596if (editedAC->hasAttribute(attribute)) {597values.insert(editedAC->getAttribute(attribute));598}599}600// merge all values in a single string601std::ostringstream oss;602for (auto it = values.begin(); it != values.end(); it++) {603if (it != values.begin()) {604oss << " ";605}606oss << *it;607}608// obtain value to be shown in row609return oss.str();610} else {611return myAttributeTable->myEditedACs.front()->getAlternativeValueForDisabledAttributes(attribute);612}613}614615616void617GNEAttributesEditorRow::showAttributeToggleEnable(const GNEAttributeProperties* attrProperty, const bool value) {618myAttributeToggleEnableCheckButton->setText(attrProperty->getAttrStr().c_str());619myAttributeToggleEnableCheckButton->setCheck(value);620myAttributeToggleEnableCheckButton->enable();621myAttributeToggleEnableCheckButton->show();622// hide other elements623myAttributeLabel->hide();624myAttributeButton->hide();625}626627628void629GNEAttributesEditorRow::showAttributeReparent(const bool enabled) {630// update attribute button631myAttributeButton->setText(TL("Reparent"));632myAttributeButton->setHelpText(TL("Change parent of this element"));633myAttributeButton->setTipText(myAttributeButton->getHelpText());634myAttributeButton->setIcon(nullptr);635myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_REPARENT);636if (enabled) {637myAttributeButton->enable();638} else {639myAttributeButton->disable();640}641myAttributeButton->show();642// hide other elements643myAttributeLabel->hide();644myAttributeToggleEnableCheckButton->hide();645}646647648void649GNEAttributesEditorRow::showAttributeInspectParent(const GNEAttributeProperties* attrProperty, const bool enabled) {650// update attribute button651myAttributeButton->setText(attrProperty->getAttrStr().c_str());652myAttributeButton->setHelpText(TLF("Inspect % parent", attrProperty->getAttrStr()).c_str());653myAttributeButton->setTipText(myAttributeButton->getHelpText());654myAttributeButton->setIcon(GUIIconSubSys::getIcon(attrProperty->getTagPropertyParent()->getGUIIcon()));655myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_INSPECTPARENT);656if (enabled) {657myAttributeButton->enable();658} else {659myAttributeButton->disable();660}661myAttributeButton->show();662// hide other elements663myAttributeLabel->hide();664myAttributeToggleEnableCheckButton->hide();665}666667668void669GNEAttributesEditorRow::showAttributeVClass(const GNEAttributeProperties* attrProperty, const bool enabled) {670// update attribute button671myAttributeButton->setText(attrProperty->getAttrStr().c_str());672myAttributeButton->setHelpText(TL("Open dialog for editing vClasses"));673myAttributeButton->setTipText(myAttributeButton->getHelpText());674myAttributeButton->setIcon(nullptr);675myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_ALLOW);676if (enabled) {677myAttributeButton->enable();678} else {679myAttributeButton->disable();680}681myAttributeButton->show();682// hide other elements683myAttributeLabel->hide();684myAttributeToggleEnableCheckButton->hide();685}686687688void689GNEAttributesEditorRow::showAttributeColor(const GNEAttributeProperties* attrProperty, const bool enabled) {690// update attribute button691myAttributeButton->setText(attrProperty->getAttrStr().c_str());692myAttributeButton->setHelpText(TL("Open dialog for editing color"));693myAttributeButton->setTipText(myAttributeButton->getHelpText());694myAttributeButton->setIcon(GUIIconSubSys::getIcon(GUIIcon::COLORWHEEL));695myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_COLOR);696if (enabled) {697myAttributeButton->enable();698} else {699myAttributeButton->disable();700}701myAttributeButton->show();702// hide other elements703myAttributeLabel->hide();704myAttributeToggleEnableCheckButton->hide();705}706707708void709GNEAttributesEditorRow::showAttributeFile(const GNEAttributeProperties* attrProperty, const bool enabled) {710// update attribute button711myAttributeButton->setText(attrProperty->getAttrStr().c_str());712if (attrProperty->isFileOpen()) {713myAttributeButton->setHelpText(TL("Open dialog to select an existent file"));714} else {715myAttributeButton->setHelpText(TL("Open dialog to select or create an existent file"));716}717myAttributeButton->setTipText(myAttributeButton->getHelpText());718myAttributeButton->setIcon(GUIIconSubSys::getIcon(GUIIcon::OPEN));719myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_FILE);720if (enabled) {721myAttributeButton->enable();722} else {723myAttributeButton->disable();724}725myAttributeButton->show();726// hide other elements727myAttributeLabel->hide();728myAttributeToggleEnableCheckButton->hide();729}730731732void733GNEAttributesEditorRow::showAttributeLabel(const GNEAttributeProperties* attrProperty) {734myAttributeLabel->setText(attrProperty->getAttrStr().c_str());735myAttributeLabel->setTipText(attrProperty->getDefinition().c_str());736myAttributeLabel->show();737// hide other elements738myAttributeToggleEnableCheckButton->hide();739myAttributeButton->hide();740}741742743void744GNEAttributesEditorRow::hideAllAttributeElements() {745myAttributeLabel->hide();746myAttributeToggleEnableCheckButton->hide();747myAttributeButton->hide();748}749750751void752GNEAttributesEditorRow::showValueCheckButton(const std::string& value,753const bool enabled, const bool computed) {754// first we need to check if all boolean values are equal755bool allValuesEqual = true;756// declare boolean vector757std::vector<bool> booleanVector;758// check if value can be parsed to a boolean vector759if (GNEAttributeCarrier::canParse<std::vector<bool> >(value)) {760booleanVector = GNEAttributeCarrier::parse<std::vector<bool> >(value);761}762// iterate over booleans comparing all element with the first763for (const auto booleanValue : booleanVector) {764if (booleanValue != booleanVector.front()) {765allValuesEqual = false;766}767}768// use checkbox or textfield depending if all booleans are equal769if (allValuesEqual) {770if (enabled) {771myValueCheckButton->enable();772} else {773myValueCheckButton->disable();774}775// set check button776if ((booleanVector.size() > 0) && booleanVector.front()) {777myValueCheckButton->setCheck(true);778myValueCheckButton->setText("true");779} else {780myValueCheckButton->setCheck(false);781myValueCheckButton->setText("false");782}783// show check button784myValueCheckButton->show();785// hide other value elements786myValueTextField->hide();787myValueComboBox->hide();788myValueLaneUpButton->hide();789myValueLaneDownButton->hide();790} else {791// show value as string792showValueString(value, enabled, computed);793}794}795796797void798GNEAttributesEditorRow::showValueComboBox(const GNEAttributeProperties* attrProperty, const std::string& value,799const bool enabled, const bool computed) {800// first we need to check if all boolean values are equal801bool allValuesEqual = true;802// declare boolean vector803std::vector<std::string> stringVector = GNEAttributeCarrier::parse<std::vector<std::string> >(value);804// iterate over string comparing all element with the first805for (const auto& stringValue : stringVector) {806if (stringValue != stringVector.front()) {807allValuesEqual = false;808}809}810// use checkbox or textfield depending if all booleans are equal811if (allValuesEqual) {812// clear and enable comboBox813myValueComboBox->clearItems();814myValueComboBox->setTextColor(GUIDesignTextColorBlack);815myValueComboBox->setBackColor(GUIDesignBackgroundColorWhite);816if (enabled) {817myValueComboBox->enable();818} else {819myValueComboBox->disable();820}821// fill depeding of ACAttr822if (attrProperty->getAttr() == SUMO_ATTR_VCLASS) {823// add all vClasses with their icons824for (const auto& vClassStr : SumoVehicleClassStrings.getStrings()) {825myValueComboBox->appendIconItem(vClassStr.c_str(), VClassIcons::getVClassIcon(getVehicleClassID(vClassStr)));826}827} else if (attrProperty->isVType()) {828// get ACs829const auto& ACs = myAttributeTable->myFrameParent->getViewNet()->getNet()->getAttributeCarriers();830// fill comboBox with all vTypes and vType distributions sorted by ID831std::map<std::string, GNEDemandElement*> sortedTypes;832for (const auto& type : ACs->getDemandElements().at(SUMO_TAG_VTYPE)) {833sortedTypes[type.second->getID()] = type.second;834}835for (const auto& sortedType : sortedTypes) {836myValueComboBox->appendIconItem(sortedType.first.c_str(), sortedType.second->getACIcon());837}838sortedTypes.clear();839for (const auto& typeDistribution : ACs->getDemandElements().at(SUMO_TAG_VTYPE_DISTRIBUTION)) {840sortedTypes[typeDistribution.second->getID()] = typeDistribution.second;841}842for (const auto& sortedType : sortedTypes) {843myValueComboBox->appendIconItem(sortedType.first.c_str(), sortedType.second->getACIcon());844}845} else if (attrProperty->getAttr() == SUMO_ATTR_ICON) {846// add all POIIcons with their icons847for (const auto& POIIcon : SUMOXMLDefinitions::POIIcons.getValues()) {848myValueComboBox->appendIconItem(SUMOXMLDefinitions::POIIcons.getString(POIIcon).c_str(), POIIcons::getPOIIcon(POIIcon));849}850} else if ((attrProperty->getAttr() == SUMO_ATTR_RIGHT_OF_WAY) && (myAttributeTable->myEditedACs.size() == 1) &&851(attrProperty->getTagPropertyParent()->getTag() == SUMO_TAG_JUNCTION)) {852// special case for junction types853if (myAttributeTable->myEditedACs.front()->getAttribute(SUMO_ATTR_TYPE) == "priority") {854myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::DEFAULT).c_str(), nullptr);855myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::EDGEPRIORITY).c_str(), nullptr);856} else if (myAttributeTable->myEditedACs.front()->getAttribute(SUMO_ATTR_TYPE) == "traffic_light") {857myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::DEFAULT).c_str(), nullptr);858myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::MIXEDPRIORITY).c_str(), nullptr);859myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::ALLWAYSTOP).c_str(), nullptr);860} else {861myValueComboBox->disable();862}863} else {864// fill comboBox with discrete values865for (const auto& discreteValue : attrProperty->getDiscreteValues()) {866myValueComboBox->appendIconItem(discreteValue.c_str(), nullptr);867}868}869// set current value (or disable)870const auto index = myValueComboBox->findItem(value.c_str());871if (index < 0) {872if (myValueComboBox->getNumItems() > 0) {873myValueComboBox->setCurrentItem(0);874} else {875myValueComboBox->disable();876}877} else {878myValueComboBox->setCurrentItem(index);879}880// show comboBox button881myValueComboBox->show();882// hide other value elements883myValueTextField->hide();884myValueCheckButton->hide();885myValueLaneUpButton->hide();886myValueLaneDownButton->hide();887} else {888// show value as string889showValueString(value, enabled, computed);890}891}892893894void895GNEAttributesEditorRow::showValueString(const std::string& value, const bool enabled, const bool computed) {896// clear and enable comboBox897myValueTextField->setText(value.c_str());898if (computed) {899myValueTextField->setTextColor(GUIDesignTextColorBlue);900} else {901myValueTextField->setTextColor(GUIDesignTextColorBlack);902}903if (enabled) {904myValueTextField->enable();905} else {906myValueTextField->disable();907}908// show list of values909myValueTextField->show();910// hide other value elements911myValueCheckButton->hide();912myValueComboBox->hide();913}914915916void917GNEAttributesEditorRow::showMoveLaneButtons(const std::string& laneID) {918// retrieve lane919const auto lane = myAttributeTable->myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveLane(laneID, false);920// check lane921if (lane) {922// check if disable move up923if ((lane->getIndex() + 1) >= (int)lane->getParentEdge()->getChildLanes().size()) {924myValueLaneUpButton->disable();925} else {926myValueLaneUpButton->enable();927}928// check if disable move down929if ((lane->getIndex() - 1) < 0) {930myValueLaneDownButton->disable();931} else {932myValueLaneDownButton->enable();933}934} else {935// if lane doesn't exist, disable both936myValueLaneUpButton->disable();937myValueLaneDownButton->disable();938}939}940941942void943GNEAttributesEditorRow::enableElements(const GNEAttributeProperties* attrProperty, const bool forceDisable) {944const auto& editModes = myAttributeTable->myFrameParent->getViewNet()->getEditModes();945const auto tagProperty = attrProperty->getTagPropertyParent();946// by default we assume that elements are disabled947bool enableElements = false;948if (forceDisable) {949enableElements = false;950} else if (editModes.isCurrentSupermodeNetwork()) {951if (tagProperty->isNetworkElement() || tagProperty->isAdditionalElement()) {952enableElements = true;953} else if ((tagProperty->getTag() == SUMO_TAG_TAZSOURCE) || (tagProperty->getTag() == SUMO_TAG_TAZSINK)) {954enableElements = true;955}956} else if (editModes.isCurrentSupermodeDemand() && tagProperty->isDemandElement()) {957enableElements = true;958} else if (editModes.isCurrentSupermodeData() && (tagProperty->isDataElement() || tagProperty->isMeanData())) {959enableElements = true;960}961if (!enableElements) {962myAttributeToggleEnableCheckButton->disable();963myAttributeButton->disable();964myValueTextField->disable();965myValueComboBox->disable();966myValueCheckButton->disable();967myValueLaneUpButton->disable();968myValueLaneDownButton->disable();969}970}971972973bool974GNEAttributesEditorRow::isAttributeEnabled(const GNEAttributeProperties* attrProperty) const {975if (attrProperty->isAlwaysEnabled()) {976return true;977} else {978for (const auto& AC : myAttributeTable->myEditedACs) {979if (AC->isAttributeEnabled(attrProperty->getAttr())) {980return true;981}982}983return false;984}985}986987/****************************************************************************/988989990