Added save state keys to most of the RPEs in the material editor and component to save expand/collapse state

Saving main window fancy docking state so all of the dock widgets save/restore visibly and positioning

Added window decoration wrapper inside material editor main window for saving/restoring window position, size, state

Added object names to several QT widgets so that their state could be captured and restored
This commit is contained in:
guthadam
2021-05-07 20:16:05 -05:00
parent 14e992c7e1
commit e9165ed911
10 changed files with 111 additions and 73 deletions
@@ -44,6 +44,7 @@ namespace AtomToolsFramework
const AZ::Uuid& instanceClassId,
AzToolsFramework::IPropertyEditorNotify* instanceNotificationHandler = {},
QWidget* parent = {},
const AZ::u32 saveStateKey = {},
const AzToolsFramework::InstanceDataHierarchy::ValueComparisonFunction& valueComparisonFunction = {});
void Refresh() override;
@@ -22,6 +22,7 @@ namespace AtomToolsFramework
const AZ::Uuid& instanceClassId,
AzToolsFramework::IPropertyEditorNotify* instanceNotificationHandler,
QWidget* parent,
const AZ::u32 saveStateKey,
const AzToolsFramework::InstanceDataHierarchy::ValueComparisonFunction& valueComparisonFunction)
: InspectorGroupWidget(parent)
{
@@ -37,6 +38,7 @@ namespace AtomToolsFramework
m_propertyEditor->SetHideRootProperties(true);
m_propertyEditor->SetAutoResizeLabels(true);
m_propertyEditor->SetValueComparisonFunction(valueComparisonFunction);
m_propertyEditor->SetSavedStateKey(saveStateKey);
m_propertyEditor->Setup(context, instanceNotificationHandler, false);
m_propertyEditor->AddInstance(instance, instanceClassId, nullptr, instanceToCompare);
m_propertyEditor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
@@ -29,9 +29,6 @@ namespace MaterialEditor
static void Reflect(AZ::ReflectContext* context);
bool m_enableGrid = true;
bool m_enableShadowCatcher = true;
bool m_enableAlternateSkybox = false;
float m_fieldOfView = 90.0f;
AZStd::vector<char> m_mainWindowState;
};
} // namespace MaterialEditor
@@ -10,46 +10,50 @@
*
*/
#include <AzFramework/Application/Application.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Utilities/QtPluginPaths.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
#include <AzToolsFramework/UI/UICore/QWidgetSavedState.h>
#include <AtomToolsFramework/Util/Util.h>
#include <Atom/Document/MaterialDocumentRequestBus.h>
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
#include <Atom/Window/MaterialEditorWindowNotificationBus.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/Document/MaterialDocumentRequestBus.h>
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
#include <Atom/Window/MaterialEditorWindowNotificationBus.h>
#include <Atom/Window/MaterialEditorWindowSettings.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzFramework/Application/Application.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
#include <AzQtComponents/Utilities/QtPluginPaths.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
#include <Viewport/MaterialViewportWidget.h>
#include <Viewport/MaterialViewportWidget.h>
#include <Window/MaterialEditorWindow.h>
#include <Window/PerformanceMonitor/PerformanceMonitorWidget.h>
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
#include <Window/HelpDialog/HelpDialog.h>
#include <Window/MaterialBrowserWidget.h>
#include <Window/MaterialEditorWindow.h>
#include <Window/MaterialInspector/MaterialInspector.h>
#include <Window/PerformanceMonitor/PerformanceMonitorWidget.h>
#include <Window/ViewportSettingsInspector/ViewportSettingsInspector.h>
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QApplication>
#include <QByteArray>
#include <QCloseEvent>
#include <QVariant>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QWindow>
#include <QVBoxLayout>
#include <QVariant>
#include <QWindow>
AZ_POP_DISABLE_WARNING
namespace MaterialEditor
@@ -57,6 +61,15 @@ namespace MaterialEditor
MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */)
: AzQtComponents::DockMainWindow(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("amazon", "MaterialEditor", "mainWindowGeometry");
// set the style sheet for RPE highlighting and other styling
AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral(":/MaterialEditor.qss"));
QApplication::setWindowIcon(QIcon(":/Icons/materialtype.svg"));
@@ -75,6 +88,7 @@ namespace MaterialEditor
m_advancedDockManager = new AzQtComponents::FancyDocking(this);
setObjectName("MaterialEditorWindow");
setDockNestingEnabled(true);
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
@@ -82,17 +96,21 @@ namespace MaterialEditor
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
m_menuBar = new QMenuBar(this);
m_menuBar->setObjectName("MenuBar");
setMenuBar(m_menuBar);
m_toolBar = new MaterialEditorToolBar(this);
m_toolBar->setObjectName("ToolBar");
addToolBar(m_toolBar);
m_centralWidget = new QWidget(this);
m_tabWidget = new AzQtComponents::TabWidget(m_centralWidget);
m_tabWidget->setObjectName("TabWidget");
m_tabWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred);
m_tabWidget->setContentsMargins(0, 0, 0, 0);
m_materialViewport = new MaterialViewportWidget(m_centralWidget);
m_materialViewport->setObjectName("Viewport");
m_materialViewport->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
QVBoxLayout* vl = new QVBoxLayout(m_centralWidget);
@@ -104,7 +122,8 @@ namespace MaterialEditor
setCentralWidget(m_centralWidget);
m_statusBar = new StatusBarWidget(this);
this->statusBar()->addPermanentWidget(m_statusBar, 1);
m_statusBar->setObjectName("StatusBar");
statusBar()->addPermanentWidget(m_statusBar, 1);
SetupMenu();
SetupTabs();
@@ -119,27 +138,26 @@ namespace MaterialEditor
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<MaterialEditorWindowSettings>(
AZ::Crc32("MaterialEditorwindowSettings"), AZ::UserSettings::CT_GLOBAL);
if (!windowSettings->m_mainWindowState.empty())
{
QByteArray windowState(windowSettings->m_mainWindowState.data(), windowSettings->m_mainWindowState.size());
m_advancedDockManager->restoreState(windowState);
}
MaterialEditorWindowRequestBus::Handler::BusConnect();
MaterialDocumentNotificationBus::Handler::BusConnect();
OnDocumentOpened(AZ::Uuid::CreateNull());
auto windowState = AZ::UserSettings::Find<AzToolsFramework::QWidgetSavedState>(
AZ::Crc32("MaterialEditorWindowState"), AZ::UserSettings::CT_GLOBAL);
if (windowState)
{
windowState->RestoreGeometry(this);
}
}
MaterialEditorWindow::~MaterialEditorWindow()
{
auto windowState = AZ::UserSettings::CreateFind<AzToolsFramework::QWidgetSavedState>(
AZ::Crc32("MaterialEditorWindowState"), AZ::UserSettings::CT_GLOBAL);
if (windowState)
{
windowState->CaptureGeometry(this);
}
MaterialDocumentNotificationBus::Handler::BusDisconnect();
MaterialEditorWindowRequestBus::Handler::BusDisconnect();
}
@@ -159,8 +177,9 @@ namespace MaterialEditor
}
auto dockWidget = new AzQtComponents::StyledDockWidget(name.c_str());
dockWidget->setObjectName(name.c_str());
dockWidget->setObjectName(QString("%1_DockWidget").arg(name.c_str()));
dockWidget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
widget->setObjectName(name.c_str());
widget->setParent(dockWidget);
widget->setMinimumSize(QSize(300, 300));
dockWidget->setWidget(widget);
@@ -218,15 +237,16 @@ namespace MaterialEditor
QSize requestedWindowSize = size() + offset;
resize(requestedWindowSize);
AZ_Assert(m_materialViewport->size() == requestedViewportSize,
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());
requestedViewportSize.width(), requestedViewportSize.height(), m_materialViewport->size().width(),
m_materialViewport->size().height());
QSize newDeviceSize = m_materialViewport->size();
AZ_Warning("Material Editor", newDeviceSize.width() == width && newDeviceSize.height() == height,
"Resizing the window did not give the expected frame size. Requested %d x %d but got %d x %d.",
width, height,
AZ_Warning(
"Material Editor", newDeviceSize.width() == width && 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());
}
@@ -250,6 +270,13 @@ namespace MaterialEditor
return;
}
// Capture docking state before shutdown
auto windowSettings = AZ::UserSettings::CreateFind<MaterialEditorWindowSettings>(
AZ::Crc32("MaterialEditorwindowSettings"), AZ::UserSettings::CT_GLOBAL);
QByteArray windowState = m_advancedDockManager->saveState();
windowSettings->m_mainWindowState.assign(windowState.begin(), windowState.end());
MaterialEditorWindowNotificationBus::Broadcast(&MaterialEditorWindowNotifications::OnMaterialEditorWindowClosing);
}
@@ -101,7 +101,6 @@ namespace MaterialEditor
m_materialEditorBrowserInteractions.reset(aznew MaterialEditorBrowserInteractions);
m_window.reset(aznew MaterialEditorWindow);
m_window->show();
}
void MaterialEditorWindowComponent::DestroyMaterialEditorWindow()
@@ -22,11 +22,8 @@ namespace MaterialEditor
{
serializeContext->Class<MaterialEditorWindowSettings, AZ::UserSettings>()
->Version(1)
->Field("enableGrid", &MaterialEditorWindowSettings::m_enableGrid)
->Field("enableShadowCatcher", &MaterialEditorWindowSettings::m_enableShadowCatcher)
->Field("enableAlternateSkybox", &MaterialEditorWindowSettings::m_enableAlternateSkybox)
->Field("fieldOfView", &MaterialEditorWindowSettings::m_fieldOfView)
;
->Field("mainWindowState", &MaterialEditorWindowSettings::m_mainWindowState)
;
if (auto editContext = serializeContext->GetEditContext())
{
@@ -34,12 +31,6 @@ namespace MaterialEditor
"MaterialEditorWindowSettings", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialEditorWindowSettings::m_enableGrid, "Enable Grid", "")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialEditorWindowSettings::m_enableShadowCatcher, "Enable Shadow Catcher", "")
->DataElement(AZ::Edit::UIHandlers::Default, &MaterialEditorWindowSettings::m_enableAlternateSkybox, "Enable Alternate Skybox", "")
->DataElement(AZ::Edit::UIHandlers::Slider, &MaterialEditorWindowSettings::m_fieldOfView, "Field Of View", "")
->Attribute(AZ::Edit::Attributes::Min, 60.0f)
->Attribute(AZ::Edit::Attributes::Max, 120.0f)
;
}
}
@@ -52,10 +43,6 @@ namespace MaterialEditor
->Attribute(AZ::Script::Attributes::Module, "render")
->Constructor()
->Constructor<const MaterialEditorWindowSettings&>()
->Property("enableGrid", BehaviorValueProperty(&MaterialEditorWindowSettings::m_enableGrid))
->Property("enableShadowCatcher", BehaviorValueProperty(&MaterialEditorWindowSettings::m_enableShadowCatcher))
->Property("enableAlternateSkybox", BehaviorValueProperty(&MaterialEditorWindowSettings::m_enableAlternateSkybox))
->Property("fieldOfView", BehaviorValueProperty(&MaterialEditorWindowSettings::m_fieldOfView))
;
}
}
@@ -39,6 +39,7 @@ namespace MaterialEditor
void MaterialInspector::Reset()
{
m_documentPath.clear();
m_documentId = AZ::Uuid::CreateNull();
m_groups = {};
@@ -55,6 +56,8 @@ namespace MaterialEditor
bool isOpen = false;
MaterialDocumentRequestBus::EventResult(isOpen, m_documentId, &MaterialDocumentRequestBus::Events::IsOpen);
MaterialDocumentRequestBus::EventResult(m_documentPath, m_documentId, &MaterialDocumentRequestBus::Events::GetAbsolutePath);
if (!m_documentId.IsNull() && isOpen)
{
// Create the top group for displaying details about the material
@@ -89,7 +92,10 @@ namespace MaterialEditor
group.m_properties.push_back(property);
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(&group, &group, group.TYPEINFO_Uuid(), this, this,
const AZ::Crc32 saveStateKey(
AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupDisplayName.c_str()));
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
[this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
AZ_UNUSED(source);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
@@ -121,7 +127,10 @@ namespace MaterialEditor
}
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(&group, &group, group.TYPEINFO_Uuid(), this, this,
const AZ::Crc32 saveStateKey(
AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupDisplayName.c_str()));
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
[this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
AZ_UNUSED(source);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
@@ -156,7 +165,10 @@ namespace MaterialEditor
}
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(&group, &group, group.TYPEINFO_Uuid(), this, this,
const AZ::Crc32 saveStateKey(
AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupDisplayName.c_str()));
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
[this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
AZ_UNUSED(source);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
@@ -64,6 +64,7 @@ namespace MaterialEditor
const AtomToolsFramework::DynamicProperty* m_activeProperty = nullptr;
AZ::Uuid m_documentId = AZ::Uuid::CreateNull();
AZStd::string m_documentPath;
AZStd::unordered_map<AZStd::string, AtomToolsFramework::DynamicPropertyGroup> m_groups;
};
} // namespace MaterialEditor
@@ -58,9 +58,11 @@ namespace MaterialEditor
const AZStd::string groupDisplayName = "General";
const AZStd::string groupDescription = "General";
const AZ::Crc32 saveStateKey(AZStd::string::format("ViewportSettingsInspector::GeneralGroup"));
AddGroup(
groupNameId, groupDisplayName, groupDescription,
new AtomToolsFramework::InspectorPropertyGroupWidget(m_viewportSettings.get(), nullptr, m_viewportSettings->TYPEINFO_Uuid(), this));
new AtomToolsFramework::InspectorPropertyGroupWidget(
m_viewportSettings.get(), nullptr, m_viewportSettings->TYPEINFO_Uuid(), this, this, saveStateKey));
}
void ViewportSettingsInspector::AddModelGroup()
@@ -92,8 +94,9 @@ namespace MaterialEditor
if (m_modelPreset)
{
const AZ::Crc32 saveStateKey(AZStd::string::format("ViewportSettingsInspector::ModelGroup"));
auto inspectorWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
m_modelPreset.get(), nullptr, m_modelPreset.get()->TYPEINFO_Uuid(), this, groupWidget);
m_modelPreset.get(), nullptr, m_modelPreset.get()->TYPEINFO_Uuid(), this, groupWidget, saveStateKey);
groupWidget->layout()->addWidget(inspectorWidget);
}
@@ -179,8 +182,9 @@ namespace MaterialEditor
if (m_lightingPreset)
{
const AZ::Crc32 saveStateKey(AZStd::string::format("ViewportSettingsInspector::LightingGroup"));
auto inspectorWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
m_lightingPreset.get(), nullptr, m_lightingPreset.get()->TYPEINFO_Uuid(), this, groupWidget);
m_lightingPreset.get(), nullptr, m_lightingPreset.get()->TYPEINFO_Uuid(), this, groupWidget, saveStateKey);
groupWidget->layout()->addWidget(inspectorWidget);
}
@@ -213,7 +213,11 @@ namespace AZ
}
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(&group, &group, group.TYPEINFO_Uuid(), this, this,
const AZ::Crc32 saveStateKey(AZStd::string::format(
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_materialAssetId.ToString<AZStd::string>().c_str(),
groupDisplayName.c_str()));
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
[this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
AZ_UNUSED(source);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);
@@ -262,7 +266,11 @@ namespace AZ
}
// Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(&group, &group, group.TYPEINFO_Uuid(), this, this,
const AZ::Crc32 saveStateKey(AZStd::string::format(
"MaterialPropertyInspector::PropertyGroup::%s::%s", m_materialAssetId.ToString<AZStd::string>().c_str(),
groupDisplayName.c_str()));
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
&group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey,
[this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {
AZ_UNUSED(source);
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target);