--- a/src/modeleditcontext.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/modeleditcontext.h Fri Mar 04 11:37:50 2022 +0200 @@ -19,10 +19,16 @@ #pragma once #include "model.h" -class Model::EditContext +/** + * @brief Provides an interface for editing a model such that signals are emitted for each edit done. + * User edits to models should always be done through this class. + */ +class ModelEditor : public QObject { + Q_OBJECT public: - ~EditContext(); + ModelEditor(Model& model); + ~ModelEditor(); template<typename T, typename... Args> ldraw::Id<T> append(Args&&... args); ldraw::id_t append(std::unique_ptr<ldraw::Object>&& object); @@ -34,51 +40,59 @@ auto setObjectProperty(ldraw::id_t id, ldraw::Property property, const QVariant& value) -> ldraw::Object::SetPropertyResult; void setObjectPoint(ldraw::id_t id, int pointId, const glm::vec3& value); - void invertObject(ldraw::id_t id); - Model& model(); + template<typename T, typename Fn> + bool modifyObject(ldraw::Id<T> id, Fn&& function); + template<typename T, typename Fn> + bool modifyObjectAt(int position, Fn&& function); + const Model& model(); +Q_SIGNALS: + void objectAdded(int position); + void objectModified(int position); + void objectRemoved(ldraw::id_t id); private: - EditContext(Model& model); - friend class Model; QSet<ldraw::id_t> modifiedObjects; Model& storedModel; }; template<ldraw::Property Property> -void Model::EditContext::setObjectProperty(const ldraw::id_t id, const ldraw::PropertyType<Property>& value) +void ModelEditor::setObjectProperty(const ldraw::id_t id, const ldraw::PropertyType<Property>& value) { - ldraw::Object* object = this->model().findObjectById(id); - if (object != nullptr) - { + this->modifyObject(id, [&](ldraw::Object* object){ object->setProperty<Property>(value); - modifiedObjects.insert(id); - } + }); } template<typename T, typename... Args> -ldraw::Id<T> Model::EditContext::append(Args&&... args) +ldraw::Id<T> ModelEditor::append(Args&&... args) { return this->storedModel.append<T>(args...); } template<typename T, typename... Args> -ldraw::Id<T> Model::EditContext::insert(int position, Args&&... args) +ldraw::Id<T> ModelEditor::insert(int position, Args&&... args) { return this->storedModel.insert<T>(position, args...); } -namespace ldraw +template<typename T, typename Fn> +bool ModelEditor::modifyObject(ldraw::Id<T> id, Fn&& function) { - /// Determines how quadrilaterals are split into triangles - enum class Diagonal + QModelIndex index = this->model().find(id); + return this->modifyObjectAt<T>(index.row(), function); +} + +template<typename T, typename Fn> +bool ModelEditor::modifyObjectAt(int position, Fn&& function) +{ + if (position >= 0 and position < this->model().size()) { - Diagonal_13, - Diagonal_24 - }; - - // Splits the specified quadrilateral into triangles. - // If it is not a quadrilateral then no action is performed - auto splitQuadrilateral(Model::EditContext& editor, - quadrilateralid_t quadrilateral_id, - Diagonal splitType = Diagonal::Diagonal_13 - ) -> std::optional<std::pair<triangleid_t, triangleid_t>>; -} + T* object = dynamic_cast<T*>(this->storedModel[position]); + if (object != nullptr) + { + Q_EMIT this->objectModified(position); + function(object); + return true; + } + } + return false; +} \ No newline at end of file