SlotComponent.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  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 <QCoreApplication>
  9. #include <AzCore/Component/ComponentApplication.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <Components/Slots/SlotComponent.h>
  12. #include <Components/Connections/ConnectionComponent.h>
  13. #include <Components/Slots/Default/DefaultSlotLayoutComponent.h>
  14. #include <Components/Slots/SlotConnectionFilterComponent.h>
  15. #include <GraphCanvas/Components/Connections/ConnectionFilters/ConnectionFilters.h>
  16. #include <GraphCanvas/Editor/AssetEditorBus.h>
  17. #include <GraphCanvas/Utils/GraphUtils.h>
  18. namespace GraphCanvas
  19. {
  20. //////////////////
  21. // SlotComponent
  22. //////////////////
  23. constexpr int k_defaultPriority = 10;
  24. void SlotComponent::Reflect(AZ::ReflectContext* context)
  25. {
  26. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  27. if (!serializeContext)
  28. {
  29. return;
  30. }
  31. serializeContext->Class<SlotConfiguration>()
  32. ->Version(2)
  33. ->Field("ConnectionType", &SlotConfiguration::m_connectionType)
  34. ->Field("Name", &SlotConfiguration::m_name)
  35. ->Field("SlotGroup", &SlotConfiguration::m_slotGroup)
  36. ->Field("ToolTip", &SlotConfiguration::m_tooltip)
  37. ->Field("IsNameHidden", &SlotConfiguration::m_isNameHidden)
  38. ;
  39. serializeContext->Class<SlotComponent, AZ::Component>()
  40. ->Version(4)
  41. ->Field("Configuration", &SlotComponent::m_slotConfiguration)
  42. ->Field("UserData", &SlotComponent::m_userData)
  43. ;
  44. AZ::EditContext* editContext = serializeContext->GetEditContext();
  45. if (!editContext)
  46. {
  47. return;
  48. }
  49. editContext->Class<SlotConfiguration>("Slot Configuration", "The slot's properties")
  50. ->ClassElement(AZ::Edit::ClassElements::EditorData, "Slot class attributes")
  51. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  52. ->DataElement(AZ::Edit::UIHandlers::Default, &SlotConfiguration::m_tooltip)
  53. ->Attribute(AZ::Edit::Attributes::ReadOnly, true)
  54. ;
  55. }
  56. AZ::Entity* SlotComponent::CreateCoreSlotEntity()
  57. {
  58. AZ::Entity* entity = aznew AZ::Entity("Slot");
  59. return entity;
  60. }
  61. SlotComponent::SlotComponent()
  62. : m_layoutPriority(k_defaultPriority)
  63. {
  64. }
  65. SlotComponent::SlotComponent(const SlotType& slotType)
  66. : m_slotType(slotType)
  67. , m_layoutPriority(k_defaultPriority)
  68. {
  69. }
  70. SlotComponent::SlotComponent(const SlotType& slotType, const SlotConfiguration& configuration)
  71. : m_slotType(slotType)
  72. , m_slotConfiguration(configuration)
  73. , m_layoutPriority(k_defaultPriority)
  74. {
  75. }
  76. void SlotComponent::Activate()
  77. {
  78. SlotRequestBus::Handler::BusConnect(GetEntityId());
  79. SceneMemberRequestBus::Handler::BusConnect(GetEntityId());
  80. }
  81. void SlotComponent::Deactivate()
  82. {
  83. SceneMemberRequestBus::Handler::BusDisconnect();
  84. SlotRequestBus::Handler::BusDisconnect();
  85. }
  86. void SlotComponent::SetScene(const AZ::EntityId&)
  87. {
  88. AZ_Error("Graph Canvas", false, "The scene cannot be set directly on a slot; it follows that of the node to which it belongs (slot: %s)", GetEntityId().ToString().data());
  89. }
  90. void SlotComponent::ClearScene(const AZ::EntityId&)
  91. {
  92. AZ_Error("Graph Canvas", false, "The scene cannot be cleared directly on a slot; it follows that of the node to which it belongs (slot: %s)", GetEntityId().ToString().data());
  93. }
  94. void SlotComponent::SignalMemberSetupComplete()
  95. {
  96. SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnMemberSetupComplete);
  97. }
  98. AZ::EntityId SlotComponent::GetScene() const
  99. {
  100. AZ::EntityId sceneId;
  101. SceneMemberRequestBus::EventResult(sceneId, m_nodeId, &SceneMemberRequests::GetScene);
  102. return sceneId;
  103. }
  104. void SlotComponent::OnSceneSet(const AZ::EntityId& sceneId)
  105. {
  106. SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnSceneSet, sceneId);
  107. }
  108. void SlotComponent::OnSceneReady()
  109. {
  110. SceneMemberNotificationBus::Event(GetEntityId(), &SceneMemberNotifications::OnSceneReady);
  111. FinalizeDisplay();
  112. }
  113. const AZ::EntityId& SlotComponent::GetNode() const
  114. {
  115. return m_nodeId;
  116. }
  117. void SlotComponent::SetNode(const AZ::EntityId& nodeId)
  118. {
  119. if (m_nodeId != nodeId)
  120. {
  121. m_nodeId = nodeId;
  122. SceneMemberNotificationBus::Handler::BusDisconnect();
  123. SceneMemberNotificationBus::Handler::BusConnect(m_nodeId);
  124. AZ::EntityId sceneId = GetScene();
  125. if (sceneId.IsValid())
  126. {
  127. OnSceneSet(sceneId);
  128. }
  129. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnRegisteredToNode, m_nodeId);
  130. }
  131. }
  132. Endpoint SlotComponent::GetEndpoint() const
  133. {
  134. return Endpoint(GetNode(), GetEntityId());
  135. }
  136. void SlotComponent::SetName(const AZStd::string& name)
  137. {
  138. if (name == m_slotConfiguration.m_name)
  139. {
  140. return;
  141. }
  142. m_slotConfiguration.m_name = name;
  143. // Default tooltip.
  144. if (m_slotConfiguration.m_tooltip.empty())
  145. {
  146. m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
  147. }
  148. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
  149. }
  150. void SlotComponent::SetDetails(const AZStd::string& name, const AZStd::string& tooltip)
  151. {
  152. if (name != m_slotConfiguration.m_name)
  153. {
  154. m_slotConfiguration.m_name = name;
  155. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
  156. }
  157. if (tooltip != m_slotConfiguration.m_tooltip)
  158. {
  159. m_slotConfiguration.m_tooltip = tooltip;
  160. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
  161. }
  162. }
  163. void SlotComponent::SetTooltip(const AZStd::string& tooltip)
  164. {
  165. if (tooltip == m_slotConfiguration.m_tooltip)
  166. {
  167. return;
  168. }
  169. m_slotConfiguration.m_tooltip = tooltip;
  170. // Default tooltip.
  171. if (m_slotConfiguration.m_tooltip.empty())
  172. {
  173. m_slotConfiguration.m_tooltip = m_slotConfiguration.m_name;
  174. }
  175. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
  176. }
  177. void SlotComponent::DisplayProposedConnection(const AZ::EntityId& connectionId, const Endpoint& /*endpoint*/)
  178. {
  179. bool needsStyleUpdate = m_connections.empty();
  180. m_connections.emplace_back(connectionId);
  181. if (needsStyleUpdate)
  182. {
  183. StyleNotificationBus::Event(GetEntityId(), &StyleNotifications::OnStyleChanged);
  184. }
  185. }
  186. void SlotComponent::RemoveProposedConnection(const AZ::EntityId& connectionId, const Endpoint& /*endpoint*/)
  187. {
  188. auto it = AZStd::find(m_connections.begin(), m_connections.end(), connectionId);
  189. if (it != m_connections.end())
  190. {
  191. m_connections.erase(it);
  192. if (m_connections.empty())
  193. {
  194. StyleNotificationBus::Event(GetEntityId(), &StyleNotifications::OnStyleChanged);
  195. }
  196. }
  197. }
  198. void SlotComponent::AddConnectionId(const AZ::EntityId& connectionId, const Endpoint& endpoint)
  199. {
  200. bool needsStyleUpdate = m_connections.empty();
  201. m_connections.emplace_back(connectionId);
  202. if (needsStyleUpdate)
  203. {
  204. StyleNotificationBus::Event(GetEntityId(), &StyleNotifications::OnStyleChanged);
  205. }
  206. SlotNotificationBus::Event(GetEntityId(), &SlotNotificationBus::Events::OnConnectedTo, connectionId, endpoint);
  207. }
  208. void SlotComponent::RemoveConnectionId(const AZ::EntityId& connectionId, const Endpoint& endpoint)
  209. {
  210. auto it = AZStd::find(m_connections.begin(), m_connections.end(), connectionId);
  211. if (it != m_connections.end())
  212. {
  213. m_connections.erase(it);
  214. if (m_connections.empty())
  215. {
  216. StyleNotificationBus::Event(GetEntityId(), &StyleNotifications::OnStyleChanged);
  217. }
  218. }
  219. SlotNotificationBus::Event(GetEntityId(), &SlotNotificationBus::Events::OnDisconnectedFrom, connectionId, endpoint);
  220. }
  221. void SlotComponent::SetDisplayOrdering(int ordering)
  222. {
  223. m_displayOrdering = ordering;
  224. }
  225. int SlotComponent::GetDisplayOrdering() const
  226. {
  227. return m_displayOrdering;
  228. }
  229. bool SlotComponent::IsConnectedTo(const Endpoint& endpoint) const
  230. {
  231. bool isConnectedTo = false;
  232. for (const AZ::EntityId& connection : m_connections)
  233. {
  234. ConnectionRequestBus::EventResult(isConnectedTo, connection, &ConnectionRequests::ContainsEndpoint, endpoint);
  235. if (isConnectedTo)
  236. {
  237. break;
  238. }
  239. }
  240. return isConnectedTo;
  241. }
  242. void SlotComponent::FindConnectionsForEndpoints(const AZStd::unordered_set<Endpoint>& searchEndpoints, AZStd::unordered_set<ConnectionId>& outConnections)
  243. {
  244. for (const AZ::EntityId& connection : m_connections)
  245. {
  246. GraphCanvas::Endpoint sourceEndpoint;
  247. ConnectionRequestBus::EventResult(sourceEndpoint, connection, &ConnectionRequests::GetSourceEndpoint);
  248. if (searchEndpoints.count(sourceEndpoint) > 0)
  249. {
  250. outConnections.insert(connection);
  251. continue;
  252. }
  253. GraphCanvas::Endpoint targetEndpoint;
  254. ConnectionRequestBus::EventResult(targetEndpoint, connection, &ConnectionRequests::GetTargetEndpoint);
  255. if (searchEndpoints.count(targetEndpoint) > 0)
  256. {
  257. outConnections.insert(connection);
  258. continue;
  259. }
  260. }
  261. }
  262. bool SlotComponent::CanDisplayConnectionTo(const Endpoint& endpoint) const
  263. {
  264. bool isConnectable = false;
  265. ConnectionMoveType moveType = ConnectionMoveType::Unknown;
  266. if (GetConnectionType() == CT_Input)
  267. {
  268. moveType = ConnectionMoveType::Target;
  269. }
  270. else if (GetConnectionType() == CT_Output)
  271. {
  272. moveType = ConnectionMoveType::Source;
  273. }
  274. ConnectionFilterRequestBus::EventResult(isConnectable, GetEntityId(), &ConnectionFilterRequests::CanConnectWith, endpoint, moveType);
  275. return isConnectable;
  276. }
  277. bool SlotComponent::CanCreateConnectionTo(const Endpoint& endpoint) const
  278. {
  279. bool isConnectable = CanDisplayConnectionTo(endpoint);
  280. if (isConnectable)
  281. {
  282. GraphId graphId = GetScene();
  283. if (GetConnectionType() == CT_Input)
  284. {
  285. isConnectable = GraphUtils::IsValidModelConnection(graphId, endpoint, GetEndpoint());
  286. }
  287. else if (GetConnectionType() == CT_Output)
  288. {
  289. isConnectable = GraphUtils::IsValidModelConnection(graphId, GetEndpoint(), endpoint);
  290. }
  291. }
  292. return isConnectable;
  293. }
  294. AZ::EntityId SlotComponent::CreateConnectionWithEndpoint(const Endpoint& otherEndpoint)
  295. {
  296. const bool createConnection = true;
  297. return CreateConnectionHelper(otherEndpoint, createConnection);
  298. }
  299. AZ::EntityId SlotComponent::DisplayConnection()
  300. {
  301. Endpoint invalidEndpoint;
  302. return DisplayConnectionWithEndpoint(invalidEndpoint);
  303. }
  304. AZ::EntityId SlotComponent::DisplayConnectionWithEndpoint(const Endpoint& otherEndpoint)
  305. {
  306. const bool createConnection = false;
  307. return CreateConnectionHelper(otherEndpoint, createConnection);
  308. }
  309. AZStd::any* SlotComponent::GetUserData()
  310. {
  311. return &m_userData;
  312. }
  313. bool SlotComponent::HasConnections() const
  314. {
  315. return m_connections.size() > 0;
  316. }
  317. AZ::EntityId SlotComponent::GetLastConnection() const
  318. {
  319. if (m_connections.size() > 0)
  320. {
  321. return m_connections.back();
  322. }
  323. return AZ::EntityId();
  324. }
  325. bool SlotComponent::IsNameHidden() const
  326. {
  327. return m_slotConfiguration.m_isNameHidden;
  328. }
  329. AZStd::vector<AZ::EntityId> SlotComponent::GetConnections() const
  330. {
  331. return m_connections;
  332. }
  333. void SlotComponent::SetConnectionDisplayState(RootGraphicsItemDisplayState displayState)
  334. {
  335. m_connectionDisplayStateStateSetter.ResetStateSetter();
  336. for (const AZ::EntityId& connectionId : m_connections)
  337. {
  338. StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
  339. RootGraphicsItemRequestBus::EventResult(stateController, connectionId, &RootGraphicsItemRequests::GetDisplayStateStateController);
  340. m_connectionDisplayStateStateSetter.AddStateController(stateController);
  341. }
  342. m_connectionDisplayStateStateSetter.SetState(displayState);
  343. }
  344. void SlotComponent::ReleaseConnectionDisplayState()
  345. {
  346. m_connectionDisplayStateStateSetter.ResetStateSetter();
  347. }
  348. void SlotComponent::ClearConnections()
  349. {
  350. AZStd::unordered_set< AZ::EntityId > deleteIds;
  351. for (AZ::EntityId connectionId : m_connections)
  352. {
  353. deleteIds.insert(connectionId);
  354. }
  355. SceneRequestBus::Event(GetScene(), &SceneRequests::Delete, deleteIds);
  356. }
  357. const SlotConfiguration& SlotComponent::GetSlotConfiguration() const
  358. {
  359. return m_slotConfiguration;
  360. }
  361. SlotConfiguration* SlotComponent::CloneSlotConfiguration() const
  362. {
  363. SlotConfiguration* slotConfiguration = aznew SlotConfiguration();
  364. PopulateSlotConfiguration((*slotConfiguration));
  365. return slotConfiguration;
  366. }
  367. void SlotComponent::RemapSlotForModel(const Endpoint& endpoint)
  368. {
  369. AZ_Assert(m_modelRedirections.empty(), "Multiple slot redirections is not currently supported with the connection deletion flow in GraphCanvas.");
  370. auto endpointIter = AZStd::find_if(m_modelRedirections.begin(), m_modelRedirections.end(), [&endpoint](const Endpoint& otherEndpoint) { return endpoint == otherEndpoint; });
  371. // Want to avoid duplicates in here
  372. if (endpointIter == m_modelRedirections.end())
  373. {
  374. m_modelRedirections.push_back(endpoint);
  375. }
  376. }
  377. bool SlotComponent::HasModelRemapping() const
  378. {
  379. return !m_modelRedirections.empty();
  380. }
  381. AZStd::vector< Endpoint > SlotComponent::GetRemappedModelEndpoints() const
  382. {
  383. return m_modelRedirections;
  384. }
  385. int SlotComponent::GetLayoutPriority() const
  386. {
  387. return m_layoutPriority;
  388. }
  389. void SlotComponent::SetLayoutPriority(int layoutPriority)
  390. {
  391. if (m_layoutPriority != layoutPriority)
  392. {
  393. m_layoutPriority = layoutPriority;
  394. SlotUINotificationBus::Event(GetEntityId(), &SlotUINotifications::OnSlotLayoutPriorityChanged, layoutPriority);
  395. }
  396. }
  397. void SlotComponent::PopulateSlotConfiguration(SlotConfiguration& slotConfiguration) const
  398. {
  399. slotConfiguration.m_connectionType = GetConnectionType();
  400. slotConfiguration.m_name = m_slotConfiguration.m_name;
  401. slotConfiguration.m_tooltip = m_slotConfiguration.m_tooltip;
  402. slotConfiguration.m_slotGroup = GetSlotGroup();
  403. }
  404. AZ::EntityId SlotComponent::CreateConnectionHelper(const Endpoint& otherEndpoint, bool createConnection)
  405. {
  406. if (createConnection)
  407. {
  408. if (otherEndpoint.IsValid() && !CanCreateConnectionTo(otherEndpoint))
  409. {
  410. return AZ::EntityId();
  411. }
  412. }
  413. Endpoint sourceEndpoint;
  414. Endpoint targetEndpoint;
  415. Endpoint endpoint(GetNode(), GetEntityId());
  416. if (GetConnectionType() == CT_Input)
  417. {
  418. sourceEndpoint = otherEndpoint;
  419. targetEndpoint = endpoint;
  420. }
  421. else
  422. {
  423. sourceEndpoint = endpoint;
  424. targetEndpoint = otherEndpoint;
  425. }
  426. AZ::Entity* connectionEntity = ConstructConnectionEntity(sourceEndpoint, targetEndpoint, createConnection);
  427. if (connectionEntity)
  428. {
  429. // Tweak to allow Extenders to just return the previously constructed element to help simplify down the
  430. // addition process.
  431. if (connectionEntity->GetState() == AZ::Entity::State::Active)
  432. {
  433. return connectionEntity->GetId();
  434. }
  435. GraphId graphId = GetScene();
  436. EditorId editorId;
  437. SceneRequestBus::EventResult(editorId, graphId, &SceneRequests::GetEditorId);
  438. AssetEditorRequestBus::Event(editorId, &AssetEditorRequests::CustomizeConnectionEntity, connectionEntity);
  439. connectionEntity->Init();
  440. connectionEntity->Activate();
  441. SceneRequestBus::Event(graphId, &SceneRequests::AddConnection, connectionEntity->GetId());
  442. return connectionEntity->GetId();
  443. }
  444. return AZ::EntityId();
  445. }
  446. AZ::Entity* SlotComponent::ConstructConnectionEntity(const Endpoint& sourceEndpoint, const Endpoint& targetEndpoint, bool createModelConnection)
  447. {
  448. return ConnectionComponent::CreateGeneralConnection(sourceEndpoint, targetEndpoint, createModelConnection);
  449. }
  450. void SlotComponent::FinalizeDisplay()
  451. {
  452. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnNameChanged, m_slotConfiguration.m_name);
  453. SlotNotificationBus::Event(GetEntityId(), &SlotNotifications::OnTooltipChanged, m_slotConfiguration.m_tooltip);
  454. OnFinalizeDisplay();
  455. }
  456. void SlotComponent::OnFinalizeDisplay()
  457. {
  458. }
  459. }