From f40314afc2de7e3edc564b31abcb431207b74eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 3 Sep 2024 17:57:17 +0200 Subject: [PATCH] Implemented remaining Map properties * Introduced a few helper functions to reduce code duplication, like MapProperties::push. * Disabled properties when they are irrelevant. * Finished connecting the signals for the remaining editor factories: StringEditorFactory, IntEditorFactory, FloatEditorFactory, PointEditorFactory, PointFEditorFactory, RectFEditorFactory and ColorEditorFactory. --- src/tiled/propertieswidget.cpp | 236 +++++++++++++++++++++++---------- src/tiled/varianteditor.cpp | 155 +++++++++++++++------- 2 files changed, 274 insertions(+), 117 deletions(-) diff --git a/src/tiled/propertieswidget.cpp b/src/tiled/propertieswidget.cpp index 3515bfc81e..21e1ff3f46 100644 --- a/src/tiled/propertieswidget.cpp +++ b/src/tiled/propertieswidget.cpp @@ -146,45 +146,6 @@ static bool anyObjectHasProperty(const QList &objects, const QString &n return false; } -class MapOrientationProperty : public EnumProperty -{ - Q_OBJECT - -public: - MapOrientationProperty(MapDocument *mapDocument, QObject *parent = nullptr) - : EnumProperty(tr("Orientation"), parent) - , mMapDocument(mapDocument) - { - setEnumNames({ - tr("Orthogonal"), - tr("Isometric"), - tr("Isometric (Staggered)"), - tr("Hexagonal (Staggered)"), - }); - setEnumValues({ - Map::Orthogonal, - Map::Isometric, - Map::Staggered, - Map::Hexagonal, - }); - } - - QVariant value() const override - { - return mMapDocument->map()->orientation(); - } - - void setValue(const QVariant &value) override - { - Map::Orientation orientation = static_cast(value.toInt()); - auto command = new ChangeMapProperty(mMapDocument, orientation); - mMapDocument->undoStack()->push(command); - } - -private: - MapDocument *mMapDocument; -}; - class MapSizeProperty : public AbstractProperty { Q_OBJECT @@ -277,58 +238,128 @@ class MapProperties : public QObject QObject *parent = nullptr) : QObject(parent) , mMapDocument(mapDocument) - , mOrientationProperty(new MapOrientationProperty(mapDocument, this)) , mSizeProperty(new MapSizeProperty(mapDocument, editorFactory, this)) , mTileSizeProperty(new TileSizeProperty(mapDocument, editorFactory, this)) { + mClassProperty = editorFactory->createProperty( + tr("Class"), + [this]() { + return map()->className(); + }, + [this](const QVariant &value) { + push(new ChangeClassName(mMapDocument, { map() }, + value.toString())); + }); + + mOrientationProperty = editorFactory->createProperty( + tr("Orientation"), + [this]() { + return QVariant::fromValue(map()->orientation()); + }, + [this](const QVariant &value) { + auto orientation = static_cast(value.toInt()); + push(new ChangeMapProperty(mMapDocument, orientation)); + }); + mInfiniteProperty = editorFactory->createProperty( tr("Infinite"), [this]() { - return mMapDocument->map()->infinite(); + return map()->infinite(); }, [this](const QVariant &value) { - auto command = new ChangeMapProperty(mMapDocument, - Map::InfiniteProperty, - value.toBool()); - mMapDocument->undoStack()->push(command); + push(new ChangeMapProperty(mMapDocument, + Map::InfiniteProperty, + value.toInt())); }); mHexSideLengthProperty = editorFactory->createProperty( tr("Hex Side Length"), [this]() { - return mMapDocument->map()->hexSideLength(); + return map()->hexSideLength(); }, [this](const QVariant &value) { - auto command = new ChangeMapProperty(mMapDocument, - Map::HexSideLengthProperty, - value.toInt()); - mMapDocument->undoStack()->push(command); + push(new ChangeMapProperty(mMapDocument, + Map::HexSideLengthProperty, + value.toInt())); }); mStaggerAxisProperty = editorFactory->createProperty( tr("Stagger Axis"), [this]() { - return QVariant::fromValue(mMapDocument->map()->staggerAxis()); + return QVariant::fromValue(map()->staggerAxis()); }, [this](const QVariant &value) { - auto command = new ChangeMapProperty(mMapDocument, - Map::StaggerAxisProperty, - value.toInt()); - mMapDocument->undoStack()->push(command); + auto staggerAxis = static_cast(value.toInt()); + push(new ChangeMapProperty(mMapDocument, staggerAxis)); }); mStaggerIndexProperty = editorFactory->createProperty( tr("Stagger Index"), [this]() { - return QVariant::fromValue(mMapDocument->map()->staggerIndex()); + return QVariant::fromValue(map()->staggerIndex()); }, [this](const QVariant &value) { - auto command = new ChangeMapProperty(mMapDocument, - Map::StaggerIndexProperty, - value.toInt()); - mMapDocument->undoStack()->push(command); + auto staggerIndex = static_cast(value.toInt()); + push(new ChangeMapProperty(mMapDocument, staggerIndex)); }); + mParallaxOriginProperty = editorFactory->createProperty( + tr("Parallax Origin"), + [this]() { + return map()->parallaxOrigin(); + }, + [this](const QVariant &value) { + push(new ChangeMapProperty(mMapDocument, value.value())); + }); + + mLayerDataFormatProperty = editorFactory->createProperty( + tr("Layer Data Format"), + [this]() { + return QVariant::fromValue(map()->layerDataFormat()); + }, + [this](const QVariant &value) { + auto layerDataFormat = static_cast(value.toInt()); + push(new ChangeMapProperty(mMapDocument, layerDataFormat)); + }); + + mChunkSizeProperty = editorFactory->createProperty( + tr("Output Chunk Size"), + [this]() { + return map()->chunkSize(); + }, + [this](const QVariant &value) { + push(new ChangeMapProperty(mMapDocument, value.toSize())); + }); + + mRenderOrderProperty = editorFactory->createProperty( + tr("Tile Render Order"), + [this]() { + return QVariant::fromValue(map()->renderOrder()); + }, + [this](const QVariant &value) { + auto renderOrder = static_cast(value.toInt()); + push(new ChangeMapProperty(mMapDocument, renderOrder)); + }); + + mCompressionLevelProperty = editorFactory->createProperty( + tr("Compression Level"), + [this]() { + return map()->compressionLevel(); + }, + [this](const QVariant &value) { + push(new ChangeMapProperty(mMapDocument, value.toInt())); + }); + + mBackgroundColorProperty = editorFactory->createProperty( + tr("Background Color"), + [this]() { + return map()->backgroundColor(); + }, + [this](const QVariant &value) { + push(new ChangeMapProperty(mMapDocument, value.value())); + }); + + updateEnabledState(); connect(mMapDocument, &MapDocument::changed, this, &MapProperties::onMapChanged); } @@ -336,19 +367,24 @@ class MapProperties : public QObject void populateEditor(VariantEditor *editor) { editor->addHeader(tr("Map")); + editor->addProperty(mClassProperty); + editor->addSeparator(); editor->addProperty(mOrientationProperty); editor->addProperty(mSizeProperty); - editor->addProperty(mTileSizeProperty); editor->addProperty(mInfiniteProperty); + editor->addProperty(mTileSizeProperty); editor->addProperty(mHexSideLengthProperty); editor->addProperty(mStaggerAxisProperty); editor->addProperty(mStaggerIndexProperty); - // editor->addProperty(mParallaxOriginProperty); - // editor->addProperty(mLayerDataFormatProperty); - // editor->addProperty(mChunkSizeProperty); - // editor->addProperty(mTileRenderOrderProperty); - // editor->addProperty(mCompressionLevelProperty); - // editor->addProperty(mBackgroundColorProperty); + editor->addSeparator(); + editor->addProperty(mParallaxOriginProperty); + editor->addSeparator(); + editor->addProperty(mLayerDataFormatProperty); + editor->addProperty(mChunkSizeProperty); + editor->addProperty(mCompressionLevelProperty); + editor->addSeparator(); + editor->addProperty(mRenderOrderProperty); + editor->addProperty(mBackgroundColorProperty); } private: @@ -376,19 +412,68 @@ class MapProperties : public QObject emit mStaggerIndexProperty->valueChanged(); break; case Map::ParallaxOriginProperty: + emit mParallaxOriginProperty->valueChanged(); + break; case Map::OrientationProperty: emit mOrientationProperty->valueChanged(); break; case Map::RenderOrderProperty: + emit mRenderOrderProperty->valueChanged(); + break; case Map::BackgroundColorProperty: + emit mBackgroundColorProperty->valueChanged(); + break; case Map::LayerDataFormatProperty: + emit mLayerDataFormatProperty->valueChanged(); + break; case Map::CompressionLevelProperty: + emit mCompressionLevelProperty->valueChanged(); + break; case Map::ChunkSizeProperty: + emit mChunkSizeProperty->valueChanged(); + break; + } + + updateEnabledState(); + } + + void updateEnabledState() + { + const auto orientation = map()->orientation(); + const bool stagger = orientation == Map::Staggered || orientation == Map::Hexagonal; + + mHexSideLengthProperty->setEnabled(orientation == Map::Hexagonal); + mStaggerAxisProperty->setEnabled(stagger); + mStaggerIndexProperty->setEnabled(stagger); + mRenderOrderProperty->setEnabled(orientation == Map::Orthogonal); + mChunkSizeProperty->setEnabled(map()->infinite()); + + switch (map()->layerDataFormat()) { + case Map::XML: + case Map::Base64: + case Map::CSV: + mCompressionLevelProperty->setEnabled(false); + break; + case Map::Base64Gzip: + case Map::Base64Zlib: + case Map::Base64Zstandard: + mCompressionLevelProperty->setEnabled(true); break; } } + void push(QUndoCommand *command) + { + mMapDocument->undoStack()->push(command); + } + + Map *map() const + { + return mMapDocument->map(); + } + MapDocument *mMapDocument; + Property *mClassProperty; Property *mOrientationProperty; Property *mSizeProperty; Property *mTileSizeProperty; @@ -399,7 +484,7 @@ class MapProperties : public QObject Property *mParallaxOriginProperty; Property *mLayerDataFormatProperty; Property *mChunkSizeProperty; - Property *mTileRenderOrderProperty; + Property *mRenderOrderProperty; Property *mCompressionLevelProperty; Property *mBackgroundColorProperty; }; @@ -831,6 +916,21 @@ void PropertiesWidget::registerEditorFactories() tr("Bottom Right"), })); + // We leave out the "Unknown" orientation, because it shouldn't occur here + registerEditorFactory(qMetaTypeId(), + std::make_unique( + QStringList { + tr("Orthogonal"), + tr("Isometric"), + tr("Isometric (Staggered)"), + tr("Hexagonal (Staggered)"), + }, + QList { + Map::Orthogonal, + Map::Isometric, + Map::Staggered, + Map::Hexagonal, + })); registerEditorFactory(qMetaTypeId(), std::make_unique( diff --git a/src/tiled/varianteditor.cpp b/src/tiled/varianteditor.cpp index 081f3f8f95..f1eebbd365 100644 --- a/src/tiled/varianteditor.cpp +++ b/src/tiled/varianteditor.cpp @@ -21,8 +21,6 @@ #include "varianteditor.h" #include "colorbutton.h" -#include "compression.h" -#include "map.h" #include "utils.h" #include "propertyeditorwidgets.h" @@ -71,9 +69,15 @@ class StringEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new QLineEdit(parent); - editor->setText(value.toString()); + auto syncEditor = [=] { + editor->setText(property->value().toString()); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(editor, &QLineEdit::textEdited, property, &Property::setValue); + return editor; } }; @@ -83,9 +87,17 @@ class IntEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new SpinBox(parent); - editor->setValue(value.toInt()); + auto syncEditor = [=] { + const QSignalBlocker blocker(editor); + editor->setValue(property->value().toInt()); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(editor, qOverload(&SpinBox::valueChanged), + property, &Property::setValue); + return editor; } }; @@ -95,9 +107,17 @@ class FloatEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new DoubleSpinBox(parent); - editor->setValue(value.toDouble()); + auto syncEditor = [=] { + const QSignalBlocker blocker(editor); + editor->setValue(property->value().toDouble()); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(editor, qOverload(&DoubleSpinBox::valueChanged), + property, &Property::setValue); + return editor; } }; @@ -108,7 +128,7 @@ class BoolEditorFactory : public EditorFactory QWidget *createEditor(Property *property, QWidget *parent) override { auto editor = new QCheckBox(parent); - auto syncEditor = [=]() { + auto syncEditor = [=] { const QSignalBlocker blocker(editor); bool checked = property->value().toBool(); editor->setChecked(checked); @@ -131,7 +151,6 @@ class PointEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new QWidget(parent); auto horizontalLayout = new QHBoxLayout(editor); horizontalLayout->setContentsMargins(QMargins()); @@ -150,8 +169,23 @@ class PointEditorFactory : public EditorFactory yLabel->setBuddy(ySpinBox); horizontalLayout->addWidget(ySpinBox, 1); - xSpinBox->setValue(value.toPoint().x()); - ySpinBox->setValue(value.toPoint().y()); + auto syncEditor = [=] { + const QSignalBlocker xBlocker(xSpinBox); + const QSignalBlocker yBlocker(ySpinBox); + const auto point = property->value().toPoint(); + xSpinBox->setValue(point.x()); + ySpinBox->setValue(point.y()); + }; + auto syncProperty = [=] { + property->setValue(QPoint(xSpinBox->value(), ySpinBox->value())); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(xSpinBox, qOverload(&SpinBox::valueChanged), + property, syncProperty); + QObject::connect(ySpinBox, qOverload(&SpinBox::valueChanged), + property, syncProperty); return editor; } @@ -162,7 +196,6 @@ class PointFEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new QWidget(parent); auto horizontalLayout = new QHBoxLayout(editor); horizontalLayout->setContentsMargins(QMargins()); @@ -181,8 +214,23 @@ class PointFEditorFactory : public EditorFactory yLabel->setBuddy(ySpinBox); horizontalLayout->addWidget(ySpinBox, 1); - xSpinBox->setValue(value.toPointF().x()); - ySpinBox->setValue(value.toPointF().y()); + auto syncEditor = [=] { + const QSignalBlocker xBlocker(xSpinBox); + const QSignalBlocker yBlocker(ySpinBox); + const auto point = property->value().toPointF(); + xSpinBox->setValue(point.x()); + ySpinBox->setValue(point.y()); + }; + auto syncProperty = [=] { + property->setValue(QPointF(xSpinBox->value(), ySpinBox->value())); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(xSpinBox, qOverload(&DoubleSpinBox::valueChanged), + property, syncProperty); + QObject::connect(ySpinBox, qOverload(&DoubleSpinBox::valueChanged), + property, syncProperty); return editor; } @@ -195,7 +243,7 @@ class SizeEditorFactory : public EditorFactory QWidget *createEditor(Property *property, QWidget *parent) override { auto editor = new SizeEdit(parent); - auto syncEditor = [property, editor]() { + auto syncEditor = [property, editor] { const QSignalBlocker blocker(editor); editor->setValue(property->value().toSize()); }; @@ -203,7 +251,7 @@ class SizeEditorFactory : public EditorFactory QObject::connect(property, &Property::valueChanged, editor, syncEditor); QObject::connect(editor, &SizeEdit::valueChanged, property, - [property, editor]() { + [property, editor] { property->setValue(editor->value()); }); @@ -216,7 +264,6 @@ class RectFEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new QWidget(parent); auto gridLayout = new QGridLayout(editor); gridLayout->setContentsMargins(QMargins()); @@ -252,11 +299,34 @@ class RectFEditorFactory : public EditorFactory heightLabel->setBuddy(heightSpinBox); gridLayout->addWidget(heightSpinBox, 1, 3); - const auto rect = value.toRectF(); - xSpinBox->setValue(rect.x()); - ySpinBox->setValue(rect.y()); - widthSpinBox->setValue(rect.width()); - heightSpinBox->setValue(rect.height()); + auto syncEditor = [=] { + const QSignalBlocker xBlocker(xSpinBox); + const QSignalBlocker yBlocker(ySpinBox); + const QSignalBlocker widthBlocker(widthSpinBox); + const QSignalBlocker heightBlocker(heightSpinBox); + const auto rect = property->value().toRectF(); + xSpinBox->setValue(rect.x()); + ySpinBox->setValue(rect.y()); + widthSpinBox->setValue(rect.width()); + heightSpinBox->setValue(rect.height()); + }; + auto syncProperty = [=] { + property->setValue(QRectF(xSpinBox->value(), + ySpinBox->value(), + widthSpinBox->value(), + heightSpinBox->value())); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(xSpinBox, qOverload(&DoubleSpinBox::valueChanged), + property, syncProperty); + QObject::connect(ySpinBox, qOverload(&DoubleSpinBox::valueChanged), + property, syncProperty); + QObject::connect(widthSpinBox, qOverload(&DoubleSpinBox::valueChanged), + property, syncProperty); + QObject::connect(heightSpinBox, qOverload(&DoubleSpinBox::valueChanged), + property, syncProperty); return editor; } @@ -267,9 +337,19 @@ class ColorEditorFactory : public EditorFactory public: QWidget *createEditor(Property *property, QWidget *parent) override { - auto value = property->value(); auto editor = new ColorButton(parent); - editor->setColor(value.value()); + auto syncEditor = [=] { + const QSignalBlocker blocker(editor); + editor->setColor(property->value().value()); + }; + syncEditor(); + + QObject::connect(property, &Property::valueChanged, editor, syncEditor); + QObject::connect(editor, &ColorButton::colorChanged, property, + [property, editor] { + property->setValue(editor->color()); + }); + return editor; } }; @@ -348,29 +428,6 @@ VariantEditor::VariantEditor(QWidget *parent) // QVariant(10), // QVariant(3.14) // }); - - // addHeader(tr("Map")); - // addProperty(new VariantProperty(tr("Class"), QString())); - // addProperty(new VariantProperty(tr("Orientation"), QVariant::fromValue(Map::Hexagonal))); - // addValue(tr("Class"), QString()); - // addSeparator(); - // addValue(tr("Orientation"), QVariant::fromValue(Map::Hexagonal)); - // addValue(tr("Infinite"), false); - // addValue(tr("Map Size"), QSize(20, 20)); - // addValue(tr("Tile Size"), QSize(14, 12)); - // addValue(tr("Tile Side Length (Hex)"), 6); - // addValue(tr("Stagger Axis"), QVariant::fromValue(Map::StaggerY)); - // addValue(tr("Stagger Index"), QVariant::fromValue(Map::StaggerEven)); - // addSeparator(); - // addValue(tr("Parallax Origin"), QPointF()); - // addSeparator(); - // addValue(tr("Tile Layer Format"), QVariant::fromValue(Map::Base64Zlib)); - // addValue(tr("Output Chunk Size"), QSize(16, 16)); - // addValue(tr("Compression Level"), -1); - // addSeparator(); - // addValue(tr("Tile Render Order"), QVariant::fromValue(Map::RightDown)); - // addValue(tr("Background Color"), QColor()); - // addHeader(tr("Custom Properties")); } void VariantEditor::clear() @@ -489,7 +546,7 @@ QWidget *EnumEditorFactory::createEditor(Property *property, QWidget *parent) editor->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); editor->setModel(&m_enumNamesModel); - auto syncEditor = [property, editor, this]() { + auto syncEditor = [property, editor, this] { const QSignalBlocker blocker(editor); if (m_enumValues.isEmpty()) editor->setCurrentIndex(property->value().toInt());