- updated filenames

Sat, 05 Jul 2014 02:02:31 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Sat, 05 Jul 2014 02:02:31 +0300
changeset 830
a741a0b9df49
parent 829
bb903e89e23c
child 831
3cd913bf0c48

- updated filenames

CMakeLists.txt file | annotate | diff | comparison | revisions
src/actions.cc file | annotate | diff | comparison | revisions
src/editmodes/abstractEditMode.cc file | annotate | diff | comparison | revisions
src/editmodes/abstractEditMode.h file | annotate | diff | comparison | revisions
src/editmodes/abstracteditmode.cc file | annotate | diff | comparison | revisions
src/editmodes/abstracteditmode.h file | annotate | diff | comparison | revisions
src/editmodes/circleMode.cc file | annotate | diff | comparison | revisions
src/editmodes/circleMode.h file | annotate | diff | comparison | revisions
src/editmodes/circlemode.cc file | annotate | diff | comparison | revisions
src/editmodes/circlemode.h file | annotate | diff | comparison | revisions
src/editmodes/drawMode.cc file | annotate | diff | comparison | revisions
src/editmodes/drawMode.h file | annotate | diff | comparison | revisions
src/editmodes/drawmode.cc file | annotate | diff | comparison | revisions
src/editmodes/drawmode.h file | annotate | diff | comparison | revisions
src/editmodes/magicWandMode.cc file | annotate | diff | comparison | revisions
src/editmodes/magicWandMode.h file | annotate | diff | comparison | revisions
src/editmodes/magicwandmode.cc file | annotate | diff | comparison | revisions
src/editmodes/magicwandmode.h file | annotate | diff | comparison | revisions
src/editmodes/selectMode.cc file | annotate | diff | comparison | revisions
src/editmodes/selectMode.h file | annotate | diff | comparison | revisions
src/editmodes/selectmode.cc file | annotate | diff | comparison | revisions
src/editmodes/selectmode.h file | annotate | diff | comparison | revisions
src/glRenderer.h file | annotate | diff | comparison | revisions
src/mainWindow.cc file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Sat Jul 05 01:45:32 2014 +0300
+++ b/CMakeLists.txt	Sat Jul 05 02:02:31 2014 +0300
@@ -47,11 +47,11 @@
 	src/primitives.cc
 	src/radioGroup.cc
 	src/version.cc
-	src/editmodes/abstracteditmode.cc
-	src/editmodes/circlemode.cc
-	src/editmodes/drawmode.cc
-	src/editmodes/magicwandmode.cc
-	src/editmodes/selectmode.cc
+	src/editmodes/abstractEditMode.cc
+	src/editmodes/circleMode.cc
+	src/editmodes/drawMode.cc
+	src/editmodes/magicWandMode.cc
+	src/editmodes/selectMode.cc
 )
 
 set (LDFORGE_HEADERS
@@ -80,11 +80,11 @@
 	src/mainWindow.h
 	src/editHistory.h
 	src/format.h
-	src/editmodes/abstracteditmode.h
-	src/editmodes/circlemode.h
-	src/editmodes/drawmode.h
-	src/editmodes/magicwandmode.h
-	src/editmodes/selectmode.h
+	src/editmodes/abstractEditMode.h
+	src/editmodes/circleMode.h
+	src/editmodes/drawMode.h
+	src/editmodes/magicWandMode.h
+	src/editmodes/selectMode.h
 )
 
 set (LDFORGE_FORMS
--- a/src/actions.cc	Sat Jul 05 01:45:32 2014 +0300
+++ b/src/actions.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -37,7 +37,7 @@
 #include "colors.h"
 #include "glCompiler.h"
 #include "ui_newpart.h"
-#include "editmodes/abstracteditmode.h"
+#include "editmodes/abstractEditMode.h"
 
 EXTERN_CFGENTRY (Bool,		drawWireframe);
 EXTERN_CFGENTRY (Bool,		bfcRedGreenView);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/abstractEditMode.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,177 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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/>.
+ */
+
+#include <QMouseEvent>
+#include <stdexcept>
+#include "abstractEditMode.h"
+#include "selectMode.h"
+#include "drawMode.h"
+#include "circleMode.h"
+#include "magicWandMode.h"
+#include "../mainWindow.h"
+#include "../glRenderer.h"
+
+AbstractEditMode::AbstractEditMode (GLRenderer* renderer) :
+	_renderer (renderer) {}
+
+AbstractEditMode::~AbstractEditMode() {}
+
+AbstractEditMode* AbstractEditMode::createByType (GLRenderer* renderer, EditModeType type)
+{
+	switch (type)
+	{
+		case EditModeType::Select: return new SelectMode (renderer);
+		case EditModeType::Draw: return new DrawMode (renderer);
+		case EditModeType::Circle: return new CircleMode (renderer);
+		case EditModeType::MagicWand: return new MagicWandMode (renderer);
+	}
+
+	throw std::logic_error ("bad type given to AbstractEditMode::createByType");
+}
+
+GLRenderer* AbstractEditMode::renderer() const
+{
+	return _renderer;
+}
+
+AbstractDrawMode::AbstractDrawMode (GLRenderer* renderer) :
+	AbstractEditMode (renderer),
+	_polybrush (QBrush (QColor (64, 192, 0, 128)))
+{
+	// Disable the context menu - we need the right mouse button
+	// for removing vertices.
+	renderer->setContextMenuPolicy (Qt::NoContextMenu);
+
+	// Use the crosshair cursor when drawing.
+	renderer->setCursor (Qt::CrossCursor);
+
+	// Clear the selection when beginning to draw.
+	getCurrentDocument()->clearSelection();
+
+	g_win->updateSelection();
+	_drawedVerts.clear();
+}
+
+AbstractSelectMode::AbstractSelectMode (GLRenderer* renderer) :
+	AbstractEditMode (renderer)
+{
+	renderer->unsetCursor();
+	renderer->setContextMenuPolicy (Qt::DefaultContextMenu);
+}
+
+// =============================================================================
+//
+void AbstractDrawMode::addDrawnVertex (Vertex const& pos)
+{
+	if (preAddVertex (pos))
+		return;
+
+	_drawedVerts << pos;
+}
+
+bool AbstractDrawMode::mouseReleased (MouseEventData const& data)
+{
+	if (Super::mouseReleased (data))
+		return true;
+
+	if ((data.releasedButtons & Qt::MidButton) && (_drawedVerts.size() < 4) && (not data.mouseMoved))
+	{
+		// Find the closest vertex to our cursor
+		double			minimumDistance = 1024.0;
+		const Vertex*	closest = null;
+		Vertex			cursorPosition = renderer()->coordconv2_3 (data.ev->pos(), false);
+		QPoint			cursorPosition2D (data.ev->pos());
+		const Axis		relZ = renderer()->getRelativeZ();
+		QVector<Vertex>	vertices;
+
+		for (auto it = renderer()->document()->vertices().begin();
+			it != renderer()->document()->vertices().end();
+			++it)
+		{
+			vertices << it.key();
+		}
+
+		// Sort the vertices in order of distance to camera
+		std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool
+		{
+			if (renderer()->getFixedCamera (renderer()->camera()).negatedDepth)
+				return a[relZ] > b[relZ];
+
+			return a[relZ] < b[relZ];
+		});
+
+		for (const Vertex& vrt : vertices)
+		{
+			// If the vertex in 2d space is very close to the cursor then we use
+			// it regardless of depth.
+			QPoint vect2d = renderer()->coordconv3_2 (vrt) - cursorPosition2D;
+			const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2);
+			if (distance2DSquared < 16.0 * 16.0)
+			{
+				closest = &vrt;
+				break;
+			}
+
+			// Check if too far away from the cursor.
+			if (distance2DSquared > 64.0 * 64.0)
+				continue;
+
+			// Not very close to the cursor. Compare using true distance,
+			// including depth.
+			const double distanceSquared = (vrt - cursorPosition).lengthSquared();
+
+			if (distanceSquared < minimumDistance)
+			{
+				minimumDistance = distanceSquared;
+				closest = &vrt;
+			}
+		}
+
+		if (closest != null)
+			addDrawnVertex (*closest);
+
+		return true;
+	}
+
+	if ((data.releasedButtons & Qt::RightButton) && (not _drawedVerts.isEmpty()))
+	{
+		// Remove the last vertex
+		_drawedVerts.removeLast();
+
+		return true;
+	}
+
+	return false;
+}
+
+void AbstractDrawMode::finishDraw (LDObjectList& objs)
+{
+	if (objs.size() > 0)
+	{
+		for (LDObjectPtr obj : objs)
+		{
+			renderer()->document()->addObject (obj);
+			renderer()->compileObject (obj);
+		}
+
+		g_win->refresh();
+		g_win->endAction();
+	}
+
+	_drawedVerts.clear();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/abstractEditMode.h	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,106 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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 "../main.h"
+
+class QPainter;
+class GLRenderer;
+class QMouseEvent;
+
+enum class EditModeType
+{
+	Select,
+	Draw,
+	Circle,
+	MagicWand,
+};
+
+class AbstractEditMode
+{
+	GLRenderer* _renderer;
+
+public:
+	struct MouseEventData
+	{
+		QMouseEvent* ev;
+		Qt::KeyboardModifiers keymods;
+		bool mouseMoved;
+		Qt::MouseButtons releasedButtons;
+	};
+
+	AbstractEditMode (GLRenderer* renderer);
+	virtual ~AbstractEditMode();
+
+	virtual bool			allowFreeCamera() const = 0;
+	virtual void			render (QPainter&) const {};
+	GLRenderer*				renderer() const;
+	virtual EditModeType	type() const = 0;
+	virtual bool			mousePressed (QMouseEvent*) { return false; }
+	virtual bool			mouseReleased (MouseEventData const&) { return false; }
+	virtual bool			mouseDoubleClicked (QMouseEvent*) { return false; }
+	virtual bool			mouseMoved (QMouseEvent*) { return false; }
+
+	static AbstractEditMode* createByType (GLRenderer* renderer, EditModeType type);
+};
+
+//
+// Base class for draw-like edit modes
+//
+class AbstractDrawMode : public AbstractEditMode
+{
+	DEFINE_CLASS (AbstractDrawMode, AbstractEditMode)
+
+protected:
+	QList<Vertex>			_drawedVerts;
+	Vertex					_rectverts[4];
+	QBrush					_polybrush;
+
+public:
+	AbstractDrawMode (GLRenderer* renderer);
+
+	virtual bool allowFreeCamera() const override
+	{
+		return false;
+	}
+
+	bool mouseReleased (const AbstractEditMode::MouseEventData& data) override;
+	void addDrawnVertex (const Vertex& pos);
+	void finishDraw (LDObjectList& objs);
+
+	virtual bool preAddVertex (Vertex const&)
+	{
+		return false;
+	}
+};
+
+//
+// Base class for select-like edit modes
+//
+class AbstractSelectMode : public AbstractEditMode
+{
+	DEFINE_CLASS (AbstractSelectMode, AbstractEditMode)
+
+public:
+	AbstractSelectMode (GLRenderer* renderer);
+
+	virtual bool allowFreeCamera() const override
+	{
+		return true;
+	}
+};
--- a/src/editmodes/abstracteditmode.cc	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include <QMouseEvent>
-#include <stdexcept>
-#include "abstracteditmode.h"
-#include "selectmode.h"
-#include "drawmode.h"
-#include "circlemode.h"
-#include "magicwandmode.h"
-#include "../mainWindow.h"
-#include "../glRenderer.h"
-
-AbstractEditMode::AbstractEditMode (GLRenderer* renderer) :
-	_renderer (renderer) {}
-
-AbstractEditMode::~AbstractEditMode() {}
-
-AbstractEditMode* AbstractEditMode::createByType (GLRenderer* renderer, EditModeType type)
-{
-	switch (type)
-	{
-		case EditModeType::Select: return new SelectMode (renderer);
-		case EditModeType::Draw: return new DrawMode (renderer);
-		case EditModeType::Circle: return new CircleMode (renderer);
-		case EditModeType::MagicWand: return new MagicWandMode (renderer);
-	}
-
-	throw std::logic_error ("bad type given to AbstractEditMode::createByType");
-}
-
-GLRenderer* AbstractEditMode::renderer() const
-{
-	return _renderer;
-}
-
-AbstractDrawMode::AbstractDrawMode (GLRenderer* renderer) :
-	AbstractEditMode (renderer),
-	_polybrush (QBrush (QColor (64, 192, 0, 128)))
-{
-	// Disable the context menu - we need the right mouse button
-	// for removing vertices.
-	renderer->setContextMenuPolicy (Qt::NoContextMenu);
-
-	// Use the crosshair cursor when drawing.
-	renderer->setCursor (Qt::CrossCursor);
-
-	// Clear the selection when beginning to draw.
-	getCurrentDocument()->clearSelection();
-
-	g_win->updateSelection();
-	_drawedVerts.clear();
-}
-
-AbstractSelectMode::AbstractSelectMode (GLRenderer* renderer) :
-	AbstractEditMode (renderer)
-{
-	renderer->unsetCursor();
-	renderer->setContextMenuPolicy (Qt::DefaultContextMenu);
-}
-
-// =============================================================================
-//
-void AbstractDrawMode::addDrawnVertex (Vertex const& pos)
-{
-	if (preAddVertex (pos))
-		return;
-
-	_drawedVerts << pos;
-}
-
-bool AbstractDrawMode::mouseReleased (MouseEventData const& data)
-{
-	if (Super::mouseReleased (data))
-		return true;
-
-	if ((data.releasedButtons & Qt::MidButton) && (_drawedVerts.size() < 4) && (not data.mouseMoved))
-	{
-		// Find the closest vertex to our cursor
-		double			minimumDistance = 1024.0;
-		const Vertex*	closest = null;
-		Vertex			cursorPosition = renderer()->coordconv2_3 (data.ev->pos(), false);
-		QPoint			cursorPosition2D (data.ev->pos());
-		const Axis		relZ = renderer()->getRelativeZ();
-		QVector<Vertex>	vertices;
-
-		for (auto it = renderer()->document()->vertices().begin();
-			it != renderer()->document()->vertices().end();
-			++it)
-		{
-			vertices << it.key();
-		}
-
-		// Sort the vertices in order of distance to camera
-		std::sort (vertices.begin(), vertices.end(), [&](const Vertex& a, const Vertex& b) -> bool
-		{
-			if (renderer()->getFixedCamera (renderer()->camera()).negatedDepth)
-				return a[relZ] > b[relZ];
-
-			return a[relZ] < b[relZ];
-		});
-
-		for (const Vertex& vrt : vertices)
-		{
-			// If the vertex in 2d space is very close to the cursor then we use
-			// it regardless of depth.
-			QPoint vect2d = renderer()->coordconv3_2 (vrt) - cursorPosition2D;
-			const double distance2DSquared = std::pow (vect2d.x(), 2) + std::pow (vect2d.y(), 2);
-			if (distance2DSquared < 16.0 * 16.0)
-			{
-				closest = &vrt;
-				break;
-			}
-
-			// Check if too far away from the cursor.
-			if (distance2DSquared > 64.0 * 64.0)
-				continue;
-
-			// Not very close to the cursor. Compare using true distance,
-			// including depth.
-			const double distanceSquared = (vrt - cursorPosition).lengthSquared();
-
-			if (distanceSquared < minimumDistance)
-			{
-				minimumDistance = distanceSquared;
-				closest = &vrt;
-			}
-		}
-
-		if (closest != null)
-			addDrawnVertex (*closest);
-
-		return true;
-	}
-
-	if ((data.releasedButtons & Qt::RightButton) && (not _drawedVerts.isEmpty()))
-	{
-		// Remove the last vertex
-		_drawedVerts.removeLast();
-
-		return true;
-	}
-
-	return false;
-}
-
-void AbstractDrawMode::finishDraw (LDObjectList& objs)
-{
-	if (objs.size() > 0)
-	{
-		for (LDObjectPtr obj : objs)
-		{
-			renderer()->document()->addObject (obj);
-			renderer()->compileObject (obj);
-		}
-
-		g_win->refresh();
-		g_win->endAction();
-	}
-
-	_drawedVerts.clear();
-}
--- a/src/editmodes/abstracteditmode.h	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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 "../main.h"
-
-class QPainter;
-class GLRenderer;
-class QMouseEvent;
-
-enum class EditModeType
-{
-	Select,
-	Draw,
-	Circle,
-	MagicWand,
-};
-
-class AbstractEditMode
-{
-	GLRenderer* _renderer;
-
-public:
-	struct MouseEventData
-	{
-		QMouseEvent* ev;
-		Qt::KeyboardModifiers keymods;
-		bool mouseMoved;
-		Qt::MouseButtons releasedButtons;
-	};
-
-	AbstractEditMode (GLRenderer* renderer);
-	virtual ~AbstractEditMode();
-
-	virtual bool			allowFreeCamera() const = 0;
-	virtual void			render (QPainter&) const {};
-	GLRenderer*				renderer() const;
-	virtual EditModeType	type() const = 0;
-	virtual bool			mousePressed (QMouseEvent*) { return false; }
-	virtual bool			mouseReleased (MouseEventData const&) { return false; }
-	virtual bool			mouseDoubleClicked (QMouseEvent*) { return false; }
-	virtual bool			mouseMoved (QMouseEvent*) { return false; }
-
-	static AbstractEditMode* createByType (GLRenderer* renderer, EditModeType type);
-};
-
-//
-// Base class for draw-like edit modes
-//
-class AbstractDrawMode : public AbstractEditMode
-{
-	DEFINE_CLASS (AbstractDrawMode, AbstractEditMode)
-
-protected:
-	QList<Vertex>			_drawedVerts;
-	Vertex					_rectverts[4];
-	QBrush					_polybrush;
-
-public:
-	AbstractDrawMode (GLRenderer* renderer);
-
-	virtual bool allowFreeCamera() const override
-	{
-		return false;
-	}
-
-	bool mouseReleased (const AbstractEditMode::MouseEventData& data) override;
-	void addDrawnVertex (const Vertex& pos);
-	void finishDraw (LDObjectList& objs);
-
-	virtual bool preAddVertex (Vertex const&)
-	{
-		return false;
-	}
-};
-
-//
-// Base class for select-like edit modes
-//
-class AbstractSelectMode : public AbstractEditMode
-{
-	DEFINE_CLASS (AbstractSelectMode, AbstractEditMode)
-
-public:
-	AbstractSelectMode (GLRenderer* renderer);
-
-	virtual bool allowFreeCamera() const override
-	{
-		return true;
-	}
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/circleMode.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,284 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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/>.
+ */
+
+#include <QPainter>
+#include "circleMode.h"
+#include "../miscallenous.h"
+#include "../ldObject.h"
+#include "../ldDocument.h"
+#include "../misc/ringFinder.h"
+#include "../primitives.h"
+#include "../glRenderer.h"
+
+CircleMode::CircleMode (GLRenderer* renderer) :
+	Super (renderer) {}
+
+EditModeType CircleMode::type() const
+{
+	return EditModeType::Circle;
+}
+
+double CircleMode::getCircleDrawDist (int pos) const
+{
+	assert (_drawedVerts.size() >= pos + 1);
+	Vertex v1 = (_drawedVerts.size() >= pos + 2) ? _drawedVerts[pos + 1] :
+		renderer()->coordconv2_3 (renderer()->mousePosition(), false);
+	Axis localx, localy;
+	renderer()->getRelativeAxes (localx, localy);
+	double dx = _drawedVerts[0][localx] - v1[localx];
+	double dy = _drawedVerts[0][localy] - v1[localy];
+	return Grid::snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate);
+}
+
+Matrix CircleMode::getCircleDrawMatrix (double scale)
+{
+	// Matrix templates. 2 is substituted with the scale value, 1 is inverted to -1 if needed.
+	static const Matrix templates[3] =
+	{
+		{ 2, 0, 0, 0, 1, 0, 0, 0, 2 },
+		{ 2, 0, 0, 0, 0, 2, 0, 1, 0 },
+		{ 0, 1, 0, 2, 0, 0, 0, 0, 2 },
+	};
+
+	Matrix transform = templates[renderer()->camera() % 3];
+
+	for (int i = 0; i < 9; ++i)
+	{
+		if (transform[i] == 2)
+			transform[i] = scale;
+		elif (transform[i] == 1 && renderer()->camera() >= 3)
+			transform[i] = -1;
+	}
+
+	return transform;
+}
+
+void CircleMode::buildCircle()
+{
+	LDObjectList objs;
+	const int segs = g_lores, divs = g_lores; // TODO: make customizable
+	double dist0 = getCircleDrawDist (0),
+		dist1 = getCircleDrawDist (1);
+	LDDocumentPtr refFile;
+	Matrix transform;
+	bool circleOrDisc = false;
+
+	if (dist1 < dist0)
+		std::swap<double> (dist0, dist1);
+
+	if (dist0 == dist1)
+	{
+		// If the radii are the same, there's no ring space to fill. Use a circle.
+		refFile = getDocument ("4-4edge.dat");
+		transform = getCircleDrawMatrix (dist0);
+		circleOrDisc = true;
+	}
+	elif (dist0 == 0 || dist1 == 0)
+	{
+		// If either radii is 0, use a disc.
+		refFile = getDocument ("4-4disc.dat");
+		transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1);
+		circleOrDisc = true;
+	}
+	elif (g_RingFinder.findRings (dist0, dist1))
+	{
+		// The ring finder found a solution, use that. Add the component rings to the file.
+		for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents())
+		{
+			// Get a ref file for this primitive. If we cannot find it in the
+			// LDraw library, generate it.
+			if ((refFile = ::getDocument (radialFileName (::Ring, g_lores, g_lores, cmp.num))) == null)
+			{
+				refFile = generatePrimitive (::Ring, g_lores, g_lores, cmp.num);
+				refFile->setImplicit (false);
+			}
+
+			LDSubfilePtr ref = spawn<LDSubfile>();
+			ref->setFileInfo (refFile);
+			ref->setTransform (getCircleDrawMatrix (cmp.scale));
+			ref->setPosition (_drawedVerts[0]);
+			ref->setColor (maincolor());
+			objs << ref;
+		}
+	}
+	else
+	{
+		// Ring finder failed, last resort: draw the ring with quads
+		QList<QLineF> c0, c1;
+		Axis localx, localy, localz;
+		renderer()->getRelativeAxes (localx, localy);
+		localz = (Axis) (3 - localx - localy);
+		double x0 = _drawedVerts[0][localx],
+			y0 = _drawedVerts[0][localy];
+
+		Vertex templ;
+		templ.setCoordinate (localx, x0);
+		templ.setCoordinate (localy, y0);
+		templ.setCoordinate (localz, renderer()->getDepthValue());
+
+		// Calculate circle coords
+		makeCircle (segs, divs, dist0, c0);
+		makeCircle (segs, divs, dist1, c1);
+
+		for (int i = 0; i < segs; ++i)
+		{
+			Vertex v0, v1, v2, v3;
+			v0 = v1 = v2 = v3 = templ;
+			v0.setCoordinate (localx, v0[localx] + c0[i].x1());
+			v0.setCoordinate (localy, v0[localy] + c0[i].y1());
+			v1.setCoordinate (localx, v1[localx] + c0[i].x2());
+			v1.setCoordinate (localy, v1[localy] + c0[i].y2());
+			v2.setCoordinate (localx, v2[localx] + c1[i].x2());
+			v2.setCoordinate (localy, v2[localy] + c1[i].y2());
+			v3.setCoordinate (localx, v3[localx] + c1[i].x1());
+			v3.setCoordinate (localy, v3[localy] + c1[i].y1());
+
+			LDQuadPtr quad (spawn<LDQuad> (v0, v1, v2, v3));
+			quad->setColor (maincolor());
+
+			// Ensure the quads always are BFC-front towards the camera
+			if (renderer()->camera() % 3 <= 0)
+				quad->invert();
+
+			objs << quad;
+		}
+	}
+
+	if (circleOrDisc && refFile != null)
+	{
+		LDSubfilePtr ref = spawn<LDSubfile>();
+		ref->setFileInfo (refFile);
+		ref->setTransform (transform);
+		ref->setPosition (_drawedVerts[0]);
+		ref->setColor (maincolor());
+		objs << ref;
+	}
+
+	finishDraw (objs);
+}
+
+void CircleMode::render (QPainter& painter) const
+{
+	QFontMetrics metrics = QFontMetrics (QFont());
+
+	// If we have not specified the center point of the circle yet, preview it on the screen.
+	if (_drawedVerts.isEmpty())
+	{
+		renderer()->drawBlip (painter, renderer()->coordconv3_2 (renderer()->position3D()));
+	}
+	else
+	{
+		QVector<Vertex> verts, verts2;
+		const double dist0 = getCircleDrawDist (0),
+			dist1 = (_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1;
+		const int segs = g_lores;
+		const double angleUnit = (2 * pi) / segs;
+		Axis relX, relY;
+		QVector<QPoint> ringpoints, circlepoints, circle2points;
+
+		renderer()->getRelativeAxes (relX, relY);
+
+		// Calculate the preview positions of vertices
+		for (int i = 0; i < segs; ++i)
+		{
+			Vertex v = g_origin;
+			v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist0));
+			v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist0));
+			verts << v;
+
+			if (dist1 != -1)
+			{
+				v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist1));
+				v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist1));
+				verts2 << v;
+			}
+		}
+
+		int i = 0;
+		for (const Vertex& v : verts + verts2)
+		{
+			// Calculate the 2D point of the vertex
+			QPoint point = renderer()->coordconv3_2 (v);
+
+			// Draw a green blip at where it is
+			renderer()->drawBlip (painter, point);
+
+			// Add it to the list of points for the green ring fill.
+			ringpoints << point;
+
+			// Also add the circle points to separate lists
+			if (i < verts.size())
+				circlepoints << point;
+			else
+				circle2points << point;
+
+			++i;
+		}
+
+		// Insert the first point as the seventeenth one so that
+		// the ring polygon is closed properly.
+		if (ringpoints.size() >= 16)
+			ringpoints.insert (16, ringpoints[0]);
+
+		// Same for the outer ring. Note that the indices are offset by 1
+		// because of the insertion done above bumps the values.
+		if (ringpoints.size() >= 33)
+			ringpoints.insert (33, ringpoints[17]);
+
+		// Draw the ring
+		painter.setBrush ((_drawedVerts.size() >= 2) ? _polybrush : Qt::NoBrush);
+		painter.setPen (Qt::NoPen);
+		painter.drawPolygon (QPolygon (ringpoints));
+
+		// Draw the circles
+		painter.setBrush (Qt::NoBrush);
+		painter.setPen (renderer()->linePen());
+		painter.drawPolygon (QPolygon (circlepoints));
+		painter.drawPolygon (QPolygon (circle2points));
+
+		// Draw the current radius in the middle of the circle.
+		QPoint origin = renderer()->coordconv3_2 (_drawedVerts[0]);
+		QString label = QString::number (dist0);
+		painter.setPen (renderer()->textPen());
+		painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label);
+
+		if (_drawedVerts.size() >= 2)
+		{
+			painter.drawText (origin.x() - (metrics.width (label) / 2),
+				origin.y() + metrics.height(), QString::number (dist1));
+		}
+	}
+}
+
+bool CircleMode::mouseReleased (MouseEventData const& data)
+{
+	if (Super::mouseReleased (data))
+		return true;
+
+	if (data.releasedButtons & Qt::LeftButton)
+	{
+		if (_drawedVerts.size() < 3)
+			addDrawnVertex (renderer()->position3D());
+		else
+			buildCircle();
+
+		return true;
+	}
+
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/circleMode.h	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,38 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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 "abstractEditMode.h"
+
+class CircleMode : public AbstractDrawMode
+{
+	DEFINE_CLASS (CircleMode, AbstractDrawMode)
+
+public:
+	CircleMode (GLRenderer* renderer);
+
+	virtual void render (QPainter& painter) const override;
+	virtual EditModeType type() const override;
+
+	double getCircleDrawDist (int pos) const;
+	Matrix getCircleDrawMatrix (double scale);
+	bool mouseReleased (const AbstractEditMode::MouseEventData& data) override;
+
+private:
+	void buildCircle();
+};
--- a/src/editmodes/circlemode.cc	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,284 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include <QPainter>
-#include "circlemode.h"
-#include "../miscallenous.h"
-#include "../ldObject.h"
-#include "../ldDocument.h"
-#include "../misc/ringFinder.h"
-#include "../primitives.h"
-#include "../glRenderer.h"
-
-CircleMode::CircleMode (GLRenderer* renderer) :
-	Super (renderer) {}
-
-EditModeType CircleMode::type() const
-{
-	return EditModeType::Circle;
-}
-
-double CircleMode::getCircleDrawDist (int pos) const
-{
-	assert (_drawedVerts.size() >= pos + 1);
-	Vertex v1 = (_drawedVerts.size() >= pos + 2) ? _drawedVerts[pos + 1] :
-		renderer()->coordconv2_3 (renderer()->mousePosition(), false);
-	Axis localx, localy;
-	renderer()->getRelativeAxes (localx, localy);
-	double dx = _drawedVerts[0][localx] - v1[localx];
-	double dy = _drawedVerts[0][localy] - v1[localy];
-	return Grid::snap (sqrt ((dx * dx) + (dy * dy)), Grid::Coordinate);
-}
-
-Matrix CircleMode::getCircleDrawMatrix (double scale)
-{
-	// Matrix templates. 2 is substituted with the scale value, 1 is inverted to -1 if needed.
-	static const Matrix templates[3] =
-	{
-		{ 2, 0, 0, 0, 1, 0, 0, 0, 2 },
-		{ 2, 0, 0, 0, 0, 2, 0, 1, 0 },
-		{ 0, 1, 0, 2, 0, 0, 0, 0, 2 },
-	};
-
-	Matrix transform = templates[renderer()->camera() % 3];
-
-	for (int i = 0; i < 9; ++i)
-	{
-		if (transform[i] == 2)
-			transform[i] = scale;
-		elif (transform[i] == 1 && renderer()->camera() >= 3)
-			transform[i] = -1;
-	}
-
-	return transform;
-}
-
-void CircleMode::buildCircle()
-{
-	LDObjectList objs;
-	const int segs = g_lores, divs = g_lores; // TODO: make customizable
-	double dist0 = getCircleDrawDist (0),
-		dist1 = getCircleDrawDist (1);
-	LDDocumentPtr refFile;
-	Matrix transform;
-	bool circleOrDisc = false;
-
-	if (dist1 < dist0)
-		std::swap<double> (dist0, dist1);
-
-	if (dist0 == dist1)
-	{
-		// If the radii are the same, there's no ring space to fill. Use a circle.
-		refFile = getDocument ("4-4edge.dat");
-		transform = getCircleDrawMatrix (dist0);
-		circleOrDisc = true;
-	}
-	elif (dist0 == 0 || dist1 == 0)
-	{
-		// If either radii is 0, use a disc.
-		refFile = getDocument ("4-4disc.dat");
-		transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1);
-		circleOrDisc = true;
-	}
-	elif (g_RingFinder.findRings (dist0, dist1))
-	{
-		// The ring finder found a solution, use that. Add the component rings to the file.
-		for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->getComponents())
-		{
-			// Get a ref file for this primitive. If we cannot find it in the
-			// LDraw library, generate it.
-			if ((refFile = ::getDocument (radialFileName (::Ring, g_lores, g_lores, cmp.num))) == null)
-			{
-				refFile = generatePrimitive (::Ring, g_lores, g_lores, cmp.num);
-				refFile->setImplicit (false);
-			}
-
-			LDSubfilePtr ref = spawn<LDSubfile>();
-			ref->setFileInfo (refFile);
-			ref->setTransform (getCircleDrawMatrix (cmp.scale));
-			ref->setPosition (_drawedVerts[0]);
-			ref->setColor (maincolor());
-			objs << ref;
-		}
-	}
-	else
-	{
-		// Ring finder failed, last resort: draw the ring with quads
-		QList<QLineF> c0, c1;
-		Axis localx, localy, localz;
-		renderer()->getRelativeAxes (localx, localy);
-		localz = (Axis) (3 - localx - localy);
-		double x0 = _drawedVerts[0][localx],
-			y0 = _drawedVerts[0][localy];
-
-		Vertex templ;
-		templ.setCoordinate (localx, x0);
-		templ.setCoordinate (localy, y0);
-		templ.setCoordinate (localz, renderer()->getDepthValue());
-
-		// Calculate circle coords
-		makeCircle (segs, divs, dist0, c0);
-		makeCircle (segs, divs, dist1, c1);
-
-		for (int i = 0; i < segs; ++i)
-		{
-			Vertex v0, v1, v2, v3;
-			v0 = v1 = v2 = v3 = templ;
-			v0.setCoordinate (localx, v0[localx] + c0[i].x1());
-			v0.setCoordinate (localy, v0[localy] + c0[i].y1());
-			v1.setCoordinate (localx, v1[localx] + c0[i].x2());
-			v1.setCoordinate (localy, v1[localy] + c0[i].y2());
-			v2.setCoordinate (localx, v2[localx] + c1[i].x2());
-			v2.setCoordinate (localy, v2[localy] + c1[i].y2());
-			v3.setCoordinate (localx, v3[localx] + c1[i].x1());
-			v3.setCoordinate (localy, v3[localy] + c1[i].y1());
-
-			LDQuadPtr quad (spawn<LDQuad> (v0, v1, v2, v3));
-			quad->setColor (maincolor());
-
-			// Ensure the quads always are BFC-front towards the camera
-			if (renderer()->camera() % 3 <= 0)
-				quad->invert();
-
-			objs << quad;
-		}
-	}
-
-	if (circleOrDisc && refFile != null)
-	{
-		LDSubfilePtr ref = spawn<LDSubfile>();
-		ref->setFileInfo (refFile);
-		ref->setTransform (transform);
-		ref->setPosition (_drawedVerts[0]);
-		ref->setColor (maincolor());
-		objs << ref;
-	}
-
-	finishDraw (objs);
-}
-
-void CircleMode::render (QPainter& painter) const
-{
-	QFontMetrics metrics = QFontMetrics (QFont());
-
-	// If we have not specified the center point of the circle yet, preview it on the screen.
-	if (_drawedVerts.isEmpty())
-	{
-		renderer()->drawBlip (painter, renderer()->coordconv3_2 (renderer()->position3D()));
-	}
-	else
-	{
-		QVector<Vertex> verts, verts2;
-		const double dist0 = getCircleDrawDist (0),
-			dist1 = (_drawedVerts.size() >= 2) ? getCircleDrawDist (1) : -1;
-		const int segs = g_lores;
-		const double angleUnit = (2 * pi) / segs;
-		Axis relX, relY;
-		QVector<QPoint> ringpoints, circlepoints, circle2points;
-
-		renderer()->getRelativeAxes (relX, relY);
-
-		// Calculate the preview positions of vertices
-		for (int i = 0; i < segs; ++i)
-		{
-			Vertex v = g_origin;
-			v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist0));
-			v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist0));
-			verts << v;
-
-			if (dist1 != -1)
-			{
-				v.setCoordinate (relX, _drawedVerts[0][relX] + (cos (i * angleUnit) * dist1));
-				v.setCoordinate (relY, _drawedVerts[0][relY] + (sin (i * angleUnit) * dist1));
-				verts2 << v;
-			}
-		}
-
-		int i = 0;
-		for (const Vertex& v : verts + verts2)
-		{
-			// Calculate the 2D point of the vertex
-			QPoint point = renderer()->coordconv3_2 (v);
-
-			// Draw a green blip at where it is
-			renderer()->drawBlip (painter, point);
-
-			// Add it to the list of points for the green ring fill.
-			ringpoints << point;
-
-			// Also add the circle points to separate lists
-			if (i < verts.size())
-				circlepoints << point;
-			else
-				circle2points << point;
-
-			++i;
-		}
-
-		// Insert the first point as the seventeenth one so that
-		// the ring polygon is closed properly.
-		if (ringpoints.size() >= 16)
-			ringpoints.insert (16, ringpoints[0]);
-
-		// Same for the outer ring. Note that the indices are offset by 1
-		// because of the insertion done above bumps the values.
-		if (ringpoints.size() >= 33)
-			ringpoints.insert (33, ringpoints[17]);
-
-		// Draw the ring
-		painter.setBrush ((_drawedVerts.size() >= 2) ? _polybrush : Qt::NoBrush);
-		painter.setPen (Qt::NoPen);
-		painter.drawPolygon (QPolygon (ringpoints));
-
-		// Draw the circles
-		painter.setBrush (Qt::NoBrush);
-		painter.setPen (renderer()->linePen());
-		painter.drawPolygon (QPolygon (circlepoints));
-		painter.drawPolygon (QPolygon (circle2points));
-
-		// Draw the current radius in the middle of the circle.
-		QPoint origin = renderer()->coordconv3_2 (_drawedVerts[0]);
-		QString label = QString::number (dist0);
-		painter.setPen (renderer()->textPen());
-		painter.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label);
-
-		if (_drawedVerts.size() >= 2)
-		{
-			painter.drawText (origin.x() - (metrics.width (label) / 2),
-				origin.y() + metrics.height(), QString::number (dist1));
-		}
-	}
-}
-
-bool CircleMode::mouseReleased (MouseEventData const& data)
-{
-	if (Super::mouseReleased (data))
-		return true;
-
-	if (data.releasedButtons & Qt::LeftButton)
-	{
-		if (_drawedVerts.size() < 3)
-			addDrawnVertex (renderer()->position3D());
-		else
-			buildCircle();
-
-		return true;
-	}
-
-	return false;
-}
--- a/src/editmodes/circlemode.h	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include "abstracteditmode.h"
-
-class CircleMode : public AbstractDrawMode
-{
-	DEFINE_CLASS (CircleMode, AbstractDrawMode)
-
-public:
-	CircleMode (GLRenderer* renderer);
-
-	virtual void render (QPainter& painter) const override;
-	virtual EditModeType type() const override;
-
-	double getCircleDrawDist (int pos) const;
-	Matrix getCircleDrawMatrix (double scale);
-	bool mouseReleased (const AbstractEditMode::MouseEventData& data) override;
-
-private:
-	void buildCircle();
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/drawMode.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,286 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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/>.
+ */
+
+#include <QPainter>
+#include <QMouseEvent>
+#include "drawMode.h"
+#include "../ldObject.h"
+#include "../glRenderer.h"
+
+CFGENTRY (Bool, drawLineLengths, true)
+CFGENTRY (Bool, drawAngles, false)
+
+DrawMode::DrawMode (GLRenderer* renderer) :
+	Super (renderer),
+	_rectdraw (false) {}
+
+EditModeType DrawMode::type() const
+{
+	return EditModeType::Draw;
+}
+
+void DrawMode::render (QPainter& painter) const
+{
+	QPoint poly[4];
+	Vertex poly3d[4];
+	int numverts = 4;
+	QFontMetrics metrics = QFontMetrics (QFont());
+
+	// Calculate polygon data
+	if (not _rectdraw)
+	{
+		numverts = _drawedVerts.size() + 1;
+		int i = 0;
+
+		for (Vertex const& vert : _drawedVerts)
+			poly3d[i++] = vert;
+
+		// Draw the cursor vertex as the last one in the list.
+		if (numverts <= 4)
+			poly3d[i] = renderer()->position3D();
+		else
+			numverts = 4;
+	}
+	else
+	{
+		// Get vertex information from m_rectverts
+		if (_drawedVerts.size() > 0)
+			for (int i = 0; i < numverts; ++i)
+				poly3d[i] = _rectverts[i];
+		else
+			poly3d[0] = renderer()->position3D();
+	}
+
+	// Convert to 2D
+	for (int i = 0; i < numverts; ++i)
+		poly[i] = renderer()->coordconv3_2 (poly3d[i]);
+
+	if (numverts > 0)
+	{
+		// Draw the polygon-to-be
+		painter.setBrush (_polybrush);
+		painter.drawPolygon (poly, numverts);
+
+		// Draw vertex blips
+		for (int i = 0; i < numverts; ++i)
+		{
+			QPoint& blip = poly[i];
+			painter.setPen (renderer()->linePen());
+			renderer()->drawBlip (painter, blip);
+
+			// Draw their coordinates
+			painter.setPen (renderer()->textPen());
+			painter.drawText (blip.x(), blip.y() - 8, poly3d[i].toString (true));
+		}
+
+		// Draw line lenghts and angle info if appropriate
+		if (numverts >= 2)
+		{
+			int numlines = (_drawedVerts.size() == 1) ? 1 : _drawedVerts.size() + 1;
+			painter.setPen (renderer()->textPen());
+
+			for (int i = 0; i < numlines; ++i)
+			{
+				const int j = (i + 1 < numverts) ? i + 1 : 0;
+				const int h = (i - 1 >= 0) ? i - 1 : numverts - 1;
+
+				if (cfg::drawLineLengths)
+				{
+					const QString label = QString::number ((poly3d[j] - poly3d[i]).length());
+					QPoint origin = QLineF (poly[i], poly[j]).pointAt (0.5).toPoint();
+					painter.drawText (origin, label);
+				}
+
+				if (cfg::drawAngles)
+				{
+					QLineF l0 (poly[h], poly[i]),
+						l1 (poly[i], poly[j]);
+
+					double angle = 180 - l0.angleTo (l1);
+
+					if (angle < 0)
+						angle = 180 - l1.angleTo (l0);
+
+					QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260"));
+					QPoint pos = poly[i];
+					pos.setY (pos.y() + metrics.height());
+
+					painter.drawText (pos, label);
+				}
+			}
+		}
+	}
+}
+
+bool DrawMode::preAddVertex (Vertex const& pos)
+{
+	// If we picked an already-existing vertex, stop drawing
+	for (Vertex& vert : _drawedVerts)
+	{
+		if (vert == pos)
+		{
+			endDraw();
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool DrawMode::mouseReleased (MouseEventData const& data)
+{
+	if (Super::mouseReleased (data))
+		return true;
+
+	if (data.releasedButtons & Qt::LeftButton)
+	{
+		if (_rectdraw)
+		{
+			if (_drawedVerts.size() == 2)
+			{
+				endDraw();
+				return true;
+			}
+		}
+		else
+		{
+			// If we have 4 verts, stop drawing.
+			if (_drawedVerts.size() >= 4)
+			{
+				endDraw();
+				return true;
+			}
+
+			if (_drawedVerts.isEmpty())
+			{
+				_rectdraw = (data.ev->modifiers() & Qt::ShiftModifier);
+				updateRectVerts();
+			}
+		}
+
+		addDrawnVertex (renderer()->position3D());
+		return true;
+	}
+
+	return false;
+}
+
+//
+// Update rect vertices when the mouse moves since the 3d position likely has changed
+//
+bool DrawMode::mouseMoved (QMouseEvent*)
+{
+	updateRectVerts();
+	return false;
+}
+
+void DrawMode::updateRectVerts()
+{
+	if (not _rectdraw)
+		return;
+
+	if (_drawedVerts.isEmpty())
+	{
+		for (int i = 0; i < 4; ++i)
+			_rectverts[i] = renderer()->position3D();
+
+		return;
+	}
+
+	Vertex v0 = _drawedVerts[0],
+		   v1 = (_drawedVerts.size() >= 2) ? _drawedVerts[1] : renderer()->position3D();
+
+	const Axis localx = renderer()->getCameraAxis (false),
+			   localy = renderer()->getCameraAxis (true),
+			   localz = (Axis) (3 - localx - localy);
+
+	for (int i = 0; i < 4; ++i)
+		_rectverts[i].setCoordinate (localz, renderer()->getDepthValue());
+
+	_rectverts[0].setCoordinate (localx, v0[localx]);
+	_rectverts[0].setCoordinate (localy, v0[localy]);
+	_rectverts[1].setCoordinate (localx, v1[localx]);
+	_rectverts[1].setCoordinate (localy, v0[localy]);
+	_rectverts[2].setCoordinate (localx, v1[localx]);
+	_rectverts[2].setCoordinate (localy, v1[localy]);
+	_rectverts[3].setCoordinate (localx, v0[localx]);
+	_rectverts[3].setCoordinate (localy, v1[localy]);
+}
+
+void DrawMode::endDraw()
+{
+	// Clean the selection and create the object
+	QList<Vertex>& verts = _drawedVerts;
+	LDObjectList objs;
+
+	if (_rectdraw)
+	{
+		LDQuadPtr quad (spawn<LDQuad>());
+
+		updateRectVerts();
+
+		for (int i = 0; i < quad->numVertices(); ++i)
+			quad->setVertex (i, _rectverts[i]);
+
+		quad->setColor (maincolor());
+		objs << quad;
+	}
+	else
+	{
+		switch (verts.size())
+		{
+			case 1:
+			{
+				// 1 vertex - add a vertex object
+				LDVertexPtr obj = spawn<LDVertex>();
+				obj->pos = verts[0];
+				obj->setColor (maincolor());
+				objs << obj;
+				break;
+			}
+
+			case 2:
+			{
+				// 2 verts - make a line
+				LDLinePtr obj = spawn<LDLine> (verts[0], verts[1]);
+				obj->setColor (edgecolor());
+				objs << obj;
+				break;
+			}
+
+			case 3:
+			case 4:
+			{
+				LDObjectPtr obj = (verts.size() == 3) ?
+					static_cast<LDObjectPtr> (spawn<LDTriangle>()) :
+					static_cast<LDObjectPtr> (spawn<LDQuad>());
+
+				obj->setColor (maincolor());
+
+				for (int i = 0; i < verts.size(); ++i)
+					obj->setVertex (i, verts[i]);
+
+				objs << obj;
+				break;
+			}
+		}
+	}
+
+	finishDraw (objs);
+	_rectdraw = false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/drawMode.h	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,39 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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 "abstractEditMode.h"
+
+class DrawMode : public AbstractDrawMode
+{
+	DEFINE_CLASS (DrawMode, AbstractDrawMode)
+	bool _rectdraw;
+
+public:
+	DrawMode (GLRenderer* renderer);
+
+	virtual void render (QPainter& painter) const override;
+	virtual EditModeType type() const override;
+	virtual bool preAddVertex (Vertex const& pos) override;
+	virtual bool mouseReleased (MouseEventData const& data) override;
+	virtual bool mouseMoved (QMouseEvent*) override;
+
+private:
+	void endDraw();
+	void updateRectVerts();
+};
--- a/src/editmodes/drawmode.cc	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,286 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include <QPainter>
-#include <QMouseEvent>
-#include "drawmode.h"
-#include "../ldObject.h"
-#include "../glRenderer.h"
-
-CFGENTRY (Bool, drawLineLengths, true)
-CFGENTRY (Bool, drawAngles, false)
-
-DrawMode::DrawMode (GLRenderer* renderer) :
-	Super (renderer),
-	_rectdraw (false) {}
-
-EditModeType DrawMode::type() const
-{
-	return EditModeType::Draw;
-}
-
-void DrawMode::render (QPainter& painter) const
-{
-	QPoint poly[4];
-	Vertex poly3d[4];
-	int numverts = 4;
-	QFontMetrics metrics = QFontMetrics (QFont());
-
-	// Calculate polygon data
-	if (not _rectdraw)
-	{
-		numverts = _drawedVerts.size() + 1;
-		int i = 0;
-
-		for (Vertex const& vert : _drawedVerts)
-			poly3d[i++] = vert;
-
-		// Draw the cursor vertex as the last one in the list.
-		if (numverts <= 4)
-			poly3d[i] = renderer()->position3D();
-		else
-			numverts = 4;
-	}
-	else
-	{
-		// Get vertex information from m_rectverts
-		if (_drawedVerts.size() > 0)
-			for (int i = 0; i < numverts; ++i)
-				poly3d[i] = _rectverts[i];
-		else
-			poly3d[0] = renderer()->position3D();
-	}
-
-	// Convert to 2D
-	for (int i = 0; i < numverts; ++i)
-		poly[i] = renderer()->coordconv3_2 (poly3d[i]);
-
-	if (numverts > 0)
-	{
-		// Draw the polygon-to-be
-		painter.setBrush (_polybrush);
-		painter.drawPolygon (poly, numverts);
-
-		// Draw vertex blips
-		for (int i = 0; i < numverts; ++i)
-		{
-			QPoint& blip = poly[i];
-			painter.setPen (renderer()->linePen());
-			renderer()->drawBlip (painter, blip);
-
-			// Draw their coordinates
-			painter.setPen (renderer()->textPen());
-			painter.drawText (blip.x(), blip.y() - 8, poly3d[i].toString (true));
-		}
-
-		// Draw line lenghts and angle info if appropriate
-		if (numverts >= 2)
-		{
-			int numlines = (_drawedVerts.size() == 1) ? 1 : _drawedVerts.size() + 1;
-			painter.setPen (renderer()->textPen());
-
-			for (int i = 0; i < numlines; ++i)
-			{
-				const int j = (i + 1 < numverts) ? i + 1 : 0;
-				const int h = (i - 1 >= 0) ? i - 1 : numverts - 1;
-
-				if (cfg::drawLineLengths)
-				{
-					const QString label = QString::number ((poly3d[j] - poly3d[i]).length());
-					QPoint origin = QLineF (poly[i], poly[j]).pointAt (0.5).toPoint();
-					painter.drawText (origin, label);
-				}
-
-				if (cfg::drawAngles)
-				{
-					QLineF l0 (poly[h], poly[i]),
-						l1 (poly[i], poly[j]);
-
-					double angle = 180 - l0.angleTo (l1);
-
-					if (angle < 0)
-						angle = 180 - l1.angleTo (l0);
-
-					QString label = QString::number (angle) + QString::fromUtf8 (QByteArray ("\302\260"));
-					QPoint pos = poly[i];
-					pos.setY (pos.y() + metrics.height());
-
-					painter.drawText (pos, label);
-				}
-			}
-		}
-	}
-}
-
-bool DrawMode::preAddVertex (Vertex const& pos)
-{
-	// If we picked an already-existing vertex, stop drawing
-	for (Vertex& vert : _drawedVerts)
-	{
-		if (vert == pos)
-		{
-			endDraw();
-			return true;
-		}
-	}
-
-	return false;
-}
-
-bool DrawMode::mouseReleased (MouseEventData const& data)
-{
-	if (Super::mouseReleased (data))
-		return true;
-
-	if (data.releasedButtons & Qt::LeftButton)
-	{
-		if (_rectdraw)
-		{
-			if (_drawedVerts.size() == 2)
-			{
-				endDraw();
-				return true;
-			}
-		}
-		else
-		{
-			// If we have 4 verts, stop drawing.
-			if (_drawedVerts.size() >= 4)
-			{
-				endDraw();
-				return true;
-			}
-
-			if (_drawedVerts.isEmpty())
-			{
-				_rectdraw = (data.ev->modifiers() & Qt::ShiftModifier);
-				updateRectVerts();
-			}
-		}
-
-		addDrawnVertex (renderer()->position3D());
-		return true;
-	}
-
-	return false;
-}
-
-//
-// Update rect vertices when the mouse moves since the 3d position likely has changed
-//
-bool DrawMode::mouseMoved (QMouseEvent*)
-{
-	updateRectVerts();
-	return false;
-}
-
-void DrawMode::updateRectVerts()
-{
-	if (not _rectdraw)
-		return;
-
-	if (_drawedVerts.isEmpty())
-	{
-		for (int i = 0; i < 4; ++i)
-			_rectverts[i] = renderer()->position3D();
-
-		return;
-	}
-
-	Vertex v0 = _drawedVerts[0],
-		   v1 = (_drawedVerts.size() >= 2) ? _drawedVerts[1] : renderer()->position3D();
-
-	const Axis localx = renderer()->getCameraAxis (false),
-			   localy = renderer()->getCameraAxis (true),
-			   localz = (Axis) (3 - localx - localy);
-
-	for (int i = 0; i < 4; ++i)
-		_rectverts[i].setCoordinate (localz, renderer()->getDepthValue());
-
-	_rectverts[0].setCoordinate (localx, v0[localx]);
-	_rectverts[0].setCoordinate (localy, v0[localy]);
-	_rectverts[1].setCoordinate (localx, v1[localx]);
-	_rectverts[1].setCoordinate (localy, v0[localy]);
-	_rectverts[2].setCoordinate (localx, v1[localx]);
-	_rectverts[2].setCoordinate (localy, v1[localy]);
-	_rectverts[3].setCoordinate (localx, v0[localx]);
-	_rectverts[3].setCoordinate (localy, v1[localy]);
-}
-
-void DrawMode::endDraw()
-{
-	// Clean the selection and create the object
-	QList<Vertex>& verts = _drawedVerts;
-	LDObjectList objs;
-
-	if (_rectdraw)
-	{
-		LDQuadPtr quad (spawn<LDQuad>());
-
-		updateRectVerts();
-
-		for (int i = 0; i < quad->numVertices(); ++i)
-			quad->setVertex (i, _rectverts[i]);
-
-		quad->setColor (maincolor());
-		objs << quad;
-	}
-	else
-	{
-		switch (verts.size())
-		{
-			case 1:
-			{
-				// 1 vertex - add a vertex object
-				LDVertexPtr obj = spawn<LDVertex>();
-				obj->pos = verts[0];
-				obj->setColor (maincolor());
-				objs << obj;
-				break;
-			}
-
-			case 2:
-			{
-				// 2 verts - make a line
-				LDLinePtr obj = spawn<LDLine> (verts[0], verts[1]);
-				obj->setColor (edgecolor());
-				objs << obj;
-				break;
-			}
-
-			case 3:
-			case 4:
-			{
-				LDObjectPtr obj = (verts.size() == 3) ?
-					static_cast<LDObjectPtr> (spawn<LDTriangle>()) :
-					static_cast<LDObjectPtr> (spawn<LDQuad>());
-
-				obj->setColor (maincolor());
-
-				for (int i = 0; i < verts.size(); ++i)
-					obj->setVertex (i, verts[i]);
-
-				objs << obj;
-				break;
-			}
-		}
-	}
-
-	finishDraw (objs);
-	_rectdraw = false;
-}
--- a/src/editmodes/drawmode.h	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include "abstracteditmode.h"
-
-class DrawMode : public AbstractDrawMode
-{
-	DEFINE_CLASS (DrawMode, AbstractDrawMode)
-	bool _rectdraw;
-
-public:
-	DrawMode (GLRenderer* renderer);
-
-	virtual void render (QPainter& painter) const override;
-	virtual EditModeType type() const override;
-	virtual bool preAddVertex (Vertex const& pos) override;
-	virtual bool mouseReleased (MouseEventData const& data) override;
-	virtual bool mouseMoved (QMouseEvent*) override;
-
-private:
-	void endDraw();
-	void updateRectVerts();
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/magicWandMode.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,215 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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/>.
+ */
+
+#include <QMouseEvent>
+#include "magicWandMode.h"
+#include "../ldDocument.h"
+#include "../mainWindow.h"
+#include "../glRenderer.h"
+
+MagicWandMode::MagicWandMode (GLRenderer* renderer) :
+	Super (renderer)
+{
+	// Get vertex<->object data
+	for (LDObjectPtr obj : getCurrentDocument()->objects())
+	{
+		// Note: this deliberately only takes vertex-objects into account.
+		// The magic wand does not process subparts.
+		for (int i = 0; i < obj->numVertices(); ++i)
+			_vertices[obj->vertex (i)] << obj;
+	}
+}
+
+EditModeType MagicWandMode::type() const
+{
+	return EditModeType::MagicWand;
+}
+
+void MagicWandMode::fillBoundaries (LDObjectPtr obj, QVector<BoundaryType>& boundaries, QVector<LDObjectPtr>& candidates)
+{
+	// All boundaries obviously share vertices with the object, therefore they're all in the list
+	// of candidates.
+	for (auto it = candidates.begin(); it != candidates.end(); ++it)
+	{
+		if ((*it)->type() != OBJ_Line || (*it)->vertex (0) == (*it)->vertex (1))
+			continue;
+
+		int matches = 0;
+
+		for (int i = 0; i < obj->numVertices(); ++i)
+		{
+			if (not eq (obj->vertex (i), (*it)->vertex (0), (*it)->vertex (1)))
+				continue;
+
+			if (++matches == 2)
+			{
+				// Boundary found. Add to boundaries list and get it off the candidates list.
+				boundaries.append (std::make_tuple ((*it)->vertex (0), (*it)->vertex (1)));
+				break;
+			}
+		}
+	}
+}
+
+void MagicWandMode::doMagic (LDObjectPtr obj, MagicWandMode::MagicType type)
+{
+	if (obj == null)
+	{
+		if (type == Set)
+		{
+			getCurrentDocument()->clearSelection();
+			g_win->buildObjList();
+		}
+
+		return;
+	}
+
+	int matchesneeded = 0;
+	QVector<BoundaryType> boundaries;
+	LDObjectType objtype = obj->type();
+
+	if (type != InternalRecursion)
+	{
+		_selection.clear();
+		_selection.append (obj);
+	}
+
+	switch (obj->type())
+	{
+		case OBJ_Line:
+		case OBJ_CondLine:
+			matchesneeded = 1;
+			break;
+
+		case OBJ_Triangle:
+		case OBJ_Quad:
+			matchesneeded = 2;
+			break;
+
+		default:
+			return;
+	}
+
+	QVector<LDObjectPtr> candidates;
+
+	// Get the list of objects that touch this object, i.e. share a vertex
+	// with this.
+	for (int i = 0; i < obj->numVertices(); ++i)
+		candidates += _vertices[obj->vertex (i)];
+
+	removeDuplicates (candidates);
+
+	// If we're dealing with surfaces, get a list of boundaries.
+	if (matchesneeded > 1)
+		fillBoundaries (obj, boundaries, candidates);
+
+	for (LDObjectPtr candidate : candidates)
+	{
+		try
+		{
+			// If we're doing this on lines, we need exact type match. Surface types (quads and
+			// triangles) can be mixed. Also don't consider self a candidate, and don't consider
+			// objects we have already processed.
+			if ((candidate == obj) ||
+				(candidate->color() != obj->color()) ||
+				(_selection.contains (candidate)) ||
+				(matchesneeded == 1 && (candidate->type() != objtype)) ||
+				((candidate->numVertices() > 2) ^ (matchesneeded == 2)))
+			{
+				throw 0;
+			}
+
+			// Now ensure the two objects share enough vertices.
+			QVector<Vertex> matches;
+
+			for (int i = 0; i < obj->numVertices(); ++i)
+			{
+				for (int j = 0; j < candidate->numVertices(); ++j)
+				{
+					if (obj->vertex(i) == candidate->vertex(j))
+					{
+						matches << obj->vertex(i);
+						break;
+					}
+				}
+			}
+
+			if (matches.size() < matchesneeded)
+				throw 0; // Not enough matches.
+
+			// Check if a boundary gets in between the objects.
+			for (auto boundary : boundaries)
+			{
+				if (eq (matches[0], std::get<0> (boundary), std::get<1> (boundary)) &&
+					eq (matches[1], std::get<0> (boundary), std::get<1> (boundary)))
+				{
+					throw 0;
+				}
+			}
+
+			_selection.append (candidate);
+			doMagic (candidate, InternalRecursion);
+		}
+		catch (int&)
+		{
+			continue;
+		}
+	}
+
+	switch (type)
+	{
+		case Set:
+			getCurrentDocument()->clearSelection();
+		case Additive:
+			for (LDObjectPtr obj : _selection)
+				obj->select();
+			break;
+
+		case Subtractive:
+			for (LDObjectPtr obj : _selection)
+				obj->deselect();
+			break;
+
+		case InternalRecursion:
+			break;
+	}
+
+	if (type != InternalRecursion)
+		g_win->buildObjList();
+}
+
+bool MagicWandMode::mouseReleased (MouseEventData const& data)
+{
+	if (Super::mouseReleased (data))
+		return true;
+
+	if (data.releasedButtons & Qt::LeftButton && not data.mouseMoved)
+	{
+		MagicType wandtype = MagicWandMode::Set;
+
+		if (data.keymods & Qt::ShiftModifier)
+			wandtype = MagicWandMode::Additive;
+		elif (data.keymods & Qt::ControlModifier)
+			wandtype = MagicWandMode::Subtractive;
+
+		doMagic (renderer()->pickOneObject (data.ev->x(), data.ev->y()), wandtype);
+		return true;
+	}
+
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/magicWandMode.h	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,49 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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 "abstractEditMode.h"
+#include "../basics.h"
+#include <QMap>
+#include <QVector>
+
+class MagicWandMode : public AbstractSelectMode
+{
+	QMap<Vertex, QVector<LDObjectPtr>> _vertices;
+	QVector<LDObjectPtr> _selection;
+
+	DEFINE_CLASS (MagicWandMode, AbstractSelectMode)
+
+public:
+	using BoundaryType = std::tuple<Vertex, Vertex>;
+	enum MagicType
+	{
+		Set,
+		Additive,
+		Subtractive,
+		InternalRecursion
+	};
+
+	MagicWandMode (GLRenderer* renderer);
+	void doMagic (LDObjectPtr obj, MagicType type);
+	virtual EditModeType type() const override;
+	virtual bool mouseReleased (MouseEventData const& data) override;
+
+private:
+	void fillBoundaries (LDObjectPtr obj, QVector<BoundaryType>& boundaries, QVector<LDObjectPtr>& candidates);
+};
--- a/src/editmodes/magicwandmode.cc	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,215 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include <QMouseEvent>
-#include "magicwandmode.h"
-#include "../ldDocument.h"
-#include "../mainWindow.h"
-#include "../glRenderer.h"
-
-MagicWandMode::MagicWandMode (GLRenderer* renderer) :
-	Super (renderer)
-{
-	// Get vertex<->object data
-	for (LDObjectPtr obj : getCurrentDocument()->objects())
-	{
-		// Note: this deliberately only takes vertex-objects into account.
-		// The magic wand does not process subparts.
-		for (int i = 0; i < obj->numVertices(); ++i)
-			_vertices[obj->vertex (i)] << obj;
-	}
-}
-
-EditModeType MagicWandMode::type() const
-{
-	return EditModeType::MagicWand;
-}
-
-void MagicWandMode::fillBoundaries (LDObjectPtr obj, QVector<BoundaryType>& boundaries, QVector<LDObjectPtr>& candidates)
-{
-	// All boundaries obviously share vertices with the object, therefore they're all in the list
-	// of candidates.
-	for (auto it = candidates.begin(); it != candidates.end(); ++it)
-	{
-		if ((*it)->type() != OBJ_Line || (*it)->vertex (0) == (*it)->vertex (1))
-			continue;
-
-		int matches = 0;
-
-		for (int i = 0; i < obj->numVertices(); ++i)
-		{
-			if (not eq (obj->vertex (i), (*it)->vertex (0), (*it)->vertex (1)))
-				continue;
-
-			if (++matches == 2)
-			{
-				// Boundary found. Add to boundaries list and get it off the candidates list.
-				boundaries.append (std::make_tuple ((*it)->vertex (0), (*it)->vertex (1)));
-				break;
-			}
-		}
-	}
-}
-
-void MagicWandMode::doMagic (LDObjectPtr obj, MagicWandMode::MagicType type)
-{
-	if (obj == null)
-	{
-		if (type == Set)
-		{
-			getCurrentDocument()->clearSelection();
-			g_win->buildObjList();
-		}
-
-		return;
-	}
-
-	int matchesneeded = 0;
-	QVector<BoundaryType> boundaries;
-	LDObjectType objtype = obj->type();
-
-	if (type != InternalRecursion)
-	{
-		_selection.clear();
-		_selection.append (obj);
-	}
-
-	switch (obj->type())
-	{
-		case OBJ_Line:
-		case OBJ_CondLine:
-			matchesneeded = 1;
-			break;
-
-		case OBJ_Triangle:
-		case OBJ_Quad:
-			matchesneeded = 2;
-			break;
-
-		default:
-			return;
-	}
-
-	QVector<LDObjectPtr> candidates;
-
-	// Get the list of objects that touch this object, i.e. share a vertex
-	// with this.
-	for (int i = 0; i < obj->numVertices(); ++i)
-		candidates += _vertices[obj->vertex (i)];
-
-	removeDuplicates (candidates);
-
-	// If we're dealing with surfaces, get a list of boundaries.
-	if (matchesneeded > 1)
-		fillBoundaries (obj, boundaries, candidates);
-
-	for (LDObjectPtr candidate : candidates)
-	{
-		try
-		{
-			// If we're doing this on lines, we need exact type match. Surface types (quads and
-			// triangles) can be mixed. Also don't consider self a candidate, and don't consider
-			// objects we have already processed.
-			if ((candidate == obj) ||
-				(candidate->color() != obj->color()) ||
-				(_selection.contains (candidate)) ||
-				(matchesneeded == 1 && (candidate->type() != objtype)) ||
-				((candidate->numVertices() > 2) ^ (matchesneeded == 2)))
-			{
-				throw 0;
-			}
-
-			// Now ensure the two objects share enough vertices.
-			QVector<Vertex> matches;
-
-			for (int i = 0; i < obj->numVertices(); ++i)
-			{
-				for (int j = 0; j < candidate->numVertices(); ++j)
-				{
-					if (obj->vertex(i) == candidate->vertex(j))
-					{
-						matches << obj->vertex(i);
-						break;
-					}
-				}
-			}
-
-			if (matches.size() < matchesneeded)
-				throw 0; // Not enough matches.
-
-			// Check if a boundary gets in between the objects.
-			for (auto boundary : boundaries)
-			{
-				if (eq (matches[0], std::get<0> (boundary), std::get<1> (boundary)) &&
-					eq (matches[1], std::get<0> (boundary), std::get<1> (boundary)))
-				{
-					throw 0;
-				}
-			}
-
-			_selection.append (candidate);
-			doMagic (candidate, InternalRecursion);
-		}
-		catch (int&)
-		{
-			continue;
-		}
-	}
-
-	switch (type)
-	{
-		case Set:
-			getCurrentDocument()->clearSelection();
-		case Additive:
-			for (LDObjectPtr obj : _selection)
-				obj->select();
-			break;
-
-		case Subtractive:
-			for (LDObjectPtr obj : _selection)
-				obj->deselect();
-			break;
-
-		case InternalRecursion:
-			break;
-	}
-
-	if (type != InternalRecursion)
-		g_win->buildObjList();
-}
-
-bool MagicWandMode::mouseReleased (MouseEventData const& data)
-{
-	if (Super::mouseReleased (data))
-		return true;
-
-	if (data.releasedButtons & Qt::LeftButton && not data.mouseMoved)
-	{
-		MagicType wandtype = MagicWandMode::Set;
-
-		if (data.keymods & Qt::ShiftModifier)
-			wandtype = MagicWandMode::Additive;
-		elif (data.keymods & Qt::ControlModifier)
-			wandtype = MagicWandMode::Subtractive;
-
-		doMagic (renderer()->pickOneObject (data.ev->x(), data.ev->y()), wandtype);
-		return true;
-	}
-
-	return false;
-}
--- a/src/editmodes/magicwandmode.h	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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 "abstracteditmode.h"
-#include "../basics.h"
-#include <QMap>
-#include <QVector>
-
-class MagicWandMode : public AbstractSelectMode
-{
-	QMap<Vertex, QVector<LDObjectPtr>> _vertices;
-	QVector<LDObjectPtr> _selection;
-
-	DEFINE_CLASS (MagicWandMode, AbstractSelectMode)
-
-public:
-	using BoundaryType = std::tuple<Vertex, Vertex>;
-	enum MagicType
-	{
-		Set,
-		Additive,
-		Subtractive,
-		InternalRecursion
-	};
-
-	MagicWandMode (GLRenderer* renderer);
-	void doMagic (LDObjectPtr obj, MagicType type);
-	virtual EditModeType type() const override;
-	virtual bool mouseReleased (MouseEventData const& data) override;
-
-private:
-	void fillBoundaries (LDObjectPtr obj, QVector<BoundaryType>& boundaries, QVector<LDObjectPtr>& candidates);
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/selectMode.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,137 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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/>.
+ */
+
+#include <QMouseEvent>
+#include "selectMode.h"
+#include "../glRenderer.h"
+#include "../addObjectDialog.h"
+#include "../mainWindow.h"
+#include "../glRenderer.h"
+
+SelectMode::SelectMode (GLRenderer* renderer) :
+	Super (renderer),
+	_rangepick (false) {}
+
+EditModeType SelectMode::type() const
+{
+	return EditModeType::Select;
+}
+
+void SelectMode::render (QPainter& painter) const
+{
+	// If we're range-picking, draw a rectangle encompassing the selection area.
+	if (_rangepick)
+	{
+		int x0 = _rangeStart.x(),
+			y0 = _rangeStart.y(),
+			x1 = renderer()->mousePosition().x(),
+			y1 = renderer()->mousePosition().y();
+
+		QRect rect (x0, y0, x1 - x0, y1 - y0);
+		QColor fillColor = (_addpick ? "#40FF00" : "#00CCFF");
+		fillColor.setAlphaF (0.2f);
+		painter.setPen (QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+		painter.setBrush (QBrush (fillColor));
+		painter.drawRect (rect);
+	}
+}
+
+bool SelectMode::mouseReleased (MouseEventData const& data)
+{
+	if (Super::mouseReleased (data))
+		return true;
+
+	if (data.releasedButtons & Qt::LeftButton)
+	{
+		if (not data.mouseMoved)
+			_rangepick = false;
+
+		if (not _rangepick)
+			_addpick = (data.keymods & Qt::ControlModifier);
+
+		if (not data.mouseMoved || _rangepick)
+		{
+			QRect area;
+			int const mx = data.ev->x();
+			int const my = data.ev->y();
+
+			if (not _rangepick)
+			{
+				area = QRect (mx, my, 1, 1);
+			}
+			else
+			{
+				int const x = min (_rangeStart.x(), mx);
+				int const y = min (_rangeStart.y(), my);
+				int const width = abs (_rangeStart.x() - mx);
+				int const height = abs (_rangeStart.y() - my);
+				area = QRect (x, y, width, height);
+			}
+
+			renderer()->pick (area, _addpick);
+		}
+
+		_rangepick = false;
+		return true;
+	}
+
+	return false;
+}
+
+bool SelectMode::mousePressed (QMouseEvent* ev)
+{
+	if (Super::mousePressed (ev))
+		return true;
+
+	if (ev->modifiers() & Qt::ControlModifier)
+	{
+		_rangepick = true;
+		_rangeStart.setX (ev->x());
+		_rangeStart.setY (ev->y());
+		_addpick = (ev->modifiers() & Qt::AltModifier);
+		return true;
+	}
+
+	return false;
+}
+
+bool SelectMode::mouseDoubleClicked (QMouseEvent* ev)
+{
+	if (Super::mouseDoubleClicked (ev))
+		return true;
+
+	if (ev->buttons() & Qt::LeftButton)
+	{
+		renderer()->document()->clearSelection();
+		LDObjectPtr obj = renderer()->pickOneObject (ev->x(), ev->y());
+
+		if (obj != null)
+		{
+			AddObjectDialog::staticDialog (obj->type(), obj);
+			g_win->endAction();
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool SelectMode::mouseMoved (QMouseEvent*)
+{
+	return _rangepick;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/editmodes/selectMode.h	Sat Jul 05 02:02:31 2014 +0300
@@ -0,0 +1,39 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013, 2014 Santeri 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 "abstractEditMode.h"
+
+class SelectMode : public AbstractSelectMode
+{
+	QPoint _rangeStart;
+	bool _rangepick;
+	bool _addpick;
+
+	DEFINE_CLASS (SelectMode, AbstractSelectMode)
+
+public:
+	SelectMode (GLRenderer* renderer);
+
+	virtual void render (QPainter& painter) const override;
+	virtual bool mousePressed (QMouseEvent* ev);
+	virtual bool mouseReleased (MouseEventData const& data) override;
+	virtual bool mouseDoubleClicked (QMouseEvent* ev);
+	virtual bool mouseMoved (QMouseEvent*) override;
+	virtual EditModeType type() const override;
+};
\ No newline at end of file
--- a/src/editmodes/selectmode.cc	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include <QMouseEvent>
-#include "selectmode.h"
-#include "../glRenderer.h"
-#include "../addObjectDialog.h"
-#include "../mainWindow.h"
-#include "../glRenderer.h"
-
-SelectMode::SelectMode (GLRenderer* renderer) :
-	Super (renderer),
-	_rangepick (false) {}
-
-EditModeType SelectMode::type() const
-{
-	return EditModeType::Select;
-}
-
-void SelectMode::render (QPainter& painter) const
-{
-	// If we're range-picking, draw a rectangle encompassing the selection area.
-	if (_rangepick)
-	{
-		int x0 = _rangeStart.x(),
-			y0 = _rangeStart.y(),
-			x1 = renderer()->mousePosition().x(),
-			y1 = renderer()->mousePosition().y();
-
-		QRect rect (x0, y0, x1 - x0, y1 - y0);
-		QColor fillColor = (_addpick ? "#40FF00" : "#00CCFF");
-		fillColor.setAlphaF (0.2f);
-		painter.setPen (QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
-		painter.setBrush (QBrush (fillColor));
-		painter.drawRect (rect);
-	}
-}
-
-bool SelectMode::mouseReleased (MouseEventData const& data)
-{
-	if (Super::mouseReleased (data))
-		return true;
-
-	if (data.releasedButtons & Qt::LeftButton)
-	{
-		if (not data.mouseMoved)
-			_rangepick = false;
-
-		if (not _rangepick)
-			_addpick = (data.keymods & Qt::ControlModifier);
-
-		if (not data.mouseMoved || _rangepick)
-		{
-			QRect area;
-			int const mx = data.ev->x();
-			int const my = data.ev->y();
-
-			if (not _rangepick)
-			{
-				area = QRect (mx, my, 1, 1);
-			}
-			else
-			{
-				int const x = min (_rangeStart.x(), mx);
-				int const y = min (_rangeStart.y(), my);
-				int const width = abs (_rangeStart.x() - mx);
-				int const height = abs (_rangeStart.y() - my);
-				area = QRect (x, y, width, height);
-			}
-
-			renderer()->pick (area, _addpick);
-		}
-
-		_rangepick = false;
-		return true;
-	}
-
-	return false;
-}
-
-bool SelectMode::mousePressed (QMouseEvent* ev)
-{
-	if (Super::mousePressed (ev))
-		return true;
-
-	if (ev->modifiers() & Qt::ControlModifier)
-	{
-		_rangepick = true;
-		_rangeStart.setX (ev->x());
-		_rangeStart.setY (ev->y());
-		_addpick = (ev->modifiers() & Qt::AltModifier);
-		return true;
-	}
-
-	return false;
-}
-
-bool SelectMode::mouseDoubleClicked (QMouseEvent* ev)
-{
-	if (Super::mouseDoubleClicked (ev))
-		return true;
-
-	if (ev->buttons() & Qt::LeftButton)
-	{
-		renderer()->document()->clearSelection();
-		LDObjectPtr obj = renderer()->pickOneObject (ev->x(), ev->y());
-
-		if (obj != null)
-		{
-			AddObjectDialog::staticDialog (obj->type(), obj);
-			g_win->endAction();
-			return true;
-		}
-	}
-
-	return false;
-}
-
-bool SelectMode::mouseMoved (QMouseEvent* ev)
-{
-	return _rangepick;
-}
--- a/src/editmodes/selectmode.h	Sat Jul 05 01:45:32 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013, 2014 Santeri 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/>.
- */
-
-#include "abstracteditmode.h"
-
-class SelectMode : public AbstractSelectMode
-{
-	QPoint _rangeStart;
-	bool _rangepick;
-	bool _addpick;
-
-	DEFINE_CLASS (SelectMode, AbstractSelectMode)
-
-public:
-	SelectMode (GLRenderer* renderer);
-
-	virtual void render (QPainter& painter) const override;
-	virtual bool mousePressed (QMouseEvent* ev);
-	virtual bool mouseReleased (MouseEventData const& data) override;
-	virtual bool mouseDoubleClicked (QMouseEvent* ev);
-	virtual bool mouseMoved (QMouseEvent*) override;
-	virtual EditModeType type() const override;
-};
\ No newline at end of file
--- a/src/glRenderer.h	Sat Jul 05 01:45:32 2014 +0300
+++ b/src/glRenderer.h	Sat Jul 05 02:02:31 2014 +0300
@@ -23,7 +23,7 @@
 #include "ldObject.h"
 #include "ldDocument.h"
 #include "glShared.h"
-#include "editmodes/abstracteditmode.h"
+#include "editmodes/abstractEditMode.h"
 
 class GLCompiler;
 class MessageManager;
--- a/src/mainWindow.cc	Sat Jul 05 01:45:32 2014 +0300
+++ b/src/mainWindow.cc	Sat Jul 05 02:02:31 2014 +0300
@@ -50,7 +50,7 @@
 #include "configuration.h"
 #include "ui_ldforge.h"
 #include "primitives.h"
-#include "editmodes/abstracteditmode.h"
+#include "editmodes/abstractEditMode.h"
 
 static bool g_isSelectionLocked = false;
 static QMap<QAction*, QKeySequence> g_defaultShortcuts;

mercurial