Refactor LDObject API

Sun, 06 Sep 2015 15:12:30 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sun, 06 Sep 2015 15:12:30 +0300
changeset 988
ac4a2ae54f76
parent 987
91281e39c50c
child 989
1cd1d082a540

Refactor LDObject API

CMakeLists.txt file | annotate | diff | comparison | revisions
src/addObjectDialog.cpp file | annotate | diff | comparison | revisions
src/dialogs/newpartdialog.cpp file | annotate | diff | comparison | revisions
src/dialogs/newpartdialog.h file | annotate | diff | comparison | revisions
src/doublemap.h file | annotate | diff | comparison | revisions
src/ldDocument.cpp file | annotate | diff | comparison | revisions
src/ldObject.cpp file | annotate | diff | comparison | revisions
src/ldObject.h file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
src/primitives.cpp file | annotate | diff | comparison | revisions
src/radioGroup.cpp file | annotate | diff | comparison | revisions
src/radioGroup.h file | annotate | diff | comparison | revisions
src/toolsets/algorithmtoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/basictoolset.cpp file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Sun Sep 06 13:46:39 2015 +0300
+++ b/CMakeLists.txt	Sun Sep 06 15:12:30 2015 +0300
@@ -105,6 +105,7 @@
 	src/hierarchyelement.h
 	src/guiutilities.h
 	src/documentloader.h
+	src/doublemap.h
 	src/dialogs/colorselector.h
 	src/dialogs/configdialog.h
 	src/dialogs/ldrawpathdialog.h
--- a/src/addObjectDialog.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/addObjectDialog.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -73,21 +73,21 @@
 			coordCount = 12;
 		} break;
 
-		case OBJ_BFC:
+		case OBJ_Bfc:
 		{
 			rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical);
 
-			for_enum (BFCStatement, i)
+			for_enum (BfcStatement, i)
 			{
 				// Separate these in two columns
-				if (int (i) == int (BFCStatement::NumValues) / 2)
+				if (int (i) == int (BfcStatement::NumValues) / 2)
 					rb_bfcType->rowBreak();
 
-				rb_bfcType->addButton (LDBFC::StatementStrings[int (i)]);
+				rb_bfcType->addButton (LDBfc::statementToString (i));
 			}
 
 			if (obj)
-				rb_bfcType->setValue ((int) static_cast<LDBFC*> (obj)->statement());
+				rb_bfcType->setValue ((int) static_cast<LDBfc*> (obj)->statement());
 		} break;
 
 		case OBJ_Subfile:
@@ -168,7 +168,7 @@
 			layout->addWidget (le_comment, 0, 1);
 			break;
 
-		case OBJ_BFC:
+		case OBJ_Bfc:
 			layout->addWidget (rb_bfcType, 0, 1);
 			break;
 
@@ -348,12 +348,12 @@
 			}
 		} break;
 
-		case OBJ_BFC:
+		case OBJ_Bfc:
 		{
-			LDBFC* bfc = InitObject<LDBFC> (obj);
+			LDBfc* bfc = InitObject<LDBfc> (obj);
 			int value = dlg.rb_bfcType->value();
-			if (value == qBound (0, value, int (BFCStatement::NumValues) - 1))
-				bfc->setStatement (BFCStatement (dlg.rb_bfcType->value()));
+			if (value == qBound (0, value, int (BfcStatement::NumValues) - 1))
+				bfc->setStatement (BfcStatement (dlg.rb_bfcType->value()));
 		} break;
 
 		case OBJ_Subfile:
--- a/src/dialogs/newpartdialog.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/dialogs/newpartdialog.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -40,15 +40,15 @@
 	ui.useCaLicense->setChecked (m_config->useCaLicense());
 }
 
-BFCStatement NewPartDialog::getWinding() const
+BfcStatement NewPartDialog::getWinding() const
 {
 	if (ui.windingCcw->isChecked())
-		return BFCStatement::CertifyCCW;
+		return BfcStatement::CertifyCCW;
 
 	if (ui.windingCw->isChecked())
-		return BFCStatement::CertifyCW;
+		return BfcStatement::CertifyCW;
 
-	return BFCStatement::NoCertify;
+	return BfcStatement::NoCertify;
 }
 
 bool NewPartDialog::useCaLicense() const
@@ -78,7 +78,7 @@
 		objs << new LDComment (CALicenseText);
 	
 	objs << new LDEmpty();
-	objs << new LDBFC (getWinding());
+	objs << new LDBfc (getWinding());
 	objs << new LDEmpty();
 	newdoc->addObjects (objs);
 }
--- a/src/dialogs/newpartdialog.h	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/dialogs/newpartdialog.h	Sun Sep 06 15:12:30 2015 +0300
@@ -29,7 +29,7 @@
 
 	QString author() const;
 	void fillHeader (LDDocument* newdoc) const;
-	BFCStatement getWinding() const;
+	BfcStatement getWinding() const;
 	bool useCaLicense() const;
 	QString title() const;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/doublemap.h	Sun Sep 06 15:12:30 2015 +0300
@@ -0,0 +1,105 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2015 Teemu Piippo
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include <QMap>
+
+template<typename Key, typename Value>
+class DoubleMap
+{
+public:
+	void clear()
+	{
+		m_map.clear();
+		m_reverseMap.clear();
+	}
+
+	void insert (const Key& key, const Value& value)
+	{
+		m_map[key] = value;
+		m_reverseMap[value] = key;
+	}
+
+	bool containsKey (const Key& key) const
+	{
+		return m_map.contains (key);
+	}
+
+	bool containsValue (const Value& value) const
+	{
+		return m_reverseMap.contains (value);
+	}
+
+	void removeKey (const Key& key)
+	{
+		m_reverseMap.remove (m_map[key]);
+		m_map.remove (key);
+	}
+
+	void removeValue (const Key& key)
+	{
+		m_reverseMap.remove (m_map[key]);
+		m_map.remove (key);
+	}
+
+	Value& lookup (const Key& key)
+	{
+		return m_map[key];
+	}
+
+	const Value& lookup (const Key& key) const
+	{
+		return m_map[key];
+	}
+
+	Key& reverseLookup (const Value& key)
+	{
+		return m_reverseMap[key];
+	}
+
+	const Key& reverseLookup (const Value& key) const
+	{
+		return m_reverseMap[key];
+	}
+
+	Value* find (const Key& key)
+	{
+		auto iterator = m_map.find (key);
+		return iterator == m_map.end() ? NULL : &(*iterator);
+	}
+
+	Key* reverseFind (const Value& value)
+	{
+		auto iterator = m_reverseMap.find (value);
+		return iterator == m_reverseMap.end() ? NULL : &(*iterator);
+	}
+
+	Value& operator[] (const Key& key)
+	{
+		return lookup (key);
+	}
+
+	const Value& operator[] (const Key& key) const
+	{
+		return lookup (key);
+	}
+
+private:
+	QMap<Key, Value> m_map;
+	QMap<Value, Key> m_reverseMap;
+};
--- a/src/ldDocument.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/ldDocument.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -761,24 +761,21 @@
 				// Handle BFC statements
 				if (tokens.size() > 2 and tokens[1] == "BFC")
 				{
-					for_enum (BFCStatement, i)
+					for_enum (BfcStatement, i)
 					{
-						if (commentTextSimplified == format ("BFC %1",
-							LDBFC::StatementStrings[int (i)]))
-						{
-							return LDSpawn<LDBFC> (i);
-						}
+						if (commentTextSimplified == format ("BFC %1", LDBfc::statementToString (i)))
+							return LDSpawn<LDBfc> (i);
 					}
 
 					// MLCAD is notorious for stuffing these statements in parts it
 					// creates. The above block only handles valid statements, so we
 					// need to handle MLCAD-style invertnext, clip and noclip separately.
 					if (commentTextSimplified == "BFC CERTIFY INVERTNEXT")
-						return LDSpawn<LDBFC> (BFCStatement::InvertNext);
+						return LDSpawn<LDBfc> (BfcStatement::InvertNext);
 					else if (commentTextSimplified == "BFC CERTIFY CLIP")
-						return LDSpawn<LDBFC> (BFCStatement::Clip);
+						return LDSpawn<LDBfc> (BfcStatement::Clip);
 					else if (commentTextSimplified == "BFC CERTIFY NOCLIP")
-						return LDSpawn<LDBFC> (BFCStatement::NoClip);
+						return LDSpawn<LDBfc> (BfcStatement::NoClip);
 				}
 
 				if (tokens.size() > 2 and tokens[1] == "!LDFORGE")
@@ -1230,11 +1227,10 @@
 //
 void LDDocument::addToSelection (LDObject* obj) // [protected]
 {
-	if (not obj->isSelected() and obj->document() == this)
+	if (obj->isSelected() and obj->document() == this)
 	{
 		m_sel << obj;
 		m_window->renderer()->compileObject (obj);
-		obj->setSelected (true);
 	}
 }
 
@@ -1242,11 +1238,10 @@
 //
 void LDDocument::removeFromSelection (LDObject* obj) // [protected]
 {
-	if (obj->isSelected() and obj->document() == this)
+	if (not obj->isSelected() and obj->document() == this)
 	{
 		m_sel.removeOne (obj);
 		m_window->renderer()->compileObject (obj);
-		obj->setSelected (false);
 	}
 }
 
@@ -1256,8 +1251,8 @@
 {
 	for (LDObject* obj : m_sel)
 	{
+		obj->deselect();
 		m_window->renderer()->compileObject (obj);
-		obj->setSelected (false);
 	}
 
 	m_sel.clear();
--- a/src/ldObject.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/ldObject.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -33,7 +33,6 @@
 
 // List of all LDObjects
 QMap<int32, LDObject*> g_allObjects;
-static int32 g_idcursor = 1; // 0 shalt be null
 
 enum { MAX_LDOBJECT_IDS = (1 << 24) };
 
@@ -47,20 +46,25 @@
 LDObject::LDObject (LDDocument* document) :
 	m_isHidden (false),
 	m_isSelected (false),
-	m_document (nullptr),
-	qObjListEntry (nullptr),
-	m_isDestroyed (false)
+	m_isDestroyed (false),
+	m_document (nullptr)
 {
 	if (document)
 		document->addObject (this);
 
 	memset (m_coords, 0, sizeof m_coords);
-	chooseID();
 
-	if (id() != 0)
-		g_allObjects[id()] = this;
+	// Let's hope that nobody goes to create 17 million objects anytime soon...
+	static int32 nextId = 1; // 0 shalt be null
+	if (nextId < MAX_LDOBJECT_IDS)
+		m_id = nextId++;
+	else
+		m_id = 0;
 
-	setRandomColor (QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128));
+	if (m_id != 0)
+		g_allObjects[m_id] = this;
+
+	m_randomColor = QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128);
 }
 
 LDSubfile::LDSubfile (LDDocument* document) :
@@ -73,7 +77,7 @@
 LDOBJ_DEFAULT_CTOR (LDCondLine, LDLine)
 LDOBJ_DEFAULT_CTOR (LDQuad, LDObject)
 LDOBJ_DEFAULT_CTOR (LDOverlay, LDObject)
-LDOBJ_DEFAULT_CTOR (LDBFC, LDObject)
+LDOBJ_DEFAULT_CTOR (LDBfc, LDObject)
 LDOBJ_DEFAULT_CTOR (LDComment, LDObject)
 
 LDObject::~LDObject()
@@ -84,26 +88,6 @@
 
 // =============================================================================
 //
-void LDObject::chooseID()
-{
-	// Let's hope that nobody goes to create 17 million objects anytime soon...
-	if (g_idcursor < MAX_LDOBJECT_IDS)
-		setID (g_idcursor++);
-	else
-		setID (0);
-}
-
-// =============================================================================
-//
-void LDObject::setVertexCoord (int i, Axis ax, double value)
-{
-	Vertex v = vertex (i);
-	v.setCoordinate (ax, value);
-	setVertex (i, v);
-}
-
-// =============================================================================
-//
 QString LDComment::asText() const
 {
 	return format ("0 %1", text());
@@ -185,23 +169,9 @@
 
 // =============================================================================
 //
-const char* LDBFC::StatementStrings[] =
+QString LDBfc::asText() const
 {
-	"CERTIFY CCW",
-	"CCW",
-	"CERTIFY CW",
-	"CW",
-	"NOCERTIFY",
-	"INVERTNEXT",
-	"CLIP",
-	"CLIP CCW",
-	"CLIP CW",
-	"NOCLIP",
-};
-
-QString LDBFC::asText() const
-{
-	return format ("0 BFC %1", StatementStrings[int (m_statement)]);
+	return format ("0 BFC %1", statementToString());
 }
 
 // =============================================================================
@@ -226,6 +196,8 @@
 
 // =============================================================================
 //
+// Replace this LDObject with another LDObject. Object is deleted in the process.
+//
 void LDObject::replace (LDObject* other)
 {
 	int idx = lineNumber();
@@ -242,6 +214,8 @@
 
 // =============================================================================
 //
+// Swap this object with another.
+//
 void LDObject::swap (LDObject* other)
 {
 	if (document() == other->document())
@@ -291,6 +265,8 @@
 
 // =============================================================================
 //
+// Deletes this object
+//
 void LDObject::destroy()
 {
 	deselect();
@@ -311,12 +287,12 @@
 
 // =============================================================================
 //
-void LDObject::setDocument (LDDocument* const& a)
+void LDObject::setDocument (LDDocument* document)
 {
-	m_document = a;
+	m_document = document;
 
-	if (a == nullptr)
-		setSelected (false);
+	if (document == nullptr)
+		m_isSelected = false;
 }
 
 // =============================================================================
@@ -414,8 +390,10 @@
 }
 
 // =============================================================================
-// -----------------------------------------------------------------------------
-long LDObject::lineNumber() const
+//
+// Index (i.e. line number) of this object
+//
+int LDObject::lineNumber() const
 {
 	if (document())
 	{
@@ -474,6 +452,8 @@
 
 // =============================================================================
 //
+// Get type name by enumerator
+//
 QString LDObject::typeName (LDObjectType type)
 {
 	return LDObject::getDefault (type)->typeName();
@@ -481,6 +461,8 @@
 
 // =============================================================================
 //
+// Get a description of a list of LDObjects
+//
 QString LDObject::describeObjects (const LDObjectList& objs)
 {
 	QString text;
@@ -513,6 +495,8 @@
 
 // =============================================================================
 //
+// What object in the current file ultimately references this?
+//
 LDObject* LDObject::topLevelParent()
 {
 	LDObject* it;
@@ -525,6 +509,8 @@
 
 // =============================================================================
 //
+// Object after this in the current file
+//
 LDObject* LDObject::next() const
 {
 	int idx = lineNumber();
@@ -537,6 +523,8 @@
 
 // =============================================================================
 //
+// Object prior to this in the current file
+//
 LDObject* LDObject::previous() const
 {
 	int idx = lineNumber();
@@ -549,13 +537,15 @@
 
 // =============================================================================
 //
-bool LDObject::previousIsInvertnext (LDBFC*& ptr)
+// Is the previous object INVERTNEXT?
+//
+bool LDObject::previousIsInvertnext (LDBfc*& ptr)
 {
 	LDObject* prev = previous();
 
-	if (prev and prev->type() == OBJ_BFC and static_cast<LDBFC*> (prev)->statement() == BFCStatement::InvertNext)
+	if (prev and prev->type() == OBJ_Bfc and static_cast<LDBfc*> (prev)->statement() == BfcStatement::InvertNext)
 	{
-		ptr = static_cast<LDBFC*> (prev);
+		ptr = static_cast<LDBfc*> (prev);
 		return true;
 	}
 
@@ -564,6 +554,8 @@
 
 // =============================================================================
 //
+// Moves this object using the given vertex as a movement List
+//
 void LDObject::move (Vertex vect)
 {
 	if (hasMatrix())
@@ -578,14 +570,66 @@
 	}
 }
 
+bool LDObject::isHidden() const
+{
+	return m_isHidden;
+}
+
+void LDObject::setHidden (bool value)
+{
+	m_isHidden = value;
+}
+
+LDObject* LDObject::parent() const
+{
+	return m_parent;
+}
+
+void LDObject::setParent (LDObject* parent)
+{
+	m_parent = parent;
+}
+
+bool LDObject::isSelected() const
+{
+	return m_isSelected;
+}
+
+qint32 LDObject::id() const
+{
+	return m_id;
+}
+
+LDColor LDObject::color() const
+{
+	return m_color;
+}
+
+QColor LDObject::randomColor() const
+{
+	return m_randomColor;
+}
+
+LDDocument* LDObject::document() const
+{
+	return m_document;
+}
+
+bool LDObject::isDestroyed() const
+{
+	return m_isDestroyed;
+}
+
 // =============================================================================
 //
+// Returns a default-constructed LDObject by the given type
+//
 LDObject* LDObject::getDefault (const LDObjectType type)
 {
 	switch (type)
 	{
 		case OBJ_Comment:		return LDSpawn<LDComment>();
-		case OBJ_BFC:			return LDSpawn<LDBFC>();
+		case OBJ_Bfc:			return LDSpawn<LDBfc>();
 		case OBJ_Line:			return LDSpawn<LDLine>();
 		case OBJ_CondLine:		return LDSpawn<LDCondLine>();
 		case OBJ_Subfile:		return LDSpawn<LDSubfile>();
@@ -602,7 +646,7 @@
 // =============================================================================
 //
 void LDObject::invert() {}
-void LDBFC::invert() {}
+void LDBfc::invert() {}
 void LDEmpty::invert() {}
 void LDComment::invert() {}
 void LDError::invert() {}
@@ -687,9 +731,9 @@
 
 	if (idx > 0)
 	{
-		LDBFC* bfc = dynamic_cast<LDBFC*> (previous());
+		LDBfc* bfc = dynamic_cast<LDBfc*> (previous());
 
-		if (bfc and bfc->statement() == BFCStatement::InvertNext)
+		if (bfc and bfc->statement() == BfcStatement::InvertNext)
 		{
 			// This is prefixed with an invertnext, thus remove it.
 			bfc->destroy();
@@ -698,7 +742,7 @@
 	}
 
 	// Not inverted, thus prefix it with a new invertnext.
-	document()->insertObj (idx, new LDBFC (BFCStatement::InvertNext));
+	document()->insertObj (idx, new LDBfc (BfcStatement::InvertNext));
 }
 
 // =============================================================================
@@ -792,13 +836,15 @@
 
 // =============================================================================
 //
-void LDObject::setColor (LDColor const& val)
+void LDObject::setColor (LDColor color)
 {
-	changeProperty (this, &m_color, val);
+	changeProperty (this, &m_color, color);
 }
 
 // =============================================================================
 //
+// Get a vertex by index
+//
 const Vertex& LDObject::vertex (int i) const
 {
 	return m_coords[i];
@@ -806,11 +852,41 @@
 
 // =============================================================================
 //
+// Set a vertex to the given value
+//
 void LDObject::setVertex (int i, const Vertex& vert)
 {
 	changeProperty (this, &m_coords[i], vert);
 }
 
+LDMatrixObject::LDMatrixObject (LDDocument* document) :
+	LDObject (document),
+	m_position (Origin) {}
+
+LDMatrixObject::LDMatrixObject (const Matrix& transform, const Vertex& pos, LDDocument* document) :
+	LDObject (document),
+	m_position (pos),
+	m_transform (transform) {}
+
+void LDMatrixObject::setCoordinate (const Axis ax, double value)
+{
+	Vertex v = position();
+
+	switch (ax)
+	{
+		case X: v.setX (value); break;
+		case Y: v.setY (value); break;
+		case Z: v.setZ (value); break;
+	}
+
+	setPosition (v);
+}
+
+const Vertex& LDMatrixObject::position() const
+{
+	return m_position;
+}
+
 // =============================================================================
 //
 void LDMatrixObject::setPosition (const Vertex& a)
@@ -820,29 +896,182 @@
 
 // =============================================================================
 //
+const Matrix& LDMatrixObject::transform() const
+{
+	return m_transform;
+}
+
 void LDMatrixObject::setTransform (const Matrix& val)
 {
 	changeProperty (this, &m_transform, val);
 }
 
+LDError::LDError (QString contents, QString reason, LDDocument* document) :
+	LDObject (document),
+	m_contents (contents),
+	m_reason (reason) {}
+
+QString LDError::reason() const
+{
+	return m_reason;
+}
+
+QString LDError::contents() const
+{
+	return m_contents;
+}
+
+QString LDError::fileReferenced() const
+{
+	return m_fileReferenced;
+}
+
+void LDError::setFileReferenced (QString value)
+{
+	m_fileReferenced = value;
+}
+
+LDComment::LDComment (QString text, LDDocument* document) :
+	LDObject (document),
+	m_text (text) {}
+
+QString LDComment::text() const
+{
+	return m_text;
+}
+
+void LDComment::setText (QString value)
+{
+	changeProperty (this, &m_text, value);
+}
+
+LDBfc::LDBfc (const BfcStatement type, LDDocument* document) :
+	LDObject (document),
+	m_statement (type) {}
+
+BfcStatement LDBfc::statement() const
+{
+	return m_statement;
+}
+
+void LDBfc::setStatement (BfcStatement value)
+{
+	m_statement = value;
+}
+
+QString LDBfc::statementToString() const
+{
+	return LDBfc::statementToString (statement());
+}
+
+QString LDBfc::statementToString (BfcStatement statement)
+{
+	static const char* statementStrings[] =
+	{
+		"CERTIFY CCW",
+		"CCW",
+		"CERTIFY CW",
+		"CW",
+		"NOCERTIFY",
+		"INVERTNEXT",
+		"CLIP",
+		"CLIP CCW",
+		"CLIP CW",
+		"NOCLIP",
+	};
+
+	if ((int) statement >= 0 and (int) statement < countof (statementStrings))
+		return QString::fromLatin1 (statementStrings[(int) statement]);
+	else
+		return "";
+}
+
+int LDOverlay::camera() const
+{
+	return m_camera;
+}
+
+void LDOverlay::setCamera (int value)
+{
+	m_camera = value;
+}
+
+int LDOverlay::x() const
+{
+	return m_x;
+}
+
+void LDOverlay::setX (int value)
+{
+	m_x = value;
+}
+
+int LDOverlay::y() const
+{
+	return m_y;
+}
+
+void LDOverlay::setY (int value)
+{
+	m_y = value;
+}
+
+int LDOverlay::width() const
+{
+	return m_width;
+}
+
+void LDOverlay::setWidth (int value)
+{
+	m_width = value;
+}
+
+int LDOverlay::height() const
+{
+	return m_height;
+}
+
+void LDOverlay::setHeight (int value)
+{
+	m_height = value;
+}
+
+QString LDOverlay::fileName() const
+{
+	return m_fileName;
+}
+
+void LDOverlay::setFileName (QString value)
+{
+	m_fileName = value;
+}
+
 // =============================================================================
 //
+// Selects this object.
+//
 void LDObject::select()
 {
-	if (document())
+	if (not isSelected() and document())
+	{
+		m_isSelected = true;
 		document()->addToSelection (this);
+	}
 }
 
 // =============================================================================
 //
+// Removes this object from selection
+//
 void LDObject::deselect()
 {
 	if (isSelected() and document())
 	{
+		m_isSelected = false;
 		document()->removeFromSelection (this);
 
 		// If this object is inverted with INVERTNEXT, deselect the INVERTNEXT as well.
-		LDBFC* invertnext;
+		LDBfc* invertnext;
 
 		if (previousIsInvertnext (invertnext))
 			invertnext->deselect();
@@ -866,18 +1095,22 @@
 
 // =============================================================================
 //
-void LDSubfile::setFileInfo (LDDocument* const& a)
+LDDocument* LDSubfile::fileInfo() const
 {
-	changeProperty (this, &m_fileInfo, a);
+	return m_fileInfo;
+}
 
-	// If it's an immediate subfile reference (i.e. this subfile belongs in an
-	// explicit file), we need to pre-compile the GL polygons for the document
-	// if they don't exist already.
-	if (a and
-		a->isCache() == false and
-		a->polygonData().isEmpty())
+void LDSubfile::setFileInfo (LDDocument* document)
+{
+	changeProperty (this, &m_fileInfo, document);
+
+	// If it's an immediate subfile reference (i.e. this subfile is in an opened document), we need to pre-compile the
+	// GL polygons for the document if they don't exist already.
+	if (document and
+		document->isCache() == false and
+		document->polygonData().isEmpty())
 	{
-		a->initializeCachedData();
+		document->initializeCachedData();
 	}
 };
 
--- a/src/ldObject.h	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/ldObject.h	Sun Sep 06 15:12:30 2015 +0300
@@ -55,7 +55,7 @@
 class LDSubfile;
 class LDDocument;
 
-class LDBFC;
+class LDBfc;
 
 //
 // Object type codes.
@@ -67,7 +67,7 @@
 	OBJ_Triangle,		//	Object represents a	triangle
 	OBJ_Line,			//	Object represents a	line
 	OBJ_CondLine,		//	Object represents a	conditional line
-	OBJ_BFC,			//	Object represents a	BFC statement
+	OBJ_Bfc,			//	Object represents a	BFC statement
 	OBJ_Overlay,		//	Object contains meta-info about an overlay image.
 	OBJ_Comment,		//	Object represents a	comment
 	OBJ_Error,			//	Object is the result of failed parsing
@@ -89,123 +89,68 @@
 //
 class LDObject
 {
-	PROPERTY (public,		bool,				isHidden,		setHidden,		STOCK_WRITE)
-	PROPERTY (public,		bool,				isSelected,		setSelected,	STOCK_WRITE)
-	PROPERTY (public,		LDObject*,			parent,			setParent,		STOCK_WRITE)
-	PROPERTY (public,		LDDocument*,		document,		setDocument,	CUSTOM_WRITE)
-	PROPERTY (private,		int32,				id,				setID,			STOCK_WRITE)
-	PROPERTY (public,		LDColor,			color,			setColor,		CUSTOM_WRITE)
-	PROPERTY (private,		QColor,				randomColor,	setRandomColor,	STOCK_WRITE)
-
 public:
 	LDObject (LDDocument* document = nullptr);
 
-	// This object as LDraw code
-	virtual QString				asText() const = 0;
-
-	// Makes a copy of this object
-	LDObject*					createCopy() const;
-
-	// What color does the object default to?
-	virtual LDColor				defaultColor() const = 0;
-
-	// Deletes this object
-	void						destroy();
-
-	// Removes this object from selection
-	void						deselect();
-
-	virtual void				getVertices (QVector<Vertex>& verts) const;
-
-	// Does this object have a matrix and position? (see LDMatrixObject)
-	virtual bool				hasMatrix() const = 0;
-
-	// Inverts this object (winding is reversed)
-	virtual void				invert() = 0;
-
-	// Is this object colored?
-	virtual bool				isColored() const = 0;
-
-	// Does this object have meaning in the part model?
-	virtual bool				isScemantic() const = 0;
-
-	// Index (i.e. line number) of this object
-	long						lineNumber() const;
-
-	// Moves this object using the given vertex as a movement List
-	void						move (Vertex vect);
-
-	// Object after this in the current file
-	LDObject*					next() const;
-
-	// Number of vertices this object has
-	virtual int					numVertices() const = 0;
+	virtual QString asText() const = 0; // This object as LDraw code
+	LDColor color() const;
+	LDObject* createCopy() const;
+	virtual LDColor defaultColor() const = 0; // What color does the object default to?
+	void deselect(); 
+	void destroy();
+	LDDocument* document() const;
+	LDPolygon* getPolygon();
+	virtual void getVertices (QVector<Vertex>& verts) const;
+	virtual bool hasMatrix() const = 0; // Does this object have a matrix and position? (see LDMatrixObject)
+	qint32 id() const;
+	virtual void invert() = 0; // Inverts this object (winding is reversed)
+	virtual bool isColored() const = 0;
+	bool isDestroyed() const;
+	bool isHidden() const;
+	virtual bool isScemantic() const = 0; // Does this object have meaning in the part model?
+	bool isSelected() const;
+	int lineNumber() const;
+	void move (Vertex vect);
+	LDObject* next() const;
+	virtual int numVertices() const = 0;
+	LDObject* parent() const;
+	LDObject* previous() const;
+	bool previousIsInvertnext (LDBfc*& ptr);
+	QColor randomColor() const;
+	void replace (LDObject* other);
+	void select();
+	void setColor (LDColor color);
+	void setDocument (LDDocument* document);
+	void setHidden (bool value);
+	void setParent (LDObject* parent);
+	void setVertex (int i, const Vertex& vert);
+	void swap (LDObject* other);
+	LDObject* topLevelParent();
+	virtual LDObjectType type() const = 0;
+	virtual QString typeName() const = 0;
+	const Vertex& vertex (int i) const;
 
-	// Object prior to this in the current file
-	LDObject*					previous() const;
-
-	// Is the previous object INVERTNEXT?
-	bool						previousIsInvertnext (LDBFC*& ptr);
-
-	// Replace this LDObject with another LDObject. Object is deleted in the process.
-	void						replace (LDObject* other);
-
-	// Selects this object.
-	void						select();
-
-	// Set a vertex to the given value
-	void						setVertex (int i, const Vertex& vert);
-
-	// Set a single coordinate of a vertex
-	void						setVertexCoord (int i, Axis ax, double value);
-
-	// Swap this object with another.
-	void						swap (LDObject* other);
-
-	// What object in the current file ultimately references this?
-	LDObject*					topLevelParent();
-
-	// Type enumerator of this object
-	virtual LDObjectType		type() const = 0;
-
-	// Type name of this object
-	virtual QString				typeName() const = 0;
-
-	// Get a vertex by index
-	const Vertex&				vertex (int i) const;
-
-	// Get type name by enumerator
-	static QString typeName (LDObjectType type);
-
-	// Returns a default-constructed LDObject by the given type
-	static LDObject* getDefault (const LDObjectType type);
-
-	// TODO: move this to LDDocument?
-	static void moveObjects (LDObjectList objs, const bool up);
-
-	// Get a description of a list of LDObjects
 	static QString describeObjects (const LDObjectList& objs);
 	static LDObject* fromID (int id);
-	LDPolygon* getPolygon();
-	bool isDestroyed() const { return m_isDestroyed; }
-
-	// TODO: make this private!
-	QListWidgetItem* qObjListEntry;
+	static LDObject* getDefault (const LDObjectType type);
+	static void moveObjects (LDObjectList objs, const bool up); // TODO: move this to LDDocument?
+	static QString typeName (LDObjectType type);
 
 protected:
 	virtual ~LDObject();
 
 private:
-	Vertex m_coords[4];
+	bool m_isHidden;
+	bool m_isSelected;
 	bool m_isDestroyed;
-	
-	void chooseID();
+	LDObject* m_parent;
+	LDDocument* m_document;
+	qint32 m_id;
+	LDColor m_color;
+	QColor m_randomColor;
+	Vertex m_coords[4];
 };
 
-//
-// Makes a new LDObject. This makes the shared pointer always use the custom
-// deleter so that all deletions go through finalDelete();
-//
 template<typename T, typename... Args>
 T* LDSpawn (Args... args)
 {
@@ -233,39 +178,20 @@
 //
 class LDMatrixObject : public LDObject
 {
-	PROPERTY (public,	Matrix,				transform,		setTransform,	CUSTOM_WRITE)
 	Vertex m_position;
 
 public:
-	LDMatrixObject (LDDocument* document = nullptr) :
-		LDObject (document),
-		m_position (Origin) {}
-
-	LDMatrixObject (const Matrix& transform, const Vertex& pos, LDDocument* document = nullptr) :
-		LDObject (document),
-		m_transform (transform),
-		m_position (pos) {}
-
-	inline const Vertex& position() const
-	{
-		return m_position;
-	}
+	LDMatrixObject (LDDocument* document = nullptr);
+	LDMatrixObject (const Matrix& transform, const Vertex& pos, LDDocument* document = nullptr);
 
-	void setCoordinate (const Axis ax, double value)
-	{
-		Vertex v = position();
+	const Vertex& position() const;
+	void setCoordinate (const Axis ax, double value);
+	void setPosition (const Vertex& a);
+	const Matrix& transform() const;
+	void setTransform (const Matrix& value);
 
-		switch (ax)
-		{
-			case X: v.setX (value); break;
-			case Y: v.setY (value); break;
-			case Z: v.setZ (value); break;
-		}
-
-		setPosition (v);
-	}
-
-	void setPosition (const Vertex& a);
+private:
+	Matrix m_transform;
 };
 
 //
@@ -282,15 +208,18 @@
 	LDOBJ_UNCOLORED
 	LDOBJ_SCEMANTIC
 	LDOBJ_NO_MATRIX
-	PROPERTY (public,	QString,	fileReferenced, setFileReferenced,	STOCK_WRITE)
-	PROPERTY (private,	QString,	contents,		setContents,		STOCK_WRITE)
-	PROPERTY (private,	QString,	reason,			setReason,			STOCK_WRITE)
 
 public:
-	LDError (QString contents, QString reason, LDDocument* document = nullptr) :
-		LDObject (document),
-		m_contents (contents),
-		m_reason (reason) {}
+	LDError (QString contents, QString reason, LDDocument* document = nullptr);
+	QString reason() const;
+	QString contents() const;
+	QString fileReferenced() const;
+	void setFileReferenced (QString value);
+
+private:
+	QString m_fileReferenced; // If this error was caused by inability to open a file, what file was that?
+	QString m_contents; // The LDraw code that was being parsed
+	QString m_reason;
 };
 
 //
@@ -313,7 +242,6 @@
 //
 class LDComment : public LDObject
 {
-	PROPERTY (public, QString, text, setText, STOCK_WRITE)
 	LDOBJ (Comment)
 	LDOBJ_NAME (comment)
 	LDOBJ_VERTICES (0)
@@ -322,16 +250,19 @@
 	LDOBJ_NO_MATRIX
 
 public:
-	LDComment (QString text, LDDocument* document = nullptr) :
-		LDObject (document),
-		m_text (text) {}
+	LDComment (QString text, LDDocument* document = nullptr);
+	QString text() const;
+	void setText (QString value);
+
+private:
+	QString m_text;
 };
 
 //
 //
 // Represents a 0 BFC statement in the LDraw code.
 //
-enum class BFCStatement
+enum class BfcStatement
 {
 	CertifyCCW,
 	CCW,
@@ -348,24 +279,27 @@
 	FirstValue = CertifyCCW
 };
 
-class LDBFC : public LDObject
+class LDBfc : public LDObject
 {
 public:
-	LDOBJ (BFC)
+	LDOBJ (Bfc)
 	LDOBJ_NAME (bfc)
 	LDOBJ_VERTICES (0)
 	LDOBJ_UNCOLORED
-	LDOBJ_CUSTOM_SCEMANTIC { return (statement() == BFCStatement::InvertNext); }
+	LDOBJ_CUSTOM_SCEMANTIC { return (statement() == BfcStatement::InvertNext); }
 	LDOBJ_NO_MATRIX
-	PROPERTY (public, BFCStatement, statement, setStatement, STOCK_WRITE)
 
 public:
-	LDBFC (const BFCStatement type, LDDocument* document = nullptr) :
-		LDObject (document),
-		m_statement (type) {}
+	LDBfc (const BfcStatement type, LDDocument* document = nullptr);
 
-	// Statement strings
-	static const char* StatementStrings[];
+	BfcStatement statement() const;
+	void setStatement (BfcStatement value);
+	QString statementToString() const;
+
+	static QString statementToString (BfcStatement statement);
+
+private:
+	BfcStatement m_statement;
 };
 
 //
@@ -382,27 +316,19 @@
 	LDOBJ_DEFAULTCOLOR (MainColor)
 	LDOBJ_SCEMANTIC
 	LDOBJ_HAS_MATRIX
-	PROPERTY (public, LDDocument*, fileInfo, setFileInfo, CUSTOM_WRITE)
 
 public:
-	enum InlineFlag
-	{
-		DeepInline     = (1 << 0),
-		CacheInline    = (1 << 1),
-		RendererInline = (1 << 2),
-		DeepCacheInline = (DeepInline | CacheInline),
-	};
-
-	Q_DECLARE_FLAGS (InlineFlags, InlineFlag)
-
 	// Inlines this subfile.
+	LDDocument* fileInfo() const;
+	virtual void getVertices (QVector<Vertex>& verts) const override;
 	LDObjectList inlineContents (bool deep, bool render);
 	QList<LDPolygon> inlinePolygons();
-	virtual void getVertices (QVector<Vertex>& verts) const override;
+	void setFileInfo (LDDocument* fileInfo);
+
+private:
+	LDDocument* m_fileInfo;
 };
 
-Q_DECLARE_OPERATORS_FOR_FLAGS (LDSubfile::InlineFlags)
-
 //
 // LDLine
 //
@@ -489,8 +415,7 @@
 //
 // LDOverlay
 //
-// Overlay image meta, stored in the header of parts so as to preserve overlay
-// information.
+// Overlay image meta, stored in the header of parts so as to preserve overlay information.
 //
 class LDOverlay : public LDObject
 {
@@ -500,12 +425,28 @@
 	LDOBJ_UNCOLORED
 	LDOBJ_NON_SCEMANTIC
 	LDOBJ_NO_MATRIX
-	PROPERTY (public,	int,		camera,		setCamera,		STOCK_WRITE)
-	PROPERTY (public,	int,		x,			setX,			STOCK_WRITE)
-	PROPERTY (public,	int,		y,			setY,			STOCK_WRITE)
-	PROPERTY (public,	int,		width,		setWidth,		STOCK_WRITE)
-	PROPERTY (public,	int,		height,		setHeight,		STOCK_WRITE)
-	PROPERTY (public,	QString,	fileName,	setFileName,	STOCK_WRITE)
+
+public:
+	int camera() const;
+	QString fileName() const;
+	int height() const;
+	void setCamera (int value);
+	void setFileName (QString value);
+	void setHeight (int value);
+	void setWidth (int value);
+	void setX (int value);
+	void setY (int value);
+	int width() const;
+	int x() const;
+	int y() const;
+
+private:
+	int m_camera;
+	int m_x;
+	int m_y;
+	int m_width;
+	int m_height;
+	QString m_fileName;
 };
 
 // Other common LDraw stuff
--- a/src/mainwindow.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/mainwindow.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -376,6 +376,7 @@
 	// doesn't trigger selection updating so that the selection doesn't get lost
 	// while this is done.
 	g_isSelectionLocked = true;
+	m_objectsInList.clear();
 
 	for (int i = 0; i < ui.objectList->count(); ++i)
 		delete ui.objectList->item (i);
@@ -436,9 +437,9 @@
 				break;
 			}
 
-			case OBJ_BFC:
+			case OBJ_Bfc:
 			{
-				descr = LDBFC::StatementStrings[int (static_cast<LDBFC*> (obj)->statement())];
+				descr = static_cast<LDBfc*> (obj)->statementToString();
 				break;
 			}
 
@@ -485,7 +486,7 @@
 			item->setForeground (obj->color().faceColor());
 		}
 
-		obj->qObjListEntry = item;
+		m_objectsInList.insert (obj, item);
 		ui.objectList->insertItem (ui.objectList->count(), item);
 	}
 
@@ -504,7 +505,7 @@
 		return;
 
 	LDObject* obj = selectedObjects().first();
-	ui.objectList->scrollToItem (obj->qObjListEntry);
+	ui.objectList->scrollToItem (m_objectsInList[obj]);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -524,7 +525,7 @@
 	{
 		for (QListWidgetItem* item : items)
 		{
-			if (item == obj->qObjListEntry)
+			if (item == m_objectsInList[obj])
 			{
 				obj->select();
 				break;
@@ -629,10 +630,12 @@
 
 	for (LDObject* obj : selectedObjects())
 	{
-		if (obj->qObjListEntry == nullptr)
+		QListWidgetItem** itempointer = m_objectsInList.find (obj);
+
+		if (not itempointer)
 			continue;
 
-		int row = ui.objectList->row (obj->qObjListEntry);
+		int row = ui.objectList->row (*itempointer);
 
 		if (top == -1)
 		{
@@ -657,6 +660,7 @@
 			ui.objectList->model()->index (bottom, 0));
 	}
 
+	// Select multiple objects at once for performance reasons
 	ui.objectList->selectionModel()->select (itemselect, QItemSelectionModel::ClearAndSelect);
 	g_isSelectionLocked = false;
 }
@@ -811,14 +815,8 @@
 //
 void MainWindow::objectListDoubleClicked (QListWidgetItem* listitem)
 {
-	for (LDObject* it : m_currentDocument->objects())
-	{
-		if (it->qObjListEntry == listitem)
-		{
-			AddObjectDialog::staticDialog (it->type(), it);
-			break;
-		}
-	}
+	LDObject* object = m_objectsInList.reverseLookup (listitem);
+	AddObjectDialog::staticDialog (object->type(), object);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
--- a/src/mainwindow.h	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/mainwindow.h	Sun Sep 06 15:12:30 2015 +0300
@@ -27,6 +27,7 @@
 #include "ldObject.h"
 #include "colors.h"
 #include "configurationvaluebag.h"
+#include "doublemap.h"
 
 class MessageManager;
 class MainWindow;
@@ -146,6 +147,7 @@
 	class QSettings* m_settings;
 	QList<LDDocument*> m_documents;
 	LDDocument* m_currentDocument;
+	DoubleMap<LDObject*, QListWidgetItem*> m_objectsInList;
 
 private slots:
 	void selectionChanged();
--- a/src/primitives.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/primitives.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -634,7 +634,7 @@
 									  divs == HighResolution ?  "48_" : ""))
 		 << LDSpawn<LDComment> (license)
 		 << LDSpawn<LDEmpty>()
-		 << LDSpawn<LDBFC> (BFCStatement::CertifyCCW)
+		 << LDSpawn<LDBfc> (BfcStatement::CertifyCCW)
 		 << LDSpawn<LDEmpty>();
 
 	document->openForEditing();
--- a/src/radioGroup.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/radioGroup.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -95,7 +95,7 @@
 
 // =============================================================================
 //
-void RadioGroup::addButton (const char* entry)
+void RadioGroup::addButton (QString entry)
 {
 	QRadioButton* button = new QRadioButton (entry);
 	addButton (button);
--- a/src/radioGroup.h	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/radioGroup.h	Sun Sep 06 15:12:30 2015 +0300
@@ -53,7 +53,7 @@
 	explicit RadioGroup (const QString& title, QList<char const*> entries, int const defaultId,
 		const Qt::Orientation orient = Qt::Vertical, QWidget* parent = nullptr);
 
-	void            addButton	(const char* entry);
+	void            addButton	(QString entry);
 	void            addButton	(QRadioButton* button);
 	Iterator        begin();
 	Iterator        end();
--- a/src/toolsets/algorithmtoolset.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/toolsets/algorithmtoolset.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -436,7 +436,7 @@
 	QString			parentpath (currentDocument()->fullPath());
 
 	// BFC type of the new subfile - it shall inherit the BFC type of the parent document
-	BFCStatement	bfctype (BFCStatement::NoCertify);
+	BfcStatement	bfctype (BfcStatement::NoCertify);
 
 	// Dirname of the new subfile
 	QString			subdirname (Dirname (parentpath));
@@ -521,9 +521,9 @@
 
 	// Determine the BFC winding type used in the main document - it is to
 	// be carried over to the subfile.
-	for (LDObjectIterator<LDBFC> it (currentDocument()); it.isValid(); ++it)
+	for (LDObjectIterator<LDBfc> it (currentDocument()); it.isValid(); ++it)
 	{
-		if (isOneOf (it->statement(), BFCStatement::CertifyCCW, BFCStatement::CertifyCW, BFCStatement::NoCertify))
+		if (isOneOf (it->statement(), BfcStatement::CertifyCCW, BfcStatement::CertifyCW, BfcStatement::NoCertify))
 		{
 			bfctype = it->statement();
 			break;
@@ -550,7 +550,7 @@
 		objs << LDSpawn<LDComment> (license);
 
 	objs << LDSpawn<LDEmpty>();
-	objs << LDSpawn<LDBFC> (bfctype);
+	objs << LDSpawn<LDBfc> (bfctype);
 	objs << LDSpawn<LDEmpty>();
 
 	doc->addObjects (objs);
--- a/src/toolsets/basictoolset.cpp	Sun Sep 06 13:46:39 2015 +0300
+++ b/src/toolsets/basictoolset.cpp	Sun Sep 06 15:12:30 2015 +0300
@@ -252,7 +252,7 @@
 
 void BasicToolset::newBFC()
 {
-	AddObjectDialog::staticDialog (OBJ_BFC, nullptr);
+	AddObjectDialog::staticDialog (OBJ_Bfc, nullptr);
 }
 
 void BasicToolset::edit()

mercurial