--- 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); +}