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..826d2427b1 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h @@ -0,0 +1,90 @@ +/* + * 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 +#include +#endif + +namespace AtomToolsFramework +{ + //! AtomToolsDocumentMainWindow + class AtomToolsDocumentMainWindow + : public AtomToolsMainWindow + , private AtomToolsDocumentNotificationBus::Handler + { + Q_OBJECT + public: + AZ_CLASS_ALLOCATOR(AtomToolsDocumentMainWindow, AZ::SystemAllocator, 0); + + using Base = AtomToolsMainWindow; + + AtomToolsDocumentMainWindow(QWidget* parent = 0); + ~AtomToolsDocumentMainWindow(); + + protected: + void AddDocumentMenus(); + void AddDocumentTabBar(); + + QString GetDocumentPath(const AZ::Uuid& documentId) const; + + AZ::Uuid GetDocumentTabId(const int tabIndex) const; + + void AddDocumentTab( + const AZ::Uuid& documentId, + const AZStd::string& label, + const AZStd::string& toolTip); + + void RemoveDocumentTab(const AZ::Uuid& documentId); + + void UpdateDocumentTab( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); + + void SelectPrevDocumentTab(); + void SelectNextDocumentTab(); + + virtual QWidget* CreateDocumentTabView(const AZ::Uuid& documentId); + virtual void OpenDocumentTabContextMenu(); + virtual bool GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath); + virtual bool GetOpenDocumentParams(AZStd::string& openPath); + + // 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 closeEvent(QCloseEvent* closeEvent) override; + + template + QAction* CreateAction(const QString& text, Functor functor, const QKeySequence& shortcut = 0); + + QAction* m_actionNew = {}; + QAction* m_actionOpen = {}; + QAction* m_actionClose = {}; + QAction* m_actionCloseAll = {}; + QAction* m_actionCloseOthers = {}; + QAction* m_actionSave = {}; + QAction* m_actionSaveAsCopy = {}; + QAction* m_actionSaveAsChild = {}; + QAction* m_actionSaveAll = {}; + + QAction* m_actionUndo = {}; + QAction* m_actionRedo = {}; + + QAction* m_actionNextTab = {}; + QAction* m_actionPreviousTab = {}; + + AzQtComponents::TabWidget* m_tabWidget = {}; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h index 2a304c9a8c..fab6e2fb01 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Window/AtomToolsMainWindow.h @@ -7,18 +7,14 @@ */ #pragma once + #include - #include - #include #include #include -#include #include -#include -#include namespace AtomToolsFramework { @@ -38,28 +34,26 @@ namespace AtomToolsFramework bool IsDockWidgetVisible(const AZStd::string& name) const override; AZStd::vector GetDockWidgetNames() const override; - virtual void CreateMenu(); - virtual void CreateTabBar(); - - virtual void AddTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, AZStd::function widgetCreator); - virtual void RemoveTabForDocumentId(const AZ::Uuid& documentId); - virtual void UpdateTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified); - virtual AZ::Uuid GetDocumentIdFromTab(const int tabIndex) const; - - virtual void OpenTabContextMenu(); - virtual void SelectPreviousTab(); - virtual void SelectNextTab(); - void SetStatusMessage(const QString& message); void SetStatusWarning(const QString& message); void SetStatusError(const QString& message); - AzQtComponents::FancyDocking* m_advancedDockManager = nullptr; - AzQtComponents::TabWidget* m_tabWidget = nullptr; - QLabel* m_statusMessage = nullptr; + void AddCommonMenus(); + + virtual void OpenSettings(); + virtual void OpenHelp(); + virtual void OpenAbout(); + + AzQtComponents::FancyDocking* m_advancedDockManager = {}; + + QLabel* m_statusMessage = {}; + + QMenu* m_menuFile = {}; + QMenu* m_menuEdit = {}; + QMenu* m_menuView = {}; + QMenu* m_menuHelp = {}; AZStd::unordered_map m_dockWidgets; + AZStd::unordered_map m_dockActions; }; } // namespace AtomToolsFramework 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..c39bfc8327 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentMainWindow.cpp @@ -0,0 +1,493 @@ +/* + * 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 + +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +#include +#include +#include +#include +#include +AZ_POP_DISABLE_WARNING + +namespace AtomToolsFramework +{ + AtomToolsDocumentMainWindow::AtomToolsDocumentMainWindow(QWidget* parent /* = 0 */) + : AtomToolsMainWindow(parent) + { + setObjectName("AtomToolsDocumentMainWindow"); + AddDocumentMenus(); + AddDocumentTabBar(); + AtomToolsDocumentNotificationBus::Handler::BusConnect(); + } + + AtomToolsDocumentMainWindow::~AtomToolsDocumentMainWindow() + { + AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); + } + + void AtomToolsDocumentMainWindow::AddDocumentMenus() + { + QAction* insertPostion = !m_menuFile->actions().empty() ? m_menuFile->actions().front() : nullptr; + + // Generating the main menu manually because it's easier and we will have some dynamic or data driven entries + m_actionNew = CreateAction("&New...", [this]() { + AZStd::string openPath; + AZStd::string savePath; + if (GetCreateDocumentParams(openPath, savePath)) + { + AtomToolsDocumentSystemRequestBus::Broadcast( + &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath); + } + }, QKeySequence::New); + m_menuFile->insertAction(insertPostion, m_actionNew); + + m_actionOpen = CreateAction("&Open...", [this]() { + AZStd::string openPath; + if (GetOpenDocumentParams(openPath)) + { + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath); + } + }, QKeySequence::Open); + m_menuFile->insertAction(insertPostion, m_actionOpen); + m_menuFile->insertSeparator(insertPostion); + + m_actionSave = CreateAction("&Save", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Save); + m_menuFile->insertAction(insertPostion, m_actionSave); + + m_actionSaveAsCopy = CreateAction("Save &As...", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + const QString documentPath = GetDocumentPath(documentId); + + bool result = false; + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, + documentId, GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::SaveAs); + m_menuFile->insertAction(insertPostion, m_actionSaveAsCopy); + + m_actionSaveAsChild = CreateAction("Save As &Child...", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + const QString documentPath = GetDocumentPath(documentId); + + bool result = false; + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, + documentId, GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData()); + if (!result) + { + SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId))); + } + }); + m_menuFile->insertAction(insertPostion, m_actionSaveAsChild); + + m_actionSaveAll = CreateAction("Save A&ll", [this]() { + bool result = false; + AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments); + if (!result) + { + SetStatusError(tr("Document save all failed")); + } + }); + m_menuFile->insertAction(insertPostion, m_actionSaveAll); + m_menuFile->insertSeparator(insertPostion); + + m_actionClose = CreateAction("&Close", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }, QKeySequence::Close); + m_menuFile->insertAction(insertPostion, m_actionClose); + + m_actionCloseAll = CreateAction("Close All", [this]() { + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + }); + m_menuFile->insertAction(insertPostion, m_actionCloseAll); + + m_actionCloseOthers = CreateAction("Close Others", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + }); + m_menuFile->insertAction(insertPostion, m_actionCloseOthers); + m_menuFile->insertSeparator(insertPostion); + + insertPostion = !m_menuEdit->actions().empty() ? m_menuEdit->actions().front() : nullptr; + + m_actionUndo = CreateAction("&Undo", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Undo); + if (!result) + { + SetStatusError(tr("Document undo failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Undo); + m_menuEdit->insertAction(insertPostion, m_actionUndo); + + m_actionRedo = CreateAction("&Redo", [this]() { + const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex()); + bool result = false; + AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Redo); + if (!result) + { + SetStatusError(tr("Document redo failed: %1").arg(GetDocumentPath(documentId))); + } + }, QKeySequence::Redo); + m_menuEdit->insertAction(insertPostion, m_actionRedo); + m_menuEdit->insertSeparator(insertPostion); + + insertPostion = !m_menuView->actions().empty() ? m_menuView->actions().front() : nullptr; + + m_actionPreviousTab = CreateAction( + "&Previous Tab", + [this]() + { + SelectPrevDocumentTab(); + }, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); //QKeySequence::PreviousChild is mapped incorrectly in Qt + m_menuView->insertAction(insertPostion, m_actionPreviousTab); + + m_actionNextTab = CreateAction("&Next Tab", [this]() { + SelectNextDocumentTab(); + }, Qt::CTRL | Qt::Key_Tab); //QKeySequence::NextChild works as expected but mirroring Previous + m_menuView->insertAction(insertPostion, m_actionNextTab); + m_menuView->insertSeparator(insertPostion); + } + + void AtomToolsDocumentMainWindow::AddDocumentTabBar() + { + m_tabWidget = new AzQtComponents::TabWidget(centralWidget()); + m_tabWidget->setObjectName("TabWidget"); + m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + m_tabWidget->setContentsMargins(0, 0, 0, 0); + + // The tab bar should only be visible if it has active documents + m_tabWidget->setVisible(false); + m_tabWidget->setTabBarAutoHide(false); + m_tabWidget->setMovable(true); + m_tabWidget->setTabsClosable(true); + m_tabWidget->setUsesScrollButtons(true); + + // 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 = GetDocumentTabId(tabIndex); + AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + }); + + connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) { + const AZ::Uuid documentId = GetDocumentTabId(tabIndex); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }); + + // Add context menu for right-clicking on tabs + m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); + connect(m_tabWidget, &QWidget::customContextMenuRequested, this, [this]() { + OpenDocumentTabContextMenu(); + }); + + centralWidget()->layout()->addWidget(m_tabWidget); + } + + QString AtomToolsDocumentMainWindow::GetDocumentPath(const AZ::Uuid& documentId) const + { + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); + return absolutePath.c_str(); + } + + AZ::Uuid AtomToolsDocumentMainWindow::GetDocumentTabId(const int tabIndex) const + { + const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); + if (!tabData.isNull()) + { + // We need to be able to convert between a UUID and a string to store and retrieve a document ID from the tab bar + const QString documentIdString = tabData.toString(); + const QByteArray documentIdBytes = documentIdString.toUtf8(); + const AZ::Uuid documentId(documentIdBytes.data(), documentIdBytes.size()); + return documentId; + } + return AZ::Uuid::CreateNull(); + } + + void AtomToolsDocumentMainWindow::AddDocumentTab( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip) + { + // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. + // This prevents the OnDocumentOpened notification from being sent recursively. + const QSignalBlocker blocker(m_tabWidget); + + // If a tab for this document already exists then select it instead of creating a new one + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentTabId(tabIndex)) + { + m_tabWidget->setCurrentIndex(tabIndex); + m_tabWidget->repaint(); + return; + } + } + + const int tabIndex = m_tabWidget->addTab(CreateDocumentTabView(documentId), label.c_str()); + + // The user can manually reorder tabs which will invalidate any association by index. + // We need to store the document ID with the tab using the tab instead of a separate mapping. + m_tabWidget->tabBar()->setTabData(tabIndex, QVariant(documentId.ToString())); + m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); + m_tabWidget->setCurrentIndex(tabIndex); + m_tabWidget->setVisible(true); + m_tabWidget->repaint(); + } + + void AtomToolsDocumentMainWindow::RemoveDocumentTab(const AZ::Uuid& documentId) + { + // We are not blocking signals here because we want closing tabs to close the associated document + // and automatically select the next document. + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentTabId(tabIndex)) + { + m_tabWidget->removeTab(tabIndex); + m_tabWidget->setVisible(m_tabWidget->count() > 0); + m_tabWidget->repaint(); + break; + } + } + } + + void AtomToolsDocumentMainWindow::UpdateDocumentTab( + const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) + { + // Whenever a document is opened, saved, or modified we need to update the tab label + if (!documentId.IsNull()) + { + // Because tab order and indexes can change from user interactions, we cannot store a map + // between a tab index and document ID. + // We must iterate over all of the tabs to find the one associated with this document. + for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) + { + if (documentId == GetDocumentTabId(tabIndex)) + { + // We use an asterisk prepended to the file name to denote modified document + // Appending is standard and preferred but the tabs elide from the + // end (instead of middle) and cut it off + const AZStd::string modifiedLabel = isModified ? "* " + label : label; + m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); + m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); + m_tabWidget->repaint(); + break; + } + } + } + } + + void AtomToolsDocumentMainWindow::SelectPrevDocumentTab() + { + if (m_tabWidget->count() > 1) + { + // Adding count to wrap around when index <= 0 + m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + m_tabWidget->count() - 1) % m_tabWidget->count()); + } + } + + void AtomToolsDocumentMainWindow::SelectNextDocumentTab() + { + if (m_tabWidget->count() > 1) + { + m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); + } + } + + QWidget* AtomToolsDocumentMainWindow::CreateDocumentTabView(const AZ::Uuid& documentId) + { + AZ_UNUSED(documentId); + auto contentWidget = new QWidget(centralWidget()); + contentWidget->setContentsMargins(0, 0, 0, 0); + contentWidget->setFixedSize(0, 0); + return contentWidget; + } + + void AtomToolsDocumentMainWindow::OpenDocumentTabContextMenu() + { + 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 = GetDocumentTabId(clickedTabIndex); + AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId); + }); + tabMenu.addAction("Close", [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId); + }); + auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() { + const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex); + AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId); + }); + closeOthersAction->setEnabled(tabBar->count() > 1); + tabMenu.exec(QCursor::pos()); + } + } + + bool AtomToolsDocumentMainWindow::GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) + { + AZ_UNUSED(openPath); + AZ_UNUSED(savePath); + return false; + } + + bool AtomToolsDocumentMainWindow::GetOpenDocumentParams(AZStd::string& openPath) + { + AZ_UNUSED(openPath); + return false; + } + + void AtomToolsDocumentMainWindow::OnDocumentOpened(const AZ::Uuid& documentId) + { + bool isOpen = false; + AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen); + bool isSavable = false; + AtomToolsDocumentRequestBus::EventResult(isSavable, documentId, &AtomToolsDocumentRequestBus::Events::IsSavable); + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + bool canUndo = false; + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &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. + AddDocumentTab(documentId, filename, absolutePath); + UpdateDocumentTab(documentId, filename, absolutePath, isModified); + } + + const bool hasTabs = m_tabWidget->count() > 0; + + // Update menu options + m_actionNew->setEnabled(true); + m_actionOpen->setEnabled(true); + 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_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + + m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); + m_actionNextTab->setEnabled(m_tabWidget->count() > 1); + + activateWindow(); + raise(); + + const QString documentPath = GetDocumentPath(documentId); + if (!documentPath.isEmpty()) + { + SetStatusMessage(tr("Document opened: %1").arg(documentPath)); + } + } + + void AtomToolsDocumentMainWindow::OnDocumentClosed(const AZ::Uuid& documentId) + { + RemoveDocumentTab(documentId); + SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); + } + + void AtomToolsDocumentMainWindow::OnDocumentModified(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateDocumentTab(documentId, filename, absolutePath, isModified); + } + + void AtomToolsDocumentMainWindow::OnDocumentUndoStateChanged(const AZ::Uuid& documentId) + { + if (documentId == GetDocumentTabId(m_tabWidget->currentIndex())) + { + bool canUndo = false; + AtomToolsDocumentRequestBus::EventResult(canUndo, documentId, &AtomToolsDocumentRequestBus::Events::CanUndo); + bool canRedo = false; + AtomToolsDocumentRequestBus::EventResult(canRedo, documentId, &AtomToolsDocumentRequestBus::Events::CanRedo); + m_actionUndo->setEnabled(canUndo); + m_actionRedo->setEnabled(canRedo); + } + } + + void AtomToolsDocumentMainWindow::OnDocumentSaved(const AZ::Uuid& documentId) + { + bool isModified = false; + AtomToolsDocumentRequestBus::EventResult(isModified, documentId, &AtomToolsDocumentRequestBus::Events::IsModified); + AZStd::string absolutePath; + AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AZStd::string filename; + AzFramework::StringFunc::Path::GetFullFileName(absolutePath.c_str(), filename); + UpdateDocumentTab(documentId, filename, absolutePath, isModified); + SetStatusMessage(tr("Document saved: %1").arg(GetDocumentPath(documentId))); + } + + + void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent) + { + bool didClose = true; + AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); + if (!didClose) + { + closeEvent->ignore(); + return; + } + + AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing); + } + + template + QAction* AtomToolsDocumentMainWindow::CreateAction(const QString& text, Functor functor, const QKeySequence& shortcut) + { + QAction* action = new QAction(text, this); + action->setShortcut(shortcut); + connect(action, &QAction::triggered, this, functor); + return action; + } +} // namespace AtomToolsFramework + +//#include diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index cd7d49d8d3..aeca51230a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -7,6 +7,11 @@ */ #include +#include + +#include +#include +#include #include #include @@ -23,6 +28,8 @@ namespace AtomToolsFramework setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); + AddCommonMenus(); + m_statusMessage = new QLabel(statusBar()); statusBar()->addPermanentWidget(m_statusMessage, 1); @@ -65,6 +72,10 @@ namespace AtomToolsFramework addDockWidget(aznumeric_cast(area), dockWidget); resizeDocks({ dockWidget }, { 400 }, aznumeric_cast(orientation)); m_dockWidgets[name] = dockWidget; + + m_dockActions[name] = m_menuView->addAction(name.c_str(), [this, name](){ + SetDockWidgetVisible(name, !IsDockWidgetVisible(name)); + }); return true; } @@ -76,6 +87,12 @@ namespace AtomToolsFramework delete dockWidgetItr->second; m_dockWidgets.erase(dockWidgetItr); } + auto dockActionItr = m_dockActions.find(name); + if (dockActionItr != m_dockActions.end()) + { + delete dockActionItr->second; + m_dockActions.erase(dockActionItr); + } } void AtomToolsMainWindow::SetDockWidgetVisible(const AZStd::string& name, bool visible) @@ -108,145 +125,6 @@ namespace AtomToolsFramework return names; } - void AtomToolsMainWindow::CreateMenu() - { - auto menuBar = new QMenuBar(this); - menuBar->setObjectName("MenuBar"); - setMenuBar(menuBar); - } - - void AtomToolsMainWindow::CreateTabBar() - { - m_tabWidget = new AzQtComponents::TabWidget(centralWidget()); - m_tabWidget->setObjectName("TabWidget"); - m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); - m_tabWidget->setContentsMargins(0, 0, 0, 0); - - // The tab bar should only be visible if it has active documents - m_tabWidget->setVisible(false); - m_tabWidget->setTabBarAutoHide(false); - m_tabWidget->setMovable(true); - m_tabWidget->setTabsClosable(true); - m_tabWidget->setUsesScrollButtons(true); - - // Add context menu for right-clicking on tabs - m_tabWidget->setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu); - connect( - m_tabWidget, &QWidget::customContextMenuRequested, this, - [this]() - { - OpenTabContextMenu(); - }); - - centralWidget()->layout()->addWidget(m_tabWidget); - } - - void AtomToolsMainWindow::AddTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, AZStd::function widgetCreator) - { - // Blocking signals from the tab bar so the currentChanged signal is not sent while a document is already being opened. - // This prevents the OnDocumentOpened notification from being sent recursively. - const QSignalBlocker blocker(m_tabWidget); - - // If a tab for this document already exists then select it instead of creating a new one - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - m_tabWidget->setCurrentIndex(tabIndex); - m_tabWidget->repaint(); - return; - } - } - - const int tabIndex = m_tabWidget->addTab(widgetCreator(), label.c_str()); - - // The user can manually reorder tabs which will invalidate any association by index. - // We need to store the document ID with the tab using the tab instead of a separate mapping. - m_tabWidget->tabBar()->setTabData(tabIndex, QVariant(documentId.ToString())); - m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); - m_tabWidget->setCurrentIndex(tabIndex); - m_tabWidget->setVisible(true); - m_tabWidget->repaint(); - } - - void AtomToolsMainWindow::RemoveTabForDocumentId(const AZ::Uuid& documentId) - { - // We are not blocking signals here because we want closing tabs to close the associated document - // and automatically select the next document. - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - m_tabWidget->removeTab(tabIndex); - m_tabWidget->setVisible(m_tabWidget->count() > 0); - m_tabWidget->repaint(); - break; - } - } - } - - void AtomToolsMainWindow::UpdateTabForDocumentId( - const AZ::Uuid& documentId, const AZStd::string& label, const AZStd::string& toolTip, bool isModified) - { - // Whenever a document is opened, saved, or modified we need to update the tab label - if (!documentId.IsNull()) - { - // Because tab order and indexes can change from user interactions, we cannot store a map - // between a tab index and document ID. - // We must iterate over all of the tabs to find the one associated with this document. - for (int tabIndex = 0; tabIndex < m_tabWidget->count(); ++tabIndex) - { - if (documentId == GetDocumentIdFromTab(tabIndex)) - { - // We use an asterisk prepended to the file name to denote modified document - // Appending is standard and preferred but the tabs elide from the - // end (instead of middle) and cut it off - const AZStd::string modifiedLabel = isModified ? "* " + label : label; - m_tabWidget->setTabText(tabIndex, modifiedLabel.c_str()); - m_tabWidget->setTabToolTip(tabIndex, toolTip.c_str()); - m_tabWidget->repaint(); - break; - } - } - } - } - - AZ::Uuid AtomToolsMainWindow::GetDocumentIdFromTab(const int tabIndex) const - { - const QVariant tabData = m_tabWidget->tabBar()->tabData(tabIndex); - if (!tabData.isNull()) - { - // We need to be able to convert between a UUID and a string to store and retrieve a document ID from the tab bar - const QString documentIdString = tabData.toString(); - const QByteArray documentIdBytes = documentIdString.toUtf8(); - const AZ::Uuid documentId(documentIdBytes.data(), documentIdBytes.size()); - return documentId; - } - return AZ::Uuid::CreateNull(); - } - - void AtomToolsMainWindow::OpenTabContextMenu() - { - } - - void AtomToolsMainWindow::SelectPreviousTab() - { - if (m_tabWidget->count() > 1) - { - // Adding count to wrap around when index <= 0 - m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + m_tabWidget->count() - 1) % m_tabWidget->count()); - } - } - - void AtomToolsMainWindow::SelectNextTab() - { - if (m_tabWidget->count() > 1) - { - m_tabWidget->setCurrentIndex((m_tabWidget->currentIndex() + 1) % m_tabWidget->count()); - } - } - void AtomToolsMainWindow::SetStatusMessage(const QString& message) { m_statusMessage->setText(QString("%1").arg(message)); @@ -261,4 +139,50 @@ namespace AtomToolsFramework { m_statusMessage->setText(QString("%1").arg(message)); } + + void AtomToolsMainWindow::AddCommonMenus() + { + m_menuFile = menuBar()->addMenu("&File"); + m_menuEdit = menuBar()->addMenu("&Edit"); + m_menuView = menuBar()->addMenu("&View"); + m_menuHelp = menuBar()->addMenu("&Help"); + + 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_menuFile->addAction("E&xit", [this]() { + close(); + }, QKeySequence::Quit); + + m_menuEdit->addAction("&Settings...", [this]() { + OpenSettings(); + }, QKeySequence::Preferences); + + m_menuHelp->addAction("&Help...", [this]() { + OpenHelp(); + }); + + m_menuHelp->addAction("&About...", [this]() { + OpenAbout(); + }); + } + + void AtomToolsMainWindow::OpenSettings() + { + } + + void AtomToolsMainWindow::OpenHelp() + { + } + + void AtomToolsMainWindow::OpenAbout() + { + } } // namespace AtomToolsFramework 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 diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index 8922591580..0be6925701 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -9,15 +9,9 @@ #include #include #include -#include -#include #include -#include -#include #include #include -#include -#include #include #include #include @@ -33,7 +27,6 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include -#include #include #include AZ_POP_DISABLE_WARNING @@ -41,7 +34,7 @@ AZ_POP_DISABLE_WARNING namespace MaterialEditor { MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */) - : AtomToolsFramework::AtomToolsMainWindow(parent) + : AtomToolsFramework::AtomToolsDocumentMainWindow(parent) { resize(1280, 1024); @@ -74,9 +67,6 @@ namespace MaterialEditor 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); @@ -105,16 +95,9 @@ namespace MaterialEditor 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(); @@ -146,16 +129,43 @@ namespace MaterialEditor m_materialViewport->UnlockRenderTargetSize(); } + bool MaterialEditorWindow::GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) + { + CreateMaterialDialog createDialog(this); + createDialog.adjustSize(); + + if (createDialog.exec() == QDialog::Accepted && + !createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() && + !createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty()) + { + savePath = createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData(); + openPath = createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(); + return true; + } + return false; + } + + bool MaterialEditorWindow::GetOpenDocumentParams(AZStd::string& openPath) + { + const AZStd::vector assetTypes = { azrtti_typeid() }; + openPath = AtomToolsFramework::GetOpenFileInfo(assetTypes).absoluteFilePath().toUtf8().constData(); + return !openPath.empty(); + } + + void MaterialEditorWindow::OpenSettings() + { + SettingsDialog dialog(this); + dialog.exec(); + } + + void MaterialEditorWindow::OpenHelp() + { + HelpDialog dialog(this); + dialog.exec(); + } + 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); @@ -163,368 +173,7 @@ namespace MaterialEditor 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()); - } + Base::closeEvent(closeEvent); } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h index b7d0cbf8da..bed2aa34e4 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h @@ -9,9 +9,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include -#include -#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include @@ -21,80 +19,36 @@ AZ_POP_DISABLE_WARNING 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. - */ + //! 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 + : public AtomToolsFramework::AtomToolsDocumentMainWindow { Q_OBJECT public: AZ_CLASS_ALLOCATOR(MaterialEditorWindow, AZ::SystemAllocator, 0); - using Base = AtomToolsFramework::AtomToolsMainWindow; + using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; MaterialEditorWindow(QWidget* parent = 0); - ~MaterialEditorWindow(); + ~MaterialEditorWindow() = default; - private: + protected: 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; + bool GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) override; + bool GetOpenDocumentParams(AZStd::string& openPath) override; + void OpenSettings() override; + void OpenHelp() 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/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index 6354f8beba..29dafe99fe 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -5,24 +5,15 @@ * 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 AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include #include #include #include @@ -32,7 +23,7 @@ AZ_POP_DISABLE_WARNING namespace ShaderManagementConsole { ShaderManagementConsoleWindow::ShaderManagementConsoleWindow(QWidget* parent /* = 0 */) - : AtomToolsFramework::AtomToolsMainWindow(parent) + : AtomToolsFramework::AtomToolsDocumentMainWindow(parent) { resize(1280, 1024); @@ -50,9 +41,6 @@ namespace ShaderManagementConsole m_toolBar->setObjectName("ToolBar"); addToolBar(m_toolBar); - CreateMenu(); - CreateTabBar(); - AddDockWidget("Asset Browser", new ShaderManagementConsoleBrowserWidget, Qt::BottomDockWidgetArea, Qt::Vertical); AddDockWidget("Python Terminal", new AzToolsFramework::CScriptTermDialog, Qt::BottomDockWidgetArea, Qt::Horizontal); @@ -61,356 +49,36 @@ namespace ShaderManagementConsole // Restore geometry and show the window mainWindowWrapper->showFromSettings(); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); + // Disable unused actions + m_actionNew->setVisible(false); + m_actionNew->setEnabled(false); + m_actionSaveAsChild->setVisible(false); + m_actionSaveAsChild->setEnabled(false); + OnDocumentOpened(AZ::Uuid::CreateNull()); } - ShaderManagementConsoleWindow::~ShaderManagementConsoleWindow() - { - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); - } - - void ShaderManagementConsoleWindow::closeEvent(QCloseEvent* closeEvent) - { - bool didClose = true; - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments); - if (!didClose) - { - closeEvent->ignore(); - return; - } - - AtomToolsFramework::AtomToolsMainWindowNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsMainWindowNotifications::OnMainWindowClosing); - } - - void ShaderManagementConsoleWindow::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, documentId]{ - // The document tab contains a table view. - auto contentWidget = new QTableView(centralWidget()); - contentWidget->setSelectionBehavior(QAbstractItemView::SelectRows); - contentWidget->setModel(CreateDocumentContent(documentId)); - return contentWidget; - }); - } - - UpdateTabForDocumentId(documentId, filename, absolutePath, isModified); - - const bool hasTabs = m_tabWidget->count() > 0; - - // Update menu options - 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_actionSaveAll->setEnabled(hasTabs); - - m_actionExit->setEnabled(true); - - m_actionUndo->setEnabled(canUndo); - m_actionRedo->setEnabled(canRedo); - m_actionSettings->setEnabled(false); - - m_actionAssetBrowser->setEnabled(true); - m_actionPythonTerminal->setEnabled(true); - m_actionPreviousTab->setEnabled(m_tabWidget->count() > 1); - m_actionNextTab->setEnabled(m_tabWidget->count() > 1); - - m_actionHelp->setEnabled(false); - m_actionAbout->setEnabled(false); - - activateWindow(); - raise(); - - const QString documentPath = GetDocumentPath(documentId); - if (!documentPath.isEmpty()) - { - SetStatusMessage(tr("Document opened: %1").arg(documentPath)); - } - } - - void ShaderManagementConsoleWindow::OnDocumentClosed(const AZ::Uuid& documentId) - { - RemoveTabForDocumentId(documentId); - SetStatusMessage(tr("Document closed: %1").arg(GetDocumentPath(documentId))); - } - - void ShaderManagementConsoleWindow::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 ShaderManagementConsoleWindow::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 ShaderManagementConsoleWindow::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 ShaderManagementConsoleWindow::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_actionOpen = m_menuFile->addAction("&Open...", [this]() { - const AZStd::vector assetTypes = { - }; - - 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_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]() { - }, QKeySequence::Preferences); - m_actionSettings->setEnabled(false); - - m_menuView = menuBar()->addMenu("&View"); - - m_actionAssetBrowser = m_menuView->addAction("&Asset Browser", [this]() { - const AZStd::string label = "Asset Browser"; - SetDockWidgetVisible(label, !IsDockWidgetVisible(label)); - }); - - m_actionPythonTerminal = m_menuView->addAction("Python &Terminal", [this]() { - const AZStd::string label = "Python Terminal"; - 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]() { - }); - - m_actionAbout = m_menuHelp->addAction("&About...", [this]() { - }); - } - - void ShaderManagementConsoleWindow::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 ShaderManagementConsoleWindow::GetDocumentPath(const AZ::Uuid& documentId) const - { - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Handler::GetAbsolutePath); - return absolutePath.c_str(); - } - - void ShaderManagementConsoleWindow::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()); - } - } - - QStandardItemModel* ShaderManagementConsoleWindow::CreateDocumentContent(const AZ::Uuid& documentId) + QWidget* ShaderManagementConsoleWindow::CreateDocumentTabView(const AZ::Uuid& documentId) { AZStd::unordered_set optionNames; size_t shaderOptionCount = 0; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderOptionCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderOptionCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount); for (size_t optionIndex = 0; optionIndex < shaderOptionCount; ++optionIndex) { AZ::RPI::ShaderOptionDescriptor shaderOptionDesc; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderOptionDesc, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor, optionIndex); const char* optionName = shaderOptionDesc.GetName().GetCStr(); optionNames.insert(optionName); } size_t shaderVariantCount = 0; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderVariantCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderVariantCount, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount); auto model = new QStandardItemModel(); model->setRowCount(static_cast(shaderVariantCount)); @@ -425,7 +93,8 @@ namespace ShaderManagementConsole for (int variantIndex = 0; variantIndex < shaderVariantCount; ++variantIndex) { AZ::RPI::ShaderVariantListSourceData::VariantInfo shaderVariantInfo; - ShaderManagementConsoleDocumentRequestBus::EventResult(shaderVariantInfo, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo, variantIndex); + ShaderManagementConsoleDocumentRequestBus::EventResult( + shaderVariantInfo, documentId, &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo, variantIndex); model->setHeaderData(variantIndex, Qt::Vertical, QString::number(variantIndex)); @@ -442,7 +111,11 @@ namespace ShaderManagementConsole } } - return model; + // The document tab contains a table view. + auto contentWidget = new QTableView(centralWidget()); + contentWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + contentWidget->setModel(model); + return contentWidget; } } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h index 2b682f6c09..3ba122674a 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h @@ -11,9 +11,7 @@ #if !defined(Q_MOC_RUN) #include #include -#include -#include -#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include @@ -25,69 +23,23 @@ AZ_POP_DISABLE_WARNING namespace ShaderManagementConsole { - /** - * ShaderManagementConsoleWindow 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... - */ + //! ShaderManagementConsoleWindow 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... class ShaderManagementConsoleWindow - : public AtomToolsFramework::AtomToolsMainWindow - , private AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + : public AtomToolsFramework::AtomToolsDocumentMainWindow { Q_OBJECT public: AZ_CLASS_ALLOCATOR(ShaderManagementConsoleWindow, AZ::SystemAllocator, 0); - using Base = AtomToolsFramework::AtomToolsMainWindow; + using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; ShaderManagementConsoleWindow(QWidget* parent = 0); - ~ShaderManagementConsoleWindow(); + ~ShaderManagementConsoleWindow() = default; - private: - // 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; - - QStandardItemModel* CreateDocumentContent(const AZ::Uuid& documentId); + protected: + QWidget* CreateDocumentTabView(const AZ::Uuid& documentId) override; ShaderManagementConsoleToolBar* m_toolBar = nullptr; - - QMenu* m_menuFile = {}; - QMenu* m_menuNew = {}; - QAction* m_actionOpen = {}; - QAction* m_actionOpenRecent = {}; - QAction* m_actionClose = {}; - QAction* m_actionCloseAll = {}; - QAction* m_actionCloseOthers = {}; - QAction* m_actionSave = {}; - QAction* m_actionSaveAsCopy = {}; - 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_actionPythonTerminal = {}; - QAction* m_actionNextTab = {}; - QAction* m_actionPreviousTab = {}; - - QMenu* m_menuHelp = {}; - QAction* m_actionHelp = {}; - QAction* m_actionAbout = {}; }; } // namespace ShaderManagementConsole