Path: blob/main/src/netedit/frames/GNEAttributesEditorRow.cpp
169678 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 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*) {403RGBColor color = RGBColor::BLACK;404// If previous attribute wasn't correct, set black as default color405if (GNEAttributeCarrier::canParse<RGBColor>(myValueTextField->getText().text())) {406color = GNEAttributeCarrier::parse<RGBColor>(myValueTextField->getText().text());407} else if (myAttrProperty->hasDefaultValue()) {408color = myAttrProperty->getDefaultColorValue();409}410// declare colorDialog411const auto colorDialog = new GNEColorDialog(myAttributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows(), color);412// continue depending of result413if (colorDialog->getResult() == GNEDialog::Result::ACCEPT) {414myValueTextField->setText(toString(colorDialog->getColor()).c_str(), TRUE);415}416return 1;417}418419420long421GNEAttributesEditorRow::onCmdOpenVClassDialog(FXObject*, FXSelector, void*) {422// declare allowVClassesDialog423const auto allowVClassesDialog = new GNEVClassesDialog(myAttributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows(),424myAttrProperty->getAttr(), myValueTextField->getText().text());425// continue depending of result426if (allowVClassesDialog->getResult() == GNEDialog::Result::ACCEPT) {427myValueTextField->setText(allowVClassesDialog->getModifiedVClasses().c_str(), TRUE);428}429return 1;430}431432433long434GNEAttributesEditorRow::onCmdOpenFileDialog(FXObject*, FXSelector, void*) {435// open dialog436const auto fileDialog = GNEFileDialog(myAttributeTable->getFrameParent()->getViewNet()->getViewParent()->getGNEAppWindows(),437myAttrProperty->getAttrStr(),438myAttrProperty->getFilenameExtensions(),439myAttrProperty->isFileSave() ? GNEFileDialog::OpenMode::SAVE : GNEFileDialog::OpenMode::LOAD_SINGLE,440GNEFileDialog::ConfigType::NETEDIT);441// update text field442if (fileDialog.getResult() == GNEDialog::Result::ACCEPT) {443myValueTextField->setText(fileDialog.getFilename().c_str(), TRUE);444}445return 1;446}447448449long450GNEAttributesEditorRow::onCmdReparent(FXObject*, FXSelector, void*) {451myAttributeTable->enableReparent();452return 1;453}454455456long457GNEAttributesEditorRow::onCmdInspectParent(FXObject*, FXSelector, void*) {458myAttributeTable->inspectParent();459return 1;460}461462463long464GNEAttributesEditorRow::onCmdMoveLaneUp(FXObject*, FXSelector, void*) {465myAttributeTable->moveLaneUp();466return 1;467}468469470long471GNEAttributesEditorRow::onCmdMoveLaneDown(FXObject*, FXSelector, void*) {472myAttributeTable->moveLaneDown();473return 1;474}475476477long478GNEAttributesEditorRow::onCmdSetAttribute(FXObject* obj, FXSelector, void*) {479if (myAttributeTable->myEditedACs.empty()) {480return 0;481}482const auto& editedAC = myAttributeTable->myEditedACs.front();483const auto attribute = myAttrProperty->getAttr();484// continue depending of clicked object485if (obj == myValueCheckButton) {486// Set true o false depending of the checkBox487if (myValueCheckButton->getCheck()) {488myValueCheckButton->setText("true");489} else {490myValueCheckButton->setText("false");491}492myAttributeTable->setAttribute(attribute, myValueCheckButton->getText().text());493} else if (obj == myValueComboBox) {494const std::string newValue = myValueComboBox->getText().text();495// check if the new comboBox value is valid496if (editedAC->isValid(attribute, newValue)) {497myValueComboBox->setTextColor(GUIDesignTextColorBlack);498myValueComboBox->setBackColor(GUIDesignBackgroundColorWhite);499myValueComboBox->killFocus();500myAttributeTable->setAttribute(attribute, newValue);501} else {502// edit colors503myValueComboBox->setTextColor(GUIDesignTextColorRed);504if (newValue.empty()) {505myValueComboBox->setBackColor(GUIDesignBackgroundColorRed);506}507}508} else if (obj == myValueTextField) {509// first check if set default value510if (myValueTextField->getText().empty() && myAttrProperty->hasDefaultValue() && !myAttrProperty->isVClass()) {511// update text field without notify512myValueTextField->setText(myAttrProperty->getDefaultStringValue().c_str(), FALSE);513}514// if we're editing an angle, check if filter between [0,360]515if ((attribute == SUMO_ATTR_ANGLE) && GNEAttributeCarrier::canParse<double>(myValueTextField->getText().text())) {516// filter anglea and update text field without notify517const double angle = fmod(GNEAttributeCarrier::parse<double>(myValueTextField->getText().text()), 360);518myValueTextField->setText(toString(angle).c_str(), FALSE);519}520// if we're editing a position or a shape, strip whitespace after comma521if ((attribute == SUMO_ATTR_POSITION) || (attribute == SUMO_ATTR_SHAPE)) {522std::string shape(myValueTextField->getText().text());523while (shape.find(", ") != std::string::npos) {524shape = StringUtils::replace(shape, ", ", ",");525}526myValueTextField->setText(toString(shape).c_str(), FALSE);527}528// if we're editing a int, strip decimal value529if (myAttrProperty->isInt() && GNEAttributeCarrier::canParse<double>(myValueTextField->getText().text())) {530double doubleValue = GNEAttributeCarrier::parse<double>(myValueTextField->getText().text());531if ((doubleValue - (int)doubleValue) == 0) {532myValueTextField->setText(toString((int)doubleValue).c_str(), FALSE);533}534}535// after apply all filters, obtain value536const std::string newValue = myValueTextField->getText().text();537// check if the new textField value is valid538if (editedAC->isValid(attribute, newValue)) {539myValueTextField->setTextColor(GUIDesignTextColorBlack);540myValueTextField->setBackColor(GUIDesignBackgroundColorWhite);541myValueTextField->killFocus();542if (myAttributeTable->isEditorTypeEditor() || newValue.empty() || (attribute != SUMO_ATTR_ID)) {543myAttributeTable->setAttribute(attribute, newValue);544}545} else {546// edit colors547myValueTextField->setTextColor(GUIDesignTextColorRed);548if (newValue.empty()) {549myValueTextField->setBackColor(GUIDesignBackgroundColorRed);550}551}552}553return 1;554}555556557long558GNEAttributesEditorRow::onCmdToggleEnableAttribute(FXObject*, FXSelector, void*) {559myAttributeTable->toggleEnableAttribute(myAttrProperty->getAttr(), myAttributeToggleEnableCheckButton->getCheck() == TRUE);560return 0;561}562563564GNEAttributesEditorRow::GNEAttributesEditorRow() :565myAttributeTable(nullptr) {566}567568569const std::string570GNEAttributesEditorRow::getAttributeValue(const bool enabled) const {571const auto attribute = myAttrProperty->getAttr();572// if we're in creator mode, generate ID573if ((attribute == SUMO_ATTR_ID) && (myAttributeTable->myEditorType == GNEAttributesEditorType::EditorType::CREATOR)) {574const auto& ACs = myAttributeTable->getFrameParent()->getViewNet()->getNet()->getAttributeCarriers();575const auto parentTag = myAttrProperty->getTagPropertyParent()->getTag();576if (myAttrProperty->getTagPropertyParent()->getTag() == SUMO_TAG_EDGE) {577return ACs->generateEdgeID();578} else if (myAttrProperty->getTagPropertyParent()->isAdditionalElement()) {579return ACs->generateAdditionalID(parentTag);580} else if (myAttrProperty->getTagPropertyParent()->isDemandElement()) {581return ACs->generateDemandElementID(parentTag);582} else if (myAttrProperty->getTagPropertyParent()->isMeanData()) {583return ACs->generateMeanDataID(parentTag);584} else if (parentTag == SUMO_TAG_TYPE) {585return ACs->generateEdgeTypeID();586} else if (parentTag == SUMO_TAG_DATASET) {587return ACs->generateDataSetID();588}589}590if (enabled) {591// Declare a set of occurring values and insert attribute's values of item (note: We use a set to avoid repeated values)592std::set<std::string> values;593// iterate over edited attributes and insert every value in set594for (const auto& editedAC : myAttributeTable->myEditedACs) {595if (editedAC->hasAttribute(attribute)) {596values.insert(editedAC->getAttribute(attribute));597}598}599// merge all values in a single string600std::ostringstream oss;601for (auto it = values.begin(); it != values.end(); it++) {602if (it != values.begin()) {603oss << " ";604}605oss << *it;606}607// obtain value to be shown in row608return oss.str();609} else {610return myAttributeTable->myEditedACs.front()->getAlternativeValueForDisabledAttributes(attribute);611}612}613614615void616GNEAttributesEditorRow::showAttributeToggleEnable(const GNEAttributeProperties* attrProperty, const bool value) {617myAttributeToggleEnableCheckButton->setText(attrProperty->getAttrStr().c_str());618myAttributeToggleEnableCheckButton->setCheck(value);619myAttributeToggleEnableCheckButton->enable();620myAttributeToggleEnableCheckButton->show();621// hide other elements622myAttributeLabel->hide();623myAttributeButton->hide();624}625626627void628GNEAttributesEditorRow::showAttributeReparent(const bool enabled) {629// update attribute button630myAttributeButton->setText(TL("Reparent"));631myAttributeButton->setHelpText(TL("Change parent of this element"));632myAttributeButton->setTipText(myAttributeButton->getHelpText());633myAttributeButton->setIcon(nullptr);634myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_REPARENT);635if (enabled) {636myAttributeButton->enable();637} else {638myAttributeButton->disable();639}640myAttributeButton->show();641// hide other elements642myAttributeLabel->hide();643myAttributeToggleEnableCheckButton->hide();644}645646647void648GNEAttributesEditorRow::showAttributeInspectParent(const GNEAttributeProperties* attrProperty, const bool enabled) {649// update attribute button650myAttributeButton->setText(attrProperty->getAttrStr().c_str());651myAttributeButton->setHelpText(TLF("Inspect % parent", attrProperty->getAttrStr()).c_str());652myAttributeButton->setTipText(myAttributeButton->getHelpText());653myAttributeButton->setIcon(GUIIconSubSys::getIcon(attrProperty->getTagPropertyParent()->getGUIIcon()));654myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_INSPECTPARENT);655if (enabled) {656myAttributeButton->enable();657} else {658myAttributeButton->disable();659}660myAttributeButton->show();661// hide other elements662myAttributeLabel->hide();663myAttributeToggleEnableCheckButton->hide();664}665666667void668GNEAttributesEditorRow::showAttributeVClass(const GNEAttributeProperties* attrProperty, const bool enabled) {669// update attribute button670myAttributeButton->setText(attrProperty->getAttrStr().c_str());671myAttributeButton->setHelpText(TL("Open dialog for editing vClasses"));672myAttributeButton->setTipText(myAttributeButton->getHelpText());673myAttributeButton->setIcon(nullptr);674myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_ALLOW);675if (enabled) {676myAttributeButton->enable();677} else {678myAttributeButton->disable();679}680myAttributeButton->show();681// hide other elements682myAttributeLabel->hide();683myAttributeToggleEnableCheckButton->hide();684}685686687void688GNEAttributesEditorRow::showAttributeColor(const GNEAttributeProperties* attrProperty, const bool enabled) {689// update attribute button690myAttributeButton->setText(attrProperty->getAttrStr().c_str());691myAttributeButton->setHelpText(TL("Open dialog for editing color"));692myAttributeButton->setTipText(myAttributeButton->getHelpText());693myAttributeButton->setIcon(GUIIconSubSys::getIcon(GUIIcon::COLORWHEEL));694myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_COLOR);695if (enabled) {696myAttributeButton->enable();697} else {698myAttributeButton->disable();699}700myAttributeButton->show();701// hide other elements702myAttributeLabel->hide();703myAttributeToggleEnableCheckButton->hide();704}705706707void708GNEAttributesEditorRow::showAttributeFile(const GNEAttributeProperties* attrProperty, const bool enabled) {709// update attribute button710myAttributeButton->setText(attrProperty->getAttrStr().c_str());711if (attrProperty->isFileOpen()) {712myAttributeButton->setHelpText(TL("Open dialog to select an existent file"));713} else {714myAttributeButton->setHelpText(TL("Open dialog to select or create an existent file"));715}716myAttributeButton->setTipText(myAttributeButton->getHelpText());717myAttributeButton->setIcon(GUIIconSubSys::getIcon(GUIIcon::OPEN));718myAttributeButton->setSelector(MID_GNE_ATTRIBUTESEDITORROW_OPENDIALOG_FILE);719if (enabled) {720myAttributeButton->enable();721} else {722myAttributeButton->disable();723}724myAttributeButton->show();725// hide other elements726myAttributeLabel->hide();727myAttributeToggleEnableCheckButton->hide();728}729730731void732GNEAttributesEditorRow::showAttributeLabel(const GNEAttributeProperties* attrProperty) {733myAttributeLabel->setText(attrProperty->getAttrStr().c_str());734myAttributeLabel->show();735// hide other elements736myAttributeToggleEnableCheckButton->hide();737myAttributeButton->hide();738}739740741void742GNEAttributesEditorRow::hideAllAttributeElements() {743myAttributeLabel->hide();744myAttributeToggleEnableCheckButton->hide();745myAttributeButton->hide();746}747748749void750GNEAttributesEditorRow::showValueCheckButton(const std::string& value,751const bool enabled, const bool computed) {752// first we need to check if all boolean values are equal753bool allValuesEqual = true;754// declare boolean vector755std::vector<bool> booleanVector;756// check if value can be parsed to a boolean vector757if (GNEAttributeCarrier::canParse<std::vector<bool> >(value)) {758booleanVector = GNEAttributeCarrier::parse<std::vector<bool> >(value);759}760// iterate over booleans comparing all element with the first761for (const auto& booleanValue : booleanVector) {762if (booleanValue != booleanVector.front()) {763allValuesEqual = false;764}765}766// use checkbox or textfield depending if all booleans are equal767if (allValuesEqual) {768if (enabled) {769myValueCheckButton->enable();770} else {771myValueCheckButton->disable();772}773// set check button774if ((booleanVector.size() > 0) && booleanVector.front()) {775myValueCheckButton->setCheck(true);776myValueCheckButton->setText("true");777} else {778myValueCheckButton->setCheck(false);779myValueCheckButton->setText("false");780}781// show check button782myValueCheckButton->show();783// hide other value elements784myValueTextField->hide();785myValueComboBox->hide();786myValueLaneUpButton->hide();787myValueLaneDownButton->hide();788} else {789// show value as string790showValueString(value, enabled, computed);791}792}793794795void796GNEAttributesEditorRow::showValueComboBox(const GNEAttributeProperties* attrProperty, const std::string& value,797const bool enabled, const bool computed) {798// first we need to check if all boolean values are equal799bool allValuesEqual = true;800// declare boolean vector801std::vector<std::string> stringVector = GNEAttributeCarrier::parse<std::vector<std::string> >(value);802// iterate over string comparing all element with the first803for (const auto& stringValue : stringVector) {804if (stringValue != stringVector.front()) {805allValuesEqual = false;806}807}808// use checkbox or textfield depending if all booleans are equal809if (allValuesEqual) {810// clear and enable comboBox811myValueComboBox->clearItems();812myValueComboBox->setTextColor(GUIDesignTextColorBlack);813myValueComboBox->setBackColor(GUIDesignBackgroundColorWhite);814if (enabled) {815myValueComboBox->enable();816} else {817myValueComboBox->disable();818}819// fill depeding of ACAttr820if (attrProperty->getAttr() == SUMO_ATTR_VCLASS) {821// add all vClasses with their icons822for (const auto& vClassStr : SumoVehicleClassStrings.getStrings()) {823myValueComboBox->appendIconItem(vClassStr.c_str(), VClassIcons::getVClassIcon(getVehicleClassID(vClassStr)));824}825} else if (attrProperty->isVType()) {826// get ACs827const auto& ACs = myAttributeTable->myFrameParent->getViewNet()->getNet()->getAttributeCarriers();828// fill comboBox with all vTypes and vType distributions sorted by ID829std::map<std::string, GNEDemandElement*> sortedTypes;830for (const auto& type : ACs->getDemandElements().at(SUMO_TAG_VTYPE)) {831sortedTypes[type.second->getID()] = type.second;832}833for (const auto& sortedType : sortedTypes) {834myValueComboBox->appendIconItem(sortedType.first.c_str(), sortedType.second->getACIcon());835}836sortedTypes.clear();837for (const auto& typeDistribution : ACs->getDemandElements().at(SUMO_TAG_VTYPE_DISTRIBUTION)) {838sortedTypes[typeDistribution.second->getID()] = typeDistribution.second;839}840for (const auto& sortedType : sortedTypes) {841myValueComboBox->appendIconItem(sortedType.first.c_str(), sortedType.second->getACIcon());842}843} else if (attrProperty->getAttr() == SUMO_ATTR_ICON) {844// add all POIIcons with their icons845for (const auto& POIIcon : SUMOXMLDefinitions::POIIcons.getValues()) {846myValueComboBox->appendIconItem(SUMOXMLDefinitions::POIIcons.getString(POIIcon).c_str(), POIIcons::getPOIIcon(POIIcon));847}848} else if ((attrProperty->getAttr() == SUMO_ATTR_RIGHT_OF_WAY) && (myAttributeTable->myEditedACs.size() == 1) &&849(attrProperty->getTagPropertyParent()->getTag() == SUMO_TAG_JUNCTION)) {850// special case for junction types851if (myAttributeTable->myEditedACs.front()->getAttribute(SUMO_ATTR_TYPE) == "priority") {852myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::DEFAULT).c_str(), nullptr);853myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::EDGEPRIORITY).c_str(), nullptr);854} else if (myAttributeTable->myEditedACs.front()->getAttribute(SUMO_ATTR_TYPE) == "traffic_light") {855myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::DEFAULT).c_str(), nullptr);856myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::MIXEDPRIORITY).c_str(), nullptr);857myValueComboBox->appendIconItem(SUMOXMLDefinitions::RightOfWayValues.getString(RightOfWay::ALLWAYSTOP).c_str(), nullptr);858} else {859myValueComboBox->disable();860}861} else {862// fill comboBox with discrete values863for (const auto& discreteValue : attrProperty->getDiscreteValues()) {864myValueComboBox->appendIconItem(discreteValue.c_str(), nullptr);865}866}867// set current value (or disable)868const auto index = myValueComboBox->findItem(value.c_str());869if (index < 0) {870if (myValueComboBox->getNumItems() > 0) {871myValueComboBox->setCurrentItem(0);872} else {873myValueComboBox->disable();874}875} else {876myValueComboBox->setCurrentItem(index);877}878// show comboBox button879myValueComboBox->show();880// hide other value elements881myValueTextField->hide();882myValueCheckButton->hide();883myValueLaneUpButton->hide();884myValueLaneDownButton->hide();885} else {886// show value as string887showValueString(value, enabled, computed);888}889}890891892void893GNEAttributesEditorRow::showValueString(const std::string& value, const bool enabled, const bool computed) {894// clear and enable comboBox895myValueTextField->setText(value.c_str());896if (computed) {897myValueTextField->setTextColor(GUIDesignTextColorBlue);898} else {899myValueTextField->setTextColor(GUIDesignTextColorBlack);900}901if (enabled) {902myValueTextField->enable();903} else {904myValueTextField->disable();905}906// show list of values907myValueTextField->show();908// hide other value elements909myValueCheckButton->hide();910myValueComboBox->hide();911}912913914void915GNEAttributesEditorRow::showMoveLaneButtons(const std::string& laneID) {916// retrieve lane917const auto lane = myAttributeTable->myFrameParent->getViewNet()->getNet()->getAttributeCarriers()->retrieveLane(laneID, false);918// check lane919if (lane) {920// check if disable move up921if ((lane->getIndex() + 1) >= (int)lane->getParentEdge()->getChildLanes().size()) {922myValueLaneUpButton->disable();923} else {924myValueLaneUpButton->enable();925}926// check if disable move down927if ((lane->getIndex() - 1) < 0) {928myValueLaneDownButton->disable();929} else {930myValueLaneDownButton->enable();931}932} else {933// if lane doesn't exist, disable both934myValueLaneUpButton->disable();935myValueLaneDownButton->disable();936}937}938939940void941GNEAttributesEditorRow::enableElements(const GNEAttributeProperties* attrProperty, const bool forceDisable) {942const auto& editModes = myAttributeTable->myFrameParent->getViewNet()->getEditModes();943const auto tagProperty = attrProperty->getTagPropertyParent();944// by default we assume that elements are disabled945bool enableElements = false;946if (forceDisable) {947enableElements = false;948} else if (editModes.isCurrentSupermodeNetwork()) {949if (tagProperty->isNetworkElement() || tagProperty->isAdditionalElement()) {950enableElements = true;951} else if ((tagProperty->getTag() == SUMO_TAG_TAZSOURCE) || (tagProperty->getTag() == SUMO_TAG_TAZSINK)) {952enableElements = true;953}954} else if (editModes.isCurrentSupermodeDemand() && tagProperty->isDemandElement()) {955enableElements = true;956} else if (editModes.isCurrentSupermodeData() && (tagProperty->isDataElement() || tagProperty->isMeanData())) {957enableElements = true;958}959if (!enableElements) {960myAttributeToggleEnableCheckButton->disable();961myAttributeButton->disable();962myValueTextField->disable();963myValueComboBox->disable();964myValueCheckButton->disable();965myValueLaneUpButton->disable();966myValueLaneDownButton->disable();967}968}969970971bool972GNEAttributesEditorRow::isAttributeEnabled(const GNEAttributeProperties* attrProperty) const {973if (attrProperty->isAlwaysEnabled()) {974return true;975} else {976for (const auto& AC : myAttributeTable->myEditedACs) {977if (AC->isAttributeEnabled(attrProperty->getAttr())) {978return true;979}980}981return false;982}983}984985/****************************************************************************/986987988