DynamicNodeConfig.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AtomToolsFramework/Graph/DynamicNode/DynamicNodeConfig.h>
  9. #include <AtomToolsFramework/Graph/DynamicNode/DynamicNodeManagerRequestBus.h>
  10. #include <AtomToolsFramework/Graph/DynamicNode/DynamicNodeUtil.h>
  11. #include <AtomToolsFramework/Util/Util.h>
  12. #include <AzCore/RTTI/BehaviorContext.h>
  13. #include <AzCore/Serialization/EditContext.h>
  14. #include <AzCore/Serialization/Json/JsonUtils.h>
  15. #include <AzCore/Serialization/SerializeContext.h>
  16. namespace AtomToolsFramework
  17. {
  18. void DynamicNodeConfig::Reflect(AZ::ReflectContext* context)
  19. {
  20. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  21. {
  22. serializeContext->Class<DynamicNodeConfig>()
  23. ->Version(0)
  24. ->Field("id", &DynamicNodeConfig::m_id)
  25. ->Field("category", &DynamicNodeConfig::m_category)
  26. ->Field("title", &DynamicNodeConfig::m_title)
  27. ->Field("subTitle", &DynamicNodeConfig::m_subTitle)
  28. ->Field("titlePaletteName", &DynamicNodeConfig::m_titlePaletteName)
  29. ->Field("description", &DynamicNodeConfig::m_description)
  30. ->Field("slotDataTypeGroups", &DynamicNodeConfig::m_slotDataTypeGroups)
  31. ->Field("settings", &DynamicNodeConfig::m_settings)
  32. ->Field("propertySlots", &DynamicNodeConfig::m_propertySlots)
  33. ->Field("inputSlots", &DynamicNodeConfig::m_inputSlots)
  34. ->Field("outputSlots", &DynamicNodeConfig::m_outputSlots)
  35. ;
  36. if (auto editContext = serializeContext->GetEditContext())
  37. {
  38. editContext->Class<DynamicNodeConfig>("DynamicNodeConfig", "Configuration settings defining the slots and UI of a dynamic node.")
  39. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  40. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  41. ->SetDynamicEditDataProvider(&DynamicNodeConfig::GetDynamicEditData)
  42. ->UIElement(AZ::Edit::UIHandlers::Button, "", "Generate a new random UUID to uniquely identify this node.")
  43. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &DynamicNodeConfig::ResetUuid)
  44. ->Attribute(AZ::Edit::Attributes::ButtonText, &DynamicNodeConfig::GetUuidText)
  45. ->UIElement(AZ::Edit::UIHandlers::Button, "", "Add new settings groups from settings registered with this tool.")
  46. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &DynamicNodeConfig::AddRegisteredSettingGroups)
  47. ->Attribute(AZ::Edit::Attributes::ButtonText, "Add Setting Groups")
  48. ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_category, "Category", "Name of the category where this node will appear in the node palette.")
  49. ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_title, "Title", "Title that will appear at the top of the node UI in a graph.")
  50. ->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.")
  51. ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_titlePaletteName, "Title Palette Name", "Name of the node title bar UI palette style sheet entry.")
  52. ->DataElement(AZ_CRC_CE("MultilineStringDialog"), &DynamicNodeConfig::m_description, "Description", "Description about this node's behavior.")
  53. ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_slotDataTypeGroups, "Slot Data Type Groups", "Groups of slots that should have the same types.")
  54. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  55. ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  56. ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  57. ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  58. ->ElementAttribute(AZ::Edit::Attributes::Handler, AZ_CRC_CE("MultiStringSelectDelimited"))
  59. ->ElementAttribute(AZ_CRC_CE("Options"), &DynamicNodeConfig::GetSlotNames)
  60. ->ElementAttribute(AZ_CRC_CE("DelimitersForJoin"), "|")
  61. ->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.")
  62. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  63. ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  64. ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  65. ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  66. ->ElementAttribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  67. ->ElementAttribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  68. ->ElementAttribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  69. ->ElementAttribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  70. ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_inputSlots, "Input Slots", "Container of dynamic node input slot configurations.")
  71. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  72. ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  73. ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  74. ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  75. ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_outputSlots, "Output Slots", "Container of dynamic node output slot configurations.")
  76. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  77. ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  78. ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  79. ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  80. ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicNodeConfig::m_propertySlots, "Property Slots", "Container hub dynamic node property slot configurations.")
  81. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
  82. ->Attribute(AZ::Edit::Attributes::ClearNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  83. ->Attribute(AZ::Edit::Attributes::AddNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  84. ->Attribute(AZ::Edit::Attributes::RemoveNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  85. ;
  86. }
  87. }
  88. if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  89. {
  90. behaviorContext->Class<DynamicNodeConfig>("DynamicNodeConfig")
  91. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  92. ->Attribute(AZ::Script::Attributes::Category, "Editor")
  93. ->Attribute(AZ::Script::Attributes::Module, "atomtools")
  94. ->Constructor()
  95. ->Constructor<const DynamicNodeConfig&>()
  96. ->Property("id", BehaviorValueProperty(&DynamicNodeConfig::m_id))
  97. ->Property("category", BehaviorValueProperty(&DynamicNodeConfig::m_category))
  98. ->Property("title", BehaviorValueProperty(&DynamicNodeConfig::m_title))
  99. ->Property("subTitle", BehaviorValueProperty(&DynamicNodeConfig::m_subTitle))
  100. ->Property("titlePaletteName", BehaviorValueProperty(&DynamicNodeConfig::m_titlePaletteName))
  101. ->Property("description", BehaviorValueProperty(&DynamicNodeConfig::m_description))
  102. ->Property("slotDataTypeGroups", BehaviorValueProperty(&DynamicNodeConfig::m_slotDataTypeGroups))
  103. ->Property("settings", BehaviorValueProperty(&DynamicNodeConfig::m_settings))
  104. ->Property("inputSlots", BehaviorValueProperty(&DynamicNodeConfig::m_inputSlots))
  105. ->Property("outputSlots", BehaviorValueProperty(&DynamicNodeConfig::m_outputSlots))
  106. ->Property("propertySlots", BehaviorValueProperty(&DynamicNodeConfig::m_propertySlots))
  107. ;
  108. }
  109. }
  110. DynamicNodeConfig::DynamicNodeConfig(
  111. const AZStd::string& category,
  112. const AZStd::string& title,
  113. const AZStd::string& subTitle,
  114. const DynamicNodeSettingsMap& settings,
  115. const AZStd::vector<DynamicNodeSlotConfig>& inputSlots,
  116. const AZStd::vector<DynamicNodeSlotConfig>& outputSlots,
  117. const AZStd::vector<DynamicNodeSlotConfig>& propertySlots)
  118. : m_category(category)
  119. , m_title(title)
  120. , m_subTitle(subTitle)
  121. , m_settings(settings)
  122. , m_inputSlots(inputSlots)
  123. , m_outputSlots(outputSlots)
  124. , m_propertySlots(propertySlots)
  125. {
  126. }
  127. bool DynamicNodeConfig::Save(const AZStd::string& path) const
  128. {
  129. auto saveResult = AZ::JsonSerializationUtils::SaveObjectToFile(this, GetPathWithoutAlias(path));
  130. if (!saveResult)
  131. {
  132. AZ_Error("DynamicNodeConfig", false, "Failed to save (%s). %s", path.c_str(), saveResult.GetError().c_str());
  133. return false;
  134. }
  135. return true;
  136. }
  137. bool DynamicNodeConfig::Load(const AZStd::string& path)
  138. {
  139. auto loadResult = AZ::JsonSerializationUtils::LoadAnyObjectFromFile(GetPathWithoutAlias(path));
  140. if (!loadResult)
  141. {
  142. AZ_Error("DynamicNodeConfig", false, "Failed to load (%s). %s", path.c_str(), loadResult.GetError().c_str());
  143. return false;
  144. }
  145. if (!loadResult.GetValue().is<DynamicNodeConfig>())
  146. {
  147. AZ_Error("DynamicNodeConfig", false, "Failed to load (%s). Doesn't contain correct type", path.c_str());
  148. return false;
  149. }
  150. *this = AZStd::any_cast<DynamicNodeConfig>(loadResult.GetValue());
  151. ValidateSlots();
  152. return true;
  153. }
  154. void DynamicNodeConfig::ValidateSlots()
  155. {
  156. VisitDynamicNodeSlotConfigs(
  157. *this,
  158. [](DynamicNodeSlotConfig& slotConfig)
  159. {
  160. slotConfig.ValidateDataTypes();
  161. });
  162. }
  163. void DynamicNodeConfig::AutoFillMissingData()
  164. {
  165. VisitDynamicNodeSlotConfigs(
  166. *this,
  167. [](DynamicNodeSlotConfig& slotConfig)
  168. {
  169. slotConfig.AutoFillMissingData();
  170. });
  171. }
  172. AZStd::vector<AZStd::string> DynamicNodeConfig::GetSlotNames() const
  173. {
  174. AZStd::vector<AZStd::string> slotNames;
  175. VisitDynamicNodeSlotConfigs(
  176. *this,
  177. [&slotNames](const DynamicNodeSlotConfig& slotConfig)
  178. {
  179. slotNames.push_back(slotConfig.m_name);
  180. });
  181. return slotNames;
  182. }
  183. AZ::Crc32 DynamicNodeConfig::AddRegisteredSettingGroups()
  184. {
  185. if (AddRegisteredSettingGroupsToMap(m_settings))
  186. {
  187. return AZ::Edit::PropertyRefreshLevels::EntireTree;
  188. }
  189. return AZ::Edit::PropertyRefreshLevels::None;
  190. }
  191. AZ::Crc32 DynamicNodeConfig::ResetUuid()
  192. {
  193. m_id = AZ::Uuid::CreateRandom();
  194. return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
  195. }
  196. AZStd::string DynamicNodeConfig::GetUuidText() const
  197. {
  198. return "Reset UUID: " + m_id.ToString<AZStd::string>();
  199. }
  200. const AZ::Edit::ElementData* DynamicNodeConfig::GetDynamicEditData(
  201. const void* handlerPtr, const void* elementPtr, const AZ::Uuid& elementType)
  202. {
  203. const DynamicNodeConfig* owner = reinterpret_cast<const DynamicNodeConfig*>(handlerPtr);
  204. if (elementType == azrtti_typeid<AZStd::string>())
  205. {
  206. return FindDynamicEditDataForSetting(owner->m_settings, elementPtr);
  207. }
  208. return nullptr;
  209. }
  210. } // namespace AtomToolsFramework