Atom Tools: Saving tool settings, made inspector configurable, moved to ATF

Changed material editor inspector into generic, configurable, document inspector and moved to atom tools framework
Renamed atom tools framework settings registry utility functions
Added more settings registry utility functions to get, set, and save values and objects
Added saving tool settings to atom tools application

Signed-off-by: Guthrie Adams <guthadam@amazon.com>
development
Guthrie Adams 4 years ago
parent c0299f0ad7
commit 01786b2966

@ -0,0 +1,72 @@
/*
* 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 <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
#endif
namespace AtomToolsFramework
{
//! This is a specialized inspector widget that populates itself by inspecting document reflected object info.
//! Each element of an AtomToolsDocument object info vector will be displayed in a collapsible RPE group in the inspector.
//! Property changes emitted from each RPE will be tracked and used to signal undo/redo events in the document.
class AtomToolsDocumentInspector
: public InspectorWidget
, public AtomToolsDocumentNotificationBus::Handler
, public AzToolsFramework::IPropertyEditorNotify
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(AtomToolsDocumentInspector, AZ::SystemAllocator, 0);
AtomToolsDocumentInspector(const AZ::Crc32& toolId, QWidget* parent = nullptr);
~AtomToolsDocumentInspector() override;
//! Set the ID of the document that will be used to populate the inspector
void SetDocumentId(const AZ::Uuid& documentId);
//! Set a prefix string for storing registry settings
void SetDocumentSettingsPrefix(const AZStd::string& prefix);
using NodeIndicatorFunction = AZStd::function<const char*(const AzToolsFramework::InstanceDataNode*)>;
//! Set a function that will be used to determine what, if any, icon should be displayed next to a property in the inspector
void SetIndicatorFunction(const NodeIndicatorFunction& indicatorFunction);
// InspectorRequestBus::Handler overrides...
void Reset() override;
private:
// AtomToolsDocumentNotificationBus::Handler implementation
void OnDocumentObjectInfoChanged(const AZ::Uuid& documentId, const DocumentObjectInfo& objectInfo, bool rebuilt) override;
// AzToolsFramework::IPropertyEditorNotify overrides...
void BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) override;
void AfterPropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode) override;
void SealUndoStack() override {}
void RequestPropertyContextMenu([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, const QPoint&) override {}
void PropertySelectionChanged([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, bool) override {}
const AZ::Crc32 m_toolId = {};
bool m_editInProgress = {};
AZ::Uuid m_documentId = AZ::Uuid::CreateNull();
NodeIndicatorFunction m_nodeIndicatorFunction;
AZStd::string m_documentSettingsPrefix = "/O3DE/AtomToolsFramework/AtomToolsDocumentInspector";
};
} // namespace AtomToolsFramework

@ -9,8 +9,12 @@
#pragma once #pragma once
#if !defined(Q_MOC_RUN) #if !defined(Q_MOC_RUN)
#include <AzCore/Memory/SystemAllocator.h>
#include <AtomToolsFramework/Inspector/InspectorRequestBus.h> #include <AtomToolsFramework/Inspector/InspectorRequestBus.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/string/string.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QVBoxLayout> #include <QVBoxLayout>
@ -36,8 +40,10 @@ namespace AtomToolsFramework
Q_OBJECT Q_OBJECT
public: public:
AZ_CLASS_ALLOCATOR(InspectorWidget, AZ::SystemAllocator, 0); AZ_CLASS_ALLOCATOR(InspectorWidget, AZ::SystemAllocator, 0);
AZ_RTTI(AtomToolsFramework::InspectorWidget, "{D77A5F5F-0536-4249-916F-328B272E1AAB}");
static void Reflect(AZ::ReflectContext* context);
explicit InspectorWidget(QWidget* parent = nullptr); InspectorWidget(QWidget* parent = nullptr);
~InspectorWidget() override; ~InspectorWidget() override;
// InspectorRequestBus::Handler overrides... // InspectorRequestBus::Handler overrides...
@ -74,6 +80,8 @@ namespace AtomToolsFramework
void ExpandAll() override; void ExpandAll() override;
void CollapseAll() override; void CollapseAll() override;
void SetGroupSettingsPrefix(const AZStd::string& prefix);
protected: protected:
virtual bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const; virtual bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const;
virtual void OnGroupExpanded(const AZStd::string& groupName); virtual void OnGroupExpanded(const AZStd::string& groupName);
@ -81,14 +89,15 @@ namespace AtomToolsFramework
virtual void OnHeaderClicked(const AZStd::string& groupName, QMouseEvent* event); virtual void OnHeaderClicked(const AZStd::string& groupName, QMouseEvent* event);
private: private:
QScopedPointer<Ui::InspectorWidget> m_ui;
struct GroupWidgetPair struct GroupWidgetPair
{ {
InspectorGroupHeaderWidget* m_header; InspectorGroupHeaderWidget* m_header;
QWidget* m_panel; QWidget* m_panel;
}; };
QScopedPointer<Ui::InspectorWidget> m_ui;
AZStd::string m_collapsedGroupSettingName;
AZStd::unordered_set<AZ::u32> m_collapsedGroups;
AZStd::unordered_map<AZStd::string, GroupWidgetPair> m_groups; AZStd::unordered_map<AZStd::string, GroupWidgetPair> m_groups;
}; };
} // namespace AtomToolsFramework } // namespace AtomToolsFramework

@ -11,14 +11,8 @@
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h> #include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h> #include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h> #include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/any.h> #include <AzCore/std/any.h>
namespace AzToolsFramework
{
class InstanceDataNode;
}
namespace AtomToolsFramework namespace AtomToolsFramework
{ {
//! Convert an editor property stored in a AZStd::any into a material property value //! Convert an editor property stored in a AZStd::any into a material property value
@ -39,9 +33,6 @@ namespace AtomToolsFramework
//! Convert and assign editor dynamic property configuration fields to material property meta data //! Convert and assign editor dynamic property configuration fields to material property meta data
void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig); void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig);
//! Compare equality of data types and values of editor property stored in AZStd::any
bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB);
//! Convert the property value into the format that will be stored in the source data //! Convert the property value into the format that will be stored in the source data
//! This is primarily needed to support conversions of special types like enums and images //! This is primarily needed to support conversions of special types like enums and images
//! @param exportPath absolute path of the file being saved //! @param exportPath absolute path of the file being saved
@ -52,14 +43,4 @@ namespace AtomToolsFramework
[[maybe_unused]] const AZ::Name& propertyId, [[maybe_unused]] const AZ::Name& propertyId,
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
AZ::RPI::MaterialPropertyValue& propertyValue); AZ::RPI::MaterialPropertyValue& propertyValue);
//! Generate a file path that is relative to either the source asset root or the export path
//! @param exportPath absolute path of the file being saved
//! @param referencePath absolute path of a file that will be treated as an external reference
//! @param relativeToExportPath specifies if the path is relative to the source asset root or the export path
AZStd::string GetExteralReferencePath(
const AZStd::string& exportPath, const AZStd::string& referencePath, const bool relativeToExportPath = false);
//! Traverse up the instance data node hierarchy to find the containing dynamic property object
const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode);
} // namespace AtomToolsFramework } // namespace AtomToolsFramework

@ -9,9 +9,12 @@
#pragma once #pragma once
#include <AzCore/Asset/AssetManager.h> #include <AzCore/Asset/AssetManager.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/PlatformDef.h> #include <AzCore/PlatformDef.h>
#include <AzCore/Settings/SettingsRegistry.h> #include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/std/any.h>
#include <AzCore/std/containers/vector.h> #include <AzCore/std/containers/vector.h>
#include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QFileInfo> #include <QFileInfo>
@ -23,14 +26,6 @@ class QImage;
namespace AtomToolsFramework namespace AtomToolsFramework
{ {
template<typename T>
T GetSettingOrDefault(AZStd::string_view path, const T& defaultValue)
{
T result;
auto settingsRegistry = AZ::SettingsRegistry::Get();
return (settingsRegistry && settingsRegistry->Get(result, path)) ? result : defaultValue;
}
using LoadImageAsyncCallback = AZStd::function<void(const QImage&)>; using LoadImageAsyncCallback = AZStd::function<void(const QImage&)>;
void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback); void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback);
@ -39,4 +34,67 @@ namespace AtomToolsFramework
QFileInfo GetUniqueFileInfo(const QString& initialPath); QFileInfo GetUniqueFileInfo(const QString& initialPath);
QFileInfo GetDuplicationFileInfo(const QString& initialPath); QFileInfo GetDuplicationFileInfo(const QString& initialPath);
bool LaunchTool(const QString& baseName, const QStringList& arguments); bool LaunchTool(const QString& baseName, const QStringList& arguments);
//! Generate a file path that is relative to either the source asset root or the export path
//! @param exportPath absolute path of the file being saved
//! @param referencePath absolute path of a file that will be treated as an external reference
//! @param relativeToExportPath specifies if the path is relative to the source asset root or the export path
AZStd::string GetExteralReferencePath(
const AZStd::string& exportPath, const AZStd::string& referencePath, const bool relativeToExportPath = false);
//! Compare equality of data types and values of editor property stored in AZStd::any
bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB);
//! Traverse up the instance data hierarchy to find a node containing the corresponding type
template<typename T>
const T* FindAncestorInstanceDataNodeByType(const AzToolsFramework::InstanceDataNode* pNode)
{
// Traverse up the hierarchy from the input node to search for an instance matching the specified type
for (const auto* currentNode = pNode; currentNode; currentNode = currentNode->GetParent())
{
const auto* context = currentNode->GetSerializeContext();
const auto* classData = currentNode->GetClassMetadata();
if (context && classData)
{
if (context->CanDowncast(classData->m_typeId, azrtti_typeid<T>(), classData->m_azRtti, nullptr))
{
return static_cast<const T*>(currentNode->FirstInstance());
}
}
}
return nullptr;
}
template<typename T>
T GetSettingsValue(AZStd::string_view path, const T& defaultValue = {})
{
T result;
auto settingsRegistry = AZ::SettingsRegistry::Get();
return (settingsRegistry && settingsRegistry->Get(result, path)) ? result : defaultValue;
}
template<typename T>
bool SetSettingsValue(AZStd::string_view path, const T& value)
{
auto settingsRegistry = AZ::SettingsRegistry::Get();
return settingsRegistry && settingsRegistry->Set(path, value);
}
template<typename T>
T GetSettingsObject(AZStd::string_view path, const T& defaultValue = {})
{
T result;
auto settingsRegistry = AZ::SettingsRegistry::Get();
return (settingsRegistry && settingsRegistry->GetObject<T>(result, path)) ? result : defaultValue;
}
template<typename T>
bool SetSettingsObject(AZStd::string_view path, const T& value)
{
auto settingsRegistry = AZ::SettingsRegistry::Get();
return settingsRegistry && settingsRegistry->SetObject<T>(path, value);
}
bool SaveSettingsToFile(const AZ::IO::FixedMaxPath& savePath, const AZStd::vector<AZStd::string>& filters);
} // namespace AtomToolsFramework } // namespace AtomToolsFramework

@ -29,6 +29,7 @@ namespace AtomToolsFramework
~AtomToolsMainWindow(); ~AtomToolsMainWindow();
protected: protected:
// AtomToolsMainWindowRequestBus::Handler overrides...
void ActivateWindow() override; void ActivateWindow() override;
bool AddDockWidget(const AZStd::string& name, QWidget* widget, uint32_t area, uint32_t orientation) override; bool AddDockWidget(const AZStd::string& name, QWidget* widget, uint32_t area, uint32_t orientation) override;
void RemoveDockWidget(const AZStd::string& name) override; void RemoveDockWidget(const AZStd::string& name) override;

@ -70,9 +70,9 @@ namespace AtomToolsFramework
m_styleManager->initialize(this, engineRootPath); m_styleManager->initialize(this, engineRootPath);
const int updateIntervalWhenActive = const int updateIntervalWhenActive =
aznumeric_cast<int>(GetSettingOrDefault<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenActive", 1)); aznumeric_cast<int>(GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenActive", 1));
const int updateIntervalWhenNotActive = const int updateIntervalWhenNotActive =
aznumeric_cast<int>(GetSettingOrDefault<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenNotActive", 64)); aznumeric_cast<int>(GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenNotActive", 64));
m_timer.setInterval(updateIntervalWhenActive); m_timer.setInterval(updateIntervalWhenActive);
connect(&m_timer, &QTimer::timeout, this, [this]() connect(&m_timer, &QTimer::timeout, this, [this]()
@ -188,7 +188,7 @@ namespace AtomToolsFramework
Base::StartCommon(systemEntity); Base::StartCommon(systemEntity);
const bool clearLogFile = GetSettingOrDefault("/O3DE/AtomToolsFramework/Application/ClearLogOnStart", false); const bool clearLogFile = GetSettingsValue("/O3DE/AtomToolsFramework/Application/ClearLogOnStart", false);
m_traceLogger.OpenLogFile(m_targetName + ".log", clearLogFile); m_traceLogger.OpenLogFile(m_targetName + ".log", clearLogFile);
ConnectToAssetProcessor(); ConnectToAssetProcessor();
@ -197,7 +197,7 @@ namespace AtomToolsFramework
AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast(
&AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized);
const bool enableSourceControl = GetSettingOrDefault("/O3DE/AtomToolsFramework/Application/EnableSourceControl", true); const bool enableSourceControl = GetSettingsValue("/O3DE/AtomToolsFramework/Application/EnableSourceControl", true);
AzToolsFramework::SourceControlConnectionRequestBus::Broadcast( AzToolsFramework::SourceControlConnectionRequestBus::Broadcast(
&AzToolsFramework::SourceControlConnectionRequests::EnableSourceControl, enableSourceControl); &AzToolsFramework::SourceControlConnectionRequests::EnableSourceControl, enableSourceControl);
@ -238,6 +238,12 @@ namespace AtomToolsFramework
void AtomToolsApplication::Destroy() void AtomToolsApplication::Destroy()
{ {
m_styleManager.reset(); m_styleManager.reset();
// Save application settings to settings registry file
AZ::IO::FixedMaxPath savePath = AZ::Utils::GetProjectPath();
savePath /= AZStd::string::format("user/Registry/%s.setreg", m_targetName.c_str());
SaveSettingsToFile(savePath, { "/O3DE/AtomToolsFramework", AZStd::string::format("/O3DE/Atom/%s", m_targetName.c_str()) });
UnloadSettings(); UnloadSettings();
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();

@ -106,9 +106,9 @@ namespace AtomToolsFramework
const AZStd::vector<AssetBrowserEntry*> entries = m_ui->m_assetBrowserTreeViewWidget->GetSelectedAssets(); const AZStd::vector<AssetBrowserEntry*> entries = m_ui->m_assetBrowserTreeViewWidget->GetSelectedAssets();
const bool promptToOpenMultipleFiles = const bool promptToOpenMultipleFiles =
GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/AssetBrowser/PromptToOpenMultipleFiles", true); GetSettingsValue<bool>("/O3DE/AtomToolsFramework/AssetBrowser/PromptToOpenMultipleFiles", true);
const AZ::u64 promptToOpenMultipleFilesThreshold = const AZ::u64 promptToOpenMultipleFilesThreshold =
GetSettingOrDefault<AZ::u64>("/O3DE/AtomToolsFramework/AssetBrowser/PromptToOpenMultipleFilesThreshold", 10); GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetBrowser/PromptToOpenMultipleFilesThreshold", 10);
if (promptToOpenMultipleFiles && promptToOpenMultipleFilesThreshold <= entries.size()) if (promptToOpenMultipleFiles && promptToOpenMultipleFilesThreshold <= entries.size())
{ {

@ -71,11 +71,11 @@ namespace AtomToolsFramework
QListWidgetItem* AssetGridDialog::CreateListItem(const SelectableAsset& selectableAsset) QListWidgetItem* AssetGridDialog::CreateListItem(const SelectableAsset& selectableAsset)
{ {
const int itemBorder = aznumeric_cast<int>( const int itemBorder = aznumeric_cast<int>(
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemBorder", 4)); AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetGridDialog/ItemBorder", 4));
const int itemSpacing = aznumeric_cast<int>( const int itemSpacing = aznumeric_cast<int>(
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemSpacing", 10)); AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetGridDialog/ItemSpacing", 10));
const int headerHeight = aznumeric_cast<int>( const int headerHeight = aznumeric_cast<int>(
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/HeaderHeight", 15)); AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetGridDialog/HeaderHeight", 15));
const QSize gridSize = m_ui->m_assetList->gridSize(); const QSize gridSize = m_ui->m_assetList->gridSize();
m_ui->m_assetList->setGridSize(QSize( m_ui->m_assetList->setGridSize(QSize(

@ -13,6 +13,7 @@
#include <AtomToolsFramework/Document/AtomToolsDocument.h> #include <AtomToolsFramework/Document/AtomToolsDocument.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystem.h> #include <AtomToolsFramework/Document/AtomToolsDocumentSystem.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h> #include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
#include <AtomToolsFrameworkSystemComponent.h> #include <AtomToolsFrameworkSystemComponent.h>
namespace AtomToolsFramework namespace AtomToolsFramework
@ -23,6 +24,7 @@ namespace AtomToolsFramework
DynamicPropertyGroup::Reflect(context); DynamicPropertyGroup::Reflect(context);
AtomToolsDocument::Reflect(context); AtomToolsDocument::Reflect(context);
AtomToolsDocumentSystem::Reflect(context); AtomToolsDocumentSystem::Reflect(context);
InspectorWidget::Reflect(context);
if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context)) if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
{ {

@ -0,0 +1,120 @@
/*
* 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 <AtomToolsFramework/Document/AtomToolsDocumentInspector.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
namespace AtomToolsFramework
{
AtomToolsDocumentInspector::AtomToolsDocumentInspector(const AZ::Crc32& toolId, QWidget* parent)
: InspectorWidget(parent)
, m_toolId(toolId)
{
AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
}
AtomToolsDocumentInspector::~AtomToolsDocumentInspector()
{
AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
}
void AtomToolsDocumentInspector::SetDocumentId(const AZ::Uuid& documentId)
{
AddGroupsBegin();
m_documentId = documentId;
AtomToolsDocumentRequestBus::Event(
m_documentId,
[&](AtomToolsDocumentRequests* documentRequests)
{
if (documentRequests->IsOpen())
{
// Create a unique settings prefix string per document using a CRC of the document path
const AZStd::string groupSettingsPrefix = m_documentSettingsPrefix +
AZStd::string::format("/%08x/GroupSettings", aznumeric_cast<AZ::u32>(AZ::Crc32(documentRequests->GetAbsolutePath())));
SetGroupSettingsPrefix(groupSettingsPrefix);
// This will automatically expose all document contents to an inspector with a collapsible group per object.
// In the case of the material editor, this will be one inspector group per property group.
for (auto& objectInfo : documentRequests->GetObjectInfo())
{
// Passing in same main and comparison instance to enable custom value comparison
const AZ::Crc32 groupSaveStateKey(
AZStd::string::format("%s/%s", groupSettingsPrefix.c_str(), objectInfo.m_name.c_str()));
auto propertyGroupWidget = new InspectorPropertyGroupWidget(
objectInfo.m_objectPtr, objectInfo.m_objectPtr, objectInfo.m_objectType, this, this, groupSaveStateKey, {},
m_nodeIndicatorFunction, 0);
AddGroup(objectInfo.m_name, objectInfo.m_displayName, objectInfo.m_description, propertyGroupWidget);
SetGroupVisible(objectInfo.m_name, objectInfo.m_visible);
}
}
InspectorRequestBus::Handler::BusConnect(m_documentId);
});
AddGroupsEnd();
}
void AtomToolsDocumentInspector::SetDocumentSettingsPrefix(const AZStd::string& prefix)
{
m_documentSettingsPrefix = prefix;
}
void AtomToolsDocumentInspector::SetIndicatorFunction(const NodeIndicatorFunction& indicatorFunction)
{
m_nodeIndicatorFunction = indicatorFunction;
}
void AtomToolsDocumentInspector::Reset()
{
m_documentId = AZ::Uuid::CreateNull();
m_editInProgress = false;
InspectorWidget::Reset();
}
void AtomToolsDocumentInspector::OnDocumentObjectInfoChanged(
[[maybe_unused]] const AZ::Uuid& documentId, const DocumentObjectInfo& objectInfo, bool rebuilt)
{
if (m_documentId == documentId)
{
SetGroupVisible(objectInfo.m_name, objectInfo.m_visible);
if (rebuilt)
{
RebuildGroup(objectInfo.m_name);
}
else
{
RefreshGroup(objectInfo.m_name);
}
}
}
void AtomToolsDocumentInspector::BeforePropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode)
{
if (!m_editInProgress)
{
m_editInProgress = true;
AtomToolsDocumentRequestBus::Event(m_documentId, &AtomToolsDocumentRequestBus::Events::BeginEdit);
}
}
void AtomToolsDocumentInspector::SetPropertyEditingComplete([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode)
{
if (m_editInProgress)
{
m_editInProgress = false;
AtomToolsDocumentRequestBus::Event(m_documentId, &AtomToolsDocumentRequestBus::Events::EndEdit);
}
}
} // namespace AtomToolsFramework
//#include <AtomToolsFramework/Document/moc_AtomToolsDocumentInspector.cpp>

@ -500,4 +500,4 @@ namespace AtomToolsFramework
} }
} // namespace AtomToolsFramework } // namespace AtomToolsFramework
//#include <Document/moc_AtomToolsDocumentMainWindow.cpp> //#include <AtomToolsFramework/Document/moc_AtomToolsDocumentMainWindow.cpp>

@ -368,7 +368,7 @@ namespace AtomToolsFramework
void AtomToolsDocumentSystem::ReopenDocuments() void AtomToolsDocumentSystem::ReopenDocuments()
{ {
const bool enableHotReload = GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/AtomToolsDocumentSystem/EnableHotReload", true); const bool enableHotReload = GetSettingsValue<bool>("/O3DE/AtomToolsFramework/AtomToolsDocumentSystem/EnableHotReload", true);
if (!enableHotReload) if (!enableHotReload)
{ {
m_documentIdsWithDependencyChanges.clear(); m_documentIdsWithDependencyChanges.clear();
@ -377,7 +377,7 @@ namespace AtomToolsFramework
} }
const bool enableHotReloadPrompts = const bool enableHotReloadPrompts =
GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/AtomToolsDocumentSystem/EnableHotReloadPrompts", true); GetSettingsValue<bool>("/O3DE/AtomToolsFramework/AtomToolsDocumentSystem/EnableHotReloadPrompts", true);
for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges) for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges)
{ {

@ -6,27 +6,69 @@
* *
*/ */
#include <QMenu>
#include <QScrollArea>
#include <QScrollBar>
#include <QSizePolicy>
#include <AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h> #include <AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h>
#include <AtomToolsFramework/Inspector/InspectorGroupWidget.h> #include <AtomToolsFramework/Inspector/InspectorGroupWidget.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h> #include <AtomToolsFramework/Inspector/InspectorWidget.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Inspector/ui_InspectorWidget.h> #include <Inspector/ui_InspectorWidget.h>
#include <QMenu>
#include <QScrollArea>
#include <QScrollBar>
#include <QSizePolicy>
namespace AtomToolsFramework namespace AtomToolsFramework
{ {
void InspectorWidget::Reflect(AZ::ReflectContext* context)
{
if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->RegisterGenericType<AZStd::unordered_set<AZ::u32>>();
serialize->Class<InspectorWidget>()
->Version(0);
}
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<InspectorRequestBus>("InspectorRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "atomtools")
->Event("ClearHeading", &InspectorRequestBus::Events::ClearHeading)
->Event("Reset", &InspectorRequestBus::Events::Reset)
->Event("AddGroupsBegin", &InspectorRequestBus::Events::AddGroupsBegin)
->Event("AddGroupsEnd", &InspectorRequestBus::Events::AddGroupsEnd)
->Event("SetGroupVisible", &InspectorRequestBus::Events::SetGroupVisible)
->Event("IsGroupVisible", &InspectorRequestBus::Events::IsGroupVisible)
->Event("IsGroupHidden", &InspectorRequestBus::Events::IsGroupHidden)
->Event("RefreshGroup", &InspectorRequestBus::Events::RefreshGroup)
->Event("RebuildGroup", &InspectorRequestBus::Events::RebuildGroup)
->Event("RefreshAll", &InspectorRequestBus::Events::RefreshAll)
->Event("RebuildAll", &InspectorRequestBus::Events::RebuildAll)
->Event("ExpandGroup", &InspectorRequestBus::Events::ExpandGroup)
->Event("CollapseGroup", &InspectorRequestBus::Events::CollapseGroup)
->Event("IsGroupExpanded", &InspectorRequestBus::Events::IsGroupExpanded)
->Event("ExpandAll", &InspectorRequestBus::Events::ExpandAll)
->Event("CollapseAll", &InspectorRequestBus::Events::CollapseAll)
;
}
}
InspectorWidget::InspectorWidget(QWidget* parent) InspectorWidget::InspectorWidget(QWidget* parent)
: QWidget(parent) : QWidget(parent)
, m_ui(new Ui::InspectorWidget) , m_ui(new Ui::InspectorWidget)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
SetGroupSettingsPrefix("/O3DE/AtomToolsFramework/InspectorWidget");
} }
InspectorWidget::~InspectorWidget() InspectorWidget::~InspectorWidget()
{ {
SetSettingsObject(m_collapsedGroupSettingName, m_collapsedGroups);
InspectorRequestBus::Handler::BusDisconnect();
} }
void InspectorWidget::AddHeading(QWidget* headingWidget) void InspectorWidget::AddHeading(QWidget* headingWidget)
@ -52,6 +94,7 @@ namespace AtomToolsFramework
delete child; delete child;
} }
m_groups.clear(); m_groups.clear();
InspectorRequestBus::Handler::BusDisconnect();
} }
void InspectorWidget::AddGroupsBegin() void InspectorWidget::AddGroupsBegin()
@ -202,20 +245,31 @@ namespace AtomToolsFramework
} }
} }
void InspectorWidget::SetGroupSettingsPrefix(const AZStd::string& prefix)
{
if (!m_collapsedGroupSettingName.empty())
{
SetSettingsObject(m_collapsedGroupSettingName, m_collapsedGroups);
}
m_collapsedGroupSettingName = prefix + "/CollapsedGroups";
m_collapsedGroups = GetSettingsObject<AZStd::unordered_set<AZ::u32>>(m_collapsedGroupSettingName);
}
bool InspectorWidget::ShouldGroupAutoExpanded(const AZStd::string& groupName) const bool InspectorWidget::ShouldGroupAutoExpanded(const AZStd::string& groupName) const
{ {
AZ_UNUSED(groupName); auto stateItr = m_collapsedGroups.find(AZ::Crc32(groupName));
return true; return stateItr == m_collapsedGroups.end();
} }
void InspectorWidget::OnGroupExpanded(const AZStd::string& groupName) void InspectorWidget::OnGroupExpanded(const AZStd::string& groupName)
{ {
AZ_UNUSED(groupName); m_collapsedGroups.erase(AZ::Crc32(groupName));
} }
void InspectorWidget::OnGroupCollapsed(const AZStd::string& groupName) void InspectorWidget::OnGroupCollapsed(const AZStd::string& groupName)
{ {
AZ_UNUSED(groupName); m_collapsedGroups.insert(AZ::Crc32(groupName));
} }
void InspectorWidget::OnHeaderClicked(const AZStd::string& groupName, QMouseEvent* event) void InspectorWidget::OnHeaderClicked(const AZStd::string& groupName, QMouseEvent* event)

@ -6,21 +6,14 @@
* *
*/ */
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h> #include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Reflect/Image/ImageAsset.h> #include <Atom/RPI.Reflect/Image/ImageAsset.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h> #include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h> #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h> #include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AzCore/Math/Color.h> #include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AzCore/Math/Vector2.h> #include <AtomToolsFramework/Util/Util.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
namespace AtomToolsFramework namespace AtomToolsFramework
{ {
@ -132,41 +125,6 @@ namespace AtomToolsFramework
} }
} }
template<typename T>
bool ComparePropertyValues(const AZStd::any& valueA, const AZStd::any& valueB)
{
return valueA.is<T>() && valueB.is<T>() && *AZStd::any_cast<T>(&valueA) == *AZStd::any_cast<T>(&valueB);
}
bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB)
{
if (valueA.type() != valueB.type())
{
return false;
}
if (ComparePropertyValues<bool>(valueA, valueB) ||
ComparePropertyValues<int32_t>(valueA, valueB) ||
ComparePropertyValues<uint32_t>(valueA, valueB) ||
ComparePropertyValues<float>(valueA, valueB) ||
ComparePropertyValues<AZ::Vector2>(valueA, valueB) ||
ComparePropertyValues<AZ::Vector3>(valueA, valueB) ||
ComparePropertyValues<AZ::Vector4>(valueA, valueB) ||
ComparePropertyValues<AZ::Color>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::AssetId>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::Data::AssetData>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::ImageAsset>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::MaterialAsset>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::MaterialTypeAsset>>(valueA, valueB) ||
ComparePropertyValues<AZStd::string>(valueA, valueB))
{
return true;
}
return false;
}
bool ConvertToExportFormat( bool ConvertToExportFormat(
const AZStd::string& exportPath, const AZStd::string& exportPath,
[[maybe_unused]] const AZ::Name& propertyId, [[maybe_unused]] const AZ::Name& propertyId,
@ -223,51 +181,4 @@ namespace AtomToolsFramework
return true; return true;
} }
AZStd::string GetExteralReferencePath(
const AZStd::string& exportPath, const AZStd::string& referencePath, const bool relativeToExportPath)
{
if (referencePath.empty())
{
return {};
}
if (!relativeToExportPath)
{
AZStd::string watchFolder;
AZ::Data::AssetInfo assetInfo;
bool sourceInfoFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(),
assetInfo, watchFolder);
if (sourceInfoFound)
{
return assetInfo.m_relativePath;
}
}
AZ::IO::BasicPath<AZStd::string> exportFolder(exportPath);
exportFolder.RemoveFilename();
return AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix();
}
const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode)
{
// Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property
for (const AzToolsFramework::InstanceDataNode* currentNode = pNode; currentNode; currentNode = currentNode->GetParent())
{
const AZ::SerializeContext* context = currentNode->GetSerializeContext();
const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata();
if (context && classData)
{
if (context->CanDowncast(
classData->m_typeId, azrtti_typeid<AtomToolsFramework::DynamicProperty>(), classData->m_azRtti, nullptr))
{
return static_cast<const AtomToolsFramework::DynamicProperty*>(currentNode->FirstInstance());
}
}
}
return nullptr;
}
} // namespace AtomToolsFramework } // namespace AtomToolsFramework

@ -9,12 +9,20 @@
#include <Atom/ImageProcessing/ImageObject.h> #include <Atom/ImageProcessing/ImageObject.h>
#include <Atom/ImageProcessing/ImageProcessingBus.h> #include <Atom/ImageProcessing/ImageProcessingBus.h>
#include <AtomToolsFramework/Util/Util.h> #include <AtomToolsFramework/Util/Util.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/IO/SystemFile.h> #include <AzCore/IO/SystemFile.h>
#include <AzCore/Jobs/JobFunction.h> #include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/StringFunc/StringFunc.h> #include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Utils/Utils.h> #include <AzCore/Utils/Utils.h>
#include <AzFramework/API/ApplicationAPI.h> #include <AzFramework/API/ApplicationAPI.h>
#include <AzQtComponents/Components/Widgets/FileDialog.h> #include <AzQtComponents/Components/Widgets/FileDialog.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h> #include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
@ -27,6 +35,49 @@ AZ_POP_DISABLE_WARNING
namespace AtomToolsFramework namespace AtomToolsFramework
{ {
bool SaveSettingsToFile(const AZ::IO::FixedMaxPath& savePath, const AZStd::vector<AZStd::string>& filters)
{
auto registry = AZ::SettingsRegistry::Get();
if (registry == nullptr)
{
AZ_Warning("AtomToolsFramework", false, "Unable to access global settings registry.");
return false;
}
AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings;
dumperSettings.m_prettifyOutput = true;
dumperSettings.m_includeFilter = [filters](AZStd::string_view path)
{
for (const auto& filter : filters)
{
if (filter.starts_with(path.substr(0, filter.size())))
{
return true;
}
}
return false;
};
AZStd::string stringBuffer;
AZ::IO::ByteContainerStream stringStream(&stringBuffer);
if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(*registry, "", stringStream, dumperSettings))
{
AZ_Warning("AtomToolsFramework", false, R"(Unable to save changes to the registry file at "%s"\n)", savePath.c_str());
return false;
}
bool saved = false;
constexpr auto configurationMode =
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
if (AZ::IO::SystemFile outputFile; outputFile.Open(savePath.c_str(), configurationMode))
{
saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size();
}
AZ_Warning("AtomToolsFramework", saved, R"(Unable to save registry file to path "%s"\n)", savePath.c_str());
return saved;
}
void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback) void LoadImageAsync(const AZStd::string& path, LoadImageAsyncCallback callback)
{ {
AZ::Job* job = AZ::CreateJobFunction( AZ::Job* job = AZ::CreateJobFunction(
@ -178,4 +229,63 @@ namespace AtomToolsFramework
return QProcess::startDetached(launchPath.c_str(), arguments, engineRoot.c_str()); return QProcess::startDetached(launchPath.c_str(), arguments, engineRoot.c_str());
} }
}
AZStd::string GetExteralReferencePath(
const AZStd::string& exportPath, const AZStd::string& referencePath, const bool relativeToExportPath)
{
if (referencePath.empty())
{
return {};
}
if (!relativeToExportPath)
{
AZStd::string watchFolder;
AZ::Data::AssetInfo assetInfo;
bool sourceInfoFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(),
assetInfo, watchFolder);
if (sourceInfoFound)
{
return assetInfo.m_relativePath;
}
}
AZ::IO::BasicPath<AZStd::string> exportFolder(exportPath);
exportFolder.RemoveFilename();
return AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix();
}
template<typename T>
bool ComparePropertyValues(const AZStd::any& valueA, const AZStd::any& valueB)
{
return valueA.is<T>() && valueB.is<T>() && *AZStd::any_cast<T>(&valueA) == *AZStd::any_cast<T>(&valueB);
}
bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB)
{
if (valueA.type() != valueB.type())
{
return false;
}
if (ComparePropertyValues<bool>(valueA, valueB) || ComparePropertyValues<int32_t>(valueA, valueB) ||
ComparePropertyValues<uint32_t>(valueA, valueB) || ComparePropertyValues<float>(valueA, valueB) ||
ComparePropertyValues<AZ::Vector2>(valueA, valueB) || ComparePropertyValues<AZ::Vector3>(valueA, valueB) ||
ComparePropertyValues<AZ::Vector4>(valueA, valueB) || ComparePropertyValues<AZ::Color>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::AssetId>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::Data::AssetData>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::ImageAsset>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::MaterialAsset>>(valueA, valueB) ||
ComparePropertyValues<AZ::Data::Asset<AZ::RPI::MaterialTypeAsset>>(valueA, valueB) ||
ComparePropertyValues<AZStd::string>(valueA, valueB))
{
return true;
}
return false;
}
} // namespace AtomToolsFramework

@ -8,7 +8,7 @@
#include <AzTest/AzTest.h> #include <AzTest/AzTest.h>
#include <Atom/Utils/TestUtils/AssetSystemStub.h> #include <Atom/Utils/TestUtils/AssetSystemStub.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h> #include <AtomToolsFramework/Util/Util.h>
namespace UnitTest namespace UnitTest
{ {

@ -15,6 +15,7 @@ set(FILES
Include/AtomToolsFramework/Communication/LocalSocket.h Include/AtomToolsFramework/Communication/LocalSocket.h
Include/AtomToolsFramework/Debug/TraceRecorder.h Include/AtomToolsFramework/Debug/TraceRecorder.h
Include/AtomToolsFramework/Document/AtomToolsDocument.h Include/AtomToolsFramework/Document/AtomToolsDocument.h
Include/AtomToolsFramework/Document/AtomToolsDocumentInspector.h
Include/AtomToolsFramework/Document/AtomToolsDocumentSystem.h Include/AtomToolsFramework/Document/AtomToolsDocumentSystem.h
Include/AtomToolsFramework/Document/AtomToolsDocumentApplication.h Include/AtomToolsFramework/Document/AtomToolsDocumentApplication.h
Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h
@ -51,6 +52,7 @@ set(FILES
Source/Communication/LocalSocket.cpp Source/Communication/LocalSocket.cpp
Source/Debug/TraceRecorder.cpp Source/Debug/TraceRecorder.cpp
Source/Document/AtomToolsDocument.cpp Source/Document/AtomToolsDocument.cpp
Source/Document/AtomToolsDocumentInspector.cpp
Source/Document/AtomToolsDocumentApplication.cpp Source/Document/AtomToolsDocumentApplication.cpp
Source/Document/AtomToolsDocumentMainWindow.cpp Source/Document/AtomToolsDocumentMainWindow.cpp
Source/Document/AtomToolsDocumentSystem.cpp Source/Document/AtomToolsDocumentSystem.cpp

@ -18,6 +18,7 @@
#include <AtomCore/Instance/Instance.h> #include <AtomCore/Instance/Instance.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h> #include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h> #include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzCore/RTTI/BehaviorContext.h> #include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h> #include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h> #include <AzCore/Serialization/SerializeContext.h>

@ -64,7 +64,7 @@ namespace MaterialEditor
m_ui->m_materialTypeComboBox->model()->sort(0, Qt::AscendingOrder); m_ui->m_materialTypeComboBox->model()->sort(0, Qt::AscendingOrder);
const AZStd::string defaultMaterialType = AtomToolsFramework::GetSettingOrDefault<AZStd::string>( const AZStd::string defaultMaterialType = AtomToolsFramework::GetSettingsValue<AZStd::string>(
"/O3DE/Atom/MaterialEditor/CreateMaterialDialog/DefaultMaterialType", "StandardPBR"); "/O3DE/Atom/MaterialEditor/CreateMaterialDialog/DefaultMaterialType", "StandardPBR");
const int index = m_ui->m_materialTypeComboBox->findText(defaultMaterialType.c_str()); const int index = m_ui->m_materialTypeComboBox->findText(defaultMaterialType.c_str());

@ -9,6 +9,7 @@
#include <Atom/RPI.Edit/Material/MaterialSourceData.h> #include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h> #include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h> #include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AtomToolsFramework/Util/Util.h> #include <AtomToolsFramework/Util/Util.h>
#include <AzQtComponents/Components/StyleManager.h> #include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Components/WindowDecorationWrapper.h> #include <AzQtComponents/Components/WindowDecorationWrapper.h>
@ -17,7 +18,6 @@
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h> #include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
#include <Window/MaterialEditorWindow.h> #include <Window/MaterialEditorWindow.h>
#include <Window/MaterialEditorWindowSettings.h> #include <Window/MaterialEditorWindowSettings.h>
#include <Window/MaterialInspector/MaterialInspector.h>
#include <Window/SettingsDialog/SettingsDialog.h> #include <Window/SettingsDialog/SettingsDialog.h>
#include <Window/ViewportSettingsInspector/ViewportSettingsInspector.h> #include <Window/ViewportSettingsInspector/ViewportSettingsInspector.h>
@ -78,7 +78,20 @@ namespace MaterialEditor
QDesktopServices::openUrl(QUrl::fromLocalFile(absolutePath.c_str())); QDesktopServices::openUrl(QUrl::fromLocalFile(absolutePath.c_str()));
}); });
AddDockWidget("Inspector", new MaterialInspector(m_toolId), Qt::RightDockWidgetArea, Qt::Vertical); m_materialInspector = new AtomToolsFramework::AtomToolsDocumentInspector(m_toolId, this);
m_materialInspector->SetDocumentSettingsPrefix("/O3DE/Atom/MaterialEditor/MaterialInspector");
m_materialInspector->SetIndicatorFunction(
[](const AzToolsFramework::InstanceDataNode* node)
{
const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(node);
if (property && !AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue))
{
return ":/Icons/changed_property.svg";
}
return ":/Icons/blank.png";
});
AddDockWidget("Inspector", m_materialInspector, Qt::RightDockWidgetArea, Qt::Vertical);
AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Vertical); AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Vertical);
SetDockWidgetVisible("Viewport Settings", false); SetDockWidgetVisible("Viewport Settings", false);
@ -98,6 +111,12 @@ namespace MaterialEditor
OnDocumentOpened(AZ::Uuid::CreateNull()); OnDocumentOpened(AZ::Uuid::CreateNull());
} }
void MaterialEditorWindow::OnDocumentOpened(const AZ::Uuid& documentId)
{
Base::OnDocumentOpened(documentId);
m_materialInspector->SetDocumentId(documentId);
}
void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height)
{ {
QSize requestedViewportSize = QSize(width, height) / devicePixelRatioF(); QSize requestedViewportSize = QSize(width, height) / devicePixelRatioF();

@ -9,6 +9,7 @@
#pragma once #pragma once
#if !defined(Q_MOC_RUN) #if !defined(Q_MOC_RUN)
#include <AtomToolsFramework/Document/AtomToolsDocumentInspector.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h> #include <AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
@ -35,10 +36,15 @@ namespace MaterialEditor
MaterialEditorWindow(const AZ::Crc32& toolId, QWidget* parent = 0); MaterialEditorWindow(const AZ::Crc32& toolId, QWidget* parent = 0);
protected: protected:
// AtomToolsFramework::AtomToolsMainWindowRequestBus::Handler overrides...
void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override;
void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override; void LockViewportRenderTargetSize(uint32_t width, uint32_t height) override;
void UnlockViewportRenderTargetSize() override; void UnlockViewportRenderTargetSize() override;
// AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler overrides...
void OnDocumentOpened(const AZ::Uuid& documentId) override;
// AtomToolsFramework::AtomToolsDocumentMainWindow overrides...
bool GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) override; bool GetCreateDocumentParams(AZStd::string& openPath, AZStd::string& savePath) override;
bool GetOpenDocumentParams(AZStd::string& openPath) override; bool GetOpenDocumentParams(AZStd::string& openPath) override;
void OpenSettings() override; void OpenSettings() override;
@ -47,6 +53,7 @@ namespace MaterialEditor
void closeEvent(QCloseEvent* closeEvent) override; void closeEvent(QCloseEvent* closeEvent) override;
AtomToolsFramework::AtomToolsDocumentInspector* m_materialInspector = {};
MaterialViewportWidget* m_materialViewport = {}; MaterialViewportWidget* m_materialViewport = {};
MaterialEditorToolBar* m_toolBar = {}; MaterialEditorToolBar* m_toolBar = {};
}; };

@ -19,7 +19,6 @@ namespace MaterialEditor
serializeContext->Class<MaterialEditorWindowSettings, AZ::UserSettings>() serializeContext->Class<MaterialEditorWindowSettings, AZ::UserSettings>()
->Version(1) ->Version(1)
->Field("mainWindowState", &MaterialEditorWindowSettings::m_mainWindowState) ->Field("mainWindowState", &MaterialEditorWindowSettings::m_mainWindowState)
->Field("inspectorCollapsedGroups", &MaterialEditorWindowSettings::m_inspectorCollapsedGroups)
; ;
if (auto editContext = serializeContext->GetEditContext()) if (auto editContext = serializeContext->GetEditContext())

@ -27,6 +27,5 @@ namespace MaterialEditor
static void Reflect(AZ::ReflectContext* context); static void Reflect(AZ::ReflectContext* context);
AZStd::vector<char> m_mainWindowState; AZStd::vector<char> m_mainWindowState;
AZStd::unordered_set<AZ::u32> m_inspectorCollapsedGroups;
}; };
} // namespace MaterialEditor } // namespace MaterialEditor

@ -1,159 +0,0 @@
/*
* 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 <Atom/RPI.Edit/Common/AssetUtils.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <Window/MaterialInspector/MaterialInspector.h>
namespace MaterialEditor
{
MaterialInspector::MaterialInspector(const AZ::Crc32& toolId, QWidget* parent)
: AtomToolsFramework::InspectorWidget(parent)
, m_toolId(toolId)
{
m_windowSettings = AZ::UserSettings::CreateFind<MaterialEditorWindowSettings>(
AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
}
MaterialInspector::~MaterialInspector()
{
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
}
void MaterialInspector::Reset()
{
m_documentPath.clear();
m_documentId = AZ::Uuid::CreateNull();
m_activeProperty = {};
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorWidget::Reset();
}
bool MaterialInspector::ShouldGroupAutoExpanded(const AZStd::string& groupName) const
{
auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupName));
return stateItr == m_windowSettings->m_inspectorCollapsedGroups.end();
}
void MaterialInspector::OnGroupExpanded(const AZStd::string& groupName)
{
m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupName));
}
void MaterialInspector::OnGroupCollapsed(const AZStd::string& groupName)
{
m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupName));
}
void MaterialInspector::OnDocumentOpened(const AZ::Uuid& documentId)
{
AddGroupsBegin();
m_documentId = documentId;
bool isOpen = false;
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
isOpen, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen);
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
m_documentPath, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
if (!m_documentId.IsNull() && isOpen)
{
// This will automatically expose all document contents to an inspector with a collapsible group per object. In the case of the
// material editor, this will be one inspector group per property group.
AZStd::vector<AtomToolsFramework::DocumentObjectInfo> objects;
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
objects, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetObjectInfo);
for (auto& objectInfo : objects)
{
// Passing in same main and comparison instance to enable custom value comparison for highlighting modified properties
auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget(
objectInfo.m_objectPtr, objectInfo.m_objectPtr, objectInfo.m_objectType, this, this,
GetGroupSaveStateKey(objectInfo.m_name), {},
[this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0);
AddGroup(objectInfo.m_name, objectInfo.m_displayName, objectInfo.m_description, propertyGroupWidget);
SetGroupVisible(objectInfo.m_name, objectInfo.m_visible);
}
AtomToolsFramework::InspectorRequestBus::Handler::BusConnect(m_documentId);
}
AddGroupsEnd();
}
AZ::Crc32 MaterialInspector::GetGroupSaveStateKey(const AZStd::string& groupName) const
{
return AZ::Crc32(AZStd::string::format("MaterialInspector::PropertyGroup::%s::%s", m_documentPath.c_str(), groupName.c_str()));
}
bool MaterialInspector::IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const
{
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(node);
return property && !AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
}
const char* MaterialInspector::GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const
{
if (IsInstanceNodePropertyModifed(node))
{
return ":/Icons/changed_property.svg";
}
return ":/Icons/blank.png";
}
void MaterialInspector::OnDocumentObjectInfoChanged(
[[maybe_unused]] const AZ::Uuid& documentId, const AtomToolsFramework::DocumentObjectInfo& objectInfo, bool rebuilt)
{
SetGroupVisible(objectInfo.m_name, objectInfo.m_visible);
if (rebuilt)
{
RebuildGroup(objectInfo.m_name);
}
else
{
RefreshGroup(objectInfo.m_name);
}
}
void MaterialInspector::BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode)
{
// This function is called before every single property change whether it's a button click or dragging a slider. We only want to
// begin tracking undo state for the first change in the sequence, when the user begins to drag the slider.
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode);
if (!m_activeProperty && property)
{
m_activeProperty = property;
AtomToolsFramework::AtomToolsDocumentRequestBus::Event(
m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::BeginEdit);
}
}
void MaterialInspector::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode)
{
// If tracking has started and editing has completed then we can stop tracking undue state for this sequence of changes.
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode);
if (m_activeProperty && m_activeProperty == property)
{
AtomToolsFramework::AtomToolsDocumentRequestBus::Event(
m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::EndEdit);
m_activeProperty = {};
}
}
} // namespace MaterialEditor
#include <Window/MaterialInspector/moc_MaterialInspector.cpp>

@ -1,71 +0,0 @@
/*
* 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 <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h>
#include <AtomToolsFramework/Inspector/InspectorWidget.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
#include <Window/MaterialEditorWindowSettings.h>
#endif
namespace MaterialEditor
{
//! Provides controls for viewing and editing document settings.
class MaterialInspector
: public AtomToolsFramework::InspectorWidget
, public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
, public AzToolsFramework::IPropertyEditorNotify
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(MaterialInspector, AZ::SystemAllocator, 0);
MaterialInspector(const AZ::Crc32& toolId, QWidget* parent = nullptr);
~MaterialInspector() override;
// AtomToolsFramework::InspectorRequestBus::Handler overrides...
void Reset() override;
protected:
bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const override;
void OnGroupExpanded(const AZStd::string& groupName) override;
void OnGroupCollapsed(const AZStd::string& groupName) override;
private:
AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const;
bool IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const;
const char* GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const;
// AtomToolsDocumentNotificationBus::Handler implementation
void OnDocumentOpened(const AZ::Uuid& documentId) override;
void OnDocumentObjectInfoChanged(
const AZ::Uuid& documentId, const AtomToolsFramework::DocumentObjectInfo& objectInfo, bool rebuilt) override;
// AzToolsFramework::IPropertyEditorNotify overrides...
void BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) override;
void AfterPropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {}
void SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode) override;
void SealUndoStack() override {}
void RequestPropertyContextMenu([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, const QPoint&) override {}
void PropertySelectionChanged([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, bool) override {}
const AZ::Crc32 m_toolId = {};
// Tracking the property that is activiley being edited in the inspector
const AtomToolsFramework::DynamicProperty* m_activeProperty = {};
AZ::Uuid m_documentId = AZ::Uuid::CreateNull();
AZStd::string m_documentPath;
AZStd::intrusive_ptr<MaterialEditorWindowSettings> m_windowSettings;
};
} // namespace MaterialEditor

@ -6,19 +6,19 @@
* *
*/ */
#include <Window/SettingsDialog/SettingsWidget.h>
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h> #include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
#include <Window/SettingsDialog/SettingsWidget.h>
namespace MaterialEditor namespace MaterialEditor
{ {
SettingsWidget::SettingsWidget(QWidget* parent) SettingsWidget::SettingsWidget(QWidget* parent)
: AtomToolsFramework::InspectorWidget(parent) : AtomToolsFramework::InspectorWidget(parent)
{ {
SetGroupSettingsPrefix("/O3DE/Atom/MaterialEditor/SettingsWidget");
} }
SettingsWidget::~SettingsWidget() SettingsWidget::~SettingsWidget()
{ {
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
} }
void SettingsWidget::Populate() void SettingsWidget::Populate()
@ -29,7 +29,6 @@ namespace MaterialEditor
void SettingsWidget::Reset() void SettingsWidget::Reset()
{ {
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorWidget::Reset(); AtomToolsFramework::InspectorWidget::Reset();
} }
} // namespace MaterialEditor } // namespace MaterialEditor

@ -32,9 +32,7 @@ namespace MaterialEditor
m_viewportSettings = m_viewportSettings =
AZ::UserSettings::CreateFind<MaterialViewportSettings>(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL); AZ::UserSettings::CreateFind<MaterialViewportSettings>(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL);
m_windowSettings = AZ::UserSettings::CreateFind<MaterialEditorWindowSettings>( SetGroupSettingsPrefix("/O3DE/Atom/MaterialEditor/ViewportSettingsInspector");
AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL);
MaterialViewportNotificationBus::Handler::BusConnect(); MaterialViewportNotificationBus::Handler::BusConnect();
} }
@ -43,7 +41,6 @@ namespace MaterialEditor
m_lightingPreset.reset(); m_lightingPreset.reset();
m_modelPreset.reset(); m_modelPreset.reset();
MaterialViewportNotificationBus::Handler::BusDisconnect(); MaterialViewportNotificationBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
} }
void ViewportSettingsInspector::Populate() void ViewportSettingsInspector::Populate()
@ -144,7 +141,7 @@ namespace MaterialEditor
}); });
const int itemSize = aznumeric_cast<int>( const int itemSize = aznumeric_cast<int>(
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/MaterialEditor/AssetGridDialog/ModelItemSize", 180)); AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/Atom/MaterialEditor/AssetGridDialog/ModelItemSize", 180));
AtomToolsFramework::AssetGridDialog dialog( AtomToolsFramework::AssetGridDialog dialog(
"Model Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow()); "Model Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow());
@ -270,7 +267,7 @@ namespace MaterialEditor
}); });
const int itemSize = aznumeric_cast<int>( const int itemSize = aznumeric_cast<int>(
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/MaterialEditor/AssetGridDialog/LightingItemSize", 180)); AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/Atom/MaterialEditor/AssetGridDialog/LightingItemSize", 180));
AtomToolsFramework::AssetGridDialog dialog( AtomToolsFramework::AssetGridDialog dialog(
"Lighting Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow()); "Lighting Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow());
@ -338,7 +335,6 @@ namespace MaterialEditor
m_viewportSettings->m_displayMapperOperationType = viewportRequests->GetDisplayMapperOperationType(); m_viewportSettings->m_displayMapperOperationType = viewportRequests->GetDisplayMapperOperationType();
}); });
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorWidget::Reset(); AtomToolsFramework::InspectorWidget::Reset();
} }
@ -433,23 +429,6 @@ namespace MaterialEditor
{ {
return AZ::Crc32(AZStd::string::format("ViewportSettingsInspector::PropertyGroup::%s", groupName.c_str())); return AZ::Crc32(AZStd::string::format("ViewportSettingsInspector::PropertyGroup::%s", groupName.c_str()));
} }
bool ViewportSettingsInspector::ShouldGroupAutoExpanded(const AZStd::string& groupName) const
{
auto stateItr = m_windowSettings->m_inspectorCollapsedGroups.find(GetGroupSaveStateKey(groupName));
return stateItr == m_windowSettings->m_inspectorCollapsedGroups.end();
}
void ViewportSettingsInspector::OnGroupExpanded(const AZStd::string& groupName)
{
m_windowSettings->m_inspectorCollapsedGroups.erase(GetGroupSaveStateKey(groupName));
}
void ViewportSettingsInspector::OnGroupCollapsed(const AZStd::string& groupName)
{
m_windowSettings->m_inspectorCollapsedGroups.insert(GetGroupSaveStateKey(groupName));
}
} // namespace MaterialEditor } // namespace MaterialEditor
#include <Window/ViewportSettingsInspector/moc_ViewportSettingsInspector.cpp> #include <Window/ViewportSettingsInspector/moc_ViewportSettingsInspector.cpp>

@ -16,7 +16,6 @@
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h> #include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI_Internals.h>
#include <Viewport/MaterialViewportNotificationBus.h> #include <Viewport/MaterialViewportNotificationBus.h>
#include <Viewport/MaterialViewportSettings.h> #include <Viewport/MaterialViewportSettings.h>
#include <Window/MaterialEditorWindowSettings.h>
#endif #endif
namespace MaterialEditor namespace MaterialEditor
@ -75,13 +74,9 @@ namespace MaterialEditor
AZStd::string GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const; AZStd::string GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const;
AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const; AZ::Crc32 GetGroupSaveStateKey(const AZStd::string& groupName) const;
bool ShouldGroupAutoExpanded(const AZStd::string& groupName) const override;
void OnGroupExpanded(const AZStd::string& groupName) override;
void OnGroupCollapsed(const AZStd::string& groupName) override;
AZ::Render::ModelPresetPtr m_modelPreset; AZ::Render::ModelPresetPtr m_modelPreset;
AZ::Render::LightingPresetPtr m_lightingPreset; AZ::Render::LightingPresetPtr m_lightingPreset;
AZStd::intrusive_ptr<MaterialViewportSettings> m_viewportSettings; AZStd::intrusive_ptr<MaterialViewportSettings> m_viewportSettings;
AZStd::intrusive_ptr<MaterialEditorWindowSettings> m_windowSettings;
}; };
} // namespace MaterialEditor } // namespace MaterialEditor

@ -46,8 +46,6 @@ set(FILES
Source/Window/ToolBar/ModelPresetComboBox.cpp Source/Window/ToolBar/ModelPresetComboBox.cpp
Source/Window/ToolBar/LightingPresetComboBox.h Source/Window/ToolBar/LightingPresetComboBox.h
Source/Window/ToolBar/LightingPresetComboBox.cpp Source/Window/ToolBar/LightingPresetComboBox.cpp
Source/Window/MaterialInspector/MaterialInspector.h
Source/Window/MaterialInspector/MaterialInspector.cpp
Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h
Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp
) )

@ -14,8 +14,11 @@
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h> #include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
#include <Atom/RPI.Edit/Material/MaterialUtils.h> #include <Atom/RPI.Edit/Material/MaterialUtils.h>
#include <Atom/RPI.Reflect/Material/MaterialFunctor.h> #include <Atom/RPI.Reflect/Material/MaterialFunctor.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h> #include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h> #include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h> #include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AtomToolsFramework/Util/Util.h> #include <AtomToolsFramework/Util/Util.h>
@ -24,9 +27,6 @@
#include <AzToolsFramework/API/EditorAssetSystemAPI.h> #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h> #include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h> #include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConfig.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QApplication> #include <QApplication>
@ -54,7 +54,6 @@ namespace AZ
MaterialPropertyInspector::~MaterialPropertyInspector() MaterialPropertyInspector::~MaterialPropertyInspector()
{ {
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect();
AZ::EntitySystemBus::Handler::BusDisconnect(); AZ::EntitySystemBus::Handler::BusDisconnect();
EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect(); EditorMaterialSystemComponentNotificationBus::Handler::BusDisconnect();
@ -137,7 +136,6 @@ namespace AZ
m_dirtyPropertyFlags.set(); m_dirtyPropertyFlags.set();
m_internalEditNotification = {}; m_internalEditNotification = {};
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
AtomToolsFramework::InspectorWidget::Reset(); AtomToolsFramework::InspectorWidget::Reset();
} }
@ -590,7 +588,7 @@ namespace AZ
bool MaterialPropertyInspector::IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const bool MaterialPropertyInspector::IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const
{ {
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(node); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(node);
return property && !AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue); return property && !AtomToolsFramework::ArePropertyValuesEqual(property->GetValue(), property->GetConfig().m_parentValue);
} }
@ -719,7 +717,7 @@ namespace AZ
// This function is called continuously anytime a property changes until the edit has completed // This function is called continuously anytime a property changes until the edit has completed
// Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has // Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has
// started and ended // started and ended
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(pNode);
if (property) if (property)
{ {
if (m_activeProperty != property) if (m_activeProperty != property)
@ -731,7 +729,7 @@ namespace AZ
void MaterialPropertyInspector::AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) void MaterialPropertyInspector::AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode)
{ {
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(pNode);
if (property) if (property)
{ {
if (m_activeProperty == property) if (m_activeProperty == property)
@ -748,7 +746,7 @@ namespace AZ
// As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been // As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been
// completed but they are not being called following that pattern. when this function executes the changes to the property // completed but they are not being called following that pattern. when this function executes the changes to the property
// are ready to be committed or reverted // are ready to be committed or reverted
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(pNode);
if (property) if (property)
{ {
if (m_activeProperty == property) if (m_activeProperty == property)

@ -15,10 +15,11 @@
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h> #include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialUtils.h> #include <Atom/RPI.Edit/Material/MaterialUtils.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h> #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h> #include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h> #include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h> #include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzFramework/API/ApplicationAPI.h> #include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h> #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h> #include <AzToolsFramework/API/ToolsApplicationAPI.h>

@ -6,10 +6,6 @@
* *
*/ */
#include <Material/EditorMaterialModelUvNameMapInspector.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h> #include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Edit/Common/JsonUtils.h> #include <Atom/RPI.Edit/Common/JsonUtils.h>
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h> #include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
@ -19,11 +15,13 @@
#include <Atom/RPI.Reflect/Material/MaterialAsset.h> #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h> #include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h> #include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h> #include <AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h> #include <AtomToolsFramework/Util/Util.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h> #include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <Material/EditorMaterialModelUvNameMapInspector.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QApplication> #include <QApplication>
@ -47,15 +45,16 @@ namespace AZ
const RPI::MaterialModelUvOverrideMap& matModUvOverrides, const RPI::MaterialModelUvOverrideMap& matModUvOverrides,
const AZStd::unordered_set<AZ::Name>& modelUvNames, const AZStd::unordered_set<AZ::Name>& modelUvNames,
MaterialModelUvOverrideMapChangedCallBack matModUvOverrideMapChangedCallBack, MaterialModelUvOverrideMapChangedCallBack matModUvOverrideMapChangedCallBack,
QWidget* parent QWidget* parent)
)
: AtomToolsFramework::InspectorWidget(parent) : AtomToolsFramework::InspectorWidget(parent)
, m_matModUvOverrideMapChangedCallBack(matModUvOverrideMapChangedCallBack) , m_matModUvOverrideMapChangedCallBack(matModUvOverrideMapChangedCallBack)
, m_matModUvOverrides(matModUvOverrides) , m_matModUvOverrides(matModUvOverrides)
{ {
// Load the originating product asset from which the new source has set will be generated // Load the originating product asset from which the new source has set will be generated
auto materialAssetOutcome = AZ::RPI::AssetUtils::LoadAsset<AZ::RPI::MaterialAsset>(assetId); auto materialAssetOutcome = AZ::RPI::AssetUtils::LoadAsset<AZ::RPI::MaterialAsset>(assetId);
AZ_Error("AZ::Render::EditorMaterialComponentInspector", materialAssetOutcome, "Failed to load material asset: %s", assetId.ToString<AZStd::string>().c_str()); AZ_Error(
"AZ::Render::EditorMaterialComponentInspector", materialAssetOutcome, "Failed to load material asset: %s",
assetId.ToString<AZStd::string>().c_str());
auto materialAsset = materialAssetOutcome.GetValue(); auto materialAsset = materialAssetOutcome.GetValue();
@ -68,12 +67,13 @@ namespace AZ
MaterialModelUvNameMapInspector::~MaterialModelUvNameMapInspector() MaterialModelUvNameMapInspector::~MaterialModelUvNameMapInspector()
{ {
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect();
} }
void MaterialModelUvNameMapInspector::Reset() void MaterialModelUvNameMapInspector::Reset()
{ {
AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); m_activeProperty = {};
m_group = {};
AtomToolsFramework::InspectorWidget::Reset(); AtomToolsFramework::InspectorWidget::Reset();
} }
@ -119,7 +119,7 @@ namespace AZ
// For some reason the reflected property editor notifications are not symmetrical // For some reason the reflected property editor notifications are not symmetrical
// This function is called continuously anytime a property changes until the edit has completed // This function is called continuously anytime a property changes until the edit has completed
// Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has started and ended // Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has started and ended
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(pNode);
if (property && m_activeProperty != property) if (property && m_activeProperty != property)
{ {
m_activeProperty = property; m_activeProperty = property;
@ -128,7 +128,7 @@ namespace AZ
void MaterialModelUvNameMapInspector::AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) void MaterialModelUvNameMapInspector::AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode)
{ {
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(pNode);
if (property && m_activeProperty == property) if (property && m_activeProperty == property)
{ {
uint32_t index = 0; uint32_t index = 0;
@ -159,7 +159,7 @@ namespace AZ
{ {
// As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been completed but they are not being called following that pattern. // As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been completed but they are not being called following that pattern.
// when this function executes the changes to the property are ready to be committed or reverted // when this function executes the changes to the property are ready to be committed or reverted
const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); const auto property = AtomToolsFramework::FindAncestorInstanceDataNodeByType<AtomToolsFramework::DynamicProperty>(pNode);
if (property && m_activeProperty == property) if (property && m_activeProperty == property)
{ {
uint32_t index = 0; uint32_t index = 0;

@ -53,9 +53,9 @@ namespace AZ
thumbnailConfig.m_modelId = assetInfo.m_assetId; thumbnailConfig.m_modelId = assetInfo.m_assetId;
thumbnailConfig.m_materialId = SharedPreviewUtils::GetAssetIdForProductPath( thumbnailConfig.m_materialId = SharedPreviewUtils::GetAssetIdForProductPath(
AtomToolsFramework::GetSettingOrDefault<AZStd::string>(MaterialAssetPathSetting, DefaultMaterialPath)); AtomToolsFramework::GetSettingsValue<AZStd::string>(MaterialAssetPathSetting, DefaultMaterialPath));
thumbnailConfig.m_lightingId = SharedPreviewUtils::GetAssetIdForProductPath( thumbnailConfig.m_lightingId = SharedPreviewUtils::GetAssetIdForProductPath(
AtomToolsFramework::GetSettingOrDefault<AZStd::string>(LightingAssetPathSetting, DefaultLightingPresetPath)); AtomToolsFramework::GetSettingsValue<AZStd::string>(LightingAssetPathSetting, DefaultLightingPresetPath));
} }
else if (assetInfo.m_assetType == RPI::MaterialAsset::RTTI_Type()) else if (assetInfo.m_assetType == RPI::MaterialAsset::RTTI_Type())
{ {
@ -65,10 +65,10 @@ namespace AZ
"/O3DE/Atom/CommonFeature/SharedPreview/MaterialAssetType/LightingAssetPath"; "/O3DE/Atom/CommonFeature/SharedPreview/MaterialAssetType/LightingAssetPath";
thumbnailConfig.m_modelId = SharedPreviewUtils::GetAssetIdForProductPath( thumbnailConfig.m_modelId = SharedPreviewUtils::GetAssetIdForProductPath(
AtomToolsFramework::GetSettingOrDefault<AZStd::string>(ModelAssetPathSetting, DefaultModelPath)); AtomToolsFramework::GetSettingsValue<AZStd::string>(ModelAssetPathSetting, DefaultModelPath));
thumbnailConfig.m_materialId = assetInfo.m_assetId; thumbnailConfig.m_materialId = assetInfo.m_assetId;
thumbnailConfig.m_lightingId = SharedPreviewUtils::GetAssetIdForProductPath( thumbnailConfig.m_lightingId = SharedPreviewUtils::GetAssetIdForProductPath(
AtomToolsFramework::GetSettingOrDefault<AZStd::string>(LightingAssetPathSetting, DefaultLightingPresetPath)); AtomToolsFramework::GetSettingsValue<AZStd::string>(LightingAssetPathSetting, DefaultLightingPresetPath));
} }
else if (assetInfo.m_assetType == RPI::AnyAsset::RTTI_Type()) else if (assetInfo.m_assetType == RPI::AnyAsset::RTTI_Type())
{ {
@ -78,9 +78,9 @@ namespace AZ
"/O3DE/Atom/CommonFeature/SharedPreview/LightingAssetType/MaterialAssetPath"; "/O3DE/Atom/CommonFeature/SharedPreview/LightingAssetType/MaterialAssetPath";
thumbnailConfig.m_modelId = SharedPreviewUtils::GetAssetIdForProductPath( thumbnailConfig.m_modelId = SharedPreviewUtils::GetAssetIdForProductPath(
AtomToolsFramework::GetSettingOrDefault<AZStd::string>(ModelAssetPathSetting, DefaultModelPath)); AtomToolsFramework::GetSettingsValue<AZStd::string>(ModelAssetPathSetting, DefaultModelPath));
thumbnailConfig.m_materialId = SharedPreviewUtils::GetAssetIdForProductPath( thumbnailConfig.m_materialId = SharedPreviewUtils::GetAssetIdForProductPath(
AtomToolsFramework::GetSettingOrDefault<AZStd::string>(MaterialAssetPathSetting, "materials/reflectionprobe/reflectionprobevisualization.azmaterial")); AtomToolsFramework::GetSettingsValue<AZStd::string>(MaterialAssetPathSetting, "materials/reflectionprobe/reflectionprobevisualization.azmaterial"));
thumbnailConfig.m_lightingId = assetInfo.m_assetId; thumbnailConfig.m_lightingId = assetInfo.m_assetId;
} }

Loading…
Cancel
Save