move drawState to Document

Wed, 25 May 2022 18:29:49 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Wed, 25 May 2022 18:29:49 +0300
changeset 197
0e729e681a2c
parent 196
6bcb284679d4
child 198
eb9d900dc79a

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;

mercurial