src/document.cpp

changeset 197
0e729e681a2c
parent 191
d355d4c52d51
child 198
eb9d900dc79a
--- 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);
+}

mercurial