/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include #include #include #include #include #include #include #include namespace AtomToolsFramework { void DynamicNodeConfig::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() ->Version(0) ->Field("id", &DynamicNodeConfig::m_id) ->Field("category", &DynamicNodeConfig::m_category) ->Field("title", &DynamicNodeConfig::m_title) ->Field("subTitle", &DynamicNodeConfig::m_subTitle) ->Field("titlePaletteName", &DynamicNodeConfig::m_titlePaletteName) ->Field("description", &DynamicNodeConfig::m_description) ->Field("slotDataTypeGroups", &DynamicNodeConfig::m_slotDataTypeGroups) ->Field("settings", &DynamicNodeConfig::m_settings) ->Field("propertySlots", &DynamicNodeConfig::m_propertySlots) ->Field("inputSlots", &DynamicNodeConfig::m_inputSlots) ->Field("outputSlots", &DynamicNodeConfig::m_outputSlots) ; if (auto editContext = serializeContext->GetEditContext()) { editContext->Class("DynamicNodeConfig", "Configuration settings defining the slots and UI of a dynamic node.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->SetDynamicEditDataProvider(&DynamicNodeConfig::GetDynamicEditData) ->UIElement(AZ::Edit::UIHandlers::Button, "", "Generate a new random UUID to uniquely identify this node.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &DynamicNodeConfig::ResetUuid) ->Attribute(AZ::Edit::Attributes::ButtonText, &DynamicNodeConfig::GetUuidText) ->UIElement(AZ::Edit::UIHandlers::Button, "", "Add new settings groups from settings registered with this tool.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, &DynamicNodeConfig::AddRegisteredSettingGroups) ->Attribute(AZ::Edit::Attributes::ButtonText, "Add Setting Groups") ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_category, "Category", "Name of the category where this node will appear in the node palette.") ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_title, "Title", "Title that will appear at the top of the node UI in a graph.") ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_subTitle, "Sub Title", "Secondary title that will appear below the main title on the node UI in a graph.") ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_titlePaletteName, "Title Palette Name", "Name of the node title bar UI palette style sheet entry.") ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_description, "Description", "Description about this node's behavior.") ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_slotDataTypeGroups, "Slot Data Type Groups", "Groups of slots that should have the same types.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->ElementAttribute(AZ::Edit::Attributes::Handler, AZ_CRC_CE("MultiStringSelectDelimited")) ->ElementAttribute(AZ_CRC_CE("Options"), &DynamicNodeConfig::GetSlotNames) ->ElementAttribute(AZ_CRC_CE("DelimitersForJoin"), "|") ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_settings, "Settings", "Table of strings that can be used for any context specific or user defined data for each node.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->ElementAttribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->ElementAttribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->ElementAttribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->ElementAttribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_inputSlots, "Input Slots", "Container of dynamic node input slot configurations.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_outputSlots, "Output Slots", "Container of dynamic node output slot configurations.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_propertySlots, "Property Slots", "Container hub dynamic node property slot configurations.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ; } } if (auto behaviorContext = azrtti_cast(context)) { behaviorContext->Class("DynamicNodeConfig") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) ->Attribute(AZ::Script::Attributes::Category, "Editor") ->Attribute(AZ::Script::Attributes::Module, "atomtools") ->Constructor() ->Constructor() ->Property("id", BehaviorValueProperty(&DynamicNodeConfig::m_id)) ->Property("category", BehaviorValueProperty(&DynamicNodeConfig::m_category)) ->Property("title", BehaviorValueProperty(&DynamicNodeConfig::m_title)) ->Property("subTitle", BehaviorValueProperty(&DynamicNodeConfig::m_subTitle)) ->Property("titlePaletteName", BehaviorValueProperty(&DynamicNodeConfig::m_titlePaletteName)) ->Property("description", BehaviorValueProperty(&DynamicNodeConfig::m_description)) ->Property("slotDataTypeGroups", BehaviorValueProperty(&DynamicNodeConfig::m_slotDataTypeGroups)) ->Property("settings", BehaviorValueProperty(&DynamicNodeConfig::m_settings)) ->Property("inputSlots", BehaviorValueProperty(&DynamicNodeConfig::m_inputSlots)) ->Property("outputSlots", BehaviorValueProperty(&DynamicNodeConfig::m_outputSlots)) ->Property("propertySlots", BehaviorValueProperty(&DynamicNodeConfig::m_propertySlots)) ; } } DynamicNodeConfig::DynamicNodeConfig( const AZStd::string& category, const AZStd::string& title, const AZStd::string& subTitle, const DynamicNodeSettingsMap& settings, const AZStd::vector& inputSlots, const AZStd::vector& outputSlots, const AZStd::vector& propertySlots) : m_category(category) , m_title(title) , m_subTitle(subTitle) , m_settings(settings) , m_inputSlots(inputSlots) , m_outputSlots(outputSlots) , m_propertySlots(propertySlots) { } bool DynamicNodeConfig::Save(const AZStd::string& path) const { auto saveResult = AZ::JsonSerializationUtils::SaveObjectToFile(this, GetPathWithoutAlias(path)); if (!saveResult) { AZ_Error("DynamicNodeConfig", false, "Failed to save (%s). %s", path.c_str(), saveResult.GetError().c_str()); return false; } return true; } bool DynamicNodeConfig::Load(const AZStd::string& path) { auto loadResult = AZ::JsonSerializationUtils::LoadAnyObjectFromFile(GetPathWithoutAlias(path)); if (!loadResult) { AZ_Error("DynamicNodeConfig", false, "Failed to load (%s). %s", path.c_str(), loadResult.GetError().c_str()); return false; } if (!loadResult.GetValue().is()) { AZ_Error("DynamicNodeConfig", false, "Failed to load (%s). Doesn't contain correct type", path.c_str()); return false; } *this = AZStd::any_cast(loadResult.GetValue()); ValidateSlots(); return true; } void DynamicNodeConfig::ValidateSlots() { VisitDynamicNodeSlotConfigs( *this, [](DynamicNodeSlotConfig& slotConfig) { slotConfig.ValidateDataTypes(); }); } void DynamicNodeConfig::AutoFillMissingData() { VisitDynamicNodeSlotConfigs( *this, [](DynamicNodeSlotConfig& slotConfig) { slotConfig.AutoFillMissingData(); }); } AZStd::vector DynamicNodeConfig::GetSlotNames() const { AZStd::vector slotNames; VisitDynamicNodeSlotConfigs( *this, [&slotNames](const DynamicNodeSlotConfig& slotConfig) { slotNames.push_back(slotConfig.m_name); }); return slotNames; } AZ::Crc32 DynamicNodeConfig::AddRegisteredSettingGroups() { if (AddRegisteredSettingGroupsToMap(m_settings)) { return AZ::Edit::PropertyRefreshLevels::EntireTree; } return AZ::Edit::PropertyRefreshLevels::None; } AZ::Crc32 DynamicNodeConfig::ResetUuid() { m_id = AZ::Uuid::CreateRandom(); return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; } AZStd::string DynamicNodeConfig::GetUuidText() const { return "Reset UUID: " + m_id.ToString(); } const AZ::Edit::ElementData* DynamicNodeConfig::GetDynamicEditData( const void* handlerPtr, const void* elementPtr, const AZ::Uuid& elementType) { const DynamicNodeConfig* owner = reinterpret_cast(handlerPtr); if (elementType == azrtti_typeid()) { return FindDynamicEditDataForSetting(owner->m_settings, elementPtr); } return nullptr; } } // namespace AtomToolsFramework