# HG changeset patch # User Teemu Piippo # Date 1646386670 -7200 # Node ID 03f8e6d42e13a499eb850d3a4157b5a6bce7a228 # Parent e628fc2e0c72e77bd5942ef6be2065ecc91147f3 Major refactoring - Model now just stores objects - Document contains business logic - Model::EditContext is now ModelEditor, no longer a nested class diff -r e628fc2e0c72 -r 03f8e6d42e13 CMakeLists.txt --- a/CMakeLists.txt Thu Mar 03 21:13:16 2022 +0200 +++ b/CMakeLists.txt Fri Mar 04 11:37:50 2022 +0200 @@ -22,6 +22,7 @@ source_group("1 Foundation code" REGULAR_EXPRESSION "src/.+\\.(cpp|h|ui)") source_group("4 OpenGL renderer" REGULAR_EXPRESSION "src/gl/.+\\.(cpp|h|ui)") source_group("5 LDraw line types" REGULAR_EXPRESSION "src/linetypes/.+\\.(cpp|h|ui)") +source_group("5.1 LDraw algorithms" REGULAR_EXPRESSION "src/ldrawalgorithm.(cpp|h|ui)") source_group("3.2 Widgets" REGULAR_EXPRESSION "src/(ui|widgets)/.+\\.(cpp|h|ui)") source_group("3.1 Settings editor" REGULAR_EXPRESSION "src/settingseditor/.+\\.(cpp|h|ui)") source_group("3 User interface" REGULAR_EXPRESSION "src/(mainwindow|document|documentmanager|uiutilities)\\.(cpp|h|ui)") @@ -35,6 +36,7 @@ src/edithistory.cpp src/geometry.cpp src/header.cpp + src/ldrawalgorithm.cpp src/libraries.cpp src/invert.cpp src/main.cpp @@ -89,6 +91,7 @@ src/geometry.h src/header.h src/invert.h + src/ldrawalgorithm.h src/libraries.h src/main.h src/mainwindow.h diff -r e628fc2e0c72 -r 03f8e6d42e13 src/document.cpp --- a/src/document.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/document.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -132,9 +132,13 @@ this->renderer->setOverpaintCallback(fn); } -Model::EditContext Document::editModel() +std::unique_ptr Document::editModel() { - return this->model->edit(); + std::unique_ptr editorPointer = std::make_unique(*this->model); + connect(editorPointer.get(), &ModelEditor::objectModified, [&](int position){ + this->model->emitDataChangedSignal(position); + }); + return editorPointer; } void Document::applyToVertices(VertexMap::ApplyFunction fn) const @@ -154,9 +158,9 @@ { this->tools.clear(); this->tools.reserve(3); - this->tools.push_back(new SelectTool{this->model, this}); - this->tools.push_back(new DrawTool{this->model, this}); - this->tools.push_back(new TransformTool{this->model, this}); + this->tools.push_back(new SelectTool{this}); + this->tools.push_back(new DrawTool{this}); + this->tools.push_back(new TransformTool{this}); for (BaseTool* const toolInstance : this->tools) { QAction* action = new QAction{toolInstance->name(), this}; @@ -228,3 +232,8 @@ { this->renderer->adjustGridToView(); } + +const Model &Document::getModel() +{ + return *this->model; +} diff -r e628fc2e0c72 -r 03f8e6d42e13 src/document.h --- a/src/document.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/document.h Fri Mar 04 11:37:50 2022 +0200 @@ -44,10 +44,11 @@ void restoreSplitterState(const QByteArray& state); void setRenderPreferences(const gl::RenderPreferences& newPreferences); void setCanvasOverpaintCallback(Canvas::OverpaintCallback fn); - Model::EditContext editModel(); + std::unique_ptr editModel(); void applyToVertices(VertexMap::ApplyFunction fn) const; void handleKeyPress(QKeyEvent* event); void adjustGridToView(); + const Model& getModel(); Q_SIGNALS: void newStatusText(const QString& newStatusText); void splitterChanged(); diff -r e628fc2e0c72 -r 03f8e6d42e13 src/documentmanager.cpp --- a/src/documentmanager.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/documentmanager.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -136,9 +136,8 @@ file.open(QFile::ReadOnly | QFile::Text); std::unique_ptr newModel = std::make_unique(this); QTextStream textStream{&file}; - Model::EditContext editor = newModel->edit(); Parser parser{file}; - parser.parseBody(editor); + parser.parseBody(*newModel); std::optional result; if (file.error() == QFile::NoError) { diff -r e628fc2e0c72 -r 03f8e6d42e13 src/edithistory.cpp --- a/src/edithistory.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/edithistory.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -24,32 +24,32 @@ } -void InsertHistoryEntry::undo(Model::EditContext &editContext) +void InsertHistoryEntry::undo(ModelEditor &editContext) { editContext.remove(this->position); } -void InsertHistoryEntry::redo(Model::EditContext &editContext) +void InsertHistoryEntry::redo(ModelEditor &editContext) { } -void DeleteHistoryEntry::undo(Model::EditContext &editContext) +void DeleteHistoryEntry::undo(ModelEditor &editContext) { static_cast(this)->redo(editContext); } -void DeleteHistoryEntry::redo(Model::EditContext &editContext) +void DeleteHistoryEntry::redo(ModelEditor &editContext) { static_cast(this)->undo(editContext); } -void EditHistoryEntry::undo(Model::EditContext &editContext) +void EditHistoryEntry::undo(ModelEditor &editContext) { } -void EditHistoryEntry::redo(Model::EditContext &editContext) +void EditHistoryEntry::redo(ModelEditor &editContext) { } diff -r e628fc2e0c72 -r 03f8e6d42e13 src/edithistory.h --- a/src/edithistory.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/edithistory.h Fri Mar 04 11:37:50 2022 +0200 @@ -20,11 +20,13 @@ #include "main.h" #include "model.h" +class ModelEditor; + class AbstractHistoryEntry { public: - virtual void undo(Model::EditContext& editContext) = 0; - virtual void redo(Model::EditContext& editContext) = 0; + virtual void undo(ModelEditor& editContext) = 0; + virtual void redo(ModelEditor& editContext) = 0; }; class InsertHistoryEntry : public AbstractHistoryEntry @@ -33,8 +35,8 @@ InsertHistoryEntry(int position, const QByteArray& state) : position{position}, state{state} {} - void undo(Model::EditContext& editContext) override; - void redo(Model::EditContext& editContext) override; + void undo(ModelEditor& editContext) override; + void redo(ModelEditor& editContext) override; protected: int position; QByteArray state; @@ -43,8 +45,8 @@ class DeleteHistoryEntry : public InsertHistoryEntry { public: - void undo(Model::EditContext& editContext) override; - void redo(Model::EditContext& editContext) override; + void undo(ModelEditor& editContext) override; + void redo(ModelEditor& editContext) override; }; class EditHistoryEntry : public AbstractHistoryEntry @@ -54,8 +56,8 @@ position{position}, stateBefore{stateBefore}, stateAfter{stateAfter} {} - void undo(Model::EditContext& editContext) override; - void redo(Model::EditContext& editContext) override; + void undo(ModelEditor& editContext) override; + void redo(ModelEditor& editContext) override; private: int position; QByteArray stateBefore; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/model.cpp --- a/src/model.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/model.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -60,17 +60,6 @@ } /** - * @brief Obtains an editing context for this model. - * Editing contexts are used to perform modifications to the model. - * @return editing context - */ -Model::EditContext Model::edit() -{ - this->editCounter += 1; - return {*this}; -} - -/** * @brief @overload QAbstractListModel::rowCount * @return size */ @@ -158,34 +147,17 @@ #endif /** - * @brief Called by the editing context to signal to the model that editing is done. - */ -void Model::editFinished() -{ - this->editCounter -= 1; -} - -/** - * @brief Called by the editing context to indicate that the specified object has been modified. - * @param id ID of the object that has been modified - */ -void Model::objectModified(ldraw::id_t id) -{ - const QModelIndex index = this->find(id); - Q_EMIT this->dataChanged(index, index); -} - -/** * @brief Adds the given object into the model. * @param object r-value reference to the object */ -void Model::append(ModelObjectPointer&& object) +ldraw::id_t Model::append(ModelObjectPointer&& object) { const int position = static_cast(this->body.size()); Q_EMIT this->beginInsertRows({}, position, position); this->body.push_back(std::move(object)); Q_EMIT this->endInsertRows(); - Q_EMIT this->objectAdded(position); + this->objectsById[object->id] = object.get(); + return object->id; } /** @@ -197,13 +169,16 @@ if (position >= 0 and position < signed_cast(this->body.size())) { Q_EMIT this->beginRemoveRows({}, position, position); - const ldraw::id_t id = this->body[position]->id; this->body.erase(std::begin(this->body) + position); Q_EMIT this->endRemoveRows(); - Q_EMIT this->objectRemoved(id); } } +void Model::emitDataChangedSignal(int position) +{ + Q_EMIT this->dataChanged(this->index(position), this->index(position)); +} + /** * @brief Gets the object pointer at the specified position * @param index Position of the object @@ -279,32 +254,3 @@ out << object->toLDrawCode() << "\r\n"; }); } - -/** - * @brief Modifies the !LDRAW_ORG line so that it becomes unofficial - */ -void makeUnofficial(Model& model) -{ - if (model.size() >= 4) - { - const ldraw::Object* ldrawOrgLine = model[3]; - if (isA(ldrawOrgLine)) - { - const QString& body = ldrawOrgLine->getProperty(); - if (body.startsWith("!LDRAW_ORG ") and not body.startsWith("!LDRAW_ORG Unofficial_")) - { - // Add Unofficial_ to part type - QStringList tokens = body.split(" "); - tokens[1] = "Unofficial_" + tokens[1]; - // Remove the UPDATE tag if it's there - if (tokens.size() >= 4 && tokens[2] == "UPDATE") - { - tokens.removeAt(3); - tokens.removeAt(2); - } - Model::EditContext editor = model.edit(); - editor.setObjectProperty(ldrawOrgLine->id, tokens.join(" ")); - } - } - } -} diff -r e628fc2e0c72 -r 03f8e6d42e13 src/model.h --- a/src/model.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/model.h Fri Mar 04 11:37:50 2022 +0200 @@ -34,13 +34,11 @@ { Q_OBJECT public: - class EditContext; Model(QObject* parent = nullptr); Model(const Model&) = delete; int size() const; ldraw::id_t at(int index) const; - EditContext edit(); int rowCount(const QModelIndex&) const override; QVariant data(const QModelIndex& index, int role) const override; ldraw::Object* findObjectById(const ldraw::id_t id); @@ -59,30 +57,20 @@ Get2Result get2(ldraw::Id id) const; ldraw::Object* operator[](int index); const ldraw::Object* operator[](int index) const; -Q_SIGNALS: - void objectAdded(int position); - void objectModified(int position); - void objectRemoved(ldraw::id_t id); -private: using ModelObjectPointer = std::unique_ptr; template ldraw::Id append(Args&&... args); - void append(ModelObjectPointer&& object); + ldraw::id_t append(ModelObjectPointer&& object); template ldraw::Id insert(std::size_t position, Args&&... args); void remove(int position); - void editFinished(); - void objectModified(ldraw::id_t id); + void emitDataChangedSignal(int position); +private: bool modified = false; std::vector body; std::map objectsById; - /** - * @brief Amount of model edit contexts active - */ - int editCounter = 0; }; -void makeUnofficial(Model& model); void save(const Model& model, QIODevice *device); /** @@ -112,7 +100,6 @@ this->body.push_back(std::make_unique(args...)); ldraw::Object* pointer = this->body.back().get(); this->objectsById[pointer->id] = pointer; - Q_EMIT objectAdded(static_cast(this->body.size() - 1)); Q_EMIT endInsertRows(); return ldraw::Id{pointer->id.value}; } @@ -124,7 +111,6 @@ this->body.insert(std::begin(this->body) + position, std::make_unique(args...)); ldraw::Object* pointer = this->body[position].get(); this->objectsById[pointer->id] = pointer; - Q_EMIT objectAdded(static_cast(position)); Q_EMIT endInsertRows(); return ldraw::Id{pointer->id.value}; } diff -r e628fc2e0c72 -r 03f8e6d42e13 src/modeleditcontext.cpp --- a/src/modeleditcontext.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/modeleditcontext.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -20,40 +20,42 @@ #include "linetypes/triangle.h" #include "linetypes/quadrilateral.h" -Model::EditContext::EditContext(Model& model) : +ModelEditor::ModelEditor(Model& model) : storedModel{model} { } -Model::EditContext::~EditContext() +ModelEditor::~ModelEditor() { for (ldraw::id_t id : this->modifiedObjects) { - this->model().objectModified(id); + const QModelIndex index = this->model().find(id); + if (index.isValid()) + { + Q_EMIT this->objectModified(index.row()); + } } - this->model().editFinished(); } -ldraw::id_t Model::EditContext::append(std::unique_ptr&& object) +ldraw::id_t ModelEditor::append(std::unique_ptr&& object) { - const ldraw::id_t id = object->id; - this->model().objectsById[id] = object.get(); - this->model().append(std::move(object)); - return id; + this->storedModel.append(std::move(object)); + Q_EMIT this->objectAdded(this->model().size() - 1); + return object->id; } -void Model::EditContext::remove(int position) +void ModelEditor::remove(int position) { - this->model().remove(position); + this->storedModel.remove(position); } -auto Model::EditContext::setObjectProperty( +auto ModelEditor::setObjectProperty( const ldraw::id_t id, const ldraw::Property property, const QVariant& value) -> ldraw::Object::SetPropertyResult { - ldraw::Object* const object = this->model().findObjectById(id); + ldraw::Object* const object = this->storedModel.findObjectById(id); if (object != nullptr) { const ldraw::Object::SetPropertyResult result = object->setProperty(ldraw::PropertyKeyValue{property, value}); @@ -66,9 +68,9 @@ } } -void Model::EditContext::setObjectPoint(ldraw::id_t id, int pointId, const glm::vec3& value) +void ModelEditor::setObjectPoint(ldraw::id_t id, int pointId, const glm::vec3& value) { - ldraw::Object* object = this->model().findObjectById(id); + ldraw::Object* object = this->storedModel.findObjectById(id); if (object != nullptr) { object->setProperty(ldraw::PropertyKeyValue{ldraw::pointProperty(pointId), QVariant::fromValue(value)}); @@ -76,53 +78,8 @@ } } -void Model::EditContext::invertObject(ldraw::id_t id) -{ - auto it = this->model().objectsById.find(id); - if (it != this->model().objectsById.end()) - { - ldraw::Object* object = it->second; - object->invert(); - } -} - -Model& Model::EditContext::model() +const Model &ModelEditor::model() { return this->storedModel; } -static std::array splitTriangles(ldraw::Diagonal diagonal, const std::array& points) -{ - std::array result; - switch (diagonal) - { - case ldraw::Diagonal::Diagonal_13: - result = {geom::Triangle{points[0], points[1], points[2]}, {points[0], points[2], points[3]}}; - break; - case ldraw::Diagonal::Diagonal_24: - result = {geom::Triangle{points[0], points[1], points[3]}, {points[1], points[2], points[3]}}; - break; - } - return result; -} - -auto ldraw::splitQuadrilateral( - Model::EditContext& editor, - ldraw::quadrilateralid_t quadrilateral_id, - ldraw::Diagonal splitType -) -> std::optional> -{ - std::optional> result; - const auto resolved = editor.model().get2(quadrilateral_id); - if (resolved.object != nullptr) - { - const ldraw::Color color = resolved.object->colorIndex; - const std::array split = splitTriangles(splitType, resolved.object->points); - const int position = resolved.index.row(); - editor.remove(position); - result = std::make_pair( - editor.insert(position, split[0].points, color), - editor.insert(position, split[1].points, color)); - } - return result; -} diff -r e628fc2e0c72 -r 03f8e6d42e13 src/modeleditcontext.h --- 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 ldraw::Id append(Args&&... args); ldraw::id_t append(std::unique_ptr&& 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 + bool modifyObject(ldraw::Id id, Fn&& function); + template + 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 modifiedObjects; Model& storedModel; }; template -void Model::EditContext::setObjectProperty(const ldraw::id_t id, const ldraw::PropertyType& value) +void ModelEditor::setObjectProperty(const ldraw::id_t id, const ldraw::PropertyType& value) { - ldraw::Object* object = this->model().findObjectById(id); - if (object != nullptr) - { + this->modifyObject(id, [&](ldraw::Object* object){ object->setProperty(value); - modifiedObjects.insert(id); - } + }); } template -ldraw::Id Model::EditContext::append(Args&&... args) +ldraw::Id ModelEditor::append(Args&&... args) { return this->storedModel.append(args...); } template -ldraw::Id Model::EditContext::insert(int position, Args&&... args) +ldraw::Id ModelEditor::insert(int position, Args&&... args) { return this->storedModel.insert(position, args...); } -namespace ldraw +template +bool ModelEditor::modifyObject(ldraw::Id id, Fn&& function) { - /// Determines how quadrilaterals are split into triangles - enum class Diagonal + QModelIndex index = this->model().find(id); + return this->modifyObjectAt(index.row(), function); +} + +template +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>; -} + T* object = dynamic_cast(this->storedModel[position]); + if (object != nullptr) + { + Q_EMIT this->objectModified(position); + function(object); + return true; + } + } + return false; +} \ No newline at end of file diff -r e628fc2e0c72 -r 03f8e6d42e13 src/parser.cpp --- a/src/parser.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/parser.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -233,7 +233,7 @@ * @brief Parses the model body into the given model. * @param editor Handle to model edit context */ -void Parser::parseBody(Model::EditContext& editor) +void Parser::parseBody(Model& model) { bool invertNext = false; while (not this->device.atEnd()) @@ -249,10 +249,10 @@ continue; } std::unique_ptr object = parseFromString(line); - auto id = editor.append(std::move(object)); + model.append(std::move(object)); if (invertNext) { - editor.invertObject(id); + model[model.size() - 1]->invert(); } invertNext = false; } diff -r e628fc2e0c72 -r 03f8e6d42e13 src/parser.h --- a/src/parser.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/parser.h Fri Mar 04 11:37:50 2022 +0200 @@ -30,7 +30,7 @@ enum { EndOfModel = -1 }; Parser(QIODevice& device, QObject* parent = nullptr); LDHeader parseHeader(Winding& winding); - void parseBody(Model::EditContext& editor); + void parseBody(Model &model); static std::unique_ptr parseFromString(QString line); private: enum HeaderParseResult {ParseSuccess, ParseFailure, StopParsing}; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/polygoncache.cpp --- a/src/polygoncache.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/polygoncache.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -6,8 +6,8 @@ { const auto mark = [this](){ this->needRecache = true; }; connect(model, &Model::dataChanged, mark); - connect(model, &Model::objectAdded, mark); - connect(model, &Model::objectRemoved, mark); + connect(model, &Model::rowsInserted, mark); + connect(model, &Model::rowsRemoved, mark); } /** diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/basetool.cpp --- a/src/tools/basetool.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/basetool.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -1,5 +1,9 @@ #include "basetool.h" +#include "document.h" -BaseTool::BaseTool(Model*, QWidget *parent) : - QObject{parent}, - parentWidget{parent} {} +BaseTool::BaseTool(Document *document) : + QObject{document}, + parentWidget{document}, + document{document} +{ +} diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/basetool.h --- a/src/tools/basetool.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/basetool.h Fri Mar 04 11:37:50 2022 +0200 @@ -10,7 +10,7 @@ Q_OBJECT public: - BaseTool(Model* model, QWidget* parent = nullptr); + BaseTool(Document* document); virtual QString name() const = 0; virtual QString toolTip() const = 0; @@ -24,5 +24,6 @@ virtual void overpaint(Canvas*, QPainter*) const {} protected: QWidget* const parentWidget; + Document* const document; }; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/drawtool.cpp --- a/src/tools/drawtool.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/drawtool.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -12,8 +12,10 @@ static const QBrush polygonBrush = {QColor{64, 255, 128, 192}}; static const QBrush badPolygonBrush = {QColor{255, 96, 96, 192}}; -DrawTool::DrawTool(Model *model, QWidget *parent) : - BaseTool{model, parent} {} +DrawTool::DrawTool(Document* document) : + BaseTool{document} +{ +} QString DrawTool::name() const { @@ -142,17 +144,17 @@ { if (this->polygon.size() >= 2 and this->polygon.size() <= 4) { - Model::EditContext edit = document->editModel(); + std::unique_ptr modelEditor = document->editModel(); switch (this->polygon.size()) { case 2: - edit.append(vectorToArray<2>(this->polygon), ldraw::EDGE_COLOR); + modelEditor->append(vectorToArray<2>(this->polygon), ldraw::EDGE_COLOR); break; case 3: - edit.append(vectorToArray<3>(this->polygon), ldraw::MAIN_COLOR); + modelEditor->append(vectorToArray<3>(this->polygon), ldraw::MAIN_COLOR); break; case 4: - edit.append(vectorToArray<4>(this->polygon), ldraw::MAIN_COLOR); + modelEditor->append(vectorToArray<4>(this->polygon), ldraw::MAIN_COLOR); break; } } diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/drawtool.h --- a/src/tools/drawtool.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/drawtool.h Fri Mar 04 11:37:50 2022 +0200 @@ -6,7 +6,7 @@ Q_OBJECT public: - Q_INVOKABLE DrawTool(Model* model, QWidget* parent = nullptr); + Q_INVOKABLE DrawTool(Document* document); QString name() const override; QString toolTip() const override; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/selecttool.cpp --- a/src/tools/selecttool.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/selecttool.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -1,8 +1,10 @@ #include "selecttool.h" -SelectTool::SelectTool(Model* model, QWidget* parent) : - BaseTool{model, parent}, - objectEditor{new ObjectEditor{model, ldraw::NULL_ID, parent}} {} +SelectTool::SelectTool(Document* document) : + BaseTool{document}, + objectEditor{new ObjectEditor{document, ldraw::NULL_ID}} +{ +} QString SelectTool::name() const { diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/selecttool.h --- a/src/tools/selecttool.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/selecttool.h Fri Mar 04 11:37:50 2022 +0200 @@ -7,7 +7,7 @@ Q_OBJECT public: - Q_INVOKABLE SelectTool(Model* model, QWidget* parent = nullptr); + Q_INVOKABLE SelectTool(Document *document); QString name() const override; QString toolTip() const override; bool mouseClick(Document*, Canvas*, QMouseEvent*) override; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/transformtool.cpp --- a/src/tools/transformtool.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/transformtool.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -3,13 +3,13 @@ #include "modeleditcontext.h" #include "linetypes/object.h" #include "transformtool.h" +#include "document.h" -TransformTool::TransformTool(Model* model, QWidget* parent) : - BaseTool{model, parent}, - model{model}, - matrixEditor{new MatrixEditor{parent}}, - button{new QPushButton{"Apply", parent}}, - widget{new QWidget{parent}} +TransformTool::TransformTool(Document* document) : + BaseTool{document}, + matrixEditor{new MatrixEditor{document}}, + button{new QPushButton{"Apply", document}}, + widget{new QWidget{document}} { widget->setLayout(new QHBoxLayout{widget}); widget->layout()->addWidget(this->matrixEditor); @@ -39,25 +39,22 @@ void TransformTool::applyButtonClicked() { - Model::EditContext editcontext = this->model->edit(); + std::unique_ptr editor = this->document->editModel(); const glm::mat4 matrix = this->matrixEditor->value(); for (ldraw::id_t id : this->selection) { - const ldraw::Object* object = model->get(id); - for (int i = 0; i < object->numPoints(); i += 1) - { - const ldraw::Property property = ldraw::pointProperty(i); - const glm::vec3& vec = matrix * glm::vec4{object->getPoint(i), 1}; - editcontext.setObjectProperty(id, property, QVariant::fromValue(vec)); - } - QVariant transformMatrix = object->getProperty(ldraw::Property::Transformation); - if (not transformMatrix.isNull()) - { - editcontext.setObjectProperty( - id, - ldraw::Property::Transformation, - QVariant::fromValue(matrix * transformMatrix.value()) - ); - } + editor->modifyObject(id, [&](ldraw::Object* object){ + for (int i = 0; i < object->numPoints(); i += 1) + { + const ldraw::Property property = ldraw::pointProperty(i); + const glm::vec3& vec = matrix * glm::vec4{object->getPoint(i), 1}; + object->setProperty({property, QVariant::fromValue(vec)}); + } + QVariant transformMatrix = object->getProperty(ldraw::Property::Transformation); + if (not transformMatrix.isNull()) + { + object->setProperty(matrix * transformMatrix.value()); + } + }); } } diff -r e628fc2e0c72 -r 03f8e6d42e13 src/tools/transformtool.h --- a/src/tools/transformtool.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/tools/transformtool.h Fri Mar 04 11:37:50 2022 +0200 @@ -7,14 +7,13 @@ { Q_OBJECT public: - Q_INVOKABLE TransformTool(Model *model, QWidget *parent = nullptr); + Q_INVOKABLE TransformTool(Document *document); virtual QString name() const override; virtual QString toolTip() const override; void selectionChanged(const QSet &newSelection) override; QWidget *toolWidget() override; private: Q_SLOT void applyButtonClicked(); - Model* const model; MatrixEditor* matrixEditor; QPushButton* button; QWidget* widget; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/ui/objecteditor.cpp --- a/src/ui/objecteditor.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/ui/objecteditor.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -1,9 +1,10 @@ #include #include "objecteditor.h" +#include "document.h" -ObjectEditor::ObjectEditor(Model* model, const ldraw::id_t id, QWidget *parent) : - QWidget{parent}, - model{model} +ObjectEditor::ObjectEditor(Document* document, const ldraw::id_t id) : + QWidget{document}, + document{document} { this->setObjectId(id); this->setLayout(new QVBoxLayout{this}); @@ -12,12 +13,12 @@ void ObjectEditor::setObjectId(const ldraw::id_t id) { this->objectId = id; - const ldraw::Object* object = this->model->get(id); + const ldraw::Object* object = this->document->getModel().get(id); if (object != nullptr and object->numPoints() > 0) { if (not this->polygonEditor.has_value()) { - this->polygonEditor.emplace(this->model, id); + this->polygonEditor.emplace(this->document, id); this->layout()->addWidget(&*this->polygonEditor); } else diff -r e628fc2e0c72 -r 03f8e6d42e13 src/ui/objecteditor.h --- a/src/ui/objecteditor.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/ui/objecteditor.h Fri Mar 04 11:37:50 2022 +0200 @@ -4,14 +4,16 @@ #include "../model.h" #include "polygonobjecteditor.h" +class Document; + class ObjectEditor : public QWidget { Q_OBJECT public: - explicit ObjectEditor(Model* model, ldraw::id_t id = ldraw::NULL_ID, QWidget* parent = nullptr); + explicit ObjectEditor(Document* document, ldraw::id_t id = ldraw::NULL_ID); void setObjectId(ldraw::id_t id); private: - Model* const model; + Document* const document; ldraw::id_t objectId = ldraw::NULL_ID; std::optional polygonEditor; }; diff -r e628fc2e0c72 -r 03f8e6d42e13 src/ui/polygonobjecteditor.cpp --- a/src/ui/polygonobjecteditor.cpp Thu Mar 03 21:13:16 2022 +0200 +++ b/src/ui/polygonobjecteditor.cpp Fri Mar 04 11:37:50 2022 +0200 @@ -1,6 +1,6 @@ #include #include -#include "model.h" +#include "document.h" #include "modeleditcontext.h" #include "widgets/vec3editor.h" #include "ui/polygonobjecteditor.h" @@ -8,9 +8,9 @@ static constexpr char INDEX_NAME[] = "_ldforge_index"; static constexpr char LABEL_NAME[] = "_ldforge_label"; -PolygonObjectEditor::PolygonObjectEditor(Model* model, ldraw::id_t id, QWidget* parent) : - QWidget{parent}, - model{model}, +PolygonObjectEditor::PolygonObjectEditor(Document* document, ldraw::id_t id) : + QWidget{document}, + document{document}, storedObjectId{ldraw::NULL_ID.value} { this->splitter.emplace(Qt::Vertical, this); @@ -53,23 +53,27 @@ void PolygonObjectEditor::setupPointWidget(int n) { - const ldraw::Object* const object = this->model->get(this->objectId()); - const ldraw::Property property = ldraw::pointProperty(n); - const QVariant value = object->getProperty(property); - if (value.isValid()) + const QModelIndex index = this->document->getModel().find(this->objectId()); + if (index.isValid()) { - std::unique_ptr editor = std::make_unique(value.value(), this); - QObject::connect(editor.get(), &Vec3Editor::valueChanged, this, &PolygonObjectEditor::pointChanged); - editor->setProperty(INDEX_NAME, QVariant::fromValue(n)); - editor->setProperty(LABEL_NAME, &ldraw::traits(property).name[0]); - this->widgets.push_back(std::move(editor)); + const ldraw::Object* const object = this->document->getModel()[index.row()]; + const ldraw::Property property = ldraw::pointProperty(n); + const QVariant value = object->getProperty(property); + if (value.isValid()) + { + std::unique_ptr editor = std::make_unique(value.value(), this); + QObject::connect(editor.get(), &Vec3Editor::valueChanged, this, &PolygonObjectEditor::pointChanged); + editor->setProperty(INDEX_NAME, QVariant::fromValue(n)); + editor->setProperty(LABEL_NAME, &ldraw::traits(property).name[0]); + this->widgets.push_back(std::move(editor)); + } } } void PolygonObjectEditor::pointChanged(const glm::vec3& value) { - Model::EditContext editcontext = this->model->edit(); + std::unique_ptr modelEditor = this->document->editModel(); const int n = this->sender()->property(INDEX_NAME).toInt(); const ldraw::Property property = ldraw::pointProperty(n); - editcontext.setObjectProperty(this->objectId(), property, QVariant::fromValue(value)); + modelEditor->setObjectProperty(this->objectId(), property, QVariant::fromValue(value)); } diff -r e628fc2e0c72 -r 03f8e6d42e13 src/ui/polygonobjecteditor.h --- a/src/ui/polygonobjecteditor.h Thu Mar 03 21:13:16 2022 +0200 +++ b/src/ui/polygonobjecteditor.h Fri Mar 04 11:37:50 2022 +0200 @@ -4,12 +4,12 @@ #include "main.h" #include "../widgets/vec3editor.h" -class Model; +class Document; class PolygonObjectEditor : public QWidget { public: - PolygonObjectEditor(Model* model, ldraw::id_t id, QWidget* parent = nullptr); + PolygonObjectEditor(Document* document, ldraw::id_t id); ~PolygonObjectEditor(); ldraw::id_t objectId() const; void setObjectId(ldraw::id_t id); @@ -17,7 +17,7 @@ void buildWidgets(); void setupPointWidget(int n); Q_SLOT void pointChanged(const glm::vec3& value); - Model* model; + Document* document; ldraw::id_t storedObjectId; std::vector> widgets; std::optional splitter;