diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h index bba299187b..931f88d0eb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h @@ -29,11 +29,13 @@ namespace AtomToolsFramework AZ_CLASS_ALLOCATOR(InspectorGroupHeaderWidget, AZ::SystemAllocator, 0); explicit InspectorGroupHeaderWidget(QWidget* parent = nullptr); - void SetExpanded(bool expanded); + void SetExpanded(bool expand); bool IsExpanded() const; Q_SIGNALS: void clicked(QMouseEvent* event); + void expanded(); + void collapsed(); protected: void mousePressEvent(QMouseEvent* event) override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h index 81b512faf2..e76837137a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorRequestBus.h @@ -56,6 +56,15 @@ namespace AtomToolsFramework //! Calls Rebuild for all InspectorGroupWidget, allowing for destructive UI changes virtual void RebuildAll() = 0; + //! Expands a specific group + virtual void ExpandGroup(const AZStd::string& groupNameId) = 0; + + //! Collapses a specific group + virtual void CollapseGroup(const AZStd::string& groupNameId) = 0; + + //! Checks the expansion state of a specific group + virtual bool IsGroupExpanded(const AZStd::string& groupNameId) const = 0; + //! Expands all groups and headers virtual void ExpandAll() = 0; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h index b0932b3b04..5fb0b731d6 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Inspector/InspectorWidget.h @@ -63,15 +63,22 @@ namespace AtomToolsFramework void RefreshAll() override; void RebuildAll() override; + void ExpandGroup(const AZStd::string& groupNameId) override; + void CollapseGroup(const AZStd::string& groupNameId) override; + bool IsGroupExpanded(const AZStd::string& groupNameId) const override; + void ExpandAll() override; void CollapseAll() override; - private: - void OnHeaderClicked(QMouseEvent* event, InspectorGroupHeaderWidget* groupHeader, QWidget* groupWidget); + protected: + virtual bool ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const; + virtual void OnGroupExpanded(const AZStd::string& groupNameId); + virtual void OnGroupCollapsed(const AZStd::string& groupNameId); + virtual void OnHeaderClicked(const AZStd::string& groupNameId, QMouseEvent* event); + private: QVBoxLayout* m_layout = nullptr; QScopedPointer m_ui; - AZStd::vector m_headers; - AZStd::vector m_groups; + AZStd::unordered_map> m_groups; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp index 41cc1e4a50..666f8f6c93 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorGroupHeaderWidget.cpp @@ -33,10 +33,21 @@ namespace AtomToolsFramework setMargin(0); } - void InspectorGroupHeaderWidget::SetExpanded(bool expanded) + void InspectorGroupHeaderWidget::SetExpanded(bool expand) { - m_expanded = expanded; - update(); + if (m_expanded != expand) + { + m_expanded = expand; + if (m_expanded) + { + emit expanded(); + } + else + { + emit collapsed(); + } + update(); + } } bool InspectorGroupHeaderWidget::IsExpanded() const diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp index ec5f9893bd..0259120d9b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Inspector/InspectorWidget.cpp @@ -39,7 +39,6 @@ namespace AtomToolsFramework m_layout = new QVBoxLayout(m_ui->m_propertyContent); m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setSpacing(0); - m_headers.clear(); m_groups.clear(); } @@ -70,16 +69,27 @@ namespace AtomToolsFramework groupHeader->setText(groupDisplayName.c_str()); groupHeader->setToolTip(groupDescription.c_str()); m_layout->addWidget(groupHeader); - m_headers.push_back(groupHeader); groupWidget->setObjectName(groupNameId.c_str()); groupWidget->setParent(m_ui->m_propertyContent); m_layout->addWidget(groupWidget); - m_groups.push_back(groupWidget); - connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupHeader, groupWidget](QMouseEvent* event) { - OnHeaderClicked(event, groupHeader, groupWidget); + m_groups[groupNameId] = AZStd::make_pair(groupHeader, groupWidget); + + connect(groupHeader, &InspectorGroupHeaderWidget::clicked, this, [this, groupNameId](QMouseEvent* event) { + OnHeaderClicked(groupNameId, event); }); + connect(groupHeader, &InspectorGroupHeaderWidget::expanded, this, [this, groupNameId]() { OnGroupExpanded(groupNameId); }); + connect(groupHeader, &InspectorGroupHeaderWidget::collapsed, this, [this, groupNameId]() { OnGroupCollapsed(groupNameId); }); + + if (ShouldGroupAutoExpanded(groupNameId)) + { + ExpandGroup(groupNameId); + } + else + { + CollapseGroup(groupNameId); + } } void InspectorWidget::RefreshGroup(const AZStd::string& groupNameId) @@ -114,50 +124,86 @@ namespace AtomToolsFramework } } + void InspectorWidget::ExpandGroup(const AZStd::string& groupNameId) + { + auto groupItr = m_groups.find(groupNameId); + if (groupItr != m_groups.end()) + { + groupItr->second.first->SetExpanded(true); + groupItr->second.second->setVisible(true); + } + } + + void InspectorWidget::CollapseGroup(const AZStd::string& groupNameId) + { + auto groupItr = m_groups.find(groupNameId); + if (groupItr != m_groups.end()) + { + groupItr->second.first->SetExpanded(false); + groupItr->second.second->setVisible(false); + } + } + + bool InspectorWidget::IsGroupExpanded(const AZStd::string& groupNameId) const + { + auto groupItr = m_groups.find(groupNameId); + return groupItr != m_groups.end() ? groupItr->second.first->IsExpanded() : false; + } + void InspectorWidget::ExpandAll() { - for (auto headerWidget : m_headers) + for (auto& groupPair : m_groups) { - headerWidget->SetExpanded(true); - } - for (auto groupWidget : m_groups) - { - groupWidget->setVisible(true); + groupPair.second.first->SetExpanded(true); + groupPair.second.second->setVisible(true); } } void InspectorWidget::CollapseAll() { - for (auto headerWidget : m_headers) + for (auto& groupPair : m_groups) { - headerWidget->SetExpanded(false); - } - for (auto groupWidget : m_groups) - { - groupWidget->setVisible(false); + groupPair.second.first->SetExpanded(false); + groupPair.second.second->setVisible(false); } } - void InspectorWidget::OnHeaderClicked(QMouseEvent* event, InspectorGroupHeaderWidget* groupHeader, QWidget* groupWidget) + bool InspectorWidget::ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const + { + AZ_UNUSED(groupNameId); + return true; + } + + void InspectorWidget::OnGroupExpanded(const AZStd::string& groupNameId) + { + AZ_UNUSED(groupNameId); + } + + void InspectorWidget::OnGroupCollapsed(const AZStd::string& groupNameId) + { + AZ_UNUSED(groupNameId); + } + + void InspectorWidget::OnHeaderClicked(const AZStd::string& groupNameId, QMouseEvent* event) { if (event->button() == Qt::MouseButton::LeftButton) { - groupHeader->SetExpanded(!groupHeader->IsExpanded()); - groupWidget->setVisible(groupHeader->IsExpanded()); + if (!IsGroupExpanded(groupNameId)) + { + ExpandGroup(groupNameId); + } + else + { + CollapseGroup(groupNameId); + } return; } if (event->button() == Qt::MouseButton::RightButton) { QMenu menu; - menu.addAction("Expand", [groupHeader, groupWidget]() { - groupHeader->SetExpanded(true); - groupWidget->setVisible(true); - })->setEnabled(!groupHeader->IsExpanded()); - menu.addAction("Collapse", [groupHeader, groupWidget]() { - groupHeader->SetExpanded(false); - groupWidget->setVisible(false); - })->setEnabled(groupHeader->IsExpanded()); + menu.addAction("Expand", [this, groupNameId]() { ExpandGroup(groupNameId); })->setEnabled(!IsGroupExpanded(groupNameId)); + menu.addAction("Collapse", [this, groupNameId]() { CollapseGroup(groupNameId); })->setEnabled(IsGroupExpanded(groupNameId)); menu.addAction("Expand All", [this]() { ExpandAll(); }); menu.addAction("Collapse All", [this]() { CollapseAll(); }); menu.exec(event->globalPos()); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h index b28d4d662b..9ff03038f7 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Window/MaterialEditorWindowSettings.h @@ -30,5 +30,6 @@ namespace MaterialEditor static void Reflect(AZ::ReflectContext* context); AZStd::vector m_mainWindowState; + AZStd::unordered_set m_inspectorCollapsedGroups; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index e62dae2986..075a58c532 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -143,7 +143,7 @@ namespace MaterialEditor // Restore additional state for docked windows auto windowSettings = AZ::UserSettings::CreateFind( - AZ::Crc32("MaterialEditorwindowSettings"), AZ::UserSettings::CT_GLOBAL); + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); if (!windowSettings->m_mainWindowState.empty()) { @@ -272,7 +272,7 @@ namespace MaterialEditor // Capture docking state before shutdown auto windowSettings = AZ::UserSettings::CreateFind( - AZ::Crc32("MaterialEditorwindowSettings"), AZ::UserSettings::CT_GLOBAL); + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); QByteArray windowState = m_advancedDockManager->saveState(); windowSettings->m_mainWindowState.assign(windowState.begin(), windowState.end()); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowSettings.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowSettings.cpp index 5ea23de8c6..da04e2ea20 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowSettings.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindowSettings.cpp @@ -23,6 +23,7 @@ namespace MaterialEditor serializeContext->Class() ->Version(1) ->Field("mainWindowState", &MaterialEditorWindowSettings::m_mainWindowState) + ->Field("inspectorCollapsedGroups", &MaterialEditorWindowSettings::m_inspectorCollapsedGroups) ; if (auto editContext = serializeContext->GetEditContext()) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index dffbd43702..2c334ad3b7 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -21,13 +21,17 @@ #include #include -#include +#include +#include namespace MaterialEditor { MaterialInspector::MaterialInspector(QWidget* parent) : AtomToolsFramework::InspectorWidget(parent) { + m_windowSettings = AZ::UserSettings::CreateFind( + AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL); + MaterialDocumentNotificationBus::Handler::BusConnect(); } @@ -47,6 +51,22 @@ namespace MaterialEditor AtomToolsFramework::InspectorWidget::Reset(); } + bool MaterialInspector::ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const + { + auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupNameId)); + return stateItr == m_windowSettings->m_inspectorCollapsedGroups.end(); + } + + void MaterialInspector::OnGroupExpanded(const AZStd::string& groupNameId) + { + m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupNameId)); + } + + void MaterialInspector::OnGroupCollapsed(const AZStd::string& groupNameId) + { + m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupNameId)); + } + void MaterialInspector::OnDocumentOpened(const AZ::Uuid& documentId) { AddGroupsBegin(); @@ -73,6 +93,20 @@ namespace MaterialEditor AddGroupsEnd(); } + AZ::Crc32 MaterialInspector::GetGroupSaveStateKey(const AZStd::string& groupNameId) const + { + return AZ::Crc32( + AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupNameId.c_str())); + } + + bool MaterialInspector::CompareInstanceNodeProperties( + const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) const + { + AZ_UNUSED(source); + const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(target); + return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue); + } + void MaterialInspector::AddDetailsGroup() { const AZ::RPI::MaterialTypeSourceData* materialTypeSourceData = nullptr; @@ -92,15 +126,9 @@ 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 - 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); - return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue); - }); + &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId), + [this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); }); AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); } @@ -127,15 +155,9 @@ namespace MaterialEditor } // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties - 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); - return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue); - }); + &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId), + [this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); }); AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); } @@ -165,15 +187,9 @@ namespace MaterialEditor } // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties - 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); - return property && AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue); - }); + &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupNameId), + [this](const auto source, const auto target) { return CompareInstanceNodeProperties(source, target); }); AddGroup(groupNameId, groupDisplayName, groupDescription, propertyGroupWidget); } } @@ -270,4 +286,4 @@ namespace MaterialEditor } } // namespace MaterialEditor -#include +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h index a7a4dddbaa..b2900b979c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h @@ -41,7 +41,16 @@ namespace MaterialEditor // AtomToolsFramework::InspectorRequestBus::Handler overrides... void Reset() override; + protected: + bool ShouldGroupAutoExpanded(const AZStd::string& groupNameId) const override; + void OnGroupExpanded(const AZStd::string& groupNameId) override; + void OnGroupCollapsed(const AZStd::string& groupNameId) override; + private: + AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupNameId) const; + bool CompareInstanceNodeProperties( + const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) const; + void AddDetailsGroup(); void AddUvNamesGroup(); void AddPropertiesGroup(); @@ -66,5 +75,6 @@ namespace MaterialEditor AZ::Uuid m_documentId = AZ::Uuid::CreateNull(); AZStd::string m_documentPath; AZStd::unordered_map m_groups; + AZStd::intrusive_ptr m_windowSettings; }; } // namespace MaterialEditor diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 1ae0610169..7f54e386fc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -215,7 +215,7 @@ namespace AZ // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties const AZ::Crc32 saveStateKey(AZStd::string::format( "MaterialPropertyInspector::PropertyGroup::%s::%s", m_materialAssetId.ToString().c_str(), - groupDisplayName.c_str())); + groupNameId.c_str())); auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( &group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey, [this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) { @@ -268,7 +268,7 @@ namespace AZ // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties const AZ::Crc32 saveStateKey(AZStd::string::format( "MaterialPropertyInspector::PropertyGroup::%s::%s", m_materialAssetId.ToString().c_str(), - groupDisplayName.c_str())); + groupNameId.c_str())); auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( &group, &group, group.TYPEINFO_Uuid(), this, this, saveStateKey, [this](const AzToolsFramework::InstanceDataNode* source, const AzToolsFramework::InstanceDataNode* target) {