src/mainwindow.cpp

changeset 1437
1a77c6156db7
parent 1436
241d3e452b32
child 1438
988b6563d47d
--- 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);
 }

mercurial