From e6ec3745d980cb2c676f9316fcb5f66214d8fd28 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 14 Jun 2024 21:21:07 -0400 Subject: [PATCH 01/19] expose tiled.project.propertyTypes to scripting, starting with some read-only propertie --- src/tiled/editableproject.cpp | 5 ++ src/tiled/editableproject.h | 4 +- src/tiled/libtilededitor.qbs | 2 + src/tiled/scriptmanager.cpp | 2 + src/tiled/scriptpropertytypes.cpp | 58 ++++++++++++++ src/tiled/scriptpropertytypes.h | 125 ++++++++++++++++++++++++++++++ 6 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/tiled/scriptpropertytypes.cpp create mode 100644 src/tiled/scriptpropertytypes.h diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index 4de58c62b4..f94c20dd5d 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -51,6 +51,11 @@ QStringList EditableProject::folders() const return project()->folders(); } +ScriptPropertyTypes *EditableProject::propertyTypes() const +{ + return new ScriptPropertyTypes(project()->propertyTypes()); +} + bool EditableProject::isReadOnly() const { return false; diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index b34c254b5d..41c7d00667 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -23,6 +23,7 @@ #include "editableasset.h" #include "project.h" +#include "scriptpropertytypes.h" #include @@ -38,6 +39,7 @@ class EditableProject final : public EditableAsset Q_PROPERTY(QString automappingRulesFile READ automappingRulesFile) Q_PROPERTY(QString fileName READ fileName) Q_PROPERTY(QStringList folders READ folders) + Q_PROPERTY(ScriptPropertyTypes *propertyTypes READ propertyTypes) public: EditableProject(ProjectDocument *projectDocument, QObject *parent = nullptr); @@ -49,7 +51,7 @@ class EditableProject final : public EditableAsset QString automappingRulesFile() const; QString fileName() const; QStringList folders() const; - + ScriptPropertyTypes *propertyTypes() const; Project *project() const; QSharedPointer createDocument() override; diff --git a/src/tiled/libtilededitor.qbs b/src/tiled/libtilededitor.qbs index c49512b3e3..5f4b627138 100644 --- a/src/tiled/libtilededitor.qbs +++ b/src/tiled/libtilededitor.qbs @@ -458,6 +458,8 @@ DynamicLibrary { "scriptmodule.h", "scriptprocess.cpp", "scriptprocess.h", + "scriptpropertytypes.cpp", + "scriptpropertytypes.h", "selectionrectangle.cpp", "selectionrectangle.h", "selectsametiletool.cpp", diff --git a/src/tiled/scriptmanager.cpp b/src/tiled/scriptmanager.cpp index b630d47ef7..31932d64b1 100644 --- a/src/tiled/scriptmanager.cpp +++ b/src/tiled/scriptmanager.cpp @@ -49,6 +49,7 @@ #include "scriptimage.h" #include "scriptmodule.h" #include "scriptprocess.h" +#include "scriptpropertytypes.h" #include "tilecollisiondock.h" #include "tilelayer.h" #include "tilelayeredit.h" @@ -412,6 +413,7 @@ void ScriptManager::initialize() registerFileInfo(engine); registerGeometry(engine); registerProcess(engine); + registerPropertyTypes(engine); loadExtensions(); } diff --git a/src/tiled/scriptpropertytypes.cpp b/src/tiled/scriptpropertytypes.cpp new file mode 100644 index 0000000000..13410a198d --- /dev/null +++ b/src/tiled/scriptpropertytypes.cpp @@ -0,0 +1,58 @@ +/* + * scriptimage.cpp + * Copyright 2020, 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 "scriptpropertytypes.h" + +namespace Tiled { + +QString ScriptPropertyType::name() const +{ + return mType->name; +} + +size_t ScriptPropertyTypes::count() +{ + return mTypes->count(); +} + +ScriptPropertyType *ScriptPropertyTypes::findTypeByName(const QString &name) +{ + const PropertyType *type = mTypes->findTypeByName(name); + if (!type) + return nullptr; + + if (type->isEnum()) + return new ScriptEnumPropertyType(static_cast(type)); + + if (type->isClass()) + return new ScriptClassPropertyType(static_cast(type)); + + return new ScriptPropertyType(type); +} + +void registerPropertyTypes(QJSEngine *jsEngine) +{ + jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), + jsEngine->newQMetaObject()); +} + +} // namespace Tiled + +#include "moc_scriptpropertytypes.cpp" diff --git a/src/tiled/scriptpropertytypes.h b/src/tiled/scriptpropertytypes.h new file mode 100644 index 0000000000..9404be08fe --- /dev/null +++ b/src/tiled/scriptpropertytypes.h @@ -0,0 +1,125 @@ +/* + * scriptimage.h + * Copyright 2020, 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 "propertytype.h" + +#include +#include + +namespace Tiled { +/** + * Scripting engine wrapper for PropertyType + */ +class ScriptPropertyType : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name) + Q_PROPERTY(bool isClass READ isClass) + Q_PROPERTY(bool isEnum READ isEnum) + Q_PROPERTY(QVariant defaultValue READ defaultValue) + +public: + ScriptPropertyType(const PropertyType *propertyType) + : mType(propertyType) + {} + + QString name() const; + bool isClass() const { return mType->isClass(); } + bool isEnum() const { return mType->isEnum(); } + QVariant defaultValue() { return mType->defaultValue(); } + +private: + const PropertyType *mType; +}; + +class ScriptEnumPropertyType : public ScriptPropertyType +{ + Q_OBJECT + + Q_PROPERTY(StorageType storageType READ storageType) + Q_PROPERTY(QStringList values READ values) + +public: + ScriptEnumPropertyType(const EnumPropertyType *propertyType) + : mEnumType(propertyType), + ScriptPropertyType(propertyType) + {} + // copied from propertytype.h + enum StorageType { + StringValue, + IntValue + }; + Q_ENUM(StorageType); + + StorageType storageType() const { return static_cast(mEnumType->storageType); } + QStringList values() const { return mEnumType->values; } + +private: + const EnumPropertyType *mEnumType; +}; + +class ScriptClassPropertyType : public ScriptPropertyType +{ + Q_OBJECT + Q_PROPERTY(QColor color READ color) + +public: + ScriptClassPropertyType(const ClassPropertyType *propertyType) + : mClassType(propertyType), + ScriptPropertyType(propertyType) + {} + QColor color() const { return mClassType->color; } + // TODO: " No viable overloaded '=' " + // void setColor(const QColor &value) { mClassType->color = value; } + +private: + + const ClassPropertyType *mClassType; +}; + + +/** + * Scripting engine wrapper for SharedPropertyTypes + */ +class ScriptPropertyTypes : public QObject +{ + Q_OBJECT + Q_PROPERTY(size_t count READ count) + +public: + ScriptPropertyTypes(SharedPropertyTypes sharedPropertyTypes) + : mTypes(sharedPropertyTypes) + {} + size_t count(); + Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); + +private: + SharedPropertyTypes mTypes; +}; + +void registerPropertyTypes(QJSEngine *jsEngine); + +} // namespace Tiled + +Q_DECLARE_METATYPE(Tiled::ScriptPropertyTypes*) +Q_DECLARE_METATYPE(Tiled::ScriptPropertyType*) + From cee8eebfd7ecbb07a8104115a5c4cc6436c58f33 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 14 Jun 2024 22:40:26 -0400 Subject: [PATCH 02/19] rename findTypeByName to findByName, starting to add removal of types --- src/libtiled/propertytype.cpp | 15 ++++++++++++ src/libtiled/propertytype.h | 1 + src/tiled/scriptpropertytypes.cpp | 38 +++++++++++++++++++++++++++++-- src/tiled/scriptpropertytypes.h | 16 ++++++++++++- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/libtiled/propertytype.cpp b/src/libtiled/propertytype.cpp index 6ab263eab6..ec7f647453 100644 --- a/src/libtiled/propertytype.cpp +++ b/src/libtiled/propertytype.cpp @@ -529,6 +529,21 @@ const PropertyType *PropertyTypes::findTypeById(int typeId) const return it == mTypes.end() ? nullptr : *it; } +/** + * Returns a pointer to the PropertyType matching the given \a typeId, or + * nullptr if it can't be found. + */ +const int PropertyTypes::findIndexByName(const QString &name) const +{ + if (name.isEmpty()) + return -1; + + for (int i =0; iname == name) + return i; + + return -1; +} /** * Returns a pointer to the PropertyType matching the given \a name and * \a usageFlags, or nullptr if it can't be found. diff --git a/src/libtiled/propertytype.h b/src/libtiled/propertytype.h index 4141a253c4..8d41892a19 100644 --- a/src/libtiled/propertytype.h +++ b/src/libtiled/propertytype.h @@ -201,6 +201,7 @@ class TILEDSHARED_EXPORT PropertyTypes void mergeObjectTypes(const QVector &objectTypes); const PropertyType *findTypeById(int typeId) const; + const int findIndexByName(const QString &name) const; const PropertyType *findTypeByName(const QString &name, int usageFlags = ClassPropertyType::AnyUsage) const; const PropertyType *findPropertyValueType(const QString &name) const; const ClassPropertyType *findClassFor(const QString &name, const Object &object) const; diff --git a/src/tiled/scriptpropertytypes.cpp b/src/tiled/scriptpropertytypes.cpp index 13410a198d..a4dc877653 100644 --- a/src/tiled/scriptpropertytypes.cpp +++ b/src/tiled/scriptpropertytypes.cpp @@ -19,6 +19,9 @@ */ #include "scriptpropertytypes.h" +#include "preferences.h" +#include "project.h" +#include "projectmanager.h" namespace Tiled { @@ -32,9 +35,8 @@ size_t ScriptPropertyTypes::count() return mTypes->count(); } -ScriptPropertyType *ScriptPropertyTypes::findTypeByName(const QString &name) +ScriptPropertyType *ScriptPropertyTypes::toScriptType(const PropertyType *type) const { - const PropertyType *type = mTypes->findTypeByName(name); if (!type) return nullptr; @@ -47,6 +49,38 @@ ScriptPropertyType *ScriptPropertyTypes::findTypeByName(const QString &name) return new ScriptPropertyType(type); } +ScriptPropertyType *ScriptPropertyTypes::findByName(const QString &name) +{ + const PropertyType *type = mTypes->findTypeByName(name); + return toScriptType(type); +} + +void ScriptPropertyTypes::removeByName(const QString &name) +{ + int index = mTypes->findIndexByName(name); + if (index < 0 ) + return + + mTypes->removeAt(index); + applyPropertyChanges(); +} + +// TODO remove if we can implement an iterator +QVectorScriptPropertyTypes::all() const +{ + QVector scriptTypes; + for (const PropertyType *type : *mTypes) + scriptTypes.append(toScriptType(type)); + return scriptTypes; +} + +void ScriptPropertyTypes::applyPropertyChanges() +{ + emit Preferences::instance()->propertyTypesChanged(); + + Project &project = ProjectManager::instance()->project(); + project.save(); +} void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), diff --git a/src/tiled/scriptpropertytypes.h b/src/tiled/scriptpropertytypes.h index 9404be08fe..345526fc55 100644 --- a/src/tiled/scriptpropertytypes.h +++ b/src/tiled/scriptpropertytypes.h @@ -23,6 +23,7 @@ #include "propertytype.h" #include +#include #include namespace Tiled { @@ -104,15 +105,28 @@ class ScriptPropertyTypes : public QObject { Q_OBJECT Q_PROPERTY(size_t count READ count) + Q_PROPERTY(QVector all READ all) public: ScriptPropertyTypes(SharedPropertyTypes sharedPropertyTypes) : mTypes(sharedPropertyTypes) {} size_t count(); - Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); + Q_INVOKABLE void removeByName(const QString &name); + Q_INVOKABLE ScriptPropertyType *findByName(const QString &name); + QVector all() const; + + // TODO: when I don't have a list of ScriptPropertyType, + // how can i make this iterable? + // Enable easy iteration over objects with range-based for + // QList::iterator begin() { return mTypes->begin(); } + // QList::iterator end() { return mTypes->end(); } + // QList::const_iterator begin() const { return mTypes->begin(); } + // QList::const_iterator end() const { return mTypes->end(); } private: + ScriptPropertyType *toScriptType(const PropertyType *type) const; + void applyPropertyChanges(); SharedPropertyTypes mTypes; }; From 687436bcbf5d64c3a867a107fc3e7c4074a214ab Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 14 Jun 2024 23:12:20 -0400 Subject: [PATCH 03/19] try adding iterator to tiled.project.propertyTypes. currently it throws a type error --- src/tiled/scriptpropertytypes.cpp | 9 ++++++++- src/tiled/scriptpropertytypes.h | 20 +++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/tiled/scriptpropertytypes.cpp b/src/tiled/scriptpropertytypes.cpp index a4dc877653..82cc4dacd2 100644 --- a/src/tiled/scriptpropertytypes.cpp +++ b/src/tiled/scriptpropertytypes.cpp @@ -19,7 +19,6 @@ */ #include "scriptpropertytypes.h" -#include "preferences.h" #include "project.h" #include "projectmanager.h" @@ -61,6 +60,7 @@ void ScriptPropertyTypes::removeByName(const QString &name) if (index < 0 ) return + // TODO the type isn't actually being deleted even when index >= 0 mTypes->removeAt(index); applyPropertyChanges(); } @@ -81,6 +81,13 @@ void ScriptPropertyTypes::applyPropertyChanges() Project &project = ProjectManager::instance()->project(); project.save(); } + +void ScriptPropertyTypes::propertyTypesChanged() +{ + mAllScriptTypes.clear(); + for (PropertyType *type : *mTypes) + mAllScriptTypes.append(toScriptType(type)); +} void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), diff --git a/src/tiled/scriptpropertytypes.h b/src/tiled/scriptpropertytypes.h index 345526fc55..6244e4930f 100644 --- a/src/tiled/scriptpropertytypes.h +++ b/src/tiled/scriptpropertytypes.h @@ -20,6 +20,7 @@ #pragma once +#include "preferences.h" #include "propertytype.h" #include @@ -110,23 +111,28 @@ class ScriptPropertyTypes : public QObject public: ScriptPropertyTypes(SharedPropertyTypes sharedPropertyTypes) : mTypes(sharedPropertyTypes) - {} + { + connect(Preferences::instance(), &Preferences::propertyTypesChanged, this, &ScriptPropertyTypes::propertyTypesChanged); + propertyTypesChanged(); + } size_t count(); Q_INVOKABLE void removeByName(const QString &name); Q_INVOKABLE ScriptPropertyType *findByName(const QString &name); QVector all() const; - // TODO: when I don't have a list of ScriptPropertyType, - // how can i make this iterable? + // TODO: how to make this class iterable so you can loop through it to pull up + // each property type? // Enable easy iteration over objects with range-based for - // QList::iterator begin() { return mTypes->begin(); } - // QList::iterator end() { return mTypes->end(); } - // QList::const_iterator begin() const { return mTypes->begin(); } - // QList::const_iterator end() const { return mTypes->end(); } + QList::iterator begin() { return mAllScriptTypes.begin(); } + QList::iterator end() { return mAllScriptTypes.end(); } + QList::const_iterator begin() const { return mAllScriptTypes.begin(); } + QList::const_iterator end() const { return mAllScriptTypes.end(); } private: ScriptPropertyType *toScriptType(const PropertyType *type) const; void applyPropertyChanges(); + void propertyTypesChanged(); + QList mAllScriptTypes; SharedPropertyTypes mTypes; }; From 6572561abce6a8f5a3d833892b2bb6c5f4f15bba Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 15 Jun 2024 14:22:46 -0400 Subject: [PATCH 04/19] remove iterator from ScriptPropertyTypes (use tiled.project.propertyTypes.all instead) and add getter for class property members. getting members of class types does not work though --- src/tiled/scriptpropertytypes.cpp | 6 ------ src/tiled/scriptpropertytypes.h | 19 ++++--------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/tiled/scriptpropertytypes.cpp b/src/tiled/scriptpropertytypes.cpp index 82cc4dacd2..dcc30bd615 100644 --- a/src/tiled/scriptpropertytypes.cpp +++ b/src/tiled/scriptpropertytypes.cpp @@ -82,12 +82,6 @@ void ScriptPropertyTypes::applyPropertyChanges() project.save(); } -void ScriptPropertyTypes::propertyTypesChanged() -{ - mAllScriptTypes.clear(); - for (PropertyType *type : *mTypes) - mAllScriptTypes.append(toScriptType(type)); -} void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), diff --git a/src/tiled/scriptpropertytypes.h b/src/tiled/scriptpropertytypes.h index 6244e4930f..654c87c299 100644 --- a/src/tiled/scriptpropertytypes.h +++ b/src/tiled/scriptpropertytypes.h @@ -83,13 +83,15 @@ class ScriptClassPropertyType : public ScriptPropertyType { Q_OBJECT Q_PROPERTY(QColor color READ color) - + Q_PROPERTY(QVariantMap members READ members) + public: ScriptClassPropertyType(const ClassPropertyType *propertyType) : mClassType(propertyType), ScriptPropertyType(propertyType) {} QColor color() const { return mClassType->color; } + QVariantMap members() const {return mClassType->members; } // TODO: " No viable overloaded '=' " // void setColor(const QColor &value) { mClassType->color = value; } @@ -111,28 +113,15 @@ class ScriptPropertyTypes : public QObject public: ScriptPropertyTypes(SharedPropertyTypes sharedPropertyTypes) : mTypes(sharedPropertyTypes) - { - connect(Preferences::instance(), &Preferences::propertyTypesChanged, this, &ScriptPropertyTypes::propertyTypesChanged); - propertyTypesChanged(); - } + {} size_t count(); Q_INVOKABLE void removeByName(const QString &name); Q_INVOKABLE ScriptPropertyType *findByName(const QString &name); QVector all() const; - // TODO: how to make this class iterable so you can loop through it to pull up - // each property type? - // Enable easy iteration over objects with range-based for - QList::iterator begin() { return mAllScriptTypes.begin(); } - QList::iterator end() { return mAllScriptTypes.end(); } - QList::const_iterator begin() const { return mAllScriptTypes.begin(); } - QList::const_iterator end() const { return mAllScriptTypes.end(); } - private: ScriptPropertyType *toScriptType(const PropertyType *type) const; void applyPropertyChanges(); - void propertyTypesChanged(); - QList mAllScriptTypes; SharedPropertyTypes mTypes; }; From ad9751f3be64c2210892347d56b82cf23a99d971 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 15 Jun 2024 15:19:38 -0400 Subject: [PATCH 05/19] restructure the property types API to make tiled.project.propertyTypes a list of types and move the utility methods for custom types to tiled.project --- src/tiled/editableproject.cpp | 54 ++++++++++- src/tiled/editableproject.h | 13 ++- src/tiled/libtilededitor.qbs | 4 +- src/tiled/scriptmanager.cpp | 2 +- src/tiled/scriptpropertytype.cpp | 40 ++++++++ ...ptpropertytypes.h => scriptpropertytype.h} | 27 +----- src/tiled/scriptpropertytypes.cpp | 93 ------------------- 7 files changed, 102 insertions(+), 131 deletions(-) create mode 100644 src/tiled/scriptpropertytype.cpp rename src/tiled/{scriptpropertytypes.h => scriptpropertytype.h} (80%) delete mode 100644 src/tiled/scriptpropertytypes.cpp diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index f94c20dd5d..5e8a851d2d 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -20,8 +20,8 @@ */ #include "editableproject.h" - #include "projectdocument.h" +#include "projectmanager.h" namespace Tiled { @@ -51,10 +51,6 @@ QStringList EditableProject::folders() const return project()->folders(); } -ScriptPropertyTypes *EditableProject::propertyTypes() const -{ - return new ScriptPropertyTypes(project()->propertyTypes()); -} bool EditableProject::isReadOnly() const { @@ -68,6 +64,54 @@ QSharedPointer EditableProject::createDocument() return nullptr; } + +ScriptPropertyType *EditableProject::toScriptType(const PropertyType *type) const +{ + if (!type) + return nullptr; + + if (type->isEnum()) + return new ScriptEnumPropertyType(static_cast(type)); + + if (type->isClass()) + return new ScriptClassPropertyType(static_cast(type)); + + return new ScriptPropertyType(type); +} + +ScriptPropertyType *EditableProject::findTypeByName(const QString &name) +{ + const PropertyType *type = project()->propertyTypes()->findTypeByName(name); + return toScriptType(type); +} + +void EditableProject::removeTypeByName(const QString &name) +{ + int index = project()->propertyTypes()->findIndexByName(name); + if (index < 0 ) + return + + // TODO the type isn't actually being deleted even when index >= 0 + project()->propertyTypes()->removeAt(index); + applyPropertyChanges(); +} + +QVectorEditableProject::propertyTypes() const +{ + QVector scriptTypes; + for (const PropertyType *type : *project()->propertyTypes()) + scriptTypes.append(toScriptType(type)); + return scriptTypes; +} + +void EditableProject::applyPropertyChanges() +{ + emit Preferences::instance()->propertyTypesChanged(); + + Project &project = ProjectManager::instance()->project(); + project.save(); +} + } // namespace Tiled #include "moc_editableproject.cpp" diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index 41c7d00667..7a26069f8f 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -23,7 +23,7 @@ #include "editableasset.h" #include "project.h" -#include "scriptpropertytypes.h" +#include "scriptpropertytype.h" #include @@ -39,8 +39,7 @@ class EditableProject final : public EditableAsset Q_PROPERTY(QString automappingRulesFile READ automappingRulesFile) Q_PROPERTY(QString fileName READ fileName) Q_PROPERTY(QStringList folders READ folders) - Q_PROPERTY(ScriptPropertyTypes *propertyTypes READ propertyTypes) - + Q_PROPERTY(QVector propertyTypes READ propertyTypes) public: EditableProject(ProjectDocument *projectDocument, QObject *parent = nullptr); @@ -51,10 +50,16 @@ class EditableProject final : public EditableAsset QString automappingRulesFile() const; QString fileName() const; QStringList folders() const; - ScriptPropertyTypes *propertyTypes() const; Project *project() const; QSharedPointer createDocument() override; + + Q_INVOKABLE void removeTypeByName(const QString &name); + Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); + QVector propertyTypes() const; +private: + ScriptPropertyType *toScriptType(const PropertyType *type) const; + void applyPropertyChanges(); }; inline Project *EditableProject::project() const diff --git a/src/tiled/libtilededitor.qbs b/src/tiled/libtilededitor.qbs index 5f4b627138..d6a5d6c5cf 100644 --- a/src/tiled/libtilededitor.qbs +++ b/src/tiled/libtilededitor.qbs @@ -458,8 +458,8 @@ DynamicLibrary { "scriptmodule.h", "scriptprocess.cpp", "scriptprocess.h", - "scriptpropertytypes.cpp", - "scriptpropertytypes.h", + "scriptpropertytype.cpp", + "scriptpropertytype.h", "selectionrectangle.cpp", "selectionrectangle.h", "selectsametiletool.cpp", diff --git a/src/tiled/scriptmanager.cpp b/src/tiled/scriptmanager.cpp index 31932d64b1..78e71aaeed 100644 --- a/src/tiled/scriptmanager.cpp +++ b/src/tiled/scriptmanager.cpp @@ -49,7 +49,7 @@ #include "scriptimage.h" #include "scriptmodule.h" #include "scriptprocess.h" -#include "scriptpropertytypes.h" +#include "scriptpropertytype.h" #include "tilecollisiondock.h" #include "tilelayer.h" #include "tilelayeredit.h" diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp new file mode 100644 index 0000000000..7cba9e06fd --- /dev/null +++ b/src/tiled/scriptpropertytype.cpp @@ -0,0 +1,40 @@ +/* + * scriptimage.cpp + * Copyright 2020, 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 "scriptpropertytype.h" +#include "project.h" +#include "projectmanager.h" + +namespace Tiled { + +QString ScriptPropertyType::name() const +{ + return mType->name; +} + +void registerPropertyTypes(QJSEngine *jsEngine) +{ + jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), + jsEngine->newQMetaObject()); +} + +} // namespace Tiled + +#include "moc_scriptpropertytype.cpp" diff --git a/src/tiled/scriptpropertytypes.h b/src/tiled/scriptpropertytype.h similarity index 80% rename from src/tiled/scriptpropertytypes.h rename to src/tiled/scriptpropertytype.h index 654c87c299..3d2712f88e 100644 --- a/src/tiled/scriptpropertytypes.h +++ b/src/tiled/scriptpropertytype.h @@ -84,7 +84,7 @@ class ScriptClassPropertyType : public ScriptPropertyType Q_OBJECT Q_PROPERTY(QColor color READ color) Q_PROPERTY(QVariantMap members READ members) - + public: ScriptClassPropertyType(const ClassPropertyType *propertyType) : mClassType(propertyType), @@ -101,34 +101,9 @@ class ScriptClassPropertyType : public ScriptPropertyType }; -/** - * Scripting engine wrapper for SharedPropertyTypes - */ -class ScriptPropertyTypes : public QObject -{ - Q_OBJECT - Q_PROPERTY(size_t count READ count) - Q_PROPERTY(QVector all READ all) - -public: - ScriptPropertyTypes(SharedPropertyTypes sharedPropertyTypes) - : mTypes(sharedPropertyTypes) - {} - size_t count(); - Q_INVOKABLE void removeByName(const QString &name); - Q_INVOKABLE ScriptPropertyType *findByName(const QString &name); - QVector all() const; - -private: - ScriptPropertyType *toScriptType(const PropertyType *type) const; - void applyPropertyChanges(); - SharedPropertyTypes mTypes; -}; - void registerPropertyTypes(QJSEngine *jsEngine); } // namespace Tiled -Q_DECLARE_METATYPE(Tiled::ScriptPropertyTypes*) Q_DECLARE_METATYPE(Tiled::ScriptPropertyType*) diff --git a/src/tiled/scriptpropertytypes.cpp b/src/tiled/scriptpropertytypes.cpp deleted file mode 100644 index dcc30bd615..0000000000 --- a/src/tiled/scriptpropertytypes.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * scriptimage.cpp - * Copyright 2020, 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 "scriptpropertytypes.h" -#include "project.h" -#include "projectmanager.h" - -namespace Tiled { - -QString ScriptPropertyType::name() const -{ - return mType->name; -} - -size_t ScriptPropertyTypes::count() -{ - return mTypes->count(); -} - -ScriptPropertyType *ScriptPropertyTypes::toScriptType(const PropertyType *type) const -{ - if (!type) - return nullptr; - - if (type->isEnum()) - return new ScriptEnumPropertyType(static_cast(type)); - - if (type->isClass()) - return new ScriptClassPropertyType(static_cast(type)); - - return new ScriptPropertyType(type); -} - -ScriptPropertyType *ScriptPropertyTypes::findByName(const QString &name) -{ - const PropertyType *type = mTypes->findTypeByName(name); - return toScriptType(type); -} - -void ScriptPropertyTypes::removeByName(const QString &name) -{ - int index = mTypes->findIndexByName(name); - if (index < 0 ) - return - - // TODO the type isn't actually being deleted even when index >= 0 - mTypes->removeAt(index); - applyPropertyChanges(); -} - -// TODO remove if we can implement an iterator -QVectorScriptPropertyTypes::all() const -{ - QVector scriptTypes; - for (const PropertyType *type : *mTypes) - scriptTypes.append(toScriptType(type)); - return scriptTypes; -} - -void ScriptPropertyTypes::applyPropertyChanges() -{ - emit Preferences::instance()->propertyTypesChanged(); - - Project &project = ProjectManager::instance()->project(); - project.save(); -} - -void registerPropertyTypes(QJSEngine *jsEngine) -{ - jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), - jsEngine->newQMetaObject()); -} - -} // namespace Tiled - -#include "moc_scriptpropertytypes.cpp" From d5010bdce064834abcc94e1298fb62bf01a15714 Mon Sep 17 00:00:00 2001 From: chris Date: Sat, 15 Jun 2024 23:26:00 -0400 Subject: [PATCH 06/19] add ClassPropertyType.ClassUsageFlag, classType.usageFlags to scripting --- src/tiled/scriptpropertytype.cpp | 2 ++ src/tiled/scriptpropertytype.h | 29 +++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index 7cba9e06fd..a5c2768384 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -33,6 +33,8 @@ void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), jsEngine->newQMetaObject()); + jsEngine->globalObject().setProperty(QStringLiteral("ClassPropertyType"), + jsEngine->newQMetaObject()); } } // namespace Tiled diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index 3d2712f88e..bf3554acf1 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -84,16 +84,41 @@ class ScriptClassPropertyType : public ScriptPropertyType Q_OBJECT Q_PROPERTY(QColor color READ color) Q_PROPERTY(QVariantMap members READ members) + Q_PROPERTY(bool drawFill READ drawFill) + Q_PROPERTY(int usageFlags READ usageFlags) public: ScriptClassPropertyType(const ClassPropertyType *propertyType) : mClassType(propertyType), ScriptPropertyType(propertyType) {} + + // TODO: a way to avoid duplicating this again? + enum ClassUsageFlag { + PropertyValueType = 0x001, + + // Keep values synchronized with Object::TypeId + LayerClass = 0x002, + MapObjectClass = 0x004, + MapClass = 0x008, + TilesetClass = 0x010, + TileClass = 0x020, + WangSetClass = 0x040, + WangColorClass = 0x080, + ProjectClass = 0x100, + AnyUsage = 0xFFF, + AnyObjectClass = AnyUsage & ~PropertyValueType, + }; + Q_ENUM(ClassUsageFlag) + QColor color() const { return mClassType->color; } - QVariantMap members() const {return mClassType->members; } // TODO: " No viable overloaded '=' " - // void setColor(const QColor &value) { mClassType->color = value; } + // void setColor(QColor &value) { mClassType->color = value; } + QVariantMap members() const {return mClassType->members; } + bool drawFill() const { return mClassType->drawFill; } + // void setDrawFill(bool value) { mClassType->drawFill = value; } + int usageFlags() const { return mClassType->usageFlags; } + //void setUsageFlags(int value) { mClassType->setUsageFlags(value); } private: From 9a0e5a85cbd5bf6ccab5001b96cfd273900da3fc Mon Sep 17 00:00:00 2001 From: chris Date: Sun, 16 Jun 2024 21:41:11 -0400 Subject: [PATCH 07/19] fix comments in propertytype.cpp --- src/libtiled/propertytype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtiled/propertytype.cpp b/src/libtiled/propertytype.cpp index ec7f647453..ed890bcfcc 100644 --- a/src/libtiled/propertytype.cpp +++ b/src/libtiled/propertytype.cpp @@ -530,8 +530,8 @@ const PropertyType *PropertyTypes::findTypeById(int typeId) const } /** - * Returns a pointer to the PropertyType matching the given \a typeId, or - * nullptr if it can't be found. + * Returns the index of the type of the given name, + * or -1 if no such type is found. */ const int PropertyTypes::findIndexByName(const QString &name) const { From 16d594e1281ea864e89cb92be7d9347a3e282da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 18 Jun 2024 15:57:03 +0200 Subject: [PATCH 08/19] Minor code style changes --- src/libtiled/propertytype.cpp | 31 +++++++++++++------------ src/libtiled/propertytype.h | 3 ++- src/tiled/editableproject.cpp | 39 +++++++++++++++++--------------- src/tiled/editableproject.h | 5 +++- src/tiled/scriptpropertytype.cpp | 8 +++---- src/tiled/scriptpropertytype.h | 17 ++++++-------- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/libtiled/propertytype.cpp b/src/libtiled/propertytype.cpp index ed890bcfcc..62ab0ad5ef 100644 --- a/src/libtiled/propertytype.cpp +++ b/src/libtiled/propertytype.cpp @@ -517,6 +517,22 @@ void PropertyTypes::mergeObjectTypes(const QVector &objectTypes) } } +/** + * Returns the index of the type of the given name, or -1 if no such type is + * found. + */ +int PropertyTypes::findIndexByName(const QString &name) const +{ + if (name.isEmpty()) + return -1; + + for (int i = 0; i < mTypes.count(); i++) + if (mTypes[i]->name == name) + return i; + + return -1; +} + /** * Returns a pointer to the PropertyType matching the given \a typeId, or * nullptr if it can't be found. @@ -529,21 +545,6 @@ const PropertyType *PropertyTypes::findTypeById(int typeId) const return it == mTypes.end() ? nullptr : *it; } -/** - * Returns the index of the type of the given name, - * or -1 if no such type is found. - */ -const int PropertyTypes::findIndexByName(const QString &name) const -{ - if (name.isEmpty()) - return -1; - - for (int i =0; iname == name) - return i; - - return -1; -} /** * Returns a pointer to the PropertyType matching the given \a name and * \a usageFlags, or nullptr if it can't be found. diff --git a/src/libtiled/propertytype.h b/src/libtiled/propertytype.h index 8d41892a19..e5c8f5188d 100644 --- a/src/libtiled/propertytype.h +++ b/src/libtiled/propertytype.h @@ -200,8 +200,9 @@ class TILEDSHARED_EXPORT PropertyTypes void merge(PropertyTypes types); void mergeObjectTypes(const QVector &objectTypes); + int findIndexByName(const QString &name) const; + const PropertyType *findTypeById(int typeId) const; - const int findIndexByName(const QString &name) const; const PropertyType *findTypeByName(const QString &name, int usageFlags = ClassPropertyType::AnyUsage) const; const PropertyType *findPropertyValueType(const QString &name) const; const ClassPropertyType *findClassFor(const QString &name, const Object &object) const; diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index 5e8a851d2d..e08694c07a 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -20,6 +20,8 @@ */ #include "editableproject.h" + +#include "preferences.h" #include "projectdocument.h" #include "projectmanager.h" @@ -31,6 +33,11 @@ EditableProject::EditableProject(ProjectDocument *projectDocument, QObject *pare setDocument(projectDocument); } +bool EditableProject::isReadOnly() const +{ + return false; +} + QString EditableProject::extensionsPath() const { return project()->mExtensionsPath; @@ -51,10 +58,12 @@ QStringList EditableProject::folders() const return project()->folders(); } - -bool EditableProject::isReadOnly() const +QVectorEditableProject::propertyTypes() const { - return false; + QVector scriptTypes; + for (const PropertyType *type : *project()->propertyTypes()) + scriptTypes.append(toScriptType(type)); + return scriptTypes; } QSharedPointer EditableProject::createDocument() @@ -64,19 +73,21 @@ QSharedPointer EditableProject::createDocument() return nullptr; } - ScriptPropertyType *EditableProject::toScriptType(const PropertyType *type) const { if (!type) return nullptr; - if (type->isEnum()) - return new ScriptEnumPropertyType(static_cast(type)); - - if (type->isClass()) + switch (type->type) { + case PropertyType::PT_Invalid: + break; + case PropertyType::PT_Class: return new ScriptClassPropertyType(static_cast(type)); + case PropertyType::PT_Enum: + return new ScriptEnumPropertyType(static_cast(type)); + } - return new ScriptPropertyType(type); + return nullptr; } ScriptPropertyType *EditableProject::findTypeByName(const QString &name) @@ -88,7 +99,7 @@ ScriptPropertyType *EditableProject::findTypeByName(const QString &name) void EditableProject::removeTypeByName(const QString &name) { int index = project()->propertyTypes()->findIndexByName(name); - if (index < 0 ) + if (index < 0) return // TODO the type isn't actually being deleted even when index >= 0 @@ -96,14 +107,6 @@ void EditableProject::removeTypeByName(const QString &name) applyPropertyChanges(); } -QVectorEditableProject::propertyTypes() const -{ - QVector scriptTypes; - for (const PropertyType *type : *project()->propertyTypes()) - scriptTypes.append(toScriptType(type)); - return scriptTypes; -} - void EditableProject::applyPropertyChanges() { emit Preferences::instance()->propertyTypesChanged(); diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index 7a26069f8f..08a2612b6d 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -40,6 +40,7 @@ class EditableProject final : public EditableAsset Q_PROPERTY(QString fileName READ fileName) Q_PROPERTY(QStringList folders READ folders) Q_PROPERTY(QVector propertyTypes READ propertyTypes) + public: EditableProject(ProjectDocument *projectDocument, QObject *parent = nullptr); @@ -50,13 +51,15 @@ class EditableProject final : public EditableAsset QString automappingRulesFile() const; QString fileName() const; QStringList folders() const; + QVector propertyTypes() const; + Project *project() const; QSharedPointer createDocument() override; Q_INVOKABLE void removeTypeByName(const QString &name); Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); - QVector propertyTypes() const; + private: ScriptPropertyType *toScriptType(const PropertyType *type) const; void applyPropertyChanges(); diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index a5c2768384..3dc21eb42a 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -1,6 +1,6 @@ /* - * scriptimage.cpp - * Copyright 2020, Thorbjørn Lindeijer + * scriptpropertytype.cpp + * Copyright 2024, chris * * This file is part of Tiled. * @@ -19,12 +19,10 @@ */ #include "scriptpropertytype.h" -#include "project.h" -#include "projectmanager.h" namespace Tiled { -QString ScriptPropertyType::name() const +const QString &ScriptPropertyType::name() const { return mType->name; } diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index bf3554acf1..456db69be2 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -1,6 +1,6 @@ /* - * scriptimage.h - * Copyright 2020, Thorbjørn Lindeijer + * scriptpropertytype.h + * Copyright 2024, chris * * This file is part of Tiled. * @@ -20,7 +20,6 @@ #pragma once -#include "preferences.h" #include "propertytype.h" #include @@ -44,7 +43,7 @@ class ScriptPropertyType : public QObject : mType(propertyType) {} - QString name() const; + const QString &name() const; bool isClass() const { return mType->isClass(); } bool isEnum() const { return mType->isEnum(); } QVariant defaultValue() { return mType->defaultValue(); } @@ -62,8 +61,8 @@ class ScriptEnumPropertyType : public ScriptPropertyType public: ScriptEnumPropertyType(const EnumPropertyType *propertyType) - : mEnumType(propertyType), - ScriptPropertyType(propertyType) + : ScriptPropertyType(propertyType) + , mEnumType(propertyType) {} // copied from propertytype.h enum StorageType { @@ -89,8 +88,8 @@ class ScriptClassPropertyType : public ScriptPropertyType public: ScriptClassPropertyType(const ClassPropertyType *propertyType) - : mClassType(propertyType), - ScriptPropertyType(propertyType) + : ScriptPropertyType(propertyType) + , mClassType(propertyType) {} // TODO: a way to avoid duplicating this again? @@ -121,7 +120,6 @@ class ScriptClassPropertyType : public ScriptPropertyType //void setUsageFlags(int value) { mClassType->setUsageFlags(value); } private: - const ClassPropertyType *mClassType; }; @@ -131,4 +129,3 @@ void registerPropertyTypes(QJSEngine *jsEngine); } // namespace Tiled Q_DECLARE_METATYPE(Tiled::ScriptPropertyType*) - From 2b4d2f46b928164faffe8c07d8f56786dd14a7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 18 Jun 2024 16:56:53 +0200 Subject: [PATCH 09/19] Fixed removal of types by name ;) --- src/tiled/editableproject.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index e08694c07a..abfaa763ab 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -100,9 +100,8 @@ void EditableProject::removeTypeByName(const QString &name) { int index = project()->propertyTypes()->findIndexByName(name); if (index < 0) - return + return; - // TODO the type isn't actually being deleted even when index >= 0 project()->propertyTypes()->removeAt(index); applyPropertyChanges(); } From 7f6b55e1deb72c7c7154e4e0a9627a9c89909000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Wed, 22 Jan 2025 12:52:51 +0100 Subject: [PATCH 10/19] Changed PropertyType instances to be managed by shared pointer This way, the type is kept alive by the ScriptPropertyType, which avoids crashes when accessing roaming pointers. Also, since it now has a non-const reference we can make the properties writable. --- src/libtiled/objecttypes.cpp | 10 +++---- src/libtiled/propertytype.cpp | 45 +++++++++++++--------------- src/libtiled/propertytype.h | 18 ++++++----- src/tiled/editableproject.cpp | 18 +++++++---- src/tiled/editableproject.h | 2 +- src/tiled/propertieswidget.cpp | 4 +-- src/tiled/propertytypesmodel.cpp | 10 +++---- src/tiled/scriptpropertytype.h | 12 ++++---- src/tiled/variantmapproperty.cpp | 6 ++-- tests/properties/test_properties.cpp | 4 +-- 10 files changed, 67 insertions(+), 62 deletions(-) diff --git a/src/libtiled/objecttypes.cpp b/src/libtiled/objecttypes.cpp index 3b9ae8708d..fa3472a70c 100644 --- a/src/libtiled/objecttypes.cpp +++ b/src/libtiled/objecttypes.cpp @@ -314,14 +314,14 @@ ObjectTypes toObjectTypes(const PropertyTypes &propertyTypes) { ObjectTypes objectTypes; - for (const PropertyType *type : std::as_const(propertyTypes)) { + for (const auto &type : std::as_const(propertyTypes)) { if (!type->isClass()) // only classes supported continue; - auto classType = static_cast(type); - objectTypes.append(ObjectType(classType->name, - classType->color, - classType->members)); + auto &classType = static_cast(*type); + objectTypes.append(ObjectType(classType.name, + classType.color, + classType.members)); } return objectTypes; diff --git a/src/libtiled/propertytype.cpp b/src/libtiled/propertytype.cpp index 62ab0ad5ef..a8b8319e0e 100644 --- a/src/libtiled/propertytype.cpp +++ b/src/libtiled/propertytype.cpp @@ -422,14 +422,11 @@ void ClassPropertyType::setUsageFlags(int flags, bool value) // PropertyTypes -PropertyTypes::~PropertyTypes() -{ - qDeleteAll(mTypes); -} +PropertyTypes::~PropertyTypes() = default; size_t PropertyTypes::count(PropertyType::Type type) const { - return std::count_if(mTypes.begin(), mTypes.end(), [&] (const PropertyType *propertyType) { + return std::count_if(begin(), end(), [&] (const SharedPropertyType &propertyType) { return propertyType->type == type; }); } @@ -445,13 +442,13 @@ void PropertyTypes::merge(PropertyTypes typesToMerge) QHash oldTypeIdToName; QList classesToProcess; - for (const auto type : typesToMerge) + for (const auto &type : typesToMerge) oldTypeIdToName.insert(type->id, type->name); while (typesToMerge.count() > 0) { auto typeToImport = typesToMerge.takeAt(0); auto typeToImportUsageFlags = typeUsageFlags(*typeToImport); - auto existingIt = std::find_if(mTypes.begin(), mTypes.end(), [&] (const PropertyType *type) { + auto existingIt = std::find_if(begin(), end(), [&] (const SharedPropertyType &type) { // Consider same type only when name matches and usage flags overlap return type->name == typeToImport->name && (typeUsageFlags(*type) & typeToImportUsageFlags) != 0; @@ -460,14 +457,14 @@ void PropertyTypes::merge(PropertyTypes typesToMerge) if (typeToImport->isClass()) classesToProcess.append(static_cast(typeToImport.get())); - if (existingIt != mTypes.end()) { + if (existingIt != end()) { // Existing types are replaced, but their ID is retained typeToImport->id = (*existingIt)->id; - delete std::exchange(*existingIt, typeToImport.release()); + *existingIt = typeToImport; } else { // New types are added, but their ID is reset typeToImport->id = 0; - add(std::move(typeToImport)); + add(typeToImport); } } @@ -501,18 +498,18 @@ void PropertyTypes::mergeObjectTypes(const QVector &objectTypes) propertyType->members = type.defaultProperties; propertyType->usageFlags = ClassPropertyType::MapObjectClass | ClassPropertyType::TileClass; - auto existingIt = std::find_if(mTypes.begin(), mTypes.end(), [&] (const PropertyType *type) { + auto existingIt = std::find_if(begin(), end(), [&] (const SharedPropertyType &type) { // Consider same type only when name matches and usage flags overlap return type->name == propertyType->name && (typeUsageFlags(*type) & propertyType->usageFlags) != 0; }); - if (existingIt != mTypes.end()) { + if (existingIt != end()) { // Replace existing classes, but retain their ID propertyType->id = (*existingIt)->id; - delete std::exchange(*existingIt, propertyType.release()); + *existingIt = SharedPropertyType(propertyType.release()); } else { - add(std::move(propertyType)); + add(SharedPropertyType(propertyType.release())); } } } @@ -539,10 +536,10 @@ int PropertyTypes::findIndexByName(const QString &name) const */ const PropertyType *PropertyTypes::findTypeById(int typeId) const { - auto it = std::find_if(mTypes.begin(), mTypes.end(), [&] (const PropertyType *type) { + auto it = std::find_if(begin(), end(), [&] (const SharedPropertyType &type) { return type->id == typeId; }); - return it == mTypes.end() ? nullptr : *it; + return it == end() ? nullptr : it->data(); } /** @@ -554,10 +551,10 @@ const PropertyType *PropertyTypes::findTypeByName(const QString &name, int usage if (name.isEmpty()) return nullptr; - auto it = std::find_if(mTypes.begin(), mTypes.end(), [&] (const PropertyType *type) { + auto it = std::find_if(begin(), end(), [&] (const SharedPropertyType &type) { return type->name == name && (typeUsageFlags(*type) & usageFlags) != 0; }); - return it == mTypes.end() ? nullptr : *it; + return it == end() ? nullptr : it->data(); } const PropertyType *PropertyTypes::findPropertyValueType(const QString &name) const @@ -570,10 +567,10 @@ const ClassPropertyType *PropertyTypes::findClassFor(const QString &name, const if (name.isEmpty()) return nullptr; - auto it = std::find_if(mTypes.begin(), mTypes.end(), [&] (const PropertyType *type) { - return type->name == name && type->isClass() && static_cast(type)->isClassFor(object); + auto it = std::find_if(begin(), end(), [&] (const SharedPropertyType &type) { + return type->name == name && type->isClass() && static_cast(*type).isClassFor(object); }); - return static_cast(it == mTypes.end() ? nullptr : *it); + return static_cast(it == end() ? nullptr : it->data()); } PropertyType *PropertyTypes::findTypeByNamePriv(const QString &name, int usageFlags) @@ -594,11 +591,11 @@ void PropertyTypes::loadFromJson(const QJsonArray &list, const QString &path) for (const auto typeValue : list) if (auto propertyType = PropertyType::createFromJson(typeValue.toObject())) - add(std::move(propertyType)); + add(SharedPropertyType(propertyType.release())); - for (PropertyType *type : mTypes) + for (auto &type : mTypes) if (type->isClass()) - resolveMemberValues(static_cast(type), context); + resolveMemberValues(static_cast(type.data()), context); } void PropertyTypes::resolveMemberValues(ClassPropertyType *classType, diff --git a/src/libtiled/propertytype.h b/src/libtiled/propertytype.h index e5c8f5188d..1bb6929853 100644 --- a/src/libtiled/propertytype.h +++ b/src/libtiled/propertytype.h @@ -175,12 +175,14 @@ class TILEDSHARED_EXPORT ClassPropertyType final : public PropertyType void setUsageFlags(int flags, bool value); }; +using SharedPropertyType = QSharedPointer; + /** * Container class for property types. */ class TILEDSHARED_EXPORT PropertyTypes { - using Types = QVector; + using Types = QVector; public: PropertyTypes() = default; @@ -189,12 +191,12 @@ class TILEDSHARED_EXPORT PropertyTypes PropertyTypes& operator=(PropertyTypes&& other) = default; - PropertyType &add(std::unique_ptr type); + PropertyType &add(const SharedPropertyType &type); void clear(); size_t count() const; size_t count(PropertyType::Type type) const; void removeAt(int index); - std::unique_ptr takeAt(int index); + SharedPropertyType takeAt(int index); PropertyType &typeAt(int index); void moveType(int from, int to); void merge(PropertyTypes types); @@ -226,14 +228,14 @@ class TILEDSHARED_EXPORT PropertyTypes int mNextId = 0; }; -inline PropertyType &PropertyTypes::add(std::unique_ptr type) +inline PropertyType &PropertyTypes::add(const SharedPropertyType &type) { if (type->id == 0) type->id = ++mNextId; else mNextId = std::max(mNextId, type->id); - mTypes.append(type.release()); + mTypes.append(type); return *mTypes.last(); } @@ -249,12 +251,12 @@ inline size_t PropertyTypes::count() const inline void PropertyTypes::removeAt(int index) { - delete mTypes.takeAt(index); + mTypes.removeAt(index); } -inline std::unique_ptr PropertyTypes::takeAt(int index) +inline SharedPropertyType PropertyTypes::takeAt(int index) { - return std::unique_ptr { mTypes.takeAt(index) }; + return mTypes.takeAt(index); } inline PropertyType &PropertyTypes::typeAt(int index) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index abfaa763ab..c0c534fa59 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -61,7 +61,7 @@ QStringList EditableProject::folders() const QVectorEditableProject::propertyTypes() const { QVector scriptTypes; - for (const PropertyType *type : *project()->propertyTypes()) + for (const auto &type : *project()->propertyTypes()) scriptTypes.append(toScriptType(type)); return scriptTypes; } @@ -73,7 +73,7 @@ QSharedPointer EditableProject::createDocument() return nullptr; } -ScriptPropertyType *EditableProject::toScriptType(const PropertyType *type) const +ScriptPropertyType *EditableProject::toScriptType(const SharedPropertyType &type) const { if (!type) return nullptr; @@ -82,9 +82,9 @@ ScriptPropertyType *EditableProject::toScriptType(const PropertyType *type) cons case PropertyType::PT_Invalid: break; case PropertyType::PT_Class: - return new ScriptClassPropertyType(static_cast(type)); + return new ScriptClassPropertyType(qSharedPointerCast(type)); case PropertyType::PT_Enum: - return new ScriptEnumPropertyType(static_cast(type)); + return new ScriptEnumPropertyType(qSharedPointerCast(type)); } return nullptr; @@ -92,8 +92,14 @@ ScriptPropertyType *EditableProject::toScriptType(const PropertyType *type) cons ScriptPropertyType *EditableProject::findTypeByName(const QString &name) { - const PropertyType *type = project()->propertyTypes()->findTypeByName(name); - return toScriptType(type); + if (name.isEmpty()) + return nullptr; + + auto &types = *project()->propertyTypes(); + auto it = std::find_if(types.begin(), types.end(), [&] (const SharedPropertyType &type) { + return type->name == name; + }); + return it == types.end() ? nullptr : toScriptType(*it); } void EditableProject::removeTypeByName(const QString &name) diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index 08a2612b6d..3313144b0a 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -61,7 +61,7 @@ class EditableProject final : public EditableAsset Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); private: - ScriptPropertyType *toScriptType(const PropertyType *type) const; + ScriptPropertyType *toScriptType(const SharedPropertyType &type) const; void applyPropertyChanges(); }; diff --git a/src/tiled/propertieswidget.cpp b/src/tiled/propertieswidget.cpp index 24c30df059..fda71152af 100644 --- a/src/tiled/propertieswidget.cpp +++ b/src/tiled/propertieswidget.cpp @@ -568,9 +568,9 @@ static bool anyObjectHasProperty(const QList &objects, const QString &n static QStringList classNamesFor(const Object &object) { QStringList names; - for (const auto type : Object::propertyTypes()) + for (const auto &type : Object::propertyTypes()) if (type->isClass()) - if (static_cast(type)->isClassFor(object)) + if (static_cast(*type).isClassFor(object)) names.append(type->name); return names; } diff --git a/src/tiled/propertytypesmodel.cpp b/src/tiled/propertytypesmodel.cpp index e5b426cc7b..231848078d 100644 --- a/src/tiled/propertytypesmodel.cpp +++ b/src/tiled/propertytypesmodel.cpp @@ -27,7 +27,7 @@ using namespace Tiled; -static bool propertyTypeLessThan(const PropertyType *a, const PropertyType *b) +static bool propertyTypeLessThan(const SharedPropertyType &a, const SharedPropertyType &b) { return QString::localeAwareCompare(a->name, b->name) < 0; } @@ -109,10 +109,10 @@ bool PropertyTypesModel::setPropertyTypeName(int row, const QString &name) if (!checkTypeNameUnused(name)) return false; - const std::unique_ptr typeWithName = std::make_unique(name.trimmed()); + const SharedPropertyType typeWithName { new EnumPropertyType(name.trimmed()) }; auto nextPropertyType = std::lower_bound(propertyTypes.begin(), propertyTypes.end(), - typeWithName.get(), + typeWithName, propertyTypeLessThan); const int newRow = nextPropertyType - propertyTypes.begin(); @@ -178,7 +178,7 @@ QModelIndex PropertyTypesModel::addPropertyType(std::unique_ptr ty const int row = mPropertyTypes->count(); beginInsertRows(QModelIndex(), row, row); - mPropertyTypes->add(std::move(type)); + mPropertyTypes->add(SharedPropertyType(type.release())); endInsertRows(); return index(row, 0); @@ -237,7 +237,7 @@ QString PropertyTypesModel::nextPropertyTypeName(PropertyType::Type type) const do { name = baseText + QString::number(number++); } while (contains_where(*mPropertyTypes, - [&] (const PropertyType *type) { return type->name == name; })); + [&] (const SharedPropertyType &type) { return type->name == name; })); return name; } diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index 456db69be2..959279d659 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -39,7 +39,7 @@ class ScriptPropertyType : public QObject Q_PROPERTY(QVariant defaultValue READ defaultValue) public: - ScriptPropertyType(const PropertyType *propertyType) + ScriptPropertyType(const SharedPropertyType &propertyType) : mType(propertyType) {} @@ -49,7 +49,7 @@ class ScriptPropertyType : public QObject QVariant defaultValue() { return mType->defaultValue(); } private: - const PropertyType *mType; + SharedPropertyType mType; }; class ScriptEnumPropertyType : public ScriptPropertyType @@ -60,7 +60,7 @@ class ScriptEnumPropertyType : public ScriptPropertyType Q_PROPERTY(QStringList values READ values) public: - ScriptEnumPropertyType(const EnumPropertyType *propertyType) + ScriptEnumPropertyType(const QSharedPointer &propertyType) : ScriptPropertyType(propertyType) , mEnumType(propertyType) {} @@ -75,7 +75,7 @@ class ScriptEnumPropertyType : public ScriptPropertyType QStringList values() const { return mEnumType->values; } private: - const EnumPropertyType *mEnumType; + QSharedPointer mEnumType; }; class ScriptClassPropertyType : public ScriptPropertyType @@ -87,7 +87,7 @@ class ScriptClassPropertyType : public ScriptPropertyType Q_PROPERTY(int usageFlags READ usageFlags) public: - ScriptClassPropertyType(const ClassPropertyType *propertyType) + ScriptClassPropertyType(const QSharedPointer &propertyType) : ScriptPropertyType(propertyType) , mClassType(propertyType) {} @@ -120,7 +120,7 @@ class ScriptClassPropertyType : public ScriptPropertyType //void setUsageFlags(int value) { mClassType->setUsageFlags(value); } private: - const ClassPropertyType *mClassType; + QSharedPointer mClassType; }; diff --git a/src/tiled/variantmapproperty.cpp b/src/tiled/variantmapproperty.cpp index 7d2239aa7e..ef2ae68c20 100644 --- a/src/tiled/variantmapproperty.cpp +++ b/src/tiled/variantmapproperty.cpp @@ -531,14 +531,14 @@ QWidget *AddValueProperty::createEditor(QWidget *parent) typeBox->addItem(m_plainTypeIcon, typeToName(objectRefTypeId()), QVariant::fromValue(ObjectRef())); typeBox->addItem(m_plainTypeIcon, typeToName(QMetaType::QString), QString()); - for (const auto propertyType : Object::propertyTypes()) { + for (const auto &propertyType : Object::propertyTypes()) { // Avoid suggesting the creation of circular dependencies between types - if (m_parentClassType && !m_parentClassType->canAddMemberOfType(propertyType)) + if (m_parentClassType && !m_parentClassType->canAddMemberOfType(propertyType.data())) continue; // Avoid suggesting classes not meant to be used as property value if (propertyType->isClass()) - if (!static_cast(propertyType)->isPropertyValueType()) + if (!static_cast(*propertyType).isPropertyValueType()) continue; const QVariant var = propertyType->wrap(propertyType->defaultValue()); diff --git a/tests/properties/test_properties.cpp b/tests/properties/test_properties.cpp index b1f48378de..75f3fc0150 100644 --- a/tests/properties/test_properties.cpp +++ b/tests/properties/test_properties.cpp @@ -578,14 +578,14 @@ void test_Properties::cleanupTestCase() EnumPropertyType &test_Properties::addEnum(const QString &name) { - auto &type = mTypes.add(std::make_unique(name)); + auto &type = mTypes.add(SharedPropertyType(new EnumPropertyType(name))); type.id = ++mNextId; return static_cast(type); } ClassPropertyType &test_Properties::addClass(const QString &name) { - auto &type = mTypes.add(std::make_unique(name)); + auto &type = mTypes.add(SharedPropertyType(new ClassPropertyType(name))); type.id = ++mNextId; return static_cast(type); } From 99a1350f9ebd09f069a6eb6639249ea727056d06 Mon Sep 17 00:00:00 2001 From: dogboydog Date: Thu, 23 Jan 2025 20:54:06 -0500 Subject: [PATCH 11/19] allow editing color, drawFill, usageFlags, enum values, enum storage type from scripting --- src/tiled/editableproject.cpp | 5 +-- src/tiled/editableproject.h | 2 +- src/tiled/scriptpropertytype.cpp | 16 +++++++++ src/tiled/scriptpropertytype.h | 56 +++++++++++++++++++++++++------- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index c0c534fa59..51f393d89a 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -102,14 +102,15 @@ ScriptPropertyType *EditableProject::findTypeByName(const QString &name) return it == types.end() ? nullptr : toScriptType(*it); } -void EditableProject::removeTypeByName(const QString &name) +bool EditableProject::removeTypeByName(const QString &name) { int index = project()->propertyTypes()->findIndexByName(name); if (index < 0) - return; + return false; project()->propertyTypes()->removeAt(index); applyPropertyChanges(); + return true; } void EditableProject::applyPropertyChanges() diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index 3313144b0a..3a24956cfb 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -57,7 +57,7 @@ class EditableProject final : public EditableAsset QSharedPointer createDocument() override; - Q_INVOKABLE void removeTypeByName(const QString &name); + Q_INVOKABLE bool removeTypeByName(const QString &name); Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); private: diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index 3dc21eb42a..fd2fe8e13f 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -18,6 +18,9 @@ * this program. If not, see . */ +#include "preferences.h" +#include "project.h" +#include "projectmanager.h" #include "scriptpropertytype.h" namespace Tiled { @@ -35,6 +38,19 @@ void registerPropertyTypes(QJSEngine *jsEngine) jsEngine->newQMetaObject()); } +/* + * Called when we make a change to a property type - + * this will reflect any property changes in the UI. + * + * TODO: Scheduling project save rather than every time + */ +void ScriptPropertyType::applyPropertyChanges() +{ + emit Preferences::instance()->propertyTypesChanged(); + + Project &project = ProjectManager::instance()->project(); + project.save(); +} } // namespace Tiled #include "moc_scriptpropertytype.cpp" diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index 959279d659..d4e2d76561 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -33,7 +33,7 @@ namespace Tiled { class ScriptPropertyType : public QObject { Q_OBJECT - Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(bool isClass READ isClass) Q_PROPERTY(bool isEnum READ isEnum) Q_PROPERTY(QVariant defaultValue READ defaultValue) @@ -44,10 +44,17 @@ class ScriptPropertyType : public QObject {} const QString &name() const; + void setName(const QString &value) + { + mType->name =value; + applyPropertyChanges(); + } bool isClass() const { return mType->isClass(); } bool isEnum() const { return mType->isEnum(); } QVariant defaultValue() { return mType->defaultValue(); } +protected: + void applyPropertyChanges(); private: SharedPropertyType mType; }; @@ -56,8 +63,8 @@ class ScriptEnumPropertyType : public ScriptPropertyType { Q_OBJECT - Q_PROPERTY(StorageType storageType READ storageType) - Q_PROPERTY(QStringList values READ values) + Q_PROPERTY(StorageType storageType READ storageType WRITE setStorageType) + Q_PROPERTY(QStringList values READ values WRITE setValues) public: ScriptEnumPropertyType(const QSharedPointer &propertyType) @@ -72,8 +79,18 @@ class ScriptEnumPropertyType : public ScriptPropertyType Q_ENUM(StorageType); StorageType storageType() const { return static_cast(mEnumType->storageType); } + void setStorageType(StorageType value) + { + mEnumType->storageType = (EnumPropertyType::StorageType)value; + applyPropertyChanges(); + } QStringList values() const { return mEnumType->values; } - + void setValues(const QStringList &values) + { + mEnumType->values.clear(); + mEnumType->values.append(values); + applyPropertyChanges(); + } private: QSharedPointer mEnumType; }; @@ -81,10 +98,10 @@ class ScriptEnumPropertyType : public ScriptPropertyType class ScriptClassPropertyType : public ScriptPropertyType { Q_OBJECT - Q_PROPERTY(QColor color READ color) + Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(QVariantMap members READ members) - Q_PROPERTY(bool drawFill READ drawFill) - Q_PROPERTY(int usageFlags READ usageFlags) + Q_PROPERTY(bool drawFill READ drawFill WRITE setDrawFill) + Q_PROPERTY(int usageFlags READ usageFlags WRITE setUsageFlags) public: ScriptClassPropertyType(const QSharedPointer &propertyType) @@ -111,13 +128,30 @@ class ScriptClassPropertyType : public ScriptPropertyType Q_ENUM(ClassUsageFlag) QColor color() const { return mClassType->color; } - // TODO: " No viable overloaded '=' " - // void setColor(QColor &value) { mClassType->color = value; } + + void setColor(QColor &value) + { + mClassType->color = value; + applyPropertyChanges(); + } QVariantMap members() const {return mClassType->members; } + // todo add members, remove members + bool drawFill() const { return mClassType->drawFill; } - // void setDrawFill(bool value) { mClassType->drawFill = value; } + void setDrawFill(bool value) + { + mClassType->drawFill = value; + applyPropertyChanges(); + } int usageFlags() const { return mClassType->usageFlags; } - //void setUsageFlags(int value) { mClassType->setUsageFlags(value); } + void setUsageFlags(int value) { + // clear any existing values first so that we set to exactly + // the new value rather than just turning all flags in `value` + // on. + mClassType->setUsageFlags(ClassUsageFlag::AnyUsage, false); + mClassType->setUsageFlags(value, true); + applyPropertyChanges(); + } private: QSharedPointer mClassType; From da70b69f02e2a9497e081fa0d9ce430f53b217f3 Mon Sep 17 00:00:00 2001 From: dogboydog Date: Sat, 25 Jan 2025 14:55:00 -0500 Subject: [PATCH 12/19] support adding new enum and class types with tiled.project scripting --- src/tiled/editableproject.cpp | 15 ++++++++++++++- src/tiled/editableproject.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index 51f393d89a..8bb000f2ec 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -112,7 +112,20 @@ bool EditableProject::removeTypeByName(const QString &name) applyPropertyChanges(); return true; } - +ScriptPropertyType *EditableProject::addClassType(const QString &name) +{ + SharedPropertyType newClassType = SharedPropertyType(new ClassPropertyType(name)); + project()->propertyTypes()->add(newClassType); + applyPropertyChanges(); + return findTypeByName(name); +} +ScriptPropertyType *EditableProject::addEnumType(const QString &name) +{ + SharedPropertyType newEnumType = SharedPropertyType(new EnumPropertyType(name)); + project()->propertyTypes()->add(newEnumType); + applyPropertyChanges(); + return findTypeByName(name); +} void EditableProject::applyPropertyChanges() { emit Preferences::instance()->propertyTypesChanged(); diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index 3a24956cfb..6328bca84b 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -59,6 +59,8 @@ class EditableProject final : public EditableAsset Q_INVOKABLE bool removeTypeByName(const QString &name); Q_INVOKABLE ScriptPropertyType *findTypeByName(const QString &name); + Q_INVOKABLE ScriptPropertyType *addClassType(const QString &name); + Q_INVOKABLE ScriptPropertyType *addEnumType(const QString &name); private: ScriptPropertyType *toScriptType(const SharedPropertyType &type) const; From 024610a2908cd845c6e9148e7aef6f02c4e7c23e Mon Sep 17 00:00:00 2001 From: dogboydog Date: Thu, 6 Mar 2025 17:58:48 -0500 Subject: [PATCH 13/19] prevent duplicate names in property types during adding or rename. allow removing members from a class --- src/tiled/editableproject.cpp | 8 +++++++ src/tiled/project.cpp | 7 ++++++ src/tiled/project.h | 1 + src/tiled/scriptpropertytype.cpp | 40 +++++++++++++++++++++++++++++++- src/tiled/scriptpropertytype.h | 10 +++----- 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index 8bb000f2ec..2481938f14 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -114,6 +114,10 @@ bool EditableProject::removeTypeByName(const QString &name) } ScriptPropertyType *EditableProject::addClassType(const QString &name) { + if (project()->propertyTypes()->findTypeByName(name)) { + project()->throwDuplicateNameError(name); + return nullptr; + } SharedPropertyType newClassType = SharedPropertyType(new ClassPropertyType(name)); project()->propertyTypes()->add(newClassType); applyPropertyChanges(); @@ -121,6 +125,10 @@ ScriptPropertyType *EditableProject::addClassType(const QString &name) } ScriptPropertyType *EditableProject::addEnumType(const QString &name) { + if (project()->propertyTypes()->findTypeByName(name)) { + project()->throwDuplicateNameError(name); + return nullptr; + } SharedPropertyType newEnumType = SharedPropertyType(new EnumPropertyType(name)); project()->propertyTypes()->add(newEnumType); applyPropertyChanges(); diff --git a/src/tiled/project.cpp b/src/tiled/project.cpp index 82907ab83b..1fdb7386ff 100644 --- a/src/tiled/project.cpp +++ b/src/tiled/project.cpp @@ -21,11 +21,13 @@ #include "project.h" #include "properties.h" #include "savefile.h" +#include "scriptmanager.h" #include #include #include #include +#include namespace Tiled { @@ -160,4 +162,9 @@ void Project::removeFolder(int index) mFolders.removeAt(index); } +void Project::throwDuplicateNameError(const QString &name) +{ + ScriptManager::instance().throwError(QCoreApplication::translate("Error Renaming Type", + "The name '%1' is already in use.").arg(name)); +} } // namespace Tiled diff --git a/src/tiled/project.h b/src/tiled/project.h index 36b968db22..107a14265d 100644 --- a/src/tiled/project.h +++ b/src/tiled/project.h @@ -56,6 +56,7 @@ class TILED_EDITOR_EXPORT Project : public Object QString mAutomappingRulesFile; QVector mCommands; CompatibilityVersion mCompatibilityVersion = Tiled_Current; + void throwDuplicateNameError(const QString &name); private: QDateTime mLastSaved; diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index fd2fe8e13f..2640c071f7 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -21,7 +21,9 @@ #include "preferences.h" #include "project.h" #include "projectmanager.h" +#include #include "scriptpropertytype.h" +#include "scriptmanager.h" namespace Tiled { @@ -29,7 +31,21 @@ const QString &ScriptPropertyType::name() const { return mType->name; } - +void ScriptPropertyType::setName(const QString &name) +{ + if (this->name() == name) + { + // nothing to do + return; + } + Project &project = ProjectManager::instance()->project(); + if (project.propertyTypes()->findTypeByName(name)) { + project.throwDuplicateNameError(name); + return; + } + mType->name = name; + applyPropertyChanges(); +} void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), @@ -51,6 +67,28 @@ void ScriptPropertyType::applyPropertyChanges() Project &project = ProjectManager::instance()->project(); project.save(); } +void ScriptClassPropertyType::addMember(const QString &name) +{ + if (this->mClassType->members.contains(name)) + { + ScriptManager::instance() + .throwError(QCoreApplication::translate("Script Errors", "A class member of the specified name '%1' already exists").arg(name)); + return; + } + // todo, how will the user specify the type of a new member ? could be a primitive or a class + this->applyPropertyChanges(); +} +void ScriptClassPropertyType::removeMember(const QString &name) +{ + if (!this->mClassType->members.contains(name)) + { + ScriptManager::instance() + .throwError(QCoreApplication::translate("Script Errors", "No class member of the specified name '%1' exists").arg(name)); + return; + } + this->mClassType->members.remove(name); + this->applyPropertyChanges(); +} } // namespace Tiled #include "moc_scriptpropertytype.cpp" diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index d4e2d76561..0871108fe0 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -44,11 +44,7 @@ class ScriptPropertyType : public QObject {} const QString &name() const; - void setName(const QString &value) - { - mType->name =value; - applyPropertyChanges(); - } + void setName(const QString &name); bool isClass() const { return mType->isClass(); } bool isEnum() const { return mType->isEnum(); } QVariant defaultValue() { return mType->defaultValue(); } @@ -135,7 +131,8 @@ class ScriptClassPropertyType : public ScriptPropertyType applyPropertyChanges(); } QVariantMap members() const {return mClassType->members; } - // todo add members, remove members + Q_INVOKABLE void removeMember(const QString& name); + Q_INVOKABLE void addMember(const QString &name); bool drawFill() const { return mClassType->drawFill; } void setDrawFill(bool value) @@ -159,7 +156,6 @@ class ScriptClassPropertyType : public ScriptPropertyType void registerPropertyTypes(QJSEngine *jsEngine); - } // namespace Tiled Q_DECLARE_METATYPE(Tiled::ScriptPropertyType*) From 4227b62e5793417d079276ddc0a616e221bd3130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 7 Mar 2025 17:39:29 +0100 Subject: [PATCH 14/19] Code tweaks and addressed type question for addMember --- src/tiled/editableproject.cpp | 30 ++++++++++++-------------- src/tiled/editableproject.h | 1 + src/tiled/scriptpropertytype.cpp | 37 +++++++++++++++++++++----------- src/tiled/scriptpropertytype.h | 8 ++++++- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index 2481938f14..3d1daeedea 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -23,7 +23,6 @@ #include "preferences.h" #include "projectdocument.h" -#include "projectmanager.h" namespace Tiled { @@ -112,34 +111,33 @@ bool EditableProject::removeTypeByName(const QString &name) applyPropertyChanges(); return true; } + ScriptPropertyType *EditableProject::addClassType(const QString &name) { - if (project()->propertyTypes()->findTypeByName(name)) { - project()->throwDuplicateNameError(name); - return nullptr; - } - SharedPropertyType newClassType = SharedPropertyType(new ClassPropertyType(name)); - project()->propertyTypes()->add(newClassType); - applyPropertyChanges(); - return findTypeByName(name); + return addPropertyType(SharedPropertyType(new ClassPropertyType(name))); } + ScriptPropertyType *EditableProject::addEnumType(const QString &name) { - if (project()->propertyTypes()->findTypeByName(name)) { - project()->throwDuplicateNameError(name); + return addPropertyType(SharedPropertyType(new EnumPropertyType(name))); +} + +ScriptPropertyType *EditableProject::addPropertyType(const SharedPropertyType &type) +{ + if (project()->propertyTypes()->findTypeByName(type->name)) { + project()->throwDuplicateNameError(type->name); return nullptr; } - SharedPropertyType newEnumType = SharedPropertyType(new EnumPropertyType(name)); - project()->propertyTypes()->add(newEnumType); + project()->propertyTypes()->add(type); applyPropertyChanges(); - return findTypeByName(name); + return toScriptType(type); } + void EditableProject::applyPropertyChanges() { emit Preferences::instance()->propertyTypesChanged(); - Project &project = ProjectManager::instance()->project(); - project.save(); + project()->save(); } } // namespace Tiled diff --git a/src/tiled/editableproject.h b/src/tiled/editableproject.h index 6328bca84b..128fb3fb2c 100644 --- a/src/tiled/editableproject.h +++ b/src/tiled/editableproject.h @@ -64,6 +64,7 @@ class EditableProject final : public EditableAsset private: ScriptPropertyType *toScriptType(const SharedPropertyType &type) const; + ScriptPropertyType *addPropertyType(const SharedPropertyType &type); void applyPropertyChanges(); }; diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index 2640c071f7..d4dbb409a6 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -18,19 +18,22 @@ * this program. If not, see . */ +#include "scriptpropertytype.h" + #include "preferences.h" #include "project.h" #include "projectmanager.h" -#include -#include "scriptpropertytype.h" #include "scriptmanager.h" +#include + namespace Tiled { const QString &ScriptPropertyType::name() const { return mType->name; } + void ScriptPropertyType::setName(const QString &name) { if (this->name() == name) @@ -46,6 +49,7 @@ void ScriptPropertyType::setName(const QString &name) mType->name = name; applyPropertyChanges(); } + void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), @@ -67,28 +71,35 @@ void ScriptPropertyType::applyPropertyChanges() Project &project = ProjectManager::instance()->project(); project.save(); } -void ScriptClassPropertyType::addMember(const QString &name) + +void ScriptClassPropertyType::addMember(const QString &name, const QVariant &value) { - if (this->mClassType->members.contains(name)) + if (mClassType->members.contains(name)) { - ScriptManager::instance() - .throwError(QCoreApplication::translate("Script Errors", "A class member of the specified name '%1' already exists").arg(name)); + ScriptManager::instance().throwError( + QCoreApplication::translate("Script Errors", + "A class member of the specified name '%1' already exists") + .arg(name)); return; } - // todo, how will the user specify the type of a new member ? could be a primitive or a class - this->applyPropertyChanges(); + mClassType->members.insert(name, value); + applyPropertyChanges(); } + void ScriptClassPropertyType::removeMember(const QString &name) { - if (!this->mClassType->members.contains(name)) + if (!mClassType->members.contains(name)) { - ScriptManager::instance() - .throwError(QCoreApplication::translate("Script Errors", "No class member of the specified name '%1' exists").arg(name)); + ScriptManager::instance().throwError( + QCoreApplication::translate("Script Errors", + "No class member of the specified name '%1' exists") + .arg(name)); return; } - this->mClassType->members.remove(name); - this->applyPropertyChanges(); + mClassType->members.remove(name); + applyPropertyChanges(); } + } // namespace Tiled #include "moc_scriptpropertytype.cpp" diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index 0871108fe0..b56c91e5ac 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -67,6 +67,7 @@ class ScriptEnumPropertyType : public ScriptPropertyType : ScriptPropertyType(propertyType) , mEnumType(propertyType) {} + // copied from propertytype.h enum StorageType { StringValue, @@ -75,18 +76,22 @@ class ScriptEnumPropertyType : public ScriptPropertyType Q_ENUM(StorageType); StorageType storageType() const { return static_cast(mEnumType->storageType); } + void setStorageType(StorageType value) { mEnumType->storageType = (EnumPropertyType::StorageType)value; applyPropertyChanges(); } + QStringList values() const { return mEnumType->values; } + void setValues(const QStringList &values) { mEnumType->values.clear(); mEnumType->values.append(values); applyPropertyChanges(); } + private: QSharedPointer mEnumType; }; @@ -132,7 +137,7 @@ class ScriptClassPropertyType : public ScriptPropertyType } QVariantMap members() const {return mClassType->members; } Q_INVOKABLE void removeMember(const QString& name); - Q_INVOKABLE void addMember(const QString &name); + Q_INVOKABLE void addMember(const QString &name, const QVariant &value); bool drawFill() const { return mClassType->drawFill; } void setDrawFill(bool value) @@ -140,6 +145,7 @@ class ScriptClassPropertyType : public ScriptPropertyType mClassType->drawFill = value; applyPropertyChanges(); } + int usageFlags() const { return mClassType->usageFlags; } void setUsageFlags(int value) { // clear any existing values first so that we set to exactly From 53dd077268ba3ce40186b6e2af3191ebcc49af8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 7 Mar 2025 20:45:07 +0100 Subject: [PATCH 15/19] Fixed return value of PropertyType.defaultValue Like this it could be somewhat useful, since now the value is typed correctly. --- src/tiled/scriptpropertytype.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index b56c91e5ac..8e86f32fa2 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -27,6 +27,7 @@ #include namespace Tiled { + /** * Scripting engine wrapper for PropertyType */ @@ -47,10 +48,11 @@ class ScriptPropertyType : public QObject void setName(const QString &name); bool isClass() const { return mType->isClass(); } bool isEnum() const { return mType->isEnum(); } - QVariant defaultValue() { return mType->defaultValue(); } + QVariant defaultValue() { return mType->wrap(mType->defaultValue()); } protected: void applyPropertyChanges(); + private: SharedPropertyType mType; }; @@ -79,7 +81,7 @@ class ScriptEnumPropertyType : public ScriptPropertyType void setStorageType(StorageType value) { - mEnumType->storageType = (EnumPropertyType::StorageType)value; + mEnumType->storageType = static_cast(value); applyPropertyChanges(); } @@ -87,8 +89,7 @@ class ScriptEnumPropertyType : public ScriptPropertyType void setValues(const QStringList &values) { - mEnumType->values.clear(); - mEnumType->values.append(values); + mEnumType->values = values; applyPropertyChanges(); } @@ -160,8 +161,6 @@ class ScriptClassPropertyType : public ScriptPropertyType QSharedPointer mClassType; }; - void registerPropertyTypes(QJSEngine *jsEngine); -} // namespace Tiled -Q_DECLARE_METATYPE(Tiled::ScriptPropertyType*) +} // namespace Tiled From feba321ec67315d504a41a6c1222cfbe91e8ebe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 7 Mar 2025 20:50:25 +0100 Subject: [PATCH 16/19] More sensible location for throwDuplicateNameError --- src/tiled/editableproject.cpp | 2 +- src/tiled/project.cpp | 7 ------- src/tiled/project.h | 1 - src/tiled/scriptpropertytype.cpp | 8 +++++++- src/tiled/scriptpropertytype.h | 2 ++ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tiled/editableproject.cpp b/src/tiled/editableproject.cpp index 3d1daeedea..8f049cef66 100644 --- a/src/tiled/editableproject.cpp +++ b/src/tiled/editableproject.cpp @@ -125,7 +125,7 @@ ScriptPropertyType *EditableProject::addEnumType(const QString &name) ScriptPropertyType *EditableProject::addPropertyType(const SharedPropertyType &type) { if (project()->propertyTypes()->findTypeByName(type->name)) { - project()->throwDuplicateNameError(type->name); + ScriptPropertyType::throwDuplicateNameError(type->name); return nullptr; } project()->propertyTypes()->add(type); diff --git a/src/tiled/project.cpp b/src/tiled/project.cpp index 1fdb7386ff..82907ab83b 100644 --- a/src/tiled/project.cpp +++ b/src/tiled/project.cpp @@ -21,13 +21,11 @@ #include "project.h" #include "properties.h" #include "savefile.h" -#include "scriptmanager.h" #include #include #include #include -#include namespace Tiled { @@ -162,9 +160,4 @@ void Project::removeFolder(int index) mFolders.removeAt(index); } -void Project::throwDuplicateNameError(const QString &name) -{ - ScriptManager::instance().throwError(QCoreApplication::translate("Error Renaming Type", - "The name '%1' is already in use.").arg(name)); -} } // namespace Tiled diff --git a/src/tiled/project.h b/src/tiled/project.h index 107a14265d..36b968db22 100644 --- a/src/tiled/project.h +++ b/src/tiled/project.h @@ -56,7 +56,6 @@ class TILED_EDITOR_EXPORT Project : public Object QString mAutomappingRulesFile; QVector mCommands; CompatibilityVersion mCompatibilityVersion = Tiled_Current; - void throwDuplicateNameError(const QString &name); private: QDateTime mLastSaved; diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index d4dbb409a6..c93d03a002 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -43,13 +43,19 @@ void ScriptPropertyType::setName(const QString &name) } Project &project = ProjectManager::instance()->project(); if (project.propertyTypes()->findTypeByName(name)) { - project.throwDuplicateNameError(name); + throwDuplicateNameError(name); return; } mType->name = name; applyPropertyChanges(); } +void ScriptPropertyType::throwDuplicateNameError(const QString &name) +{ + ScriptManager::instance().throwError( + QCoreApplication::translate("Script Errors", "The name '%1' is already in use.").arg(name)); +} + void registerPropertyTypes(QJSEngine *jsEngine) { jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index 8e86f32fa2..a2b67e1fad 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -50,6 +50,8 @@ class ScriptPropertyType : public QObject bool isEnum() const { return mType->isEnum(); } QVariant defaultValue() { return mType->wrap(mType->defaultValue()); } + static void throwDuplicateNameError(const QString &name); + protected: void applyPropertyChanges(); From 63e7c866247e6054e1540fe50bc3acd75d098201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 7 Mar 2025 21:01:57 +0100 Subject: [PATCH 17/19] Tweaks and added EnumPropertyType.addValue --- src/tiled/scriptpropertytype.cpp | 20 +++++++++----------- src/tiled/scriptpropertytype.h | 10 ++++++++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index c93d03a002..d8438533b8 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -37,10 +37,8 @@ const QString &ScriptPropertyType::name() const void ScriptPropertyType::setName(const QString &name) { if (this->name() == name) - { - // nothing to do return; - } + Project &project = ProjectManager::instance()->project(); if (project.propertyTypes()->findTypeByName(name)) { throwDuplicateNameError(name); @@ -56,14 +54,6 @@ void ScriptPropertyType::throwDuplicateNameError(const QString &name) QCoreApplication::translate("Script Errors", "The name '%1' is already in use.").arg(name)); } -void registerPropertyTypes(QJSEngine *jsEngine) -{ - jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), - jsEngine->newQMetaObject()); - jsEngine->globalObject().setProperty(QStringLiteral("ClassPropertyType"), - jsEngine->newQMetaObject()); -} - /* * Called when we make a change to a property type - * this will reflect any property changes in the UI. @@ -106,6 +96,14 @@ void ScriptClassPropertyType::removeMember(const QString &name) applyPropertyChanges(); } +void registerPropertyTypes(QJSEngine *jsEngine) +{ + jsEngine->globalObject().setProperty(QStringLiteral("EnumPropertyType"), + jsEngine->newQMetaObject()); + jsEngine->globalObject().setProperty(QStringLiteral("ClassPropertyType"), + jsEngine->newQMetaObject()); +} + } // namespace Tiled #include "moc_scriptpropertytype.cpp" diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index a2b67e1fad..0b7a67d27d 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -72,7 +72,7 @@ class ScriptEnumPropertyType : public ScriptPropertyType , mEnumType(propertyType) {} - // copied from propertytype.h + // Copied from EnumPropertyType enum StorageType { StringValue, IntValue @@ -95,6 +95,12 @@ class ScriptEnumPropertyType : public ScriptPropertyType applyPropertyChanges(); } + Q_INVOKABLE void addValue(const QString &name) + { + mEnumType->values.append(name); + applyPropertyChanges(); + } + private: QSharedPointer mEnumType; }; @@ -113,7 +119,7 @@ class ScriptClassPropertyType : public ScriptPropertyType , mClassType(propertyType) {} - // TODO: a way to avoid duplicating this again? + // Copied from ClassPropertyType enum ClassUsageFlag { PropertyValueType = 0x001, From 56380d0f88757c9eaf97321263aab628e30e0456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 7 Mar 2025 21:25:58 +0100 Subject: [PATCH 18/19] Added EnumPropertyType.nameOf With two overloads, one for raw integer values and one for PropertyValue, for convenience. The latter raises an error if it's not of the right type. --- src/tiled/scriptpropertytype.cpp | 40 ++++++++++++++++++++++++++++++++ src/tiled/scriptpropertytype.h | 21 ++++------------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index d8438533b8..200f2776a6 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -68,6 +68,44 @@ void ScriptPropertyType::applyPropertyChanges() project.save(); } +void ScriptEnumPropertyType::setStorageType(StorageType value) +{ + mEnumType->storageType = static_cast(value); + applyPropertyChanges(); +} + +void ScriptEnumPropertyType::setValues(const QStringList &values) +{ + mEnumType->values = values; + applyPropertyChanges(); +} + +void ScriptEnumPropertyType::addValue(const QString &name) +{ + mEnumType->values.append(name); + applyPropertyChanges(); +} + +QString ScriptEnumPropertyType::nameOf(int value) const +{ + if (value >= 0 && value < mEnumType->values.size()) + return mEnumType->values.at(value); + + return QString(); +} + +QString ScriptEnumPropertyType::nameOf(const QVariant &value) const +{ + const auto propertyValue = value.value(); + if (propertyValue.typeId != mEnumType->id) { + ScriptManager::instance().throwError( + QCoreApplication::translate("Script Errors", + "The specified value is not of the correct type")); + } + + return nameOf(propertyValue.value.toInt()); +} + void ScriptClassPropertyType::addMember(const QString &name, const QVariant &value) { if (mClassType->members.contains(name)) @@ -78,6 +116,7 @@ void ScriptClassPropertyType::addMember(const QString &name, const QVariant &val .arg(name)); return; } + mClassType->members.insert(name, value); applyPropertyChanges(); } @@ -92,6 +131,7 @@ void ScriptClassPropertyType::removeMember(const QString &name) .arg(name)); return; } + mClassType->members.remove(name); applyPropertyChanges(); } diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index 0b7a67d27d..d38984cc61 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -80,26 +80,15 @@ class ScriptEnumPropertyType : public ScriptPropertyType Q_ENUM(StorageType); StorageType storageType() const { return static_cast(mEnumType->storageType); } - - void setStorageType(StorageType value) - { - mEnumType->storageType = static_cast(value); - applyPropertyChanges(); - } + void setStorageType(StorageType value); QStringList values() const { return mEnumType->values; } + void setValues(const QStringList &values); - void setValues(const QStringList &values) - { - mEnumType->values = values; - applyPropertyChanges(); - } + Q_INVOKABLE void addValue(const QString &name); - Q_INVOKABLE void addValue(const QString &name) - { - mEnumType->values.append(name); - applyPropertyChanges(); - } + QString nameOf(int value) const; + QString nameOf(const QVariant &value) const; private: QSharedPointer mEnumType; From 87e307602409f2747fb2952eab5caca2eaab03a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 7 Mar 2025 21:35:12 +0100 Subject: [PATCH 19/19] Use a single shared pointer to refer to the type static_cast can be used to access the subclasses instead of storing more specifically typed shared pointers. --- src/tiled/scriptpropertytype.cpp | 21 ++++++------- src/tiled/scriptpropertytype.h | 51 +++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/tiled/scriptpropertytype.cpp b/src/tiled/scriptpropertytype.cpp index 200f2776a6..9ec68972b2 100644 --- a/src/tiled/scriptpropertytype.cpp +++ b/src/tiled/scriptpropertytype.cpp @@ -44,6 +44,7 @@ void ScriptPropertyType::setName(const QString &name) throwDuplicateNameError(name); return; } + mType->name = name; applyPropertyChanges(); } @@ -70,26 +71,26 @@ void ScriptPropertyType::applyPropertyChanges() void ScriptEnumPropertyType::setStorageType(StorageType value) { - mEnumType->storageType = static_cast(value); + enumType().storageType = static_cast(value); applyPropertyChanges(); } void ScriptEnumPropertyType::setValues(const QStringList &values) { - mEnumType->values = values; + enumType().values = values; applyPropertyChanges(); } void ScriptEnumPropertyType::addValue(const QString &name) { - mEnumType->values.append(name); + enumType().values.append(name); applyPropertyChanges(); } QString ScriptEnumPropertyType::nameOf(int value) const { - if (value >= 0 && value < mEnumType->values.size()) - return mEnumType->values.at(value); + if (value >= 0 && value < enumType().values.size()) + return enumType().values.at(value); return QString(); } @@ -97,7 +98,7 @@ QString ScriptEnumPropertyType::nameOf(int value) const QString ScriptEnumPropertyType::nameOf(const QVariant &value) const { const auto propertyValue = value.value(); - if (propertyValue.typeId != mEnumType->id) { + if (propertyValue.typeId != enumType().id) { ScriptManager::instance().throwError( QCoreApplication::translate("Script Errors", "The specified value is not of the correct type")); @@ -108,7 +109,7 @@ QString ScriptEnumPropertyType::nameOf(const QVariant &value) const void ScriptClassPropertyType::addMember(const QString &name, const QVariant &value) { - if (mClassType->members.contains(name)) + if (classType().members.contains(name)) { ScriptManager::instance().throwError( QCoreApplication::translate("Script Errors", @@ -117,13 +118,13 @@ void ScriptClassPropertyType::addMember(const QString &name, const QVariant &val return; } - mClassType->members.insert(name, value); + classType().members.insert(name, value); applyPropertyChanges(); } void ScriptClassPropertyType::removeMember(const QString &name) { - if (!mClassType->members.contains(name)) + if (!classType().members.contains(name)) { ScriptManager::instance().throwError( QCoreApplication::translate("Script Errors", @@ -132,7 +133,7 @@ void ScriptClassPropertyType::removeMember(const QString &name) return; } - mClassType->members.remove(name); + classType().members.remove(name); applyPropertyChanges(); } diff --git a/src/tiled/scriptpropertytype.h b/src/tiled/scriptpropertytype.h index d38984cc61..01adf6f4b1 100644 --- a/src/tiled/scriptpropertytype.h +++ b/src/tiled/scriptpropertytype.h @@ -46,15 +46,18 @@ class ScriptPropertyType : public QObject const QString &name() const; void setName(const QString &name); - bool isClass() const { return mType->isClass(); } - bool isEnum() const { return mType->isEnum(); } - QVariant defaultValue() { return mType->wrap(mType->defaultValue()); } + bool isClass() const { return propertyType().isClass(); } + bool isEnum() const { return propertyType().isEnum(); } + QVariant defaultValue() { return propertyType().wrap(propertyType().defaultValue()); } static void throwDuplicateNameError(const QString &name); protected: void applyPropertyChanges(); + PropertyType &propertyType() { return *mType; } + const PropertyType &propertyType() const { return *mType; } + private: SharedPropertyType mType; }; @@ -69,7 +72,6 @@ class ScriptEnumPropertyType : public ScriptPropertyType public: ScriptEnumPropertyType(const QSharedPointer &propertyType) : ScriptPropertyType(propertyType) - , mEnumType(propertyType) {} // Copied from EnumPropertyType @@ -79,10 +81,10 @@ class ScriptEnumPropertyType : public ScriptPropertyType }; Q_ENUM(StorageType); - StorageType storageType() const { return static_cast(mEnumType->storageType); } + StorageType storageType() const { return static_cast(enumType().storageType); } void setStorageType(StorageType value); - QStringList values() const { return mEnumType->values; } + QStringList values() const { return enumType().values; } void setValues(const QStringList &values); Q_INVOKABLE void addValue(const QString &name); @@ -91,7 +93,15 @@ class ScriptEnumPropertyType : public ScriptPropertyType QString nameOf(const QVariant &value) const; private: - QSharedPointer mEnumType; + EnumPropertyType &enumType() + { + return static_cast(propertyType()); + } + + const EnumPropertyType &enumType() const + { + return static_cast(propertyType()); + } }; class ScriptClassPropertyType : public ScriptPropertyType @@ -105,7 +115,6 @@ class ScriptClassPropertyType : public ScriptPropertyType public: ScriptClassPropertyType(const QSharedPointer &propertyType) : ScriptPropertyType(propertyType) - , mClassType(propertyType) {} // Copied from ClassPropertyType @@ -126,36 +135,44 @@ class ScriptClassPropertyType : public ScriptPropertyType }; Q_ENUM(ClassUsageFlag) - QColor color() const { return mClassType->color; } + QColor color() const { return classType().color; } void setColor(QColor &value) { - mClassType->color = value; + classType().color = value; applyPropertyChanges(); } - QVariantMap members() const {return mClassType->members; } + QVariantMap members() const {return classType().members; } Q_INVOKABLE void removeMember(const QString& name); Q_INVOKABLE void addMember(const QString &name, const QVariant &value); - bool drawFill() const { return mClassType->drawFill; } + bool drawFill() const { return classType().drawFill; } void setDrawFill(bool value) { - mClassType->drawFill = value; + classType().drawFill = value; applyPropertyChanges(); } - int usageFlags() const { return mClassType->usageFlags; } + int usageFlags() const { return classType().usageFlags; } void setUsageFlags(int value) { // clear any existing values first so that we set to exactly // the new value rather than just turning all flags in `value` // on. - mClassType->setUsageFlags(ClassUsageFlag::AnyUsage, false); - mClassType->setUsageFlags(value, true); + classType().setUsageFlags(ClassUsageFlag::AnyUsage, false); + classType().setUsageFlags(value, true); applyPropertyChanges(); } private: - QSharedPointer mClassType; + ClassPropertyType &classType() + { + return static_cast(propertyType()); + } + + const ClassPropertyType &classType() const + { + return static_cast(propertyType()); + } }; void registerPropertyTypes(QJSEngine *jsEngine);