Wed, 25 May 2022 18:29:49 +0300
move drawState to Document
src/document.cpp | file | annotate | diff | comparison | revisions | |
src/document.h | file | annotate | diff | comparison | revisions | |
src/ui/canvas.cpp | file | annotate | diff | comparison | revisions | |
src/ui/canvas.h | file | annotate | diff | comparison | revisions |
--- a/src/document.cpp Wed May 25 17:56:30 2022 +0300 +++ b/src/document.cpp Wed May 25 18:29:49 2022 +0300 @@ -23,6 +23,9 @@ #include "model.h" #include "modeleditor.h" #include "ui/objecteditor.h" +#include "linetypes/edge.h" +#include "linetypes/triangle.h" +#include "linetypes/quadrilateral.h" Document::Document( Model* model, @@ -50,6 +53,8 @@ this->toolsBar->setOrientation(Qt::Vertical); this->setMouseTracking(true); connect(this->ui.viewportListSplitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); + connect(this->canvas, &Canvas::mouseClick, this, &Document::canvasMouseClick); + connect(this->canvas, &Canvas::mouseMove, this, &Document::canvasMouseMove); connect(this->canvas, &Canvas::newStatusText, this, &Document::newStatusText); connect(this->canvas, &Canvas::selectionChanged, [&](const QSet<ldraw::id_t>& newSelection) { @@ -153,6 +158,7 @@ this->toolActions.push_back(action); connect(action, &QAction::triggered, this, &Document::editingModeTriggered); } + this->ui.listView->selectAll(); } void Document::editingModeTriggered() @@ -161,7 +167,7 @@ if (triggeredAction != nullptr) { const int index = triggeredAction->property(INDEX_PROPERTY).toInt(); - this->canvas->mode = static_cast<EditingMode>(index); + this->mode = static_cast<EditingMode>(index); this->ui.toolWidgetStack->setCurrentIndex(index); for (QAction* action : this->toolActions) { action->setChecked(action == triggeredAction); @@ -169,6 +175,107 @@ } } +void updatePreviewPolygon(DrawState* drawState) +{ + drawState->previewPolygon = drawState->polygon; + drawState->previewPolygon.resize(drawState->polygon.size() + 1); + drawState->previewPolygon.back() = drawState->previewPoint; + if (drawState->previewPolygon.size() > 2) + { + drawState->isconcave = not geom::isConvex(drawState->previewPolygon); + } +} + +void removeLastPoint(DrawState* drawState) +{ + if (drawState->polygon.size() > 0) + { + drawState->polygon.erase(drawState->polygon.end() - 1); + updatePreviewPolygon(drawState); + } +} + +bool isCloseToExistingPoints(const std::vector<glm::vec3>& points, const glm::vec3 &pos) +{ + return any(points, std::bind(geom::isclose, std::placeholders::_1, pos)); +} + +void Document::canvasMouseClick(QMouseEvent *event) +{ + switch(this->mode) + { + case SelectMode: + if (event->button() == Qt::LeftButton) + { + const ldraw::id_t highlighted = this->canvas->getHighlightedObject(); + QSet<ldraw::id_t> selected; + if (highlighted != ldraw::NULL_ID) { + selected.insert(highlighted); + } + this->select(selected); + event->accept(); + } + break; + case DrawMode: + if (event->button() == Qt::LeftButton and this->canvas->worldPosition.has_value()) + { + const glm::vec3& pos = this->canvas->worldPosition.value(); + if (isCloseToExistingPoints(this->drawState.polygon, pos)) + { + this->closeShape(); + } + else + { + this->drawState.polygon.push_back(pos); + updatePreviewPolygon(&this->drawState); + } + event->accept(); + } + else if (true + and event->button() == Qt::RightButton + and this->drawState.polygon.size() > 0 + ) { + this->drawState.polygon.erase(this->drawState.polygon.end() - 1); + updatePreviewPolygon(&this->drawState); + event->accept(); + } + break; + } +} + +void Document::canvasMouseMove(QMouseEvent *event) +{ + switch(this->mode) + { + case SelectMode: + break; + case DrawMode: + if (this->canvas->worldPosition.has_value()) + { + this->drawState.previewPoint = this->canvas->worldPosition.value(); + updatePreviewPolygon(&this->drawState); + this->update(); + } + event->accept(); + break; + } +} + +void Document::select(const QSet<ldraw::id_t> &selected) +{ + QItemSelectionModel* selectionModel = this->ui.listView->selectionModel(); + QItemSelection itemSelection; + for (const ldraw::id_t id : selected) + { + QModelIndex index = this->model->find(id); + if (index != QModelIndex{}) + { + itemSelection.select(index, index); + } + } + selectionModel->select(itemSelection, QItemSelectionModel::ClearAndSelect); +} + const Model &Document::getModel() const { return *this->model; @@ -178,3 +285,31 @@ { return this->canvas->selectedObjects(); } + +void Document::closeShape() +{ + if (this->drawState.polygon.size() >= 2 and this->drawState.polygon.size() <= 4) + { + std::unique_ptr<ModelEditor> modelEditor = this->editModel(); + switch (this->drawState.polygon.size()) + { + case 2: + modelEditor->append<ldraw::Edge>( + vectorToArray<2>(this->drawState.polygon), + ldraw::EDGE_COLOR); + break; + case 3: + modelEditor->append<ldraw::Triangle>( + vectorToArray<3>(this->drawState.polygon), + ldraw::MAIN_COLOR); + break; + case 4: + modelEditor->append<ldraw::Quadrilateral>( + vectorToArray<4>(this->drawState.polygon), + ldraw::MAIN_COLOR); + break; + } + } + this->drawState.polygon.clear(); + updatePreviewPolygon(&this->drawState); +}
--- a/src/document.h Wed May 25 17:56:30 2022 +0300 +++ b/src/document.h Wed May 25 18:29:49 2022 +0300 @@ -44,11 +44,17 @@ const ldraw::ColorTable& colorTable; Canvas* const canvas; Q_SLOT void editingModeTriggered(); + Q_SLOT void canvasMouseClick(QMouseEvent* event); + Q_SLOT void canvasMouseMove(QMouseEvent* event); + void select(const QSet<ldraw::id_t> &selected); + EditingMode mode; + DrawState drawState; Q_SIGNALS: void newStatusText(const QString& newStatusText); void splitterChanged(); private: void initializeTools(); + void closeShape(); Model* model; DocumentManager* const documents; VertexMap vertexMap;
--- a/src/ui/canvas.cpp Wed May 25 17:56:30 2022 +0300 +++ b/src/ui/canvas.cpp Wed May 25 18:29:49 2022 +0300 @@ -3,9 +3,6 @@ #include "modeleditor.h" #include "document.h" #include "canvas.h" -#include "linetypes/edge.h" -#include "linetypes/triangle.h" -#include "linetypes/quadrilateral.h" Canvas::Canvas( Model* model, @@ -46,31 +43,6 @@ } } -void updatePreviewPolygon(DrawState* drawState) -{ - drawState->previewPolygon = drawState->polygon; - drawState->previewPolygon.resize(drawState->polygon.size() + 1); - drawState->previewPolygon.back() = drawState->previewPoint; - if (drawState->previewPolygon.size() > 2) - { - drawState->isconcave = not geom::isConvex(drawState->previewPolygon); - } -} - -void removeLastPoint(DrawState* drawState) -{ - if (drawState->polygon.size() > 0) - { - drawState->polygon.erase(drawState->polygon.end() - 1); - updatePreviewPolygon(drawState); - } -} - -bool isCloseToExistingPoints(const std::vector<glm::vec3>& points, const glm::vec3 &pos) -{ - return any(points, std::bind(geom::isclose, std::placeholders::_1, pos)); -} - void Canvas::mouseMoveEvent(QMouseEvent* event) { const ldraw::id_t id = this->pick(event->pos()); @@ -94,21 +66,7 @@ // grid matrix. this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1}; } - switch(this->mode) - { - case SelectMode: - break; - case DrawMode: - const auto& worldPosition = this->getWorldPosition(); - if (worldPosition.has_value()) - { - this->drawState.previewPoint = worldPosition.value(); - updatePreviewPolygon(&this->drawState); - this->update(); - } - event->accept(); - break; - } + Q_EMIT this->mouseMove(event); PartRenderer::mouseMoveEvent(event); this->update(); } @@ -124,45 +82,7 @@ { if (this->totalMouseMove < (2.0 / sqrt(2)) * 5.0) { - switch(this->mode) - { - case SelectMode: - if (event->button() == Qt::LeftButton) - { - const ldraw::id_t highlighted = this->getHighlightedObject(); - this->clearSelection(); - if (highlighted != ldraw::NULL_ID) - { - this->addToSelection(highlighted); - } - event->accept(); - } - break; - case DrawMode: - if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) - { - const glm::vec3& pos = worldPosition.value(); - if (isCloseToExistingPoints(this->drawState.polygon, pos)) - { - this->closeShape(); - } - else - { - this->drawState.polygon.push_back(pos); - updatePreviewPolygon(&this->drawState); - } - event->accept(); - } - else if (true - and event->button() == Qt::RightButton - and this->drawState.polygon.size() > 0 - ) { - this->drawState.polygon.erase(this->drawState.polygon.end() - 1); - updatePreviewPolygon(&this->drawState); - event->accept(); - } - break; - } + Q_EMIT this->mouseClick(event); } PartRenderer::mouseReleaseEvent(event); this->update(); @@ -208,6 +128,11 @@ const QBrush redPolygonBrush = {QColor{255, 96, 96, 192}}; } pens; +static void renderDrawState( + QPainter* painter, + Canvas* canvas, + DrawState* drawState); + void Canvas::paintGL() { PartRenderer::paintGL(); @@ -254,39 +179,49 @@ { this->renderAxesLabels(painter); } - switch(this->mode) + if (this->drawState != nullptr) { + renderDrawState(&painter, this, this->drawState); + } + } +} + +static void renderDrawState( + QPainter* painter, + Canvas* canvas, + DrawState* drawState) +{ + switch(drawState->mode) + { + case SelectMode: + break; + case DrawMode: { - case SelectMode: - break; - case DrawMode: + painter->setPen(drawState->isconcave ? ::pens.badPolygonPen : ::pens.polygonPen); + if (drawState->previewPolygon.size() > 2 and not drawState->isconcave) { - painter.setPen(this->drawState.isconcave ? ::pens.badPolygonPen : ::pens.polygonPen); - if (this->drawState.previewPolygon.size() > 2 and not this->drawState.isconcave) + if (canvas->worldPolygonWinding(drawState->previewPolygon) == Winding::Clockwise) { - if (this->worldPolygonWinding(this->drawState.previewPolygon) == Winding::Clockwise) - { - painter.setBrush(::pens.greenPolygonBrush); - } - else - { - painter.setBrush(::pens.redPolygonBrush); - } - this->drawWorldPolygon(&painter, this->drawState.previewPolygon); + painter->setBrush(::pens.greenPolygonBrush); } else { - this->drawWorldPolyline(&painter, this->drawState.previewPolygon); + painter->setBrush(::pens.redPolygonBrush); } - painter.setBrush(::pens.pointBrush); - painter.setPen(::pens.pointPen); - for (const glm::vec3& point : this->drawState.polygon) - { - this->drawWorldPoint(&painter, point); - } - this->drawWorldPoint(&painter, this->drawState.previewPoint); + canvas->drawWorldPolygon(painter, drawState->previewPolygon); + } + else + { + canvas->drawWorldPolyline(painter, drawState->previewPolygon); } - break; + painter->setBrush(::pens.pointBrush); + painter->setPen(::pens.pointPen); + for (const glm::vec3& point : drawState->polygon) + { + canvas->drawWorldPoint(painter, point); + } + canvas->drawWorldPoint(painter, drawState->previewPoint); } + break; } } @@ -414,34 +349,6 @@ return this->gridMatrix; } -void Canvas::closeShape() -{ - if (this->drawState.polygon.size() >= 2 and this->drawState.polygon.size() <= 4) - { - std::unique_ptr<ModelEditor> modelEditor = this->document->editModel(); - switch (this->drawState.polygon.size()) - { - case 2: - modelEditor->append<ldraw::Edge>( - vectorToArray<2>(this->drawState.polygon), - ldraw::EDGE_COLOR); - break; - case 3: - modelEditor->append<ldraw::Triangle>( - vectorToArray<3>(this->drawState.polygon), - ldraw::MAIN_COLOR); - break; - case 4: - modelEditor->append<ldraw::Quadrilateral>( - vectorToArray<4>(this->drawState.polygon), - ldraw::MAIN_COLOR); - break; - } - } - this->drawState.polygon.clear(); - updatePreviewPolygon(&this->drawState); -} - /** * @brief Paints a circle at where @c worldPoint is located on the screen. * @param painter Painter to use to render
--- a/src/ui/canvas.h Wed May 25 17:56:30 2022 +0300 +++ b/src/ui/canvas.h Wed May 25 18:29:49 2022 +0300 @@ -19,8 +19,8 @@ std::vector<glm::vec3> previewPolygon; glm::vec3 previewPoint; bool isconcave = false; + EditingMode mode = SelectMode; }; - class Canvas : public PartRenderer { Q_OBJECT @@ -44,8 +44,8 @@ const glm::mat4& getGridMatrix() const; void closeShape(); glm::vec3 cameraVector() const; - DrawState drawState; - EditingMode mode = SelectMode; + std::optional<glm::vec3> worldPosition; + DrawState* drawState = nullptr; public Q_SLOTS: void handleSelectionChange(const QSet<ldraw::id_t>& selectedIds, const QSet<ldraw::id_t>& deselectedIds); void rebuildVertices(Document *document); @@ -59,8 +59,8 @@ Q_SIGNALS: void newStatusText(const QString& newStatusText); void selectionChanged(const QSet<ldraw::id_t>& newSelection); - void mouseClick(Canvas* canvas, QMouseEvent* event); - void mouseMove(Canvas* canvas, QMouseEvent* event); + void mouseClick(QMouseEvent* event); + void mouseMove(QMouseEvent* event); private: bool isGridPerpendicularToScreen(float threshold) const; QVector<QPointF> convertWorldPointsToScreenPoints(const std::vector<glm::vec3>& worldPoints) const; @@ -69,7 +69,6 @@ std::optional<GridProgram> gridProgram; std::optional<AxesProgram> axesProgram; std::optional<VertexProgram> vertexProgram; - std::optional<glm::vec3> worldPosition; glm::mat4 gridMatrix; geom::Plane gridPlane; int totalMouseMove = 0;