commit work done on mdi

Tue, 01 Jan 2019 22:30:10 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 01 Jan 2019 22:30:10 +0200
changeset 1437
1a77c6156db7
parent 1436
241d3e452b32
child 1438
988b6563d47d

commit work done on mdi

src/basics.h file | annotate | diff | comparison | revisions
src/canvas.cpp file | annotate | diff | comparison | revisions
src/canvas.h file | annotate | diff | comparison | revisions
src/configurationoptions.txt file | annotate | diff | comparison | revisions
src/documentmanager.cpp file | annotate | diff | comparison | revisions
src/documentmanager.h file | annotate | diff | comparison | revisions
src/editmodes/circleMode.cpp file | annotate | diff | comparison | revisions
src/glShared.h file | annotate | diff | comparison | revisions
src/glcamera.cpp file | annotate | diff | comparison | revisions
src/glcamera.h file | annotate | diff | comparison | revisions
src/glrenderer.cpp file | annotate | diff | comparison | revisions
src/glrenderer.h file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/mainwindow.h file | annotate | diff | comparison | revisions
src/mainwindow.ui file | annotate | diff | comparison | revisions
src/toolsets/viewtoolset.cpp file | annotate | diff | comparison | revisions
src/toolsets/viewtoolset.h file | annotate | diff | comparison | revisions
--- a/src/basics.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/basics.h	Tue Jan 01 22:30:10 2019 +0200
@@ -107,6 +107,12 @@
 template<typename... Ts>
 inline void ignore(Ts&&...) {}
 
+template<typename T, typename R>
+QMapIterator<T, R> createIterator(const QMap<T, R>& map)
+{
+	return {map};
+}
+
 qreal determinant(qreal a, qreal b, qreal c, qreal d);
 qreal determinant(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f, qreal g, qreal h, qreal i);
 qreal determinant(const QMatrix2x2& matrix);
--- a/src/canvas.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/canvas.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -24,8 +24,8 @@
 #include "algorithms/geometry.h"
 #include "generics/ring.h"
 
-Canvas::Canvas(LDDocument* document, QWidget* parent) :
-	gl::Renderer {document, parent},
+Canvas::Canvas(LDDocument* document, gl::CameraType cameraType, QWidget* parent) :
+	gl::Renderer {document, cameraType, parent},
     m_document {*document},
     m_currentEditMode {AbstractEditMode::createByType (this, EditModeType::Select)} {}
 
@@ -39,7 +39,7 @@
 	gl::Renderer::overpaint(painter);
 	QFontMetrics metrics {QFont {}};
 
-	if (camera() != gl::FreeCamera)
+	if (not currentCamera().isModelview())
 	{
 		// Paint the coordinates onto the screen.
 		Vertex idealized = currentCamera().idealize(m_position3D);
@@ -186,10 +186,10 @@
 	glEnd();
 	glDisable(GL_LINE_STIPPLE);
 
-	if (this->camera() < gl::FreeCamera)
+	if (not currentCamera().isModelview())
 	{
-		GLfloat cullz = this->cullValues[static_cast<int>(this->camera())];
-		QMatrix4x4 matrix = {
+		GLfloat cullz = this->cullValue;
+		QMatrix4x4 const matrix = {
 			1, 0, 0, cullz,
 			0, 1, 0, 0,
 			0, 0, 1, 0,
@@ -211,11 +211,6 @@
 
 	delete m_currentEditMode;
 	m_currentEditMode = AbstractEditMode::createByType(this, a);
-
-	// If we cannot use the free camera, use the top one instead.
-	if (camera() == gl::FreeCamera and not m_currentEditMode->allowFreeCamera())
-		setCamera(gl::TopCamera);
-
 	m_window->updateEditModeActions();
 	update();
 }
@@ -374,20 +369,15 @@
 
 double Canvas::currentCullValue() const
 {
-	if (this->camera() < gl::FreeCamera)
-		return gl::far - this->cullValues[static_cast<int>(this->camera())];
-	else
-		return 0.0;
+	return gl::far - this->cullValue;
 }
 
 void Canvas::setCullValue(double value)
 {
-	if (this->camera() < gl::FreeCamera)
-		this->cullValues[static_cast<int>(this->camera())] = gl::far - value;
+	this->cullValue = gl::far - value;
 }
 
 void Canvas::clearCurrentCullValue()
 {
-	if (this->camera() < gl::FreeCamera)
-		this->cullValues[static_cast<int>(this->camera())] = 0.0;
+	this->cullValue = 0.0;
 }
--- a/src/canvas.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/canvas.h	Tue Jan 01 22:30:10 2019 +0200
@@ -23,8 +23,10 @@
 
 class Canvas : public gl::Renderer
 {
+	Q_OBJECT
+
 public:
-	Canvas(LDDocument* document, QWidget* parent = nullptr);
+	Canvas(LDDocument* document, gl::CameraType cameraType, QWidget* parent = nullptr);
 	~Canvas();
 
 	EditModeType currentEditModeType() const;
@@ -62,5 +64,5 @@
 	AbstractEditMode* m_currentEditMode = nullptr;
 	Vertex m_position3D;
 	Plane m_drawPlane;
-	double cullValues[6] = {0};
+	double cullValue;
 };
--- a/src/configurationoptions.txt	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/configurationoptions.txt	Tue Jan 01 22:30:10 2019 +0200
@@ -54,7 +54,6 @@
 option SelectColorBlend = "#0080FF"
 option LineThickness = 2
 option BfcRedGreenView = false
-option Camera = 6
 option BlackEdges = false
 option DrawAxes = false
 option DrawWireframe = false
--- a/src/documentmanager.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/documentmanager.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -100,9 +100,7 @@
 		return;
 	}
 
-	m_window->openDocumentForEditing(file);
-	m_window->changeDocument (file);
-	m_window->doFullRefresh();
+	emit mainModelLoaded(file);
 	addRecentFile (path);
 	m_loadingMainFile = false;
 
--- a/src/documentmanager.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/documentmanager.h	Tue Jan 01 22:30:10 2019 +0200
@@ -52,6 +52,7 @@
 signals:
 	void documentCreated(LDDocument* document, bool cache);
 	void documentClosed(LDDocument* document);
+	void mainModelLoaded(LDDocument* document);
 
 private:
 	Q_SLOT void printParseErrorMessage(QString message);
--- a/src/editmodes/circleMode.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/editmodes/circleMode.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -167,10 +167,6 @@
 			v3.setCoordinate (localx, v3[localx] + c1[i].x1());
 			v3.setCoordinate (localy, v3[localy] + c1[i].y1());
 
-			// Ensure the quads always are BFC-front towards the camera
-			if (static_cast<int>(renderer()->camera()) % 3 <= 0)
-				qSwap(v1, v3);
-
 			// Project the vertices onto the draw plane.
 			for (Vertex* vertex : {&v0, &v1, &v2, &v3})
 				*vertex = projectToDrawPlane(*vertex);
--- a/src/glShared.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/glShared.h	Tue Jan 01 22:30:10 2019 +0200
@@ -26,6 +26,52 @@
 
 class LDObject;
 
+namespace gl
+{
+	enum CameraType
+	{
+		TopCamera,
+		FrontCamera,
+		LeftCamera,
+		BottomCamera,
+		BackCamera,
+		RightCamera,
+		FreeCamera,
+		_End
+	};
+
+	struct CameraIcon
+	{
+		QPixmap image;
+		QRect sourceRect;
+		QRect targetRect;
+		QRect hitRect;
+		CameraType camera;
+	};
+
+	class Renderer;
+	class Compiler;
+
+	static const QPen thinBorderPen {QColor {0, 0, 0, 208}, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin};
+
+	// Transformation matrices for the fixed cameras.
+	static const QMatrix4x4 topCameraMatrix = {};
+	static const QMatrix4x4 frontCameraMatrix = {1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1};
+	static const QMatrix4x4 leftCameraMatrix = {0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1};
+	static const QMatrix4x4 bottomCameraMatrix = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1};
+	static const QMatrix4x4 backCameraMatrix = {-1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1};
+	static const QMatrix4x4 rightCameraMatrix = {0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1};
+
+	// Conversion matrix from LDraw to OpenGL coordinates.
+	static const QMatrix4x4 ldrawToGLAdapterMatrix = {1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1};
+
+	enum { BlackRgb = 0xff000000 };
+	static constexpr GLfloat near = 1.0f;
+	static constexpr GLfloat far = 10000.0f;
+}
+
+MAKE_ITERABLE_ENUM(gl::CameraType)
+
 struct LDPolygon
 {
 	enum class Type : qint8 { InvalidPolygon, EdgeLine, Triangle, Quadrilateral, ConditionalEdge };
--- a/src/glcamera.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/glcamera.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -167,6 +167,11 @@
 	return m_depth;
 }
 
+bool GLCamera::isModelview() const
+{
+	return m_isFree;
+}
+
 /*
  * Returns the X-panning of this camera.
  */
--- a/src/glcamera.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/glcamera.h	Tue Jan 01 22:30:10 2019 +0200
@@ -51,6 +51,7 @@
 	Vertex realize(const Vertex& idealCoordinates) const;
 	Vertex idealize(const Vertex& realCoordinates) const;
 	double depth() const;
+	bool isModelview() const;
 	bool isAxisNegated(Axis axis) const;
 	const QString& name() const;
 	void pan(int xMove, int yMove);
--- a/src/glrenderer.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/glrenderer.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -34,56 +34,41 @@
 #include "documentmanager.h"
 #include "grid.h"
 
+static GLCamera const cameraTemplates[7] = {
+	{"Top camera", {gl::topCameraMatrix, X, Z, false, false, false}},
+	{"Front camera", {gl::frontCameraMatrix, X, Y, false,  true, false}},
+	{"Left camera", {gl::leftCameraMatrix, Z, Y,  true,  true, false}},
+	{"Bottom camera", {gl::bottomCameraMatrix, X, Z, false,  true, true}},
+	{"Back camera", {gl::backCameraMatrix, X, Y,  true,  true, true}},
+	{"Right camera", {gl::rightCameraMatrix, Z, Y, false,  true, true}},
+	{"Free camera", GLCamera::FreeCamera},
+};
+
 /*
  * Constructs a GL renderer.
  */
-gl::Renderer::Renderer(const Model* model, QWidget* parent) :
+gl::Renderer::Renderer(const Model* model, CameraType cameraType, QWidget* parent) :
     QGLWidget {parent},
     HierarchyElement {parent},
     m_model {model},
-    m_cameras {
-        {"Top camera", {topCameraMatrix, X, Z, false, false, false}}, // top
-        {"Front camera", {frontCameraMatrix, X, Y, false,  true, false}}, // front
-        {"Left camera", {leftCameraMatrix, Z, Y,  true,  true, false}}, // left
-        {"Bottom camera", {bottomCameraMatrix, X, Z, false,  true, true}}, // bottom
-        {"Back camera", {backCameraMatrix, X, Y,  true,  true, true}}, // back
-        {"Right camera", {rightCameraMatrix, Z, Y, false,  true, true}}, // right
-        {"Free camera", GLCamera::FreeCamera}, // free
-    }
+	m_camera {cameraType},
+	m_cameraInfo {::cameraTemplates[cameraType]}
 {
 	Q_ASSERT(model != nullptr);
-	m_camera = (gl::CameraType) config::camera();
 	m_compiler = new gl::Compiler (this);
 	m_toolTipTimer = new QTimer (this);
 	m_toolTipTimer->setSingleShot (true);
 	setAcceptDrops (true);
 	connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (showCameraIconTooltip()));
-	resetAllAngles();
+	resetAngles();
 	m_needZoomToFit = true;
 
-	// Init camera icons
-	for (gl::CameraType camera : iterateEnum<gl::CameraType>())
-	{
-		const char* cameraIconNames[EnumLimits<gl::CameraType>::Count] =
-		{
-		    "camera-top", "camera-front", "camera-left",
-		    "camera-bottom", "camera-back", "camera-right",
-		    "camera-free"
-		};
-
-		CameraIcon* info = &m_cameraIcons[static_cast<int>(camera)];
-		info->image = MainWindow::getIcon (cameraIconNames[static_cast<int>(camera)]);
-		info->camera = camera;
-	}
-
 	connect(
 		this->m_compiler,
 		&gl::Compiler::sceneChanged,
 		this,
 		qOverload<>(&gl::Renderer::update)
 	);
-
-	calcCameraIcons();
 }
 
 /*
@@ -108,45 +93,11 @@
 }
 
 /*
- * Calculates the camera icon locations.
- */
-void gl::Renderer::calcCameraIcons()
-{
-	int i = 0;
-	const int columns = 3;
-	const int firstAtLastRow = countof(m_cameras) - (countof(m_cameras) % columns);
-
-	for (CameraIcon& cameraIcon : m_cameraIcons)
-	{
-		int row = i / columns;
-		int column = i % columns;
-
-		// Do right-justifying on the last row.
-		if (i >= firstAtLastRow)
-			column += columns - (countof(m_cameras) % columns);
-
-		int x1 = width() - 48 + (column * 16) - 1;
-		int y1 = (row * 16) + 1;
-
-		cameraIcon.sourceRect = {0, 0, 16, 16};
-		cameraIcon.targetRect = {x1, y1, 16, 16};
-		cameraIcon.hitRect = {
-		    cameraIcon.targetRect.x(),
-		    cameraIcon.targetRect.y(),
-		    cameraIcon.targetRect.width() + 1,
-		    cameraIcon.targetRect.height() + 1
-		};
-
-		++i;
-	}
-}
-
-/*
  * Returns the camera currently in use.
  */
 GLCamera& gl::Renderer::currentCamera()
 {
-	return m_cameras[static_cast<int>(camera())];
+	return m_cameraInfo;
 }
 
 /*
@@ -154,7 +105,7 @@
  */
 const GLCamera& gl::Renderer::currentCamera() const
 {
-	return m_cameras[static_cast<int>(camera())];
+	return m_cameraInfo;
 }
 
 /*
@@ -211,21 +162,6 @@
 
 // =============================================================================
 //
-void gl::Renderer::resetAllAngles()
-{
-	gl::CameraType const oldCamera = camera();
-
-	for (gl::CameraType camera : iterateEnum<gl::CameraType>())
-	{
-		setCamera(camera);
-		resetAngles();
-	}
-
-	setCamera(oldCamera);
-}
-
-// =============================================================================
-//
 void gl::Renderer::initializeGL()
 {
 	initializeOpenGLFunctions();
@@ -246,7 +182,7 @@
 	initializeLighting();
 	m_initialized = true;
 	// Now that GL is initialized, we can reset angles.
-	resetAllAngles();
+	resetAngles();
 }
 
 void gl::Renderer::initializeLighting()
@@ -332,7 +268,6 @@
 //
 void gl::Renderer::resizeGL (int width, int height)
 {
-	calcCameraIcons();
 	glViewport (0, 0, width, height);
 	glMatrixMode (GL_PROJECTION);
 	glLoadIdentity();
@@ -340,8 +275,7 @@
 	glMatrixMode (GL_MODELVIEW);
 
 	// Unfortunately Qt does not provide a resized() signal so we have to manually feed the information.
-	for (GLCamera& camera : m_cameras)
-		camera.rendererResized(width, height);
+	m_cameraInfo.rendererResized(width, height);
 }
 
 /*
@@ -378,7 +312,7 @@
 	else
 		glDisable(GL_LIGHTING);
 
-	if (camera() != gl::FreeCamera)
+	if (not m_cameraInfo.isModelview())
 	{
 		glMatrixMode (GL_PROJECTION);
 		glPushMatrix();
@@ -563,21 +497,6 @@
 
 void gl::Renderer::overpaint(QPainter &painter)
 {
-	// Draw a background for the selected camera
-	painter.setPen(thinBorderPen);
-	painter.setBrush(QBrush {QColor {0, 128, 160, 128}});
-	painter.drawRect(m_cameraIcons[static_cast<int>(camera())].hitRect);
-
-	// Draw the camera icons
-	for (const CameraIcon& info : m_cameraIcons)
-	{
-		// Don't draw the free camera icon when we can't use the free camera
-		if (info.camera == gl::FreeCamera and not freeCameraAllowed())
-			continue;
-
-		painter.drawPixmap(info.targetRect, info.image, info.sourceRect);
-	}
-
 	// Draw a label for the current camera in the bottom left corner
 	{
 		QFontMetrics metrics {QFont {}};
@@ -591,22 +510,8 @@
 //
 void gl::Renderer::mouseReleaseEvent(QMouseEvent* event)
 {
-	bool wasLeft = (m_lastButtons & Qt::LeftButton) and not (event->buttons() & Qt::LeftButton);
+	ignore(event);
 	m_panning = false;
-
-	// Check if we selected a camera icon
-	if (wasLeft and not mouseHasMoved())
-	{
-		for (CameraIcon& info : m_cameraIcons)
-		{
-			if (info.targetRect.contains (event->pos()))
-			{
-				setCamera (info.camera);
-				break;
-			}
-		}
-	}
-
 	update();
 	m_totalMouseMove = 0;
 }
@@ -638,7 +543,7 @@
 		m_panning = true;
 		m_isCameraMoving = true;
 	}
-	else if (left and camera() == gl::FreeCamera and (xMove != 0 or yMove != 0))
+	else if (left and m_cameraInfo.isModelview() and (xMove != 0 or yMove != 0))
 	{
 		QQuaternion versor = QQuaternion::fromAxisAndAngle(yMove, xMove, 0, 0.6 * hypot(xMove, yMove));
 		m_rotation = versor * m_rotation;
@@ -692,18 +597,6 @@
 	update();
 }
 
-// =============================================================================
-//
-void gl::Renderer::setCamera(gl::CameraType camera)
-{
-	// The edit mode may forbid the free camera.
-	if (freeCameraAllowed() or camera != gl::FreeCamera)
-	{
-		m_camera = camera;
-		config::setCamera(static_cast<int>(camera));
-	}
-}
-
 /*
  * Resolves a pixel pointer to an RGB color.
  * pixel[0..2] must be valid.
@@ -829,22 +722,6 @@
 	return image.rgbSwapped().mirrored();
 }
 
-/*
- * Show a tooltip if the cursor is currently hovering over a camera icon.
- */
-void gl::Renderer::showCameraIconTooltip()
-{
-	for (CameraIcon & icon : m_cameraIcons)
-	{
-		if (icon.targetRect.contains (m_mousePosition))
-		{
-			QToolTip::showText(m_globalpos, m_cameras[static_cast<int>(icon.camera)].name());
-			update();
-			break;
-		}
-	}
-}
-
 // =============================================================================
 //
 void gl::Renderer::zoomToFit()
--- a/src/glrenderer.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/glrenderer.h	Tue Jan 01 22:30:10 2019 +0200
@@ -24,59 +24,13 @@
 #include "glcamera.h"
 #include "hierarchyelement.h"
 
-namespace gl
-{
-	enum CameraType
-	{
-		TopCamera,
-		FrontCamera,
-		LeftCamera,
-		BottomCamera,
-		BackCamera,
-		RightCamera,
-		FreeCamera,
-		_End
-	};
-
-	struct CameraIcon
-	{
-		QPixmap image;
-		QRect sourceRect;
-		QRect targetRect;
-		QRect hitRect;
-		CameraType camera;
-	};
-
-	class Renderer;
-	class Compiler;
-
-	static const QPen thinBorderPen {QColor {0, 0, 0, 208}, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin};
-
-	// Transformation matrices for the fixed cameras.
-	static const QMatrix4x4 topCameraMatrix = {};
-	static const QMatrix4x4 frontCameraMatrix = {1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1};
-	static const QMatrix4x4 leftCameraMatrix = {0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1};
-	static const QMatrix4x4 bottomCameraMatrix = {1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1};
-	static const QMatrix4x4 backCameraMatrix = {-1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1};
-	static const QMatrix4x4 rightCameraMatrix = {0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1};
-
-	// Conversion matrix from LDraw to OpenGL coordinates.
-	static const QMatrix4x4 ldrawToGLAdapterMatrix = {1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1};
-
-	enum { BlackRgb = 0xff000000 };
-	static constexpr GLfloat near = 1.0f;
-	static constexpr GLfloat far = 10000.0f;
-}
-
-MAKE_ITERABLE_ENUM(gl::CameraType)
-
 // The main renderer object, draws the brick on the screen, manages the camera and selection picking.
 class gl::Renderer : public QGLWidget, protected QOpenGLFunctions, public HierarchyElement
 {
 	Q_OBJECT
 
 public:
-	Renderer(const Model* model, QWidget* parent = nullptr);
+	Renderer(const Model* model, gl::CameraType cameraType, QWidget* parent = nullptr);
 	~Renderer();
 
 	gl::CameraType camera() const;
@@ -90,11 +44,9 @@
 	QPersistentModelIndex objectAtCursor() const;
 	QItemSelection pick(const QRect& range);
 	QModelIndex pick(int mouseX, int mouseY);
-	void resetAllAngles();
 	void resetAngles();
 	QImage screenCapture();
 	void setBackground();
-	void setCamera(gl::CameraType cam);
 	QPen textPen() const;
 	QItemSelectionModel* selectionModel() const;
 	void setSelectionModel(QItemSelectionModel* selectionModel);
@@ -132,14 +84,14 @@
 
 private:
 	const Model* const m_model;
+	gl::CameraType const m_camera;
 	gl::Compiler* m_compiler;
 	QPersistentModelIndex m_objectAtCursor;
-	gl::CameraIcon m_cameraIcons[7];
 	QTimer* m_toolTipTimer;
 	Qt::MouseButtons m_lastButtons;
 	Qt::KeyboardModifiers m_currentKeyboardModifiers;
 	QQuaternion m_rotation;
-	GLCamera m_cameras[7];
+	GLCamera m_cameraInfo;
 	bool m_useDarkBackground = false;
 	bool m_panning = false;
 	bool m_initialized = false;
@@ -150,7 +102,6 @@
 	QPoint m_mousePosition;
 	QPoint m_globalpos;
 	QPointF m_mousePositionF;
-	gl::CameraType m_camera;
 	GLuint m_axeslist;
 	int m_totalMouseMove;
 	QColor m_backgroundColor;
@@ -167,7 +118,6 @@
 	void initGLData();
 	void needZoomToFit();
 	void setPicking(bool picking);
-	Q_SLOT void showCameraIconTooltip();
 	void zoomToFit();
 	void zoomAllToFit();
 };
--- a/src/mainwindow.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/mainwindow.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -16,6 +16,8 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <QMdiArea>
+#include <QMdiSubWindow>
 #include <QMessageBox>
 #include <QContextMenuEvent>
 #include <QToolButton>
@@ -81,12 +83,14 @@
 	ui.verticalLayout->insertWidget (0, m_tabs);
 	ui.primitives->setModel(m_primitives);
 	createBlankDocument();
-	ui.rendererStack->setCurrentWidget(getRendererForDocument(m_currentDocument));
+	getRendererForDocument(m_currentDocument);
 
 	connect (m_tabs, SIGNAL (currentChanged(int)), this, SLOT (tabSelected()));
 	connect (m_tabs, SIGNAL (tabCloseRequested (int)), this, SLOT (closeTab (int)));
 	connect(m_documents, &DocumentManager::documentCreated, this, &MainWindow::newDocument);
 	connect(m_documents, SIGNAL(documentClosed(LDDocument*)), this, SLOT(documentClosed(LDDocument*)));
+	connect(m_documents, &DocumentManager::mainModelLoaded, this, &MainWindow::mainModelLoaded);
+	connect(ui.viewport, &QMdiArea::subWindowActivated, this, &MainWindow::canvasActivated);
 
 	updateActions();
 
@@ -360,6 +364,32 @@
 	documents()->openMainModel (qAct->text());
 }
 
+/*
+ * This slot function is called when a subwindow of the MDI area is selected.
+ */
+void MainWindow::canvasActivated(QMdiSubWindow* window)
+{
+	if (window != nullptr)
+	{
+		Q_ASSERT(window->mdiArea() == ui.viewport);
+		Canvas* const canvas = static_cast<Canvas*>(window->widget());
+		LDDocument* const document = canvas->document();
+
+		// Move the canvas to the top of its stack.
+		m_renderers[document].removeOne(canvas);
+		m_renderers[document].append(canvas);
+	}
+}
+
+void MainWindow::mainModelLoaded(LDDocument* document)
+{
+	openDocumentForEditing(document);
+	changeDocument(document);
+
+	for (Canvas* canvas : m_renderers[document])
+		canvas->fullUpdate();
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 // Returns the suggested position to place a new object at.
@@ -384,11 +414,17 @@
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
-// Builds the object list and tells the GL renderer to do a soft update.
+// Updates all GL renderers.
 //
 void MainWindow::refresh()
 {
-	renderer()->update();
+	auto iterator = createIterator(m_renderers);
+
+	while (iterator.hasNext())
+	{
+		for (Canvas* canvas : iterator.next().value())
+			canvas->update();
+	}
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -491,7 +527,7 @@
 		contextMenu->addAction (ui.actionSubfileSelection);
 	}
 
-	if (renderer()->camera() != gl::FreeCamera)
+	if (not renderer()->currentCamera().isModelview())
 	{
 		contextMenu->addSeparator();
 		contextMenu->addAction(ui.actionSetDrawPlane);
@@ -720,8 +756,13 @@
 //
 Canvas* MainWindow::renderer()
 {
-	Q_ASSERT(ui.rendererStack->count() > 0);
-	return static_cast<Canvas*>(ui.rendererStack->currentWidget());
+	QMdiSubWindow* const currentSubWindow = ui.viewport->currentSubWindow();
+	Q_ASSERT(currentSubWindow != nullptr);
+
+	if (currentSubWindow != nullptr)
+		return static_cast<Canvas*>(currentSubWindow->widget());
+	else
+		return nullptr;
 }
 
 // ---------------------------------------------------------------------------------------------------------------------
@@ -788,6 +829,22 @@
 	updateActions();
 }
 
+/*
+ * Creates a new camera of the specified type for the specified document.
+ * The canvas is opened in a new MDI sub window.
+ * The created canvas is returned.
+ */
+Canvas* MainWindow::createCameraForDocument(LDDocument* document, gl::CameraType cameraType)
+{
+	Canvas* canvas = new Canvas {document, cameraType, this};
+	m_renderers[document].append(canvas);
+	QMdiSubWindow* const subWindow = ui.viewport->addSubWindow(canvas);
+	m_subWindows[canvas] = subWindow;
+	connect(canvas, &QObject::destroyed, this, &MainWindow::canvasClosed);
+	ui.viewport->setActiveSubWindow(subWindow);
+	return canvas;
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 void MainWindow::newDocument(LDDocument* document, bool cache)
@@ -809,6 +866,21 @@
 	updateDocumentList();
 }
 
+/*
+ * When a canvas is closed, this clears any internal references to it.
+ */
+void MainWindow::canvasClosed()
+{
+	Canvas* canvas = qobject_cast<Canvas*>(sender());
+
+	if (canvas != nullptr)
+	{
+		LDDocument* const document = canvas->document();
+		m_renderers[document].removeAll(canvas);
+		m_subWindows.remove(canvas);
+	}
+}
+
 void MainWindow::openDocumentForEditing(LDDocument* document)
 {
 	if (document->isFrozen())
@@ -841,8 +913,6 @@
 		return;
 
 	m_currentDocument = document;
-	Canvas* renderer = getRendererForDocument(document);
-	ui.rendererStack->setCurrentWidget(renderer);
 
 	if (document)
 	{
@@ -852,13 +922,19 @@
 		print ("Changed document to %1", document->getDisplayName());
 		ui.objectList->setModel(document);
 		ui.header->setDocument(document);
-		renderer->fullUpdate();
-		QItemSelectionModel* selection = m_selections.value(document);
+
+		for (Canvas* canvas : m_renderers[document])
+			canvas->fullUpdate();
+
+		QItemSelectionModel* selection = m_selectionModels.value(document);
 
 		if (selection == nullptr)
 		{
-			m_selections[document] = ui.objectList->selectionModel();
-			renderer->setSelectionModel(m_selections[document]);
+			selection = new QItemSelectionModel;
+			m_selectionModels[document] = selection;
+
+			for (Canvas* canvas : m_renderers[document])
+				canvas->setSelectionModel(m_selectionModels[document]);
 		}
 		else
 		{
@@ -872,16 +948,19 @@
  */
 Canvas* MainWindow::getRendererForDocument(LDDocument *document)
 {
-	Canvas* renderer = m_renderers.value(document);
+	QStack<Canvas*>& renderers = m_renderers[document];
+	Canvas* canvas;
 
-	if (not renderer)
+	if (renderers.empty())
 	{
-		renderer = new Canvas {document, this};
-		m_renderers[document] = renderer;
-		ui.rendererStack->addWidget(renderer);
+		canvas = createCameraForDocument(document, gl::FreeCamera);
+	}
+	else
+	{
+		canvas = renderers.top();
 	}
 
-	return renderer;
+	return canvas;
 }
 
 void MainWindow::documentClosed(LDDocument *document)
@@ -889,19 +968,26 @@
 	print ("Closed %1", document->name());
 	updateDocumentList();
 
-	// If the current document just became implicit (i.e. user closed it), we need to get a new one to show.
+	// If the current document was just close, we need to get a new one to show.
 	if (currentDocument() == document)
 		currentDocumentClosed();
 
-	Canvas* renderer = m_renderers.value(document);
-
-	if (renderer)
+	for (Canvas* renderer : m_renderers.value(document))
 	{
-		ui.rendererStack->removeWidget(renderer);
+		ui.viewport->removeSubWindow(renderer);
+		m_subWindows.remove(renderer);
 		renderer->deleteLater();
 	}
 
 	m_renderers.remove(document);
+
+	auto selectionModel = m_selectionModels.find(document);
+
+	if (selectionModel != m_selectionModels.end())
+	{
+		delete *selectionModel;
+		m_selectionModels.erase(selectionModel);
+	}
 }
 
 QModelIndexList MainWindow::selectedIndexes() const
@@ -956,21 +1042,48 @@
 
 void MainWindow::clearSelection()
 {
-	m_selections[m_currentDocument]->clear();
+	m_selectionModels[m_currentDocument]->clear();
 }
 
 void MainWindow::select(const QModelIndex &objectIndex)
 {
 	if (objectIndex.isValid() and objectIndex.model() == m_currentDocument)
-		m_selections[m_currentDocument]->select(objectIndex, QItemSelectionModel::Select);
+		m_selectionModels[m_currentDocument]->select(objectIndex, QItemSelectionModel::Select);
+}
+
+/*
+ * Selects a camera of the specified type for the specified document.
+ * If the camera does not exist, it will be created.
+ * The selected canvas is returned.
+ */
+Canvas* MainWindow::selectCameraForDocument(LDDocument* document, gl::CameraType cameraType)
+{
+	Canvas* const currentCanvas = renderer();
+	QStack<Canvas*>& canvasStack = m_renderers[document];
+
+	if (canvasStack.empty())
+	{
+		return createCameraForDocument(document, cameraType);
+	}
+	else
+	{
+		Canvas* canvas = canvasStack.top();
+
+		if (canvas == currentCanvas)
+			canvas = canvasStack.front();
+
+		QMdiSubWindow* const subWindow = m_subWindows[canvas];
+		ui.viewport->setActiveSubWindow(subWindow);
+		return canvas;
+	}
 }
 
 QItemSelectionModel* MainWindow::currentSelectionModel()
 {
-	return m_selections[m_currentDocument];
+	return m_selectionModels[m_currentDocument];
 }
 
 void MainWindow::replaceSelection(const QItemSelection& selection)
 {
-	m_selections[m_currentDocument]->select(selection, QItemSelectionModel::ClearAndSelect);
+	m_selectionModels[m_currentDocument]->select(selection, QItemSelectionModel::ClearAndSelect);
 }
--- a/src/mainwindow.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/mainwindow.h	Tue Jan 01 22:30:10 2019 +0200
@@ -26,7 +26,9 @@
 #include <QMetaMethod>
 #include "linetypes/modelobject.h"
 #include "colors.h"
+#include "glShared.h"
 
+class QMdiSubWindow;
 class QToolButton;
 class Canvas;
 class Toolset;
@@ -48,6 +50,7 @@
 	void changeDocument (LDDocument* f);
 	void clearSelection();
 	void createBlankDocument();
+	Canvas* createCameraForDocument(LDDocument* document, gl::CameraType cameraType);
 	LDDocument* currentDocument();
 	void currentDocumentClosed();
 	QItemSelectionModel* currentSelectionModel();
@@ -70,6 +73,7 @@
 	CircularSection circleToolSection() const;
 	bool save (LDDocument* doc, bool saveAs);
 	void select(const QModelIndex& objectIndex);
+	Canvas* selectCameraForDocument(LDDocument* document, gl::CameraType cameraType);
 	QModelIndexList selectedIndexes() const;
 	QSet<LDObject*> selectedObjects() const;
 	void spawnContextMenu (const QPoint& position);
@@ -96,6 +100,7 @@
 	void updateTitle();
 	void newDocument (LDDocument* document, bool cache = false);
 	void settingsChanged();
+	void canvasClosed();
 
 protected:
 	void closeEvent (QCloseEvent* event);
@@ -103,8 +108,8 @@
 private:
 	struct ToolInfo;
 
-	QMap<LDDocument*, Canvas*> m_renderers;
-	QMap<LDDocument*, QItemSelectionModel*> m_selections;
+	QMap<LDDocument*, QStack<Canvas*>> m_renderers;
+	QMap<LDDocument*, QItemSelectionModel*> m_selectionModels;
 	PrimitiveManager* m_primitives;
 	Grid* m_grid;
 	QVector<QToolButton*>	m_colorButtons;
@@ -118,9 +123,12 @@
 	DocumentManager* m_documents;
 	LDDocument* m_currentDocument;
 	QMap<QAction*, QKeySequence> m_defaultShortcuts;
+	QMap<Canvas*, QMdiSubWindow*> m_subWindows;
 	int previousDivisions = MediumResolution;
 
 private slots:
 	void finishInitialization();
 	void recentFileClicked();
+	void canvasActivated(QMdiSubWindow* window);
+	void mainModelLoaded(LDDocument* document);
 };
--- a/src/mainwindow.ui	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/mainwindow.ui	Tue Jan 01 22:30:10 2019 +0200
@@ -24,31 +24,22 @@
       <property name="orientation">
        <enum>Qt::Horizontal</enum>
       </property>
-      <widget class="QStackedWidget" name="rendererStack">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="frameShape">
-        <enum>QFrame::StyledPanel</enum>
-       </property>
-       <property name="frameShadow">
-        <enum>QFrame::Raised</enum>
+      <widget class="QMdiArea" name="viewport">
+       <property name="viewMode">
+        <enum>QMdiArea::TabbedView</enum>
        </property>
       </widget>
       <widget class="QToolBox" name="toolBox">
        <property name="currentIndex">
-        <number>2</number>
+        <number>0</number>
        </property>
        <widget class="QWidget" name="page">
         <property name="geometry">
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>100</width>
-          <height>30</height>
+          <width>68</width>
+          <height>377</height>
          </rect>
         </property>
         <attribute name="label">
@@ -70,8 +61,8 @@
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>926</width>
-          <height>366</height>
+          <width>88</width>
+          <height>363</height>
          </rect>
         </property>
         <attribute name="label">
@@ -101,8 +92,8 @@
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>926</width>
-          <height>366</height>
+          <width>176</width>
+          <height>363</height>
          </rect>
         </property>
         <attribute name="label">
@@ -140,8 +131,8 @@
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>93</width>
-          <height>93</height>
+          <width>88</width>
+          <height>363</height>
          </rect>
         </property>
         <attribute name="label">
@@ -174,7 +165,7 @@
      <x>0</x>
      <y>0</y>
      <width>1010</width>
-     <height>26</height>
+     <height>22</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -216,6 +207,34 @@
     <property name="title">
      <string>&amp;View</string>
     </property>
+    <widget class="QMenu" name="menuCreate_View">
+     <property name="title">
+      <string>&amp;Create Camera</string>
+     </property>
+     <addaction name="actionNewTopCamera"/>
+     <addaction name="actionNewFrontCamera"/>
+     <addaction name="actionNewLeftCamera"/>
+     <addaction name="actionNewBottomCamera"/>
+     <addaction name="actionNewBackCamera"/>
+     <addaction name="actionNewRightCamera"/>
+     <addaction name="separator"/>
+     <addaction name="actionNewFreeCamera"/>
+    </widget>
+    <widget class="QMenu" name="menu_Select_Camera">
+     <property name="title">
+      <string>&amp;Select Camera</string>
+     </property>
+     <addaction name="actionSelectTopCamera"/>
+     <addaction name="actionSelectFrontCamera"/>
+     <addaction name="actionSelectLeftCamera"/>
+     <addaction name="actionSelectBottomCamera"/>
+     <addaction name="actionSelectBackCamera"/>
+     <addaction name="actionSelectRightCamera"/>
+     <addaction name="separator"/>
+     <addaction name="actionSelectFreeCamera"/>
+    </widget>
+    <addaction name="menuCreate_View"/>
+    <addaction name="menu_Select_Camera"/>
     <addaction name="actionResetView"/>
     <addaction name="actionAxes"/>
     <addaction name="actionWireframe"/>
@@ -1716,6 +1735,174 @@
     <string>Resets the drawing plane</string>
    </property>
   </action>
+  <action name="actionNewTopCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-top.png</normaloff>:/icons/camera-top.png</iconset>
+   </property>
+   <property name="text">
+    <string>New &amp;Top Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Top Camera</string>
+   </property>
+  </action>
+  <action name="actionNewFrontCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-front.png</normaloff>:/icons/camera-front.png</iconset>
+   </property>
+   <property name="text">
+    <string>New &amp;Front Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Front Camera</string>
+   </property>
+  </action>
+  <action name="actionNewLeftCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-left.png</normaloff>:/icons/camera-left.png</iconset>
+   </property>
+   <property name="text">
+    <string>New &amp;Left Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Left Camera</string>
+   </property>
+  </action>
+  <action name="actionNewBottomCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-bottom.png</normaloff>:/icons/camera-bottom.png</iconset>
+   </property>
+   <property name="text">
+    <string>New &amp;Bottom Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Bottom Camera</string>
+   </property>
+  </action>
+  <action name="actionNewBackCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-back.png</normaloff>:/icons/camera-back.png</iconset>
+   </property>
+   <property name="text">
+    <string>New B&amp;ack Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Back Camera</string>
+   </property>
+  </action>
+  <action name="actionNewRightCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-right.png</normaloff>:/icons/camera-right.png</iconset>
+   </property>
+   <property name="text">
+    <string>New &amp;Right Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Right Camera</string>
+   </property>
+  </action>
+  <action name="actionNewFreeCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-free.png</normaloff>:/icons/camera-free.png</iconset>
+   </property>
+   <property name="text">
+    <string>New Fr&amp;ee Camera</string>
+   </property>
+   <property name="toolTip">
+    <string>New Free Camera</string>
+   </property>
+  </action>
+  <action name="actionSelectTopCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-top.png</normaloff>:/icons/camera-top.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select &amp;Top Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+1</string>
+   </property>
+  </action>
+  <action name="actionSelectFrontCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-front.png</normaloff>:/icons/camera-front.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select &amp;Front Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+2</string>
+   </property>
+  </action>
+  <action name="actionSelectLeftCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-left.png</normaloff>:/icons/camera-left.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select &amp;Left Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+3</string>
+   </property>
+  </action>
+  <action name="actionSelectBottomCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-bottom.png</normaloff>:/icons/camera-bottom.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select &amp;Bottom Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+4</string>
+   </property>
+  </action>
+  <action name="actionSelectBackCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-back.png</normaloff>:/icons/camera-back.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select B&amp;ack Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+5</string>
+   </property>
+  </action>
+  <action name="actionSelectRightCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-right.png</normaloff>:/icons/camera-right.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select &amp;Right Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+6</string>
+   </property>
+  </action>
+  <action name="actionSelectFreeCamera">
+   <property name="icon">
+    <iconset resource="../ldforge.qrc">
+     <normaloff>:/icons/camera-free.png</normaloff>:/icons/camera-free.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select Fr&amp;ee Camera</string>
+   </property>
+   <property name="shortcut">
+    <string>Ctrl+7</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>
@@ -1733,6 +1920,7 @@
  </customwidgets>
  <resources>
   <include location="../ldforge.qrc"/>
+  <include location="../ldforge.qrc"/>
  </resources>
  <connections/>
 </ui>
--- a/src/toolsets/viewtoolset.cpp	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/toolsets/viewtoolset.cpp	Tue Jan 01 22:30:10 2019 +0200
@@ -163,6 +163,86 @@
 	m_window->renderer()->update();
 }
 
+void ViewToolset::newTopCamera()
+{
+	createNewCamera(gl::TopCamera);
+}
+
+void ViewToolset::newFrontCamera()
+{
+	createNewCamera(gl::FrontCamera);
+}
+
+void ViewToolset::newLeftCamera()
+{
+	createNewCamera(gl::LeftCamera);
+}
+
+void ViewToolset::newBottomCamera()
+{
+	createNewCamera(gl::BottomCamera);
+}
+
+void ViewToolset::newBackCamera()
+{
+	createNewCamera(gl::BackCamera);
+}
+
+void ViewToolset::newRightCamera()
+{
+	createNewCamera(gl::RightCamera);
+}
+
+void ViewToolset::newFreeCamera()
+{
+	createNewCamera(gl::FreeCamera);
+}
+
+void ViewToolset::selectTopCamera()
+{
+	selectCamera(gl::TopCamera);
+}
+
+void ViewToolset::selectFrontCamera()
+{
+	selectCamera(gl::FrontCamera);
+}
+
+void ViewToolset::selectLeftCamera()
+{
+	selectCamera(gl::LeftCamera);
+}
+
+void ViewToolset::selectBottomCamera()
+{
+	selectCamera(gl::BottomCamera);
+}
+
+void ViewToolset::selectBackCamera()
+{
+	selectCamera(gl::BackCamera);
+}
+
+void ViewToolset::selectRightCamera()
+{
+	selectCamera(gl::RightCamera);
+}
+
+void ViewToolset::selectFreeCamera()
+{
+	selectCamera(gl::FreeCamera);
+}
+
+void ViewToolset::createNewCamera(gl::CameraType cameraType)
+{
+	m_window->createCameraForDocument(currentDocument(), cameraType);
+}
+
+void ViewToolset::selectCamera(gl::CameraType cameraType)
+{
+	m_window->selectCameraForDocument(currentDocument(), cameraType);
+}
+
 void ViewToolset::drawAngles()
 {
 	config::toggleDrawAngles();
@@ -178,10 +258,17 @@
 	switch (object->type())
 	{
 	case LDObjectType::Quadrilateral:
-		if (not static_cast<LDQuadrilateral*>(object)->isCoPlanar())
+	case LDObjectType::Triangle:
+		if (
+			object->type() == LDObjectType::Quadrilateral
+			and not static_cast<LDQuadrilateral*>(object)->isCoPlanar()
+		) {
 			return {};
-	case LDObjectType::Triangle:
-		return Plane::fromPoints(object->vertex(0), object->vertex(1), object->vertex(2));
+		}
+		else
+		{
+			return Plane::fromPoints(object->vertex(0), object->vertex(1), object->vertex(2));
+		}
 
 	default:
 		return {};
@@ -220,7 +307,7 @@
 
 void ViewToolset::setCullDepth()
 {
-	if (m_window->renderer()->camera() == gl::FreeCamera)
+	if (m_window->renderer()->currentCamera().isModelview())
 		return;
 
 	bool ok;
--- a/src/toolsets/viewtoolset.h	Fri Dec 28 00:03:47 2018 +0200
+++ b/src/toolsets/viewtoolset.h	Tue Jan 01 22:30:10 2019 +0200
@@ -18,6 +18,7 @@
 
 #pragma once
 #include "toolset.h"
+#include "glrenderer.h"
 
 class ViewToolset : public Toolset
 {
@@ -48,4 +49,23 @@
 	Q_INVOKABLE void visibilityReveal();
 	Q_INVOKABLE void visibilityToggle();
 	Q_INVOKABLE void wireframe();
+
+	Q_INVOKABLE void newTopCamera();
+	Q_INVOKABLE void newFrontCamera();
+	Q_INVOKABLE void newLeftCamera();
+	Q_INVOKABLE void newBottomCamera();
+	Q_INVOKABLE void newBackCamera();
+	Q_INVOKABLE void newRightCamera();
+	Q_INVOKABLE void newFreeCamera();
+	Q_INVOKABLE void selectTopCamera();
+	Q_INVOKABLE void selectFrontCamera();
+	Q_INVOKABLE void selectLeftCamera();
+	Q_INVOKABLE void selectBottomCamera();
+	Q_INVOKABLE void selectBackCamera();
+	Q_INVOKABLE void selectRightCamera();
+	Q_INVOKABLE void selectFreeCamera();
+
+private:
+	void createNewCamera(gl::CameraType cameraType);
+	void selectCamera(gl::CameraType cameraType);
 };

mercurial