PolygonObjectEditor can now modify the object properly

Thu, 19 Mar 2020 21:06:06 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Thu, 19 Mar 2020 21:06:06 +0200
changeset 86
4bec0525ef1b
parent 85
40e2940605a3
child 87
93ec4d630346

PolygonObjectEditor can now modify the object properly

locale/fi.ts file | annotate | diff | comparison | revisions
locale/sv.ts file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/gl/partrenderer.cpp file | annotate | diff | comparison | revisions
src/gl/partrenderer.h file | annotate | diff | comparison | revisions
src/linetypes/conditionaledge.cpp file | annotate | diff | comparison | revisions
src/linetypes/conditionaledge.h file | annotate | diff | comparison | revisions
src/linetypes/edge.cpp file | annotate | diff | comparison | revisions
src/linetypes/edge.h file | annotate | diff | comparison | revisions
src/linetypes/errorline.cpp file | annotate | diff | comparison | revisions
src/linetypes/errorline.h file | annotate | diff | comparison | revisions
src/linetypes/metacommand.cpp file | annotate | diff | comparison | revisions
src/linetypes/metacommand.h file | annotate | diff | comparison | revisions
src/linetypes/object.cpp file | annotate | diff | comparison | revisions
src/linetypes/object.h file | annotate | diff | comparison | revisions
src/linetypes/quadrilateral.cpp file | annotate | diff | comparison | revisions
src/linetypes/quadrilateral.h file | annotate | diff | comparison | revisions
src/linetypes/subfilereference.cpp file | annotate | diff | comparison | revisions
src/linetypes/subfilereference.h file | annotate | diff | comparison | revisions
src/linetypes/triangle.cpp file | annotate | diff | comparison | revisions
src/linetypes/triangle.h file | annotate | diff | comparison | revisions
src/model.cpp file | annotate | diff | comparison | revisions
src/modeleditcontext.cpp file | annotate | diff | comparison | revisions
src/modeleditcontext.h file | annotate | diff | comparison | revisions
src/ui/polygonobjecteditor.cpp file | annotate | diff | comparison | revisions
src/ui/polygonobjecteditor.h file | annotate | diff | comparison | revisions
src/widgets/vec3editor.cpp file | annotate | diff | comparison | revisions
--- a/locale/fi.ts	Wed Mar 18 17:11:23 2020 +0200
+++ b/locale/fi.ts	Thu Mar 19 21:06:06 2020 +0200
@@ -212,6 +212,22 @@
     </message>
 </context>
 <context>
+    <name>MatrixEditor</name>
+    <message>
+        <location filename="../src/widgets/matrixeditor.ui" line="14"/>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../src/widgets/matrixeditor.ui" line="87"/>
+        <location filename="../src/widgets/matrixeditor.ui" line="94"/>
+        <location filename="../src/widgets/matrixeditor.ui" line="101"/>
+        <location filename="../src/widgets/matrixeditor.ui" line="108"/>
+        <source>×</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>MultiplyFactorDialog</name>
     <message>
         <location filename="../src/ui/multiplyfactordialog.ui" line="14"/>
@@ -237,17 +253,17 @@
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../src/gl/partrenderer.cpp" line="244"/>
+        <location filename="../src/gl/partrenderer.cpp" line="250"/>
         <source>OpenGL error: %1</source>
         <translation>OpenGL-virhe: %1</translation>
     </message>
     <message>
-        <location filename="../src/gl/partrenderer.cpp" line="245"/>
+        <location filename="../src/gl/partrenderer.cpp" line="251"/>
         <source>OpenGL error</source>
         <translation>OpenGL-virhe</translation>
     </message>
     <message>
-        <location filename="../src/gl/partrenderer.cpp" line="247"/>
+        <location filename="../src/gl/partrenderer.cpp" line="253"/>
         <source>Damn it</source>
         <translation>Hemmetti</translation>
     </message>
--- a/locale/sv.ts	Wed Mar 18 17:11:23 2020 +0200
+++ b/locale/sv.ts	Thu Mar 19 21:06:06 2020 +0200
@@ -230,6 +230,17 @@
     </message>
 </context>
 <context>
+    <name>MatrixEditor</name>
+    <message>
+        <source>Form</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>×</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>MultiplyFactorDialog</name>
     <message>
         <source>Multiply with a scalar</source>
--- a/src/document.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/document.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -70,6 +70,7 @@
 		this->renderer->handleSelectionChange(resolve(selected), resolve(deselected));
 		this->selectionChanged(resolve(this->ui.listView->selectionModel()->selection()));
 	});
+	connect(this->model, &Model::dataChanged, this->renderer, qOverload<>(&Canvas::update));
 }
 
 Document::~Document()
--- a/src/gl/partrenderer.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/gl/partrenderer.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -61,11 +61,7 @@
 		abort();
 	}
 	this->compiler->initialize();
-	this->compiler->build(this->model, this->documents, this->renderPreferences);
-	connect(this->model, &Model::dataChanged, [&]()
-	{
-		this->compiler->build(this->model, this->documents, this->renderPreferences);
-	});
+	connect(this->model, &Model::dataChanged, this, &PartRenderer::build);
 	this->initialized = true;
 	this->modelQuaternion = glm::angleAxis(glm::radians(30.0f), glm::vec3{-1, 0, 0});
 	this->modelQuaternion *= glm::angleAxis(glm::radians(225.0f), glm::vec3{-0, 1, 0});
@@ -112,6 +108,11 @@
 
 void PartRenderer::renderScene()
 {
+	if (this->needBuild)
+	{
+		this->compiler->build(this->model, this->documents, this->renderPreferences);
+		this->needBuild = false;
+	}
 	this->checkForGLErrors();
 	if (this->renderPreferences.lineAntiAliasing && this->renderPreferences.style != gl::RenderStyle::PickScene)
 	{
@@ -212,6 +213,11 @@
 {
 }
 
+void PartRenderer::build()
+{
+	this->needBuild = true;
+}
+
 void PartRenderer::renderVao(const gl::ArrayClass arrayClass)
 {
 	this->compiler->bindVertexArray(arrayClass);
@@ -370,7 +376,7 @@
 	this->renderPreferences = newPreferences;
 	if (mainColorChanged or backgroundColorChanged)
 	{
-		this->compiler->build(this->model, this->documents, this->renderPreferences);
+		this->build();
 		this->setupBackgroundColor();
 	}
 	emit this->renderPreferencesChanged();
--- a/src/gl/partrenderer.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/gl/partrenderer.h	Thu Mar 19 21:06:06 2020 +0200
@@ -57,10 +57,12 @@
 	void updateViewMatrix();
 	void updateModelMatrix();
 	void setupBackgroundColor();
+	Q_SLOT void build();
 	static constexpr double MIN_ZOOM = 0.0;
 	static constexpr double MAX_ZOOM = 3.0;
 	double zoom = 1.0;
 	bool initialized = false;
+	bool needBuild = true;
 	void renderVao(const gl::ArrayClass arrayClass);
 	void checkForGLErrors();
 };
--- a/src/linetypes/conditionaledge.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/conditionaledge.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -23,29 +23,20 @@
 {
 	switch (property)
 	{
-	case Property::ControlPoint1:
+	case Property::ControlPoint0:
 		return QVariant::fromValue(controlPoint_1);
-	case Property::ControlPoint2:
+	case Property::ControlPoint1:
 		return QVariant::fromValue(controlPoint_2);
 	default:
 		return Edge::getProperty(property);
 	}
 }
 
-auto ldraw::ConditionalEdge::setProperty(
-	Property property,
-	const QVariant& value)
-	-> SetPropertyResult
+void ldraw::ConditionalEdge::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (property)
-	{
-	case Property::ControlPoint1:
-		controlPoint_1 = value.value<glm::vec3>();
-	case Property::ControlPoint2:
-		controlPoint_2 = value.value<glm::vec3>();
-	default:
-		return Edge::setProperty(property, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(ControlPoint0, {this->controlPoint_1 = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(ControlPoint1, {this->controlPoint_2 = value;})
+	BaseClass::setProperty(result, pair);
 }
 
 QString ldraw::ConditionalEdge::textRepresentation() const
--- a/src/linetypes/conditionaledge.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/conditionaledge.h	Thu Mar 19 21:06:06 2020 +0200
@@ -18,12 +18,11 @@
 		const Color colorIndex = ldraw::edgeColor);
 	ConditionalEdge(const std::array<glm::vec3, 4>& vertices, const Color color);
 	QVariant getProperty(Property property) const override;
-	SetPropertyResult setProperty(
-		Property property,
-		const QVariant& value) override;
 	QString textRepresentation() const override;
 	int numPoints() const override;
 	const glm::vec3& getPoint(int index) const override;
 	glm::vec3 controlPoint_1 = {};
 	glm::vec3 controlPoint_2 = {};
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
--- a/src/linetypes/edge.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/edge.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -19,29 +19,20 @@
 {
 	switch (property)
 	{
-	case Property::Point1:
+	case Property::Point0:
 		return QVariant::fromValue(point_1);
-	case Property::Point2:
+	case Property::Point1:
 		return QVariant::fromValue(point_2);
 	default:
 		return BaseClass::getProperty(property);
 	}
 }
 
-auto ldraw::Edge::setProperty(Property property, const QVariant& value)
-	-> SetPropertyResult
+void ldraw::Edge::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (property)
-	{
-	case Property::Point1:
-		point_1 = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	case Property::Point2:
-		point_2 = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	default:
-		return BaseClass::setProperty(property, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point0, {this->point_1 = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point1, {this->point_2 = value;})
+	BaseClass::setProperty(result, pair);
 }
 
 QString ldraw::Edge::textRepresentation() const
--- a/src/linetypes/edge.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/edge.h	Thu Mar 19 21:06:06 2020 +0200
@@ -15,13 +15,12 @@
 		 const Color colorIndex = ldraw::edgeColor);
 	Edge(const std::array<glm::vec3, 2>& vertices, const Color color);
 	QVariant getProperty(Property property) const override;
-	SetPropertyResult setProperty(
-		Property property,
-		const QVariant& value) override;
 	QString textRepresentation() const override;
 	void getPolygons(std::vector<gl::Polygon>& polygons, GetPolygonsContext* context) const override;
 	int numPoints() const override;
 	const glm::vec3& getPoint(int index) const override;
 	glm::vec3 point_1 = {};
 	glm::vec3 point_2 = {};
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
--- a/src/linetypes/errorline.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/errorline.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -20,22 +20,11 @@
 	}
 }
 
-auto ldraw::ErrorLine::setProperty(
-	Property property,
-	const QVariant& value)
-	-> SetPropertyResult
+void ldraw::ErrorLine::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (property)
-	{
-	case Property::Text:
-		this->text = value.toString();
-		return SetPropertyResult::Success;
-	case Property::ErrorMessage:
-		this->message = value.toString();
-		return SetPropertyResult::Success;
-	default:
-		return Object::setProperty(property, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Text, {this->text = value;});
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(ErrorMessage, {this->message = value;});
+	BaseClass::setProperty(result, pair);
 }
 
 QString ldraw::ErrorLine::textRepresentation() const
--- a/src/linetypes/errorline.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/errorline.h	Thu Mar 19 21:06:06 2020 +0200
@@ -9,14 +9,14 @@
 class ldraw::ErrorLine : public Object
 {
 public:
+	using BaseClass = Object;
 	ErrorLine(QStringView text = u"", QStringView message = u"");
 	QVariant getProperty(Property property) const override;
-	SetPropertyResult setProperty(
-		Property property,
-		const QVariant& value) override;
 	QString textRepresentation() const override;
 	QBrush textRepresentationForeground() const override;
 	QBrush textRepresentationBackground() const override;
 	QString text;
 	QString message;
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
--- a/src/linetypes/metacommand.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/metacommand.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -15,20 +15,14 @@
 	}
 }
 
-auto ldraw::MetaCommand::setProperty(Property property, const QVariant& value)
-	-> SetPropertyResult
+void ldraw::MetaCommand::setProperty(ldraw::Object::SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (property)
-	{
-	case Property::Text:
-		storedText = value.toString();
-		return SetPropertyResult::Success;
-	default:
-		return Object::setProperty(property, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Text, {this->storedText = value;});
+	BaseClass::setProperty(result, pair);
 }
 
 QString ldraw::MetaCommand::textRepresentation() const
 {
 	return this->storedText;
 }
+
--- a/src/linetypes/metacommand.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/metacommand.h	Thu Mar 19 21:06:06 2020 +0200
@@ -8,12 +8,12 @@
 class ldraw::MetaCommand : public Object
 {
 public:
+	using BaseClass = Object;
 	MetaCommand() = default;
 	MetaCommand(QStringView text);
 	QVariant getProperty(Property property) const override;
-	SetPropertyResult setProperty(
-		Property property,
-		const QVariant& value) override;
 	QString textRepresentation() const override;
 	QString storedText = "";
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
--- a/src/linetypes/object.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/object.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -29,12 +29,20 @@
 	return {};
 }
 
-auto ldraw::Object::setProperty(Property id, const QVariant& value)
-	-> SetPropertyResult
+void ldraw::Object::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	Q_UNUSED(id)
-	Q_UNUSED(value)
-	return SetPropertyResult::PropertyNotHandled;
+	Q_UNUSED(result)
+	Q_UNUSED(pair)
+}
+
+/**
+ * @brief public interface to setProperty
+ */
+ldraw::Object::SetPropertyResult ldraw::Object::setProperty(const PropertyKeyValue& pair)
+{
+	SetPropertyResult result;
+	this->setProperty(&result, pair);
+	return result;
 }
 
 QBrush ldraw::Object::textRepresentationForeground() const
@@ -60,6 +68,7 @@
 
 const glm::vec3& ldraw::Object::getPoint(int index) const
 {
+	Q_UNUSED(index);
 	throw BadPointIndex{};
 }
 
@@ -84,28 +93,10 @@
 	}
 }
 
-auto ldraw::ColoredObject::setProperty(Property id, const QVariant& value)
-	-> SetPropertyResult
+void ldraw::ColoredObject::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (id)
-	{
-	case Property::Color:
-		{
-			bool ok;
-			const int value_int = value.toInt(&ok);
-			if (ok)
-			{
-				colorIndex.index = value_int;
-				return SetPropertyResult::Success;
-			}
-			else
-			{
-				return SetPropertyResult::InvalidValue;
-			}
-		}
-	default:
-		return Object::setProperty(id, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Color, {colorIndex.index = value;});
+	Object::setProperty(result, pair);
 }
 
 QString ldraw::Empty::textRepresentation() const
--- a/src/linetypes/object.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/object.h	Thu Mar 19 21:06:06 2020 +0200
@@ -30,12 +30,12 @@
 {
 	Color, // Color of the object
 	Text, // Text contained in a comment
-	Point1, // First vertex in a polygon or edge line
-	Point2, // Second vertex in a polygon or edge line
-	Point3, // Third vertex in a polygon
-	Point4, // Fourth vertex in a quadrilateral
-	ControlPoint1, // First control point in a conditional edge line
-	ControlPoint2, // Second control point in a conditional edge line
+	Point0, // First vertex in a polygon or edge line
+	Point1, // Second vertex in a polygon or edge line
+	Point2, // Third vertex in a polygon
+	Point3, // Fourth vertex in a quadrilateral
+	ControlPoint0, // First control point in a conditional edge line
+	ControlPoint1, // Second control point in a conditional edge line
 	Transformation, // 4x4 transformation matrix of a subfile reference
 	ReferenceName, // Subfile reference name
 	IsInverted, // Whether or not the object has been inverted with BFC INVERTNEXT
@@ -57,30 +57,49 @@
 
 	template<ldraw::Property property>
 	using PropertyType_t = typename PropertyType<property>::type;
+
+	struct PropertyKeyValue
+	{
+		Property key;
+		QVariant value;
+	};
+
+	constexpr Property pointProperty(int n)
+	{
+		Q_ASSERT(n >= 0 and n < 4);
+		return static_cast<Property>(static_cast<int>(Property::Point0) + n);
+	}
 }
 
 LDFORGE_DEFINE_PROPERTY_TYPE(Color, int)
 LDFORGE_DEFINE_PROPERTY_TYPE(Text, QString)
+LDFORGE_DEFINE_PROPERTY_TYPE(Point0, glm::vec3)
 LDFORGE_DEFINE_PROPERTY_TYPE(Point1, glm::vec3)
 LDFORGE_DEFINE_PROPERTY_TYPE(Point2, glm::vec3)
 LDFORGE_DEFINE_PROPERTY_TYPE(Point3, glm::vec3)
-LDFORGE_DEFINE_PROPERTY_TYPE(Point4, glm::vec3)
+LDFORGE_DEFINE_PROPERTY_TYPE(ControlPoint0, glm::vec3)
 LDFORGE_DEFINE_PROPERTY_TYPE(ControlPoint1, glm::vec3)
-LDFORGE_DEFINE_PROPERTY_TYPE(ControlPoint2, glm::vec3)
 LDFORGE_DEFINE_PROPERTY_TYPE(Transformation, glm::mat4)
 LDFORGE_DEFINE_PROPERTY_TYPE(ReferenceName, QString)
 LDFORGE_DEFINE_PROPERTY_TYPE(IsInverted, bool)
 LDFORGE_DEFINE_PROPERTY_TYPE(ErrorMessage, QString)
 
+#define LDRAW_OBJECT_HANDLE_SET_PROPERTY(PROPERTY, HANDLER) \
+	{this->handle<ldraw::Property::PROPERTY>(result, pair, \
+		[&](const ldraw::PropertyType_t<ldraw::Property::PROPERTY>& value) HANDLER);}
+
 class ldraw::Object
 {
 public:
 	enum class SetPropertyResult
 	{
 		Success = 0,
-		PropertyNotHandled,
-		InvalidValue
+		PropertyNotHandled
 	};
+	friend bool handled(SetPropertyResult result)
+	{
+		return result == SetPropertyResult::Success;
+	}
 	class BadPointIndex : public std::exception
 	{
 	};
@@ -88,10 +107,11 @@
 	Object(const Object&) = delete;
 	virtual ~Object();
 	const id_t id;
-	//virtual void toString(QTextStream &out) = 0;
 	virtual bool hasColor() const;
 	virtual QVariant getProperty(Property id) const;
-	virtual SetPropertyResult setProperty(Property id, const QVariant& value);
+	template<ldraw::Property property>
+	SetPropertyResult setProperty(const PropertyType_t<property>& value);
+	SetPropertyResult setProperty(const PropertyKeyValue& pair);
 	virtual QString textRepresentation() const = 0;
 	virtual QBrush textRepresentationForeground() const;
 	virtual QBrush textRepresentationBackground() const;
@@ -100,16 +120,39 @@
 	virtual void invert() {}
 	virtual int numPoints() const { return 0; }
 	virtual const glm::vec3& getPoint(int index) const;
+protected:
+	template<Property property, typename Function>
+	void handle(SetPropertyResult* result, const PropertyKeyValue& pair, Function function);
+	virtual void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair);
 };
 
+template<ldraw::Property property>
+ldraw::Object::SetPropertyResult ldraw::Object::setProperty(const PropertyType_t<property>& value)
+{
+	SetPropertyResult result = SetPropertyResult::PropertyNotHandled;
+	this->setProperty(&result, PropertyKeyValue{property, QVariant::fromValue(value)});
+	return result;
+}
+
+template<ldraw::Property property, typename Function>
+void ldraw::Object::handle(SetPropertyResult* result, const PropertyKeyValue& pair, Function function)
+{
+	if (pair.key == property)
+	{
+		function(pair.value.value<ldraw::PropertyType_t<property>>());
+		*result = SetPropertyResult::Success;
+	}
+}
+
 class ldraw::ColoredObject : public Object
 {
 public:
 	ColoredObject(const Color colorIndex = ldraw::mainColor);
 	bool hasColor() const override final;
 	QVariant getProperty(Property id) const override;
-	SetPropertyResult setProperty(Property id, const QVariant& value) override;
 	Color colorIndex = ldraw::mainColor;
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
 
 /**
--- a/src/linetypes/quadrilateral.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/quadrilateral.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -1,17 +1,23 @@
 #include "quadrilateral.h"
 
-ldraw::Quadrilateral::Quadrilateral(
+ldraw::Quadrilateral::Quadrilateral
+(
 	const glm::vec3& point_1,
 	const glm::vec3& point_2,
 	const glm::vec3& point_3,
 	const glm::vec3& point_4,
-	Color color_index) :
+	Color color_index
+) :
 	ColoredObject{color_index},
 	points{point_1, point_2, point_3, point_4}
 {
 }
 
-ldraw::Quadrilateral::Quadrilateral(const std::array<glm::vec3, 4>& vertices, const Color color) :
+ldraw::Quadrilateral::Quadrilateral
+(
+	const std::array<glm::vec3, 4>& vertices,
+	const Color color
+) :
 	ColoredObject{color},
 	points{vertices[0], vertices[1], vertices[2], vertices[3]}
 {
@@ -21,41 +27,26 @@
 {
 	switch (id)
 	{
-	case Property::Point1:
+	case Property::Point0:
 		return QVariant::fromValue(points[0]);
-	case Property::Point2:
+	case Property::Point1:
 		return QVariant::fromValue(points[1]);
-	case Property::Point3:
+	case Property::Point2:
 		return QVariant::fromValue(points[2]);
-	case Property::Point4:
+	case Property::Point3:
 		return QVariant::fromValue(points[3]);
 	default:
 		return ColoredObject::getProperty(id);
 	}
 }
 
-auto ldraw::Quadrilateral::setProperty(
-	const Property id,
-	const QVariant& value)
-	-> SetPropertyResult
+void ldraw::Quadrilateral::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (id)
-	{
-	case Property::Point1:
-		points[0] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	case Property::Point2:
-		points[1] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	case Property::Point3:
-		points[2] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	case Property::Point4:
-		points[3] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	default:
-		return ColoredObject::setProperty(id, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point0, {points[0] = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point1, {points[1] = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point2, {points[2] = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point3, {points[3] = value;})
+	ColoredObject::setProperty(result, pair);
 }
 
 QString ldraw::Quadrilateral::textRepresentation() const
--- a/src/linetypes/quadrilateral.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/quadrilateral.h	Thu Mar 19 21:06:06 2020 +0200
@@ -18,11 +18,12 @@
 		Color colorIndex = ldraw::mainColor);
 	Quadrilateral(const std::array<glm::vec3, 4>& vertices, const Color color);
 	QVariant getProperty(Property id) const override;
-	SetPropertyResult setProperty(Property id, const QVariant& value) override;
 	QString textRepresentation() const override;
 	void getPolygons(std::vector<gl::Polygon>& polygons, GetPolygonsContext* context) const override;
 	void invert() override;
 	int numPoints() const override;
 	const glm::vec3& getPoint(int index) const override;
 	glm::vec3 points[4] = {{}};
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
--- a/src/linetypes/subfilereference.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/subfilereference.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -2,9 +2,12 @@
 #include "documentmanager.h"
 #include "invert.h"
 
-ldraw::SubfileReference::SubfileReference(const glm::mat4& transformation,
+ldraw::SubfileReference::SubfileReference
+(
+	const glm::mat4& transformation,
 	const QString& referenceName,
-	const Color color) :
+	const Color color
+) :
 	ColoredObject{color},
 	transformation{transformation},
 	referenceName{referenceName}
@@ -24,22 +27,11 @@
 	}
 }
 
-auto ldraw::SubfileReference::setProperty(
-	Property property,
-	const QVariant& value)
-	-> SetPropertyResult
+void ldraw::SubfileReference::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (property)
-	{
-	case Property::Transformation:
-		this->transformation = value.value<glm::mat4>();
-		return SetPropertyResult::Success;
-	case Property::ReferenceName:
-		this->referenceName = value.toString();
-		return SetPropertyResult::Success;
-	default:
-		return ColoredObject::setProperty(property, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Transformation, {this->transformation = value;});
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(ReferenceName, {this->referenceName = value;});
+	ldraw::ColoredObject::setProperty(result, pair);
 }
 
 QString ldraw::SubfileReference::textRepresentation() const
@@ -47,9 +39,11 @@
 	return referenceName + " " + utility::vertexToStringParens(this->position());
 }
 
-void ldraw::SubfileReference::getPolygons(
+void ldraw::SubfileReference::getPolygons
+(
 	std::vector<gl::Polygon>& polygons,
-	GetPolygonsContext* context) const
+	GetPolygonsContext* context
+) const
 {
 	Model* model = this->resolve(context->documents);
 	if (model != nullptr)
--- a/src/linetypes/subfilereference.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/subfilereference.h	Thu Mar 19 21:06:06 2020 +0200
@@ -17,7 +17,6 @@
 		const QString &referenceName,
 		const Color color = ldraw::mainColor);
 	QVariant getProperty(Property property) const override;
-	SetPropertyResult setProperty(Property property, const QVariant& value) override;
 	QString textRepresentation() const override;
 	void getPolygons(std::vector<gl::Polygon>& polygons, GetPolygonsContext* context) const override;
 	glm::vec3 position() const;
@@ -26,4 +25,6 @@
 	glm::mat4 transformation;
 	QString referenceName;
 	bool isInverted = false;
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
--- a/src/linetypes/triangle.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/triangle.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -26,34 +26,23 @@
 {
 	switch (id)
 	{
+	case Property::Point0:
+		return QVariant::fromValue(points[0]);
 	case Property::Point1:
-		return QVariant::fromValue(points[0]);
+		return QVariant::fromValue(points[1]);
 	case Property::Point2:
-		return QVariant::fromValue(points[1]);
-	case Property::Point3:
 		return QVariant::fromValue(points[2]);
 	default:
 		return ColoredObject::getProperty(id);
 	}
 }
 
-auto ldraw::Triangle::setProperty(Property id, const QVariant& value)
-	-> SetPropertyResult
+void ldraw::Triangle::setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
 {
-	switch (id)
-	{
-	case Property::Point1:
-		points[0] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	case Property::Point2:
-		points[1] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	case Property::Point3:
-		points[2] = value.value<glm::vec3>();
-		return SetPropertyResult::Success;
-	default:
-		return ColoredObject::setProperty(id, value);
-	}
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point0, {points[0] = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point1, {points[1] = value;})
+	LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point2, {points[2] = value;})
+	ColoredObject::setProperty(result, pair);
 }
 
 QString ldraw::Triangle::textRepresentation() const
--- a/src/linetypes/triangle.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/linetypes/triangle.h	Thu Mar 19 21:06:06 2020 +0200
@@ -18,12 +18,13 @@
 	Triangle(const std::array<glm::vec3, 3>& vertices, const Color color);
 	Triangle(const glm::vec3 (&vertices)[3], const Color color);
 	QVariant getProperty(Property id) const override;
-	SetPropertyResult setProperty(Property id, const QVariant& value) override;
 	QString textRepresentation() const override;
 	void getPolygons(std::vector<gl::Polygon>& polygons, GetPolygonsContext* context) const override;
 	void invert() override;
 	int numPoints() const override;
 	const glm::vec3& getPoint(int index) const override;
 	glm::vec3 points[3] = {{}};
+protected:
+	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
 };
 
--- a/src/model.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/model.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -22,7 +22,10 @@
 #include "modeleditcontext.h"
 
 Model::Model(QObject* parent) :
-	QAbstractListModel{parent} {}
+	QAbstractListModel{parent}
+{
+	connect(this, &Model::dataChanged, [&](){ this->needRecache = true; });
+}
 
 int Model::size() const
 {
--- a/src/modeleditcontext.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/modeleditcontext.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -23,6 +23,15 @@
 {
 }
 
+Model::EditContext::~EditContext()
+{
+	for (ldraw::id_t id : this->modifiedObjects)
+	{
+		const QModelIndex index = this->model().lookup(id);
+		emit this->model().dataChanged(index, index);
+	}
+}
+
 ldraw::id_t Model::EditContext::append(std::unique_ptr<ldraw::Object>&& object)
 {
 	const ldraw::id_t id = object->id;
@@ -36,15 +45,13 @@
 	this->model().remove(position);
 }
 
-void Model::EditContext::setObjectProperty(
-	ldraw::id_t id,
-	ldraw::Property property,
-	const QVariant& value)
+void Model::EditContext::setObjectPoint(ldraw::id_t id, int pointId, const glm::vec3& value)
 {
 	ldraw::Object* object = this->model().objectAt(id);
 	if (object != nullptr)
 	{
-		object->setProperty(property, value);
+		object->setProperty(ldraw::PropertyKeyValue{ldraw::pointProperty(pointId), QVariant::fromValue(value)});
+		modifiedObjects.insert(id);
 	}
 }
 
--- a/src/modeleditcontext.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/modeleditcontext.h	Thu Mar 19 21:06:06 2020 +0200
@@ -25,21 +25,30 @@
 class Model::EditContext
 {
 public:
+	~EditContext();
 	template<typename T, typename... Args>
 	ldraw::Id<T> append(Args&&... args);
 	ldraw::id_t append(std::unique_ptr<ldraw::Object>&& object);
 	template<typename T, typename... Args>
 	ldraw::Id<T> insert(int position, Args&&... args);
 	void remove(int position);
-	void setObjectProperty(
-		ldraw::id_t object,
-		ldraw::Property property,
-		const QVariant &value);
+	template<ldraw::Property property>
+	void setObjectProperty(ldraw::id_t id, const ldraw::PropertyType_t<property>& value)
+	{
+		ldraw::Object* object = this->model().objectAt(id);
+		if (object != nullptr)
+		{
+			object->setProperty<property>(value);
+			modifiedObjects.insert(id);
+		}
+	}
+	void setObjectPoint(ldraw::id_t id, int pointId, const glm::vec3& value);
 	void invertObject(ldraw::id_t id);
 	Model& model();
 private:
 	EditContext(Model& model);
 	friend class Model;
+	QSet<ldraw::id_t> modifiedObjects;
 	Model& storedModel;
 };
 
--- a/src/ui/polygonobjecteditor.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/ui/polygonobjecteditor.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -1,8 +1,11 @@
 #include <QVBoxLayout>
 #include <QSplitter>
 #include "model.h"
+#include "modeleditcontext.h"
 #include "widgets/vec3editor.h"
-#include "polygonobjecteditor.h"
+#include "ui/polygonobjecteditor.h"
+
+constexpr char COLUMN_PROPERTY[] = "_ldforge_column";
 
 PolygonObjectEditor::PolygonObjectEditor(Model* model, ldraw::id_t id, QWidget* parent) :
 	QWidget{parent},
@@ -10,10 +13,13 @@
 	storedObjectId{ldraw::NULL_ID.value}
 {
 	this->setLayout(new QVBoxLayout{this});
-	for (std::optional<Vec3Editor>& editorPointer : this->vec3Editors)
+	for (int i = 0; i < countof(this->vec3Editors); i += 1)
 	{
+		std::optional<Vec3Editor>& editorPointer = this->vec3Editors[i];
 		editorPointer.emplace(glm::vec3{}, this);
+		editorPointer->setProperty(COLUMN_PROPERTY, QVariant::fromValue(i));
 		this->layout()->addWidget(&*editorPointer);
+		connect(&*editorPointer, &Vec3Editor::valueChanged, this, &PolygonObjectEditor::vectorChanged);
 	}
 	this->layout()->addWidget(new QSplitter{Qt::Vertical, this});
 	this->setObjectId(id);
@@ -35,6 +41,17 @@
 	this->updateNumRows();
 }
 
+void PolygonObjectEditor::vectorChanged(const glm::vec3& value)
+{
+	bool ok;
+	const int num = sender()->property(COLUMN_PROPERTY).toInt(&ok);
+	if (ok and num >= 0 and num < countof(this->vec3Editors))
+	{
+		Model::EditContext editor = this->model->edit();
+		editor.setObjectPoint(this->objectId(), num, value);
+	}
+}
+
 void PolygonObjectEditor::updateNumRows()
 {
 	const ldraw::Object* object = model->get(this->storedObjectId);
@@ -42,6 +59,7 @@
 	for (int i = 0; i < countof(this->vec3Editors); i += 1)
 	{
 		Vec3Editor& editor = *this->vec3Editors[i];
+		QSignalBlocker blocker{&editor};
 		if (i < numPoints)
 		{
 			editor.setVisible(true);
--- a/src/ui/polygonobjecteditor.h	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/ui/polygonobjecteditor.h	Thu Mar 19 21:06:06 2020 +0200
@@ -13,6 +13,7 @@
 	ldraw::id_t objectId() const;
 	void setObjectId(ldraw::id_t id);
 private:
+	Q_SLOT void vectorChanged(const glm::vec3& value);
 	void updateNumRows();
 	Model* model;
 	ldraw::id_t storedObjectId;
--- a/src/widgets/vec3editor.cpp	Wed Mar 18 17:11:23 2020 +0200
+++ b/src/widgets/vec3editor.cpp	Thu Mar 19 21:06:06 2020 +0200
@@ -19,6 +19,13 @@
 	{
 		connect(this->ui->multiply, &QPushButton::clicked, this, &Vec3Editor::multiplyPressed);
 	}
+	for (QDoubleSpinBox* spinbox : this->spinboxes())
+	{
+		connect(spinbox, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double)
+		{
+			Q_EMIT this->valueChanged(this->value());
+		});
+	}
 }
 
 Vec3Editor::~Vec3Editor()

mercurial