diff --git a/src/libtiled/mapreader.cpp b/src/libtiled/mapreader.cpp index 8981ae6041..34d91a6e21 100644 --- a/src/libtiled/mapreader.cpp +++ b/src/libtiled/mapreader.cpp @@ -137,6 +137,7 @@ class MapReaderPrivate Properties readProperties(); void readProperty(Properties *properties, const ExportContext &context); + QVariant readPropertyValue(const ExportContext &context); MapReader *p; @@ -1446,6 +1447,13 @@ void MapReaderPrivate::readProperty(Properties *properties, const ExportContext const QXmlStreamAttributes atts = xml.attributes(); QString propertyName = atts.value(QLatin1String("name")).toString(); + properties->insert(propertyName, readPropertyValue(context)); +} + +QVariant MapReaderPrivate::readPropertyValue(const ExportContext &context) +{ + const QXmlStreamAttributes atts = xml.attributes(); + ExportValue exportValue; exportValue.typeName = atts.value(QLatin1String("type")).toString(); exportValue.propertyTypeName = atts.value(QLatin1String("propertytype")).toString(); @@ -1453,6 +1461,8 @@ void MapReaderPrivate::readProperty(Properties *properties, const ExportContext const QString propertyValue = atts.value(QLatin1String("value")).toString(); exportValue.value = propertyValue; + QVariantList values; + while (xml.readNext() != QXmlStreamReader::Invalid) { if (xml.isEndElement()) { break; @@ -1462,12 +1472,17 @@ void MapReaderPrivate::readProperty(Properties *properties, const ExportContext } else if (xml.isStartElement()) { if (xml.name() == QLatin1String("properties")) exportValue.value = readProperties(); + else if (xml.name() == QLatin1String("item")) + values.append(readPropertyValue(context)); else readUnknownElement(); } } - properties->insert(propertyName, context.toPropertyValue(exportValue)); + if (exportValue.typeName == QLatin1String("list")) + exportValue.value = values; + + return context.toPropertyValue(exportValue); } diff --git a/src/libtiled/maptovariantconverter.cpp b/src/libtiled/maptovariantconverter.cpp index d79ae4d43a..810df39493 100644 --- a/src/libtiled/maptovariantconverter.cpp +++ b/src/libtiled/maptovariantconverter.cpp @@ -816,27 +816,44 @@ void MapToVariantConverter::addProperties(QVariantMap &variantMap, // TODO: Support custom property types in json1? Maybe with a customPropertyTypesMap... } - variantMap[QStringLiteral("properties")] = propertiesMap; - variantMap[QStringLiteral("propertytypes")] = propertyTypesMap; + variantMap[QStringLiteral("properties")] = std::move(propertiesMap); + variantMap[QStringLiteral("propertytypes")] = std::move(propertyTypesMap); } else { QVariantList propertiesVariantList; Properties::const_iterator it = properties.constBegin(); Properties::const_iterator it_end = properties.constEnd(); for (; it != it_end; ++it) { - const auto exportValue = context.toExportValue(it.value()); - - QVariantMap propertyVariantMap; + QVariantMap propertyVariantMap = toVariantMap(it.value(), context); propertyVariantMap[QStringLiteral("name")] = it.key(); - propertyVariantMap[QStringLiteral("value")] = exportValue.value; - propertyVariantMap[QStringLiteral("type")] = exportValue.typeName; - if (!exportValue.propertyTypeName.isEmpty()) - propertyVariantMap[QStringLiteral("propertytype")] = exportValue.propertyTypeName; - - propertiesVariantList << propertyVariantMap; + propertiesVariantList << std::move(propertyVariantMap); } variantMap[QStringLiteral("properties")] = propertiesVariantList; } } + +QVariantMap MapToVariantConverter::toVariantMap(const QVariant &propertyValue, const ExportContext &context) const +{ + const auto exportValue = context.toExportValue(propertyValue); + QVariantMap propertyVariantMap; + + propertyVariantMap[QStringLiteral("type")] = exportValue.typeName; + if (!exportValue.propertyTypeName.isEmpty()) + propertyVariantMap[QStringLiteral("propertytype")] = exportValue.propertyTypeName; + + if (exportValue.typeName == QLatin1String("list")) { + QVariantList valuesVariantList; + + const QVariantList values = propertyValue.toList(); + for (const QVariant &value : values) + valuesVariantList << toVariantMap(value, context); + + propertyVariantMap[QStringLiteral("value")] = std::move(valuesVariantList); + } else { + propertyVariantMap[QStringLiteral("value")] = exportValue.value; + } + + return propertyVariantMap; +} diff --git a/src/libtiled/maptovariantconverter.h b/src/libtiled/maptovariantconverter.h index 8f3bfd5f03..fb6ed38bd3 100644 --- a/src/libtiled/maptovariantconverter.h +++ b/src/libtiled/maptovariantconverter.h @@ -86,6 +86,7 @@ class TILEDSHARED_EXPORT MapToVariantConverter void addProperties(QVariantMap &variantMap, const Properties &properties) const; + QVariantMap toVariantMap(const QVariant &propertyValue, const ExportContext &context) const; int mVersion; QDir mDir; diff --git a/src/libtiled/mapwriter.cpp b/src/libtiled/mapwriter.cpp index 2a9926ab68..7007652158 100644 --- a/src/libtiled/mapwriter.cpp +++ b/src/libtiled/mapwriter.cpp @@ -94,6 +94,8 @@ class MapWriterPrivate void writeGroupLayer(QXmlStreamWriter &w, const GroupLayer &groupLayer); void writeProperties(QXmlStreamWriter &w, const Properties &properties); + void writeExportValue(QXmlStreamWriter &w, + const QVariant &value, const ExportContext &context); void writeImage(QXmlStreamWriter &w, const QUrl &source, const QPixmap &image, @@ -902,30 +904,48 @@ void MapWriterPrivate::writeProperties(QXmlStreamWriter &w, w.writeStartElement(QStringLiteral("property")); w.writeAttribute(QStringLiteral("name"), it.key()); - const auto exportValue = context.toExportValue(it.value()); - if (exportValue.typeName != QLatin1String("string")) - w.writeAttribute(QStringLiteral("type"), exportValue.typeName); - if (!exportValue.propertyTypeName.isEmpty()) - w.writeAttribute(QStringLiteral("propertytype"), exportValue.propertyTypeName); - - // For class property values, write out the original value, so that the - // propertytype attribute can also be written for their members where - // applicable. - if (exportValue.value.userType() == QMetaType::QVariantMap) { - writeProperties(w, it.value().value().value.toMap()); - } else { - const QString value = exportValue.value.toString(); - - if (value.contains(QLatin1Char('\n'))) - w.writeCharacters(value); - else - w.writeAttribute(QStringLiteral("value"), value); - } + writeExportValue(w, it.value(), context); - w.writeEndElement(); + w.writeEndElement(); // } - w.writeEndElement(); + w.writeEndElement(); // +} + +void MapWriterPrivate::writeExportValue(QXmlStreamWriter &w, + const QVariant &value, + const ExportContext &context) +{ + const auto exportValue = context.toExportValue(value); + if (exportValue.typeName != QLatin1String("string")) + w.writeAttribute(QStringLiteral("type"), exportValue.typeName); + if (!exportValue.propertyTypeName.isEmpty()) + w.writeAttribute(QStringLiteral("propertytype"), exportValue.propertyTypeName); + + switch (exportValue.value.userType()) { + case QMetaType::QVariantList: { + const auto values = exportValue.value.toList(); + for (const QVariant &value : values) { + w.writeStartElement(QStringLiteral("item")); + writeExportValue(w, value, context); + w.writeEndElement(); // + } + break; + } + case QMetaType::QVariantMap: + // Write out the original value, so that the propertytype attribute + // can also be written for their members where applicable. + writeProperties(w, value.value().value.toMap()); + break; + default: + const QString value = exportValue.value.toString(); + + if (value.contains(QLatin1Char('\n'))) + w.writeCharacters(value); + else + w.writeAttribute(QStringLiteral("value"), value); + break; + } } void MapWriterPrivate::writeImage(QXmlStreamWriter &w, diff --git a/src/libtiled/object.h b/src/libtiled/object.h index 52b8592657..ace92a93e1 100644 --- a/src/libtiled/object.h +++ b/src/libtiled/object.h @@ -126,6 +126,8 @@ class TILEDSHARED_EXPORT Object /** * Returns the type of the object's \a name property, as a string. + * + * This function exists only for the Python plugin. */ QString propertyType(const QString &name) const { return typeName(mProperties.value(name)); } diff --git a/src/libtiled/properties.cpp b/src/libtiled/properties.cpp index d8ab1e536c..b8f7b6d338 100644 --- a/src/libtiled/properties.cpp +++ b/src/libtiled/properties.cpp @@ -186,21 +186,6 @@ void aggregateProperties(AggregatedProperties &aggregated, const Properties &pro } } -int propertyValueId() -{ - return qMetaTypeId(); -} - -int filePathTypeId() -{ - return qMetaTypeId(); -} - -int objectRefTypeId() -{ - return qMetaTypeId(); -} - QString typeToName(int type) { // We can't handle the PropertyValue purely by its type ID, since we need to @@ -216,6 +201,8 @@ QString typeToName(int type) return QStringLiteral("color"); case QMetaType::QVariantMap: return QStringLiteral("class"); + case QMetaType::QVariantList: + return QStringLiteral("list"); default: if (type == filePathTypeId()) @@ -240,6 +227,8 @@ static int nameToType(const QString &name) return objectRefTypeId(); if (name == QLatin1String("class")) return QMetaType::QVariantMap; + if (name == QLatin1String("list")) + return QMetaType::QVariantList; return QVariant::nameToType(name.toLatin1().constData()); } @@ -252,6 +241,14 @@ QString typeName(const QVariant &value) return typeToName(value.userType()); } +QString userTypeName(const QVariant &value) +{ + if (value.userType() == propertyValueId()) + return value.value().typeName(); + + return typeToName(value.userType()); +} + const PropertyType *PropertyValue::type() const { return Object::propertyTypes().findTypeById(typeId); @@ -299,6 +296,7 @@ ExportValue ExportContext::toExportValue(const QVariant &value) const } else if (metaType == objectRefTypeId()) { exportValue.value = ObjectRef::toInt(value.value()); } else { + // Other values, including lists, do not need special handling here exportValue.value = value; } @@ -333,6 +331,9 @@ QVariant ExportContext::toPropertyValue(const QVariant &value, int metaType) con if (metaType == QMetaType::QVariantMap || metaType == propertyValueId()) return value; // should be covered by property type + if (metaType == QMetaType::QVariantList) + return value; // list elements should be converted individually + if (metaType == filePathTypeId()) { const QUrl url = toUrl(value.toString(), mPath); return QVariant::fromValue(FilePath { url }); @@ -355,6 +356,35 @@ void initializeMetatypes() QMetaType::registerConverter(&FilePath::fromString); } +QVariantList possiblePropertyValues(const ClassPropertyType *parentClassType) +{ + QVariantList values; + + values.append(false); // bool + values.append(QColor()); // color + values.append(0.0); // float + values.append(QVariant::fromValue(FilePath())); // file + values.append(0); // int + values.append(QVariant::fromValue(ObjectRef())); // object + values.append(QString()); // string + values.append(QVariant(QVariantList())); // list + + for (const auto propertyType : Object::propertyTypes()) { + // Avoid suggesting the creation of circular dependencies between types + if (parentClassType && !parentClassType->canAddMemberOfType(propertyType)) + continue; + + // Avoid suggesting classes not meant to be used as property value + if (propertyType->isClass()) + if (!static_cast(propertyType)->isPropertyValueType()) + continue; + + values.append(propertyType->wrap(propertyType->defaultValue())); + } + + return values; +} + } // namespace Tiled #include "moc_properties.cpp" diff --git a/src/libtiled/properties.h b/src/libtiled/properties.h index 5928623048..6281eef8de 100644 --- a/src/libtiled/properties.h +++ b/src/libtiled/properties.h @@ -85,7 +85,7 @@ class TILEDSHARED_EXPORT ObjectRef Q_PROPERTY(int id MEMBER id) public: - int id; + int id = 0; bool operator==(const ObjectRef &o) const { return id == o.id; } @@ -179,13 +179,16 @@ TILEDSHARED_EXPORT void mergeProperties(Properties &target, const Properties &so TILEDSHARED_EXPORT QJsonArray propertiesToJson(const Properties &properties, const ExportContext &context = ExportContext()); TILEDSHARED_EXPORT Properties propertiesFromJson(const QJsonArray &json, const ExportContext &context = ExportContext()); -TILEDSHARED_EXPORT int propertyValueId(); -TILEDSHARED_EXPORT int filePathTypeId(); -TILEDSHARED_EXPORT int objectRefTypeId(); +constexpr int propertyValueId() { return qMetaTypeId(); } +constexpr int filePathTypeId() { return qMetaTypeId(); } +constexpr int objectRefTypeId() { return qMetaTypeId(); } TILEDSHARED_EXPORT QString typeToName(int type); TILEDSHARED_EXPORT QString typeName(const QVariant &value); +TILEDSHARED_EXPORT QString userTypeName(const QVariant &value); TILEDSHARED_EXPORT void initializeMetatypes(); +TILEDSHARED_EXPORT QVariantList possiblePropertyValues(const ClassPropertyType *parentClassType = nullptr); + } // namespace Tiled diff --git a/src/libtiled/varianttomapconverter.cpp b/src/libtiled/varianttomapconverter.cpp index 972d2a6145..67ff72942c 100644 --- a/src/libtiled/varianttomapconverter.cpp +++ b/src/libtiled/varianttomapconverter.cpp @@ -190,7 +190,26 @@ Properties VariantToMapConverter::toProperties(const QVariant &propertiesVariant exportValue.typeName = propertyVariantMap[QStringLiteral("type")].toString(); exportValue.propertyTypeName = propertyVariantMap[QStringLiteral("propertytype")].toString(); - properties[propertyName] = context.toPropertyValue(exportValue); + auto &value = properties[propertyName]; + + if (exportValue.typeName == QLatin1String("list")) { + const QVariantList values = exportValue.value.toList(); + QVariantList convertedList; + convertedList.reserve(values.size()); + for (const QVariant &value : values) { + const QVariantMap valueVariantMap = value.toMap(); + ExportValue itemValue; + itemValue.value = valueVariantMap[QStringLiteral("value")]; + itemValue.typeName = valueVariantMap[QStringLiteral("type")].toString(); + itemValue.propertyTypeName = valueVariantMap[QStringLiteral("propertytype")].toString(); + + // todo: this doesn't support lists of lists + convertedList.append(context.toPropertyValue(itemValue)); + } + value = convertedList; + } else { + value = context.toPropertyValue(exportValue); + } } return properties; diff --git a/src/tiled/libtilededitor.qbs b/src/tiled/libtilededitor.qbs index 58229e2893..1abdc84475 100644 --- a/src/tiled/libtilededitor.qbs +++ b/src/tiled/libtilededitor.qbs @@ -287,6 +287,8 @@ DynamicLibrary { "layermodel.h", "layeroffsettool.cpp", "layeroffsettool.h", + "listedit.cpp", + "listedit.h", "locatorwidget.cpp", "locatorwidget.h", "magicwandtool.h", diff --git a/src/tiled/listedit.cpp b/src/tiled/listedit.cpp new file mode 100644 index 0000000000..40cccccef0 --- /dev/null +++ b/src/tiled/listedit.cpp @@ -0,0 +1,112 @@ +/* + * listedit.h + * Copyright 2024, Thorbjørn Lindeijer + * + * This file is part of Tiled. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "listedit.h" + +#include "properties.h" +#include "propertytypesmodel.h" +#include "utils.h" + +#include +#include +#include +#include + +namespace Tiled { + +ListEdit::ListEdit(QWidget *parent) + : QWidget{parent} +{ + QHBoxLayout *layout = new QHBoxLayout{this}; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + + mLabel = new QLabel{this}; + mLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); + + mAddMenu = new QMenu{this}; + + mAddButton = new QToolButton{this}; + mAddButton->setIcon(QIcon(QStringLiteral(":/images/22/add.png"))); + mAddButton->setText(tr("Add")); + mAddButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + mAddButton->setMenu(mAddMenu); + mAddButton->setPopupMode(QToolButton::MenuButtonPopup); + Utils::setThemeIcon(mAddButton, "add"); + + layout->addWidget(mLabel); + layout->addWidget(mAddButton); + + setFocusProxy(mAddButton); + setFocusPolicy(Qt::StrongFocus); + + connect(mAddButton, &QToolButton::clicked, + this, &ListEdit::addButtonClicked); + connect(mAddMenu, &QMenu::aboutToShow, + this, &ListEdit::populateAddMenu); + + connect(mAddMenu, &QMenu::triggered, this, [this](QAction *action) { + mValue.append(action->data()); + mLabel->setText(valueText(mValue)); + emit valueChanged(mValue); + }); +} + +void ListEdit::setValue(const QVariantList &value) +{ + mValue = value; + mLabel->setText(valueText(value)); +} + +QString ListEdit::valueText(const QVariantList &value) +{ + return value.isEmpty() ? tr("") + : tr("%1 items").arg(value.count()); +} + +void ListEdit::addButtonClicked() +{ + if (mValue.isEmpty()) + return mAddButton->showMenu(); + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + mValue.append(QVariant(mValue.last().metaType())); +#else + mValue.append(QVariant(mValue.last().userType(), nullptr)); +#endif + mLabel->setText(valueText(mValue)); + emit valueChanged(mValue); +} + +void ListEdit::populateAddMenu() +{ + mAddMenu->clear(); + + const QVariantList values = possiblePropertyValues(nullptr); + for (const auto &value : values) { + const QIcon icon = PropertyTypesModel::iconForProperty(value); + auto action = mAddMenu->addAction(icon, userTypeName(value)); + action->setData(value); + } +} + +} // namespace Tiled + +#include "moc_listedit.cpp" diff --git a/src/tiled/listedit.h b/src/tiled/listedit.h new file mode 100644 index 0000000000..62edb0cb1a --- /dev/null +++ b/src/tiled/listedit.h @@ -0,0 +1,60 @@ +/* + * listedit.h + * Copyright 2024, Thorbjørn Lindeijer + * + * This file is part of Tiled. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#pragma once + +#include + +class QLabel; +class QMenu; +class QToolButton; + +namespace Tiled { + +/** + * The widget that enables the user to edit a list property. + */ +class ListEdit final : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QVariantList value READ value WRITE setValue NOTIFY valueChanged FINAL) + +public: + explicit ListEdit(QWidget *parent = nullptr); + + const QVariantList &value() const { return mValue; } + void setValue(const QVariantList &value); + + static QString valueText(const QVariantList &value); + +signals: + void valueChanged(const QVariantList &value); + +private: + void addButtonClicked(); + void populateAddMenu(); + + QLabel *mLabel; + QToolButton *mAddButton; + QMenu *mAddMenu; + QVariantList mValue; +}; + +} // namespace Tiled diff --git a/src/tiled/propertiesview.cpp b/src/tiled/propertiesview.cpp index 18022825b2..402f8aa244 100644 --- a/src/tiled/propertiesview.cpp +++ b/src/tiled/propertiesview.cpp @@ -21,9 +21,10 @@ #include "propertiesview.h" #include "fileedit.h" +#include "listedit.h" +#include "propertyeditorwidgets.h" #include "textpropertyedit.h" #include "utils.h" -#include "propertyeditorwidgets.h" #include #include @@ -284,8 +285,7 @@ QWidget *IntProperty::createEditor(QWidget *parent) const QSignalBlocker blocker(spinBox); spinBox->setValue(value()); }); - connect(spinBox, qOverload(&SpinBox::valueChanged), - this, &IntProperty::setValue); + connect(spinBox, &SpinBox::valueChanged, this, &IntProperty::setValue); return widget; } @@ -304,7 +304,7 @@ QWidget *FloatProperty::createEditor(QWidget *parent) syncEditor(); connect(this, &Property::valueChanged, editor, syncEditor); - connect(editor, qOverload(&DoubleSpinBox::valueChanged), + connect(editor, &DoubleSpinBox::valueChanged, this, &FloatProperty::setValue); return editor; @@ -426,6 +426,23 @@ QWidget *SizeFProperty::createEditor(QWidget *parent) return editor; } +QWidget *VariantListProperty::createEditor(QWidget *parent) +{ + auto editor = new ListEdit(parent); + auto syncEditor = [this, editor] { + const QSignalBlocker blocker(editor); + editor->setValue(value()); + }; + syncEditor(); + + connect(this, &Property::valueChanged, editor, syncEditor); + connect(editor, &ListEdit::valueChanged, this, [this, editor] { + setValue(editor->value()); + }); + + return editor; +} + QWidget *RectProperty::createEditor(QWidget *parent) { auto editor = new RectEdit(parent); @@ -575,7 +592,7 @@ QWidget *FontProperty::createEditor(QWidget *parent) connect(this, &Property::valueChanged, fontComboBox, syncEditor); connect(fontComboBox, &QFontComboBox::currentFontChanged, this, syncProperty); - connect(sizeSpinBox, qOverload(&QSpinBox::valueChanged), this, syncProperty); + connect(sizeSpinBox, &QSpinBox::valueChanged, this, syncProperty); connect(bold, &QAbstractButton::toggled, this, syncProperty); connect(italic, &QAbstractButton::toggled, this, syncProperty); connect(underline, &QAbstractButton::toggled, this, syncProperty); @@ -629,8 +646,8 @@ QWidget *QtAlignmentProperty::createEditor(QWidget *parent) syncEditor(); connect(this, &Property::valueChanged, editor, syncEditor); - connect(horizontalComboBox, qOverload(&QComboBox::currentIndexChanged), this, syncProperty); - connect(verticalComboBox, qOverload(&QComboBox::currentIndexChanged), this, syncProperty); + connect(horizontalComboBox, &QComboBox::currentIndexChanged, this, syncProperty); + connect(verticalComboBox, &QComboBox::currentIndexChanged, this, syncProperty); return editor; } @@ -653,7 +670,7 @@ QWidget *BaseEnumProperty::createEnumEditor(QWidget *parent) syncEditor(); QObject::connect(this, &Property::valueChanged, editor, syncEditor); - QObject::connect(editor, qOverload(&QComboBox::currentIndexChanged), this, + QObject::connect(editor, &QComboBox::currentIndexChanged, this, [editor, this] { setValue(editor->currentData().toInt()); }); @@ -787,6 +804,8 @@ Property *createVariantProperty(const QString &name, return createTypedProperty(name, get, set); case QMetaType::QSizeF: return createTypedProperty(name, get, set); + case QMetaType::QVariantList: + return createTypedProperty(name, get, set); default: if (type == qMetaTypeId()) return createTypedProperty(name, get, set); diff --git a/src/tiled/propertiesview.h b/src/tiled/propertiesview.h index fbfc67076f..bd2027694d 100644 --- a/src/tiled/propertiesview.h +++ b/src/tiled/propertiesview.h @@ -403,6 +403,12 @@ struct SizeFProperty : PropertyTemplate QWidget *createEditor(QWidget *parent) override; }; +struct VariantListProperty : PropertyTemplate +{ + using PropertyTemplate::PropertyTemplate; + QWidget *createEditor(QWidget *parent) override; +}; + struct RectProperty : PropertyTemplate { Q_OBJECT diff --git a/src/tiled/propertyeditorwidgets.cpp b/src/tiled/propertyeditorwidgets.cpp index ccf5d42023..5f2756bb9b 100644 --- a/src/tiled/propertyeditorwidgets.cpp +++ b/src/tiled/propertyeditorwidgets.cpp @@ -412,8 +412,8 @@ SizeEdit::SizeEdit(QWidget *parent) { m_heightLabel, m_heightSpinBox }, }, this); - connect(m_widthSpinBox, qOverload(&QSpinBox::valueChanged), this, &SizeEdit::valueChanged); - connect(m_heightSpinBox, qOverload(&QSpinBox::valueChanged), this, &SizeEdit::valueChanged); + connect(m_widthSpinBox, &QSpinBox::valueChanged, this, &SizeEdit::valueChanged); + connect(m_heightSpinBox, &QSpinBox::valueChanged, this, &SizeEdit::valueChanged); } void SizeEdit::setValue(const QSize &size) @@ -453,8 +453,8 @@ SizeFEdit::SizeFEdit(QWidget *parent) { m_heightLabel, m_heightSpinBox }, }, this); - connect(m_widthSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &SizeFEdit::valueChanged); - connect(m_heightSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &SizeFEdit::valueChanged); + connect(m_widthSpinBox, &QDoubleSpinBox::valueChanged, this, &SizeFEdit::valueChanged); + connect(m_heightSpinBox, &QDoubleSpinBox::valueChanged, this, &SizeFEdit::valueChanged); } void SizeFEdit::setValue(const QSizeF &size) @@ -482,8 +482,8 @@ PointEdit::PointEdit(QWidget *parent) { m_yLabel, m_ySpinBox }, }, this); - connect(m_xSpinBox, qOverload(&QSpinBox::valueChanged), this, &PointEdit::valueChanged); - connect(m_ySpinBox, qOverload(&QSpinBox::valueChanged), this, &PointEdit::valueChanged); + connect(m_xSpinBox, &QSpinBox::valueChanged, this, &PointEdit::valueChanged); + connect(m_ySpinBox, &QSpinBox::valueChanged, this, &PointEdit::valueChanged); } void PointEdit::setValue(const QPoint &point) @@ -517,8 +517,8 @@ PointFEdit::PointFEdit(QWidget *parent) { m_yLabel, m_ySpinBox }, }, this); - connect(m_xSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &PointFEdit::valueChanged); - connect(m_ySpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &PointFEdit::valueChanged); + connect(m_xSpinBox, &QDoubleSpinBox::valueChanged, this, &PointFEdit::valueChanged); + connect(m_ySpinBox, &QDoubleSpinBox::valueChanged, this, &PointFEdit::valueChanged); } void PointFEdit::setValue(const QPointF &point) @@ -561,10 +561,10 @@ RectEdit::RectEdit(QWidget *parent) m_widthSpinBox->setMinimum(0); m_heightSpinBox->setMinimum(0); - connect(m_xSpinBox, qOverload(&QSpinBox::valueChanged), this, &RectEdit::valueChanged); - connect(m_ySpinBox, qOverload(&QSpinBox::valueChanged), this, &RectEdit::valueChanged); - connect(m_widthSpinBox, qOverload(&QSpinBox::valueChanged), this, &RectEdit::valueChanged); - connect(m_heightSpinBox, qOverload(&QSpinBox::valueChanged), this, &RectEdit::valueChanged); + connect(m_xSpinBox, &QSpinBox::valueChanged, this, &RectEdit::valueChanged); + connect(m_ySpinBox, &QSpinBox::valueChanged, this, &RectEdit::valueChanged); + connect(m_widthSpinBox, &QSpinBox::valueChanged, this, &RectEdit::valueChanged); + connect(m_heightSpinBox, &QSpinBox::valueChanged, this, &RectEdit::valueChanged); } void RectEdit::setValue(const QRect &rect) @@ -619,10 +619,10 @@ RectFEdit::RectFEdit(QWidget *parent) { m_heightLabel, m_heightSpinBox }, }, this); - connect(m_xSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &RectFEdit::valueChanged); - connect(m_ySpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &RectFEdit::valueChanged); - connect(m_widthSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &RectFEdit::valueChanged); - connect(m_heightSpinBox, qOverload(&QDoubleSpinBox::valueChanged), this, &RectFEdit::valueChanged); + connect(m_xSpinBox, &QDoubleSpinBox::valueChanged, this, &RectFEdit::valueChanged); + connect(m_ySpinBox, &QDoubleSpinBox::valueChanged, this, &RectFEdit::valueChanged); + connect(m_widthSpinBox, &QDoubleSpinBox::valueChanged, this, &RectFEdit::valueChanged); + connect(m_heightSpinBox, &QDoubleSpinBox::valueChanged, this, &RectFEdit::valueChanged); } void RectFEdit::setValue(const QRectF &rect) diff --git a/src/tiled/propertytypeseditor.cpp b/src/tiled/propertytypeseditor.cpp index 54ab4e7dc6..fabb11bcb1 100644 --- a/src/tiled/propertytypeseditor.cpp +++ b/src/tiled/propertytypeseditor.cpp @@ -998,7 +998,7 @@ void PropertyTypesEditor::addEnumProperties() mStorageTypeComboBox = new QComboBox(mUi->groupBox); mStorageTypeComboBox->addItems({ tr("String"), tr("Number") }); - connect(mStorageTypeComboBox, static_cast(&QComboBox::currentIndexChanged), + connect(mStorageTypeComboBox, &QComboBox::currentIndexChanged, this, [this] (int index) { if (index != -1) setStorageType(static_cast(index)); }); mValuesAsFlagsCheckBox = new QCheckBox(tr("Allow multiple values (flags)"), mUi->groupBox); diff --git a/src/tiled/propertytypesmodel.cpp b/src/tiled/propertytypesmodel.cpp index e5b426cc7b..b881a7b00b 100644 --- a/src/tiled/propertytypesmodel.cpp +++ b/src/tiled/propertytypesmodel.cpp @@ -198,17 +198,27 @@ void PropertyTypesModel::importObjectTypes(const QVector &objectType endResetModel(); } +QIcon PropertyTypesModel::iconForProperty(const QVariant &value) +{ + if (value.userType() == propertyValueId()) + if (auto type = value.value().type()) + return iconForPropertyType(type->type); + + static const QIcon plain(QStringLiteral("://images/scalable/property-type-plain.svg")); + return plain; +} + QIcon PropertyTypesModel::iconForPropertyType(PropertyType::Type type) { switch (type) { case PropertyType::PT_Invalid: break; case PropertyType::PT_Class: { - static QIcon classIcon(QStringLiteral("://images/scalable/property-type-class.svg")); + static const QIcon classIcon(QStringLiteral("://images/scalable/property-type-class.svg")); return classIcon; } case PropertyType::PT_Enum: { - static QIcon enumIcon(QStringLiteral("://images/scalable/property-type-enum.svg")); + static const QIcon enumIcon(QStringLiteral("://images/scalable/property-type-enum.svg")); return enumIcon; } } diff --git a/src/tiled/propertytypesmodel.h b/src/tiled/propertytypesmodel.h index 50719c47ea..48ebe37f43 100644 --- a/src/tiled/propertytypesmodel.h +++ b/src/tiled/propertytypesmodel.h @@ -20,7 +20,6 @@ #pragma once -#include "object.h" #include "properties.h" #include "propertytype.h" @@ -57,6 +56,7 @@ class PropertyTypesModel : public QAbstractListModel void importPropertyTypes(PropertyTypes typesToImport); void importObjectTypes(const QVector &objectTypes); + static QIcon iconForProperty(const QVariant &value); static QIcon iconForPropertyType(PropertyType::Type type); signals: diff --git a/src/tiled/variantmapproperty.cpp b/src/tiled/variantmapproperty.cpp index 7d2239aa7e..d5415e2112 100644 --- a/src/tiled/variantmapproperty.cpp +++ b/src/tiled/variantmapproperty.cpp @@ -451,7 +451,6 @@ void VariantMapProperty::emitMemberValueChanged(const QStringList &path, const Q AddValueProperty::AddValueProperty(QObject *parent) : Property(QString(), parent) - , m_plainTypeIcon(QStringLiteral("://images/scalable/property-type-plain.svg")) , m_placeholderText(tr("Property name")) { setActions(Action::AddDisabled); @@ -522,28 +521,10 @@ QWidget *AddValueProperty::createEditor(QWidget *parent) // Create combo box with property types auto typeBox = new ComboBox(parent); - // Add possible types from QVariant - typeBox->addItem(m_plainTypeIcon, typeToName(QMetaType::Bool), false); - typeBox->addItem(m_plainTypeIcon, typeToName(QMetaType::QColor), QColor()); - typeBox->addItem(m_plainTypeIcon, typeToName(QMetaType::Double), 0.0); - typeBox->addItem(m_plainTypeIcon, typeToName(filePathTypeId()), QVariant::fromValue(FilePath())); - typeBox->addItem(m_plainTypeIcon, typeToName(QMetaType::Int), 0); - typeBox->addItem(m_plainTypeIcon, typeToName(objectRefTypeId()), QVariant::fromValue(ObjectRef())); - typeBox->addItem(m_plainTypeIcon, typeToName(QMetaType::QString), QString()); - - for (const auto propertyType : Object::propertyTypes()) { - // Avoid suggesting the creation of circular dependencies between types - if (m_parentClassType && !m_parentClassType->canAddMemberOfType(propertyType)) - continue; - - // Avoid suggesting classes not meant to be used as property value - if (propertyType->isClass()) - if (!static_cast(propertyType)->isPropertyValueType()) - continue; - - const QVariant var = propertyType->wrap(propertyType->defaultValue()); - const QIcon icon = PropertyTypesModel::iconForPropertyType(propertyType->type); - typeBox->addItem(icon, propertyType->name, var); + const QVariantList values = possiblePropertyValues(m_parentClassType); + for (const auto &value : values) { + const QIcon icon = PropertyTypesModel::iconForProperty(value); + typeBox->addItem(icon, userTypeName(value), value); } // Restore previously used type @@ -553,7 +534,7 @@ QWidget *AddValueProperty::createEditor(QWidget *parent) m_value = typeBox->currentData(); - connect(typeBox, qOverload(&QComboBox::currentIndexChanged), this, [=](int index) { + connect(typeBox, &QComboBox::currentIndexChanged, this, [=](int index) { m_value = typeBox->itemData(index); session::propertyType = typeBox->currentText(); }); diff --git a/src/tiled/variantmapproperty.h b/src/tiled/variantmapproperty.h index 84df7037a8..3442113af9 100644 --- a/src/tiled/variantmapproperty.h +++ b/src/tiled/variantmapproperty.h @@ -117,7 +117,6 @@ class AddValueProperty : public Property bool eventFilter(QObject *watched, QEvent *event) override; private: - QIcon m_plainTypeIcon; QString m_placeholderText; QVariant m_value; bool m_hasFocus = false;