From e3a7e7cd30720abb32deef6007a69794f06e0ae8 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 21 Aug 2021 17:50:31 -0500 Subject: [PATCH] copied main window class from material editor Signed-off-by: Guthrie Adams --- .../Document/AtomToolsDocumentMainWindow.h | 100 ++++ .../Document/AtomToolsDocumentMainWindow.cpp | 531 ++++++++++++++++++ .../Code/atomtoolsframework_files.cmake | 2 + 3 files changed, 633 insertions(+) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h new file mode 100644 index 0000000000..b7d0cbf8da --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include + +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +AZ_POP_DISABLE_WARNING +#endif + +namespace MaterialEditor +{ + /** + * MaterialEditorWindow is the main class. Its responsibility is limited to initializing and connecting + * its panels, managing selection of assets, and performing high-level actions like saving. It contains... + * 1) MaterialBrowser - The user browses for Material (.material) assets. + * 2) MaterialViewport - The user can see the selected Material applied to a model. + * 3) MaterialPropertyInspector - The user edits the properties of the selected Material. + */ + class MaterialEditorWindow + : public AtomToolsFramework::AtomToolsMainWindow + , private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + { + Q_OBJECT + public: + AZ_CLASS_ALLOCATOR(MaterialEditorWindow, AZ::SystemAllocator, 0); + + using Base = AtomToolsFramework::AtomToolsMainWindow; + + MaterialEditorWindow(QWidget* parent = 0); + ~MaterialEditorWindow(); + + private: + void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; + void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override; + void UnlockViewportRenderTargetSize() override; + + // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides... + void OnDocumentOpened(const AZ::Uuid& documentId) override; + void OnDocumentClosed(const AZ::Uuid& documentId) override; + void OnDocumentModified(const AZ::Uuid& documentId) override; + void OnDocumentUndoStateChanged(const AZ::Uuid& documentId) override; + void OnDocumentSaved(const AZ::Uuid& documentId) override; + + void CreateMenu() override; + void CreateTabBar() override; + + QString GetDocumentPath(const AZ::Uuid& documentId) const; + + void OpenTabContextMenu() override; + + void closeEvent(QCloseEvent* closeEvent) override; + + MaterialViewportWidget* m_materialViewport = nullptr; + MaterialEditorToolBar* m_toolBar = nullptr; + + QMenu* m_menuFile = {}; + QAction* m_actionNew = {}; + QAction* m_actionOpen = {}; + QAction* m_actionOpenRecent = {}; + QAction* m_actionClose = {}; + QAction* m_actionCloseAll = {}; + QAction* m_actionCloseOthers = {}; + QAction* m_actionSave = {}; + QAction* m_actionSaveAsCopy = {}; + QAction* m_actionSaveAsChild = {}; + QAction* m_actionSaveAll = {}; + QAction* m_actionExit = {}; + + QMenu* m_menuEdit = {}; + QAction* m_actionUndo = {}; + QAction* m_actionRedo = {}; + QAction* m_actionSettings = {}; + + QMenu* m_menuView = {}; + QAction* m_actionAssetBrowser = {}; + QAction* m_actionInspector = {}; + QAction* m_actionConsole = {}; + QAction* m_actionPythonTerminal = {}; + QAction* m_actionPerfMonitor = {}; + QAction* m_actionViewportSettings = {}; + QAction* m_actionNextTab = {}; + QAction* m_actionPreviousTab = {}; + + QMenu* m_menuHelp = {}; + QAction* m_actionHelp = {}; + QAction* m_actionAbout = {}; + }; +} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp new file mode 100644 index 0000000000..8922591580 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -0,0 +1,531 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +#include +#include +#include +#include +AZ_POP_DISABLE_WARNING + +namespace MaterialEditor +{ + MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */) + : AtomToolsFramework::AtomToolsMainWindow(parent) + { + resize(1280, 1024); + + // Among other things, we need the window wrapper to save the main window size, position, and state + auto mainWindowWrapper = + new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionAutoTitleBarButtons); + mainWindowWrapper->setGuest(this); + mainWindowWrapper->enableSaveRestoreGeometry("O3DE", "MaterialEditor", "mainWindowGeometry"); + + // set the style sheet for RPE highlighting and other styling + AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral(":/MaterialEditor.qss")); + + QApplication::setWindowIcon(QIcon(":/Icons/materialeditor.svg")); + + AZ::Name apiName = AZ::RHI::Factory::Get().GetName(); + if (!apiName.IsEmpty()) + { + QString title = QString{ "%1 (%2)" }.arg(QApplication::applicationName()).arg(apiName.GetCStr()); + setWindowTitle(title); + } + else + { + AZ_Assert(false, "Render API name not found"); + setWindowTitle(QApplication::applicationName()); + } + + setObjectName("MaterialEditorWindow"); + + m_toolBar = new MaterialEditorToolBar(this); + m_toolBar->setObjectName("ToolBar"); + addToolBar(m_toolBar); + + CreateMenu(); + CreateTabBar(); + + m_materialViewport = new MaterialViewportWidget(centralWidget()); + m_materialViewport->setObjectName("Viewport"); + m_materialViewport->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + centralWidget()->layout()->addWidget(m_materialViewport); + + AddDockWidget("Asset Browser", new MaterialBrowserWidget, Qt::BottomDockWidgetArea, Qt::Vertical); + AddDockWidget("Inspector", new MaterialInspector, Qt::RightDockWidgetArea, Qt::Horizontal); + AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Horizontal); + AddDockWidget("Performance Monitor", new PerformanceMonitorWidget, Qt::RightDockWidgetArea, Qt::Horizontal); + AddDockWidget("Python Terminal", new AzToolsFramework::CScriptTermDialog, Qt::BottomDockWidgetArea, Qt::Horizontal); + + SetDockWidgetVisible("Viewport Settings", false); + SetDockWidgetVisible("Performance Monitor", false); + SetDockWidgetVisible("Python Terminal", false); + + // Restore geometry and show the window + mainWindowWrapper->showFromSettings(); + + // Restore additional state for docked windows + auto windowSettings = AZ::UserSettings::CreateFind( + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); + + if (!windowSettings->m_mainWindowState.empty()) + { + QByteArray windowState(windowSettings->m_mainWindowState.data(), static_cast(windowSettings->m_mainWindowState.size())); + m_advancedDockManager->restoreState(windowState); + } + + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); + OnDocumentOpened(AZ::Uuid::CreateNull()); + } + + MaterialEditorWindow::~MaterialEditorWindow() + { + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); + } + + + void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) + { + QSize requestedViewportSize = QSize(width, height) / devicePixelRatioF(); + QSize currentViewportSize = m_materialViewport->size(); + QSize offset = requestedViewportSize - currentViewportSize; + QSize requestedWindowSize = size() + offset; + resize(requestedWindowSize); + + AZ_Assert( + m_materialViewport->size() == requestedViewportSize, + "Resizing the window did not give the expected viewport size. Requested %d x %d but got %d x %d.", + requestedViewportSize.width(), requestedViewportSize.height(), m_materialViewport->size().width(), + m_materialViewport->size().height()); + + QSize newDeviceSize = m_materialViewport->size(); + AZ_Warning( + "Material Editor", static_cast(newDeviceSize.width()) == width && static_cast(newDeviceSize.height()) == height, + "Resizing the window did not give the expected frame size. Requested %d x %d but got %d x %d.", width, height, + newDeviceSize.width(), newDeviceSize.height()); + } + + void MaterialEditorWindow::LockViewportRenderTargetSize(uint32_t width, uint32_t height) + { + m_materialViewport->LockRenderTargetSize(width, height); + } + + void MaterialEditorWindow::UnlockViewportRenderTargetSize() + { + m_materialViewport->UnlockRenderTargetSize(); + } + + void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) + { + bool didClose = true; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + if (!didClose) + { + closeEvent->ignore(); + return; + } + + // Capture docking state before shutdown + auto windowSettings = AZ::UserSettings::CreateFind( + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); + + QByteArray windowState = m_advancedDockManager->saveState(); + windowSettings->m_mainWindowState.assign(windowState.begin(), windowState.end()); + + AtomToolsFramework::AtomToolsMainWindowNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsMainWindowNotifications::OnMainWindowClosing); + } + + void MaterialEditorWindow::OnDocumentOpened(const AZ::Uuid& documentId) + { + bool isOpen = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); + bool isSavable = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsSavable); + bool isModified = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + bool canUndo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + + // Update UI to display the new document + if (!documentId.IsNull() && isOpen) + { + // Create a new tab for the document ID and assign it's label to the file name of the document. + AddTabForDocumentId(documentId, filename, absolutePath, [this]{ + // The tab widget requires a dummy page per tab + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + }); + } + + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + + const bool hasTabs = m_tabWidget->count() > 0; + + // Update menu options + m_actionNew->setEnabled(true); + m_actionOpen->setEnabled(true); + m_actionOpenRecent->setEnabled(false); + m_actionClose->setEnabled(hasTabs); + m_actionCloseAll->setEnabled(hasTabs); + m_actionCloseOthers->setEnabled(hasTabs); + + m_actionSave->setEnabled(isOpen && isSavable); + m_actionSaveAsCopy->setEnabled(isOpen && isSavable); + m_actionSaveAsChild->setEnabled(isOpen); + m_actionSaveAll->setEnabled(hasTabs); + + m_actionExit->setEnabled(true); + + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + m_actionSettings->setEnabled(true); + + m_actionAssetBrowser->setEnabled(true); + m_actionInspector->setEnabled(true); + m_actionConsole->setEnabled(false); + m_actionPythonTerminal->setEnabled(true); + m_actionPerfMonitor->setEnabled(true); + m_actionViewportSettings->setEnabled(true); + m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); + m_actionNextTab->setEnabled(m_tabWidget->count() > 1); + + m_actionAbout->setEnabled(false); + + activateWindow(); + raise(); + + const QString documentPath = GetDocumentPath(documentId); + if (!documentPath.isEmpty()) + { + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); + } + } + + void MaterialEditorWindow::OnDocumentClosed(const AZ::Uuid& documentId) + { + RemoveTabForDocumentId(documentId); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); + } + + void MaterialEditorWindow::OnDocumentModified(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + } + + void MaterialEditorWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) + { + if (documentId == GetDocumentIdFromTab(m_tabWidget->currentIndex())) + { + bool canUndo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::CanRedo); + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + } + } + + void MaterialEditorWindow::OnDocumentSaved(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); + } + + void MaterialEditorWindow::CreateMenu() + { + Base::CreateMenu(); + + // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries + m_menuFile = menuBar()->addMenu("&File"); + + m_actionNew = m_menuFile->addAction("&New...", [this]() { + CreateMaterialDialog createDialog(this); + createDialog.adjustSize(); + + if (createDialog.exec() == QDialog::Accepted && + !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && + !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) + { + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, + createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(), + createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData()); + } + }, QKeySequence::New); + + m_actionOpen = m_menuFile->addAction("&Open...", [this]() { + const AZStd::vector assetTypes = { azrtti_typeid() }; + const AZStd::string filePath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); + if (!filePath.empty()) + { + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, filePath); + } + }, QKeySequence::Open); + + m_actionOpenRecent = m_menuFile->addAction("Open &Recent"); + + m_menuFile->addSeparator(); + + m_actionSave = m_menuFile->addAction("&Save", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Save); + + m_actionSaveAsCopy = m_menuFile->addAction("Save &As...", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const QString documentPath = GetDocumentPath(documentId); + + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, + documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::SaveAs); + + m_actionSaveAsChild = m_menuFile->addAction("Save As &Child...", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + const QString documentPath = GetDocumentPath(documentId); + + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, + documentId, AtomToolsFramework::GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }); + + m_actionSaveAll = m_menuFile->addAction("Save A&ll", [this]() { + bool result = false; + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); + if (!result) + { + SetStatusError(tr("Document save all failed")); + } + }); + + m_menuFile->addSeparator(); + + m_actionClose = m_menuFile->addAction("&Close", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }, QKeySequence::Close); + + m_actionCloseAll = m_menuFile->addAction("Close All", [this]() { + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + }); + + m_actionCloseOthers = m_menuFile->addAction("Close Others", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + }); + + m_menuFile->addSeparator(); + + m_menuFile->addAction("Run &Python...", [this]() { + const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py")); + if (!script.isEmpty()) + { + AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData()); + } + }); + + m_menuFile->addSeparator(); + + m_actionExit = m_menuFile->addAction("E&xit", [this]() { + close(); + }, QKeySequence::Quit); + + m_menuEdit = menuBar()->addMenu("&Edit"); + + m_actionUndo = m_menuEdit->addAction("&Undo", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Undo); + if (!result) + { + SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Undo); + + m_actionRedo = m_menuEdit->addAction("&Redo", [this]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::Redo); + if (!result) + { + SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Redo); + + m_menuEdit->addSeparator(); + + m_actionSettings = m_menuEdit->addAction("&Settings...", [this]() { + SettingsDialog dialog(this); + dialog.exec(); + }, QKeySequence::Preferences); + m_actionSettings->setEnabled(true); + + m_menuView = menuBar()->addMenu("&View"); + + m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { + const AZStd::string label = "Asset Browser"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionInspector = m_menuView->addAction("&Inspector", [this]() { + const AZStd::string label = "Inspector"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionConsole = m_menuView->addAction("&Console", [this]() { + }); + + m_actionPythonTerminal = m_menuView->addAction("Python &Terminal", [this]() { + const AZStd::string label = "Python Terminal"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionPerfMonitor = m_menuView->addAction("Performance &Monitor", [this]() { + const AZStd::string label = "Performance Monitor"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_actionViewportSettings = m_menuView->addAction("Viewport Settings", [this]() { + const AZStd::string label = "Viewport Settings"; + SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); + }); + + m_menuView->addSeparator(); + + m_actionPreviousTab = m_menuView->addAction("&Previous Tab", [this]() { + SelectPreviousTab(); + }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt + + m_actionNextTab = m_menuView->addAction("&Next Tab", [this]() { + SelectNextTab(); + }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous + + m_menuHelp = menuBar()->addMenu("&Help"); + + m_actionHelp = m_menuHelp->addAction("&Help...", [this]() { + HelpDialog dialog(this); + dialog.exec(); + }); + + m_actionAbout = m_menuHelp->addAction("&About...", [this]() { + }); + } + + void MaterialEditorWindow::CreateTabBar() + { + Base::CreateTabBar(); + + // This signal will be triggered whenever a tab is added, removed, selected, clicked, dragged + // When the last tab is removed tabIndex will be -1 and the document ID will be null + // This should automatically clear the active document + connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) { + const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + }); + + connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { + const AZ::Uuid documentId = GetDocumentIdFromTab(tabIndex); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }); + } + + QString MaterialEditorWindow::GetDocumentPath(const AZ::Uuid& documentId) const + { + AZStd::string absolutePath; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); + return absolutePath.c_str(); + } + + void MaterialEditorWindow::OpenTabContextMenu() + { + const QTabBar* tabBar = m_tabWidget->tabBar(); + const QPoint position = tabBar->mapFromGlobal(QCursor::pos()); + const int clickedTabIndex = tabBar->tabAt(position); + const int currentTabIndex = tabBar->currentIndex(); + if (clickedTabIndex >= 0) + { + QMenu tabMenu; + const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select"; + tabMenu.addAction(selectActionName, [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + }); + tabMenu.addAction("Close", [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }); + auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentIdFromTab(clickedTabIndex); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + }); + closeOthersAction->setEnabled(tabBar->count() > 1); + tabMenu.exec(QCursor::pos()); + } + } +} // namespace MaterialEditor + +#include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index cd056f5fcf..3d4bb82eec 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -12,6 +12,7 @@ set(FILES Include/AtomToolsFramework/Communication/LocalSocket.h Include/AtomToolsFramework/Debug/TraceRecorder.h Include/AtomToolsFramework/Document/AtomToolsDocument.h + Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h Include/AtomToolsFramework/Document/AtomToolsDocumentSystemSettings.h Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h @@ -38,6 +39,7 @@ set(FILES Source/Communication/LocalSocket.cpp Source/Debug/TraceRecorder.cpp Source/Document/AtomToolsDocument.cpp + Source/Document/AtomToolsDocumentMainWindow.cpp Source/Document/AtomToolsDocumentSystemSettings.cpp Source/Document/AtomToolsDocumentSystemComponent.cpp Source/Document/AtomToolsDocumentSystemComponent.h