GeneralSlotLayoutComponent.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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 <functional>
  9. #include <QGraphicsItem>
  10. #include <QGraphicsLayoutItem>
  11. #include <QGraphicsScene>
  12. #include <QGraphicsWidget>
  13. #include <QPainter>
  14. #include <AzCore/RTTI/TypeInfo.h>
  15. #include <Components/Nodes/General/GeneralSlotLayoutComponent.h>
  16. #include <Components/Nodes/General/GeneralNodeTitleComponent.h>
  17. #include <Components/Nodes/General/GeneralNodeFrameComponent.h>
  18. #include <GraphCanvas/Components/GeometryBus.h>
  19. #include <GraphCanvas/Components/Nodes/NodeLayoutBus.h>
  20. #include <GraphCanvas/Components/Nodes/NodeBus.h>
  21. #include <GraphCanvas/Editor/GraphCanvasProfiler.h>
  22. #include <GraphCanvas/tools.h>
  23. namespace GraphCanvas
  24. {
  25. ///////////////////////////////
  26. // GeneralSlotLayoutComponent
  27. ///////////////////////////////
  28. void GeneralSlotLayoutComponent::Reflect(AZ::ReflectContext* context)
  29. {
  30. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  31. if (serializeContext)
  32. {
  33. serializeContext->Class<SlotGroupConfiguration>()
  34. ->Version(1)
  35. ->Field("LayoutOrder", &SlotGroupConfiguration::m_layoutOrder)
  36. ;
  37. serializeContext->Class<GeneralSlotLayoutComponent, AZ::Component>()
  38. ->Version(2)
  39. ->Field("EnableDividers", &GeneralSlotLayoutComponent::m_enableDividers)
  40. ->Field("ConfigurationMap", &GeneralSlotLayoutComponent::m_slotGroupConfigurations)
  41. ;
  42. }
  43. }
  44. GeneralSlotLayoutComponent::GeneralSlotLayoutComponent()
  45. : m_enableDividers(false)
  46. {
  47. }
  48. GeneralSlotLayoutComponent::~GeneralSlotLayoutComponent()
  49. {
  50. }
  51. void GeneralSlotLayoutComponent::Init()
  52. {
  53. m_nodeSlotsUi = aznew GeneralSlotLayoutGraphicsWidget(*this);
  54. // Default ordering of the slots determined by the SlotGroupConfiguration value.
  55. // Values are displayed lowest first to highest last.
  56. //
  57. // This needs to be done using emplace and in init to deal with serialization(serialization will not step on any values
  58. // already in this map, so they all need to be added after the deserialization step has occurred)
  59. m_slotGroupConfigurations.emplace(SlotGroups::ExecutionGroup, SlotGroupConfiguration(0));
  60. m_slotGroupConfigurations.emplace(SlotGroups::PropertyGroup, SlotGroupConfiguration(1));
  61. m_slotGroupConfigurations.emplace(SlotGroups::VariableReferenceGroup, SlotGroupConfiguration(2));
  62. m_slotGroupConfigurations.emplace(SlotGroups::DataGroup, SlotGroupConfiguration(3));
  63. m_slotGroupConfigurations.emplace(SlotGroups::VariableSourceGroup, SlotGroupConfiguration(4));
  64. }
  65. void GeneralSlotLayoutComponent::Activate()
  66. {
  67. if (m_nodeSlotsUi)
  68. {
  69. m_nodeSlotsUi->Activate();
  70. }
  71. }
  72. void GeneralSlotLayoutComponent::Deactivate()
  73. {
  74. if (m_nodeSlotsUi)
  75. {
  76. m_nodeSlotsUi->Deactivate();
  77. }
  78. }
  79. QGraphicsWidget* GeneralSlotLayoutComponent::GetGraphicsWidget()
  80. {
  81. return m_nodeSlotsUi;
  82. }
  83. ////////////////////////////////////
  84. // GeneralSlotLayoutGraphicsWidget
  85. ////////////////////////////////////
  86. ////////////////////////
  87. // LayoutDividerWidget
  88. ////////////////////////
  89. GeneralSlotLayoutGraphicsWidget::LayoutDividerWidget::LayoutDividerWidget(QGraphicsItem* parent)
  90. : QGraphicsWidget(parent)
  91. {
  92. setAutoFillBackground(true);
  93. setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
  94. setContentsMargins(0, 0, 0, 0);
  95. }
  96. void GeneralSlotLayoutGraphicsWidget::LayoutDividerWidget::UpdateStyle(const Styling::StyleHelper& styleHelper)
  97. {
  98. prepareGeometryChange();
  99. qreal border = AZStd::max(1., styleHelper.GetAttribute(Styling::Attribute::BorderWidth, 0.));
  100. QColor dividerColor = styleHelper.GetColor(Styling::Attribute::BorderColor);
  101. QPalette widgetPalette = palette();
  102. widgetPalette.setColor(QPalette::ColorGroup::Active, QPalette::ColorRole::Window, dividerColor);
  103. setPalette(widgetPalette);
  104. setMinimumHeight(border);
  105. setPreferredHeight(border);
  106. setMaximumHeight(border);
  107. updateGeometry();
  108. update();
  109. }
  110. //////////////////////////
  111. // LinearSlotGroupLayout
  112. //////////////////////////
  113. GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::LinearSlotGroupWidget(QGraphicsItem* parent)
  114. : QGraphicsWidget(parent)
  115. , m_inputs(nullptr)
  116. , m_outputs(nullptr)
  117. {
  118. setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  119. m_inputs = new QGraphicsLinearLayout(Qt::Vertical);
  120. m_inputs->setContentsMargins(0, 0, 0, 0);
  121. m_inputs->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  122. {
  123. QGraphicsWidget* spacer = new QGraphicsWidget();
  124. spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  125. spacer->setContentsMargins(0, 0, 0, 0);
  126. spacer->setPreferredSize(0, 0);
  127. spacer->setMaximumHeight(0);
  128. m_inputs->addItem(spacer);
  129. }
  130. m_horizontalSpacer = new QGraphicsWidget();
  131. m_horizontalSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  132. m_horizontalSpacer->setContentsMargins(0, 0, 0, 0);
  133. m_horizontalSpacer->setPreferredSize(0, 0);
  134. m_outputs = new QGraphicsLinearLayout(Qt::Vertical);
  135. m_outputs->setContentsMargins(0, 0, 0, 0);
  136. m_outputs->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  137. {
  138. QGraphicsWidget* spacer = new QGraphicsWidget();
  139. spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  140. spacer->setContentsMargins(0, 0, 0, 0);
  141. spacer->setPreferredSize(0, 0);
  142. spacer->setMaximumHeight(0);
  143. m_outputs->addItem(spacer);
  144. }
  145. m_layout = new QGraphicsLinearLayout(Qt::Horizontal);
  146. setLayout(m_layout);
  147. m_layout->setInstantInvalidatePropagation(true);
  148. // Creating the actual display
  149. // <input><spacer><output>
  150. m_layout->addItem(m_inputs);
  151. m_layout->addItem(m_horizontalSpacer);
  152. m_layout->addItem(m_outputs);
  153. m_layout->setAlignment(m_inputs, Qt::AlignTop);
  154. m_layout->setAlignment(m_outputs, Qt::AlignTop);
  155. }
  156. void GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::DisplaySlot(const AZ::EntityId& slotId)
  157. {
  158. ConnectionType connectionType = ConnectionType::CT_Invalid;
  159. SlotRequestBus::EventResult(connectionType, slotId, &SlotRequests::GetConnectionType);
  160. SlotLayoutInfo slotInfo(slotId);
  161. if (connectionType == CT_Input)
  162. {
  163. SlotUINotificationBus::MultiHandler::BusConnect(slotId);
  164. m_inputSlotSet.insert(slotId);
  165. LayoutSlot(m_inputs, m_inputSlots, slotInfo);
  166. }
  167. else if (connectionType == CT_Output)
  168. {
  169. SlotUINotificationBus::MultiHandler::BusConnect(slotId);
  170. m_outputSlotSet.insert(slotId);
  171. LayoutSlot(m_outputs, m_outputSlots, slotInfo);
  172. }
  173. else
  174. {
  175. AZ_Warning("GraphCanvas", false, "Invalid Connection Type for slot. Cannot add to Node Layout");
  176. }
  177. }
  178. void GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::RemoveSlot(const AZ::EntityId& slotId)
  179. {
  180. ConnectionType connectionType = ConnectionType::CT_Invalid;
  181. SlotRequestBus::EventResult(connectionType, slotId, &SlotRequests::GetConnectionType);
  182. QGraphicsLayoutItem* layoutItem = GetLayoutItem(slotId);
  183. if (layoutItem)
  184. {
  185. SlotUINotificationBus::MultiHandler::BusDisconnect(slotId);
  186. if (scene())
  187. {
  188. scene()->removeItem(layoutItem->graphicsItem());
  189. }
  190. if (connectionType == CT_Input)
  191. {
  192. m_inputSlotSet.erase(slotId);
  193. m_inputs->removeItem(layoutItem);
  194. for (unsigned int i = 0; i < m_inputSlots.size(); ++i)
  195. {
  196. if (m_inputSlots[i].m_slotId == slotId)
  197. {
  198. m_inputSlots.erase(m_inputSlots.begin() + i);
  199. break;
  200. }
  201. }
  202. }
  203. else if (connectionType == CT_Output)
  204. {
  205. m_outputSlotSet.erase(slotId);
  206. m_outputs->removeItem(layoutItem);
  207. for (unsigned int i = 0; i < m_outputSlots.size(); ++i)
  208. {
  209. if (m_outputSlots[i].m_slotId == slotId)
  210. {
  211. m_outputSlots.erase(m_outputSlots.begin() + i);
  212. break;
  213. }
  214. }
  215. }
  216. }
  217. }
  218. QGraphicsLinearLayout* GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::GetLayout()
  219. {
  220. return m_layout;
  221. }
  222. QGraphicsWidget* GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::GetSpacer()
  223. {
  224. return m_horizontalSpacer;
  225. }
  226. const AZStd::vector< SlotLayoutInfo >& GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::GetInputSlots() const
  227. {
  228. return m_inputSlots;
  229. }
  230. const AZStd::vector< SlotLayoutInfo >& GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::GetOutputSlots() const
  231. {
  232. return m_outputSlots;
  233. }
  234. bool GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::IsEmpty() const
  235. {
  236. // 1 because there is a spacer in each of the layouts that we need to account for.
  237. return m_inputs->count() == 1 && m_outputs->count() == 1;
  238. }
  239. void GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::UpdateStyle(const Styling::StyleHelper& styleHelper)
  240. {
  241. prepareGeometryChange();
  242. qreal spacing = styleHelper.GetAttribute(Styling::Attribute::Spacing, 0);
  243. qreal margin = styleHelper.GetAttribute(Styling::Attribute::Margin, 0);
  244. setContentsMargins(margin, margin, margin, margin);
  245. for (QGraphicsLinearLayout* internalLayout : { m_inputs, m_outputs })
  246. {
  247. internalLayout->setSpacing(spacing);
  248. internalLayout->invalidate();
  249. internalLayout->updateGeometry();
  250. }
  251. updateGeometry();
  252. update();
  253. }
  254. void GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::OnSlotLayoutPriorityChanged(int layoutPriority)
  255. {
  256. const SlotId* slotId = SlotUINotificationBus::GetCurrentBusId();
  257. if (slotId == nullptr)
  258. {
  259. return;
  260. }
  261. AZStd::vector< SlotLayoutInfo >* layoutVector = nullptr;
  262. QGraphicsLinearLayout* layoutElement = nullptr;
  263. if (m_inputSlotSet.count((*slotId)) > 0)
  264. {
  265. layoutVector = &m_inputSlots;
  266. layoutElement = m_inputs;
  267. }
  268. else if (m_outputSlotSet.count((*slotId)) > 0)
  269. {
  270. layoutVector = &m_outputSlots;
  271. layoutElement = m_outputs;
  272. }
  273. if (layoutVector == nullptr || layoutElement == nullptr)
  274. {
  275. return;
  276. }
  277. for (auto layoutIter = layoutVector->begin(); layoutIter != layoutVector->end(); ++layoutIter)
  278. {
  279. if (layoutIter->m_slotId == (*slotId))
  280. {
  281. SlotLayoutInfo info = (*layoutIter);
  282. info.m_priority = layoutPriority;
  283. layoutVector->erase(layoutIter);
  284. QGraphicsLayoutItem* layoutItem = GetLayoutItem(info.m_slotId);
  285. layoutElement->removeItem(layoutItem);
  286. LayoutSlot(layoutElement, (*layoutVector), info);
  287. break;
  288. }
  289. }
  290. }
  291. int GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::LayoutSlot(QGraphicsLinearLayout* layout, AZStd::vector<SlotLayoutInfo>& slotList, const SlotLayoutInfo& slotInfo)
  292. {
  293. bool inserted = false;
  294. int i = 0;
  295. auto listIter = slotList.begin();
  296. while (listIter != slotList.end())
  297. {
  298. if (listIter->m_priority < slotInfo.m_priority)
  299. {
  300. inserted = true;
  301. slotList.insert(listIter, slotInfo);
  302. break;
  303. }
  304. ++i;
  305. ++listIter;
  306. }
  307. if (!inserted)
  308. {
  309. slotList.insert(slotList.end(), slotInfo);
  310. }
  311. QGraphicsLayoutItem* layoutItem = GetLayoutItem(slotInfo.m_slotId);
  312. if (layoutItem)
  313. {
  314. layout->insertItem(i, layoutItem);
  315. layout->setAlignment(layoutItem, Qt::AlignTop);
  316. SlotRequestBus::Event(slotInfo.m_slotId, &SlotRequests::SetDisplayOrdering, i);
  317. }
  318. return i;
  319. }
  320. QGraphicsLayoutItem* GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget::GetLayoutItem(const AZ::EntityId& slotId) const
  321. {
  322. QGraphicsLayoutItem* layoutItem = nullptr;
  323. VisualRequestBus::EventResult(layoutItem, slotId, &VisualRequests::AsGraphicsLayoutItem);
  324. AZ_Assert(layoutItem, "Slot must return a GraphicsLayoutItem.");
  325. return layoutItem;
  326. }
  327. ////////////////////////////////////
  328. // GeneralSlotLayoutGraphicsWidget
  329. ////////////////////////////////////
  330. GeneralSlotLayoutGraphicsWidget::GeneralSlotLayoutGraphicsWidget(GeneralSlotLayoutComponent& nodeSlots)
  331. : m_nodeSlots(nodeSlots)
  332. , m_entityId(nodeSlots.GetEntityId())
  333. , m_addedToScene(false)
  334. {
  335. setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
  336. setGraphicsItem(this);
  337. setAcceptHoverEvents(false);
  338. setFlag(ItemIsMovable, false);
  339. setContentsMargins(0, 0, 0, 0);
  340. setData(GraphicsItemName, QStringLiteral("Slots/%1").arg(static_cast<AZ::u64>(GetEntityId()), 16, 16, QChar('0')));
  341. m_groupLayout = new QGraphicsLinearLayout(Qt::Vertical);
  342. m_groupLayout->setSpacing(0);
  343. m_groupLayout->setInstantInvalidatePropagation(true);
  344. setLayout(m_groupLayout);
  345. }
  346. GeneralSlotLayoutGraphicsWidget::~GeneralSlotLayoutGraphicsWidget()
  347. {
  348. // Because I'm allowing for re-use of widgets. There's no guarantee which widgets
  349. // will have a valid parent. So we want to clear our display, then delete everything
  350. // that we own.
  351. ClearLayout();
  352. for (LayoutDividerWidget* divider : m_dividers)
  353. {
  354. delete divider;
  355. }
  356. for (auto& mapPair : m_slotGroups)
  357. {
  358. delete mapPair.second;
  359. }
  360. }
  361. void GeneralSlotLayoutGraphicsWidget::Activate()
  362. {
  363. SlotLayoutRequestBus::Handler::BusConnect(GetEntityId());
  364. NodeNotificationBus::Handler::BusConnect(GetEntityId());
  365. NodeSlotsRequestBus::Handler::BusConnect(GetEntityId());
  366. StyleNotificationBus::Handler::BusConnect(GetEntityId());
  367. SceneMemberNotificationBus::Handler::BusConnect(GetEntityId());
  368. }
  369. void GeneralSlotLayoutGraphicsWidget::OnNodeActivated()
  370. {
  371. ActivateSlots();
  372. UpdateLayout();
  373. }
  374. void GeneralSlotLayoutGraphicsWidget::Deactivate()
  375. {
  376. ClearLayout();
  377. SceneMemberNotificationBus::Handler::BusDisconnect();
  378. StyleNotificationBus::Handler::BusDisconnect();
  379. NodeSlotsRequestBus::Handler::BusDisconnect();
  380. NodeNotificationBus::Handler::BusDisconnect();
  381. SlotLayoutRequestBus::Handler::BusDisconnect();
  382. }
  383. void GeneralSlotLayoutGraphicsWidget::OnSlotAddedToNode(const AZ::EntityId& slotId)
  384. {
  385. bool needsUpate = DisplaySlot(slotId);
  386. if (needsUpate)
  387. {
  388. UpdateLayout();
  389. }
  390. }
  391. void GeneralSlotLayoutGraphicsWidget::OnSlotRemovedFromNode(const AZ::EntityId& slotId)
  392. {
  393. bool needsUpdate = RemoveSlot(slotId);
  394. if (needsUpdate)
  395. {
  396. UpdateLayout();
  397. }
  398. }
  399. QGraphicsLayoutItem* GeneralSlotLayoutGraphicsWidget::GetGraphicsLayoutItem()
  400. {
  401. return this;
  402. }
  403. QGraphicsLinearLayout* GeneralSlotLayoutGraphicsWidget::GetLinearLayout(const SlotGroup& slotGroup)
  404. {
  405. return FindCreateSlotGroupWidget(slotGroup)->GetLayout();
  406. }
  407. QGraphicsWidget* GeneralSlotLayoutGraphicsWidget::GetSpacer(const SlotGroup& slotGroup)
  408. {
  409. return FindCreateSlotGroupWidget(slotGroup)->GetSpacer();
  410. }
  411. void GeneralSlotLayoutGraphicsWidget::OnSceneSet(const AZ::EntityId& /*sceneId*/)
  412. {
  413. m_addedToScene = true;
  414. UpdateLayout();
  415. }
  416. void GeneralSlotLayoutGraphicsWidget::SetDividersEnabled(bool enabled)
  417. {
  418. m_nodeSlots.m_enableDividers = enabled;
  419. UpdateLayout();
  420. }
  421. void GeneralSlotLayoutGraphicsWidget::ConfigureSlotGroup(SlotGroup group, SlotGroupConfiguration configuration)
  422. {
  423. if (group != SlotGroups::Invalid)
  424. {
  425. m_nodeSlots.m_slotGroupConfigurations[group] = configuration;
  426. UpdateLayout();
  427. }
  428. }
  429. int GeneralSlotLayoutGraphicsWidget::GetSlotGroupDisplayOrder(SlotGroup group) const
  430. {
  431. AZStd::set<SlotGroup, SlotGroupConfigurationComparator> slotOrdering(SlotGroupConfigurationComparator(&m_nodeSlots.m_slotGroupConfigurations));
  432. for (auto& mapPair : m_slotGroups)
  433. {
  434. if (!mapPair.second->IsEmpty())
  435. {
  436. const SlotGroupConfiguration& configuration = m_nodeSlots.m_slotGroupConfigurations[mapPair.first];
  437. if (configuration.m_visible)
  438. {
  439. slotOrdering.insert(mapPair.first);
  440. }
  441. }
  442. }
  443. int counter = 1;
  444. for (const SlotGroup& slotGroup : slotOrdering)
  445. {
  446. if (slotGroup == group)
  447. {
  448. return counter;
  449. }
  450. ++counter;
  451. }
  452. return -1;
  453. }
  454. bool GeneralSlotLayoutGraphicsWidget::IsSlotGroupVisible(SlotGroup group) const
  455. {
  456. bool isVisible = false;
  457. if (group != SlotGroups::Invalid)
  458. {
  459. SlotGroupConfiguration& slotConfiguration = m_nodeSlots.m_slotGroupConfigurations[group];
  460. isVisible = slotConfiguration.m_visible;
  461. }
  462. return isVisible;
  463. }
  464. void GeneralSlotLayoutGraphicsWidget::SetSlotGroupVisible(SlotGroup group, bool visible)
  465. {
  466. if (group != SlotGroups::Invalid)
  467. {
  468. SlotGroupConfiguration& slotConfiguration = m_nodeSlots.m_slotGroupConfigurations[group];
  469. if (slotConfiguration.m_visible != visible)
  470. {
  471. slotConfiguration.m_visible = visible;
  472. UpdateLayout();
  473. }
  474. }
  475. }
  476. void GeneralSlotLayoutGraphicsWidget::ClearSlotGroup(SlotGroup group)
  477. {
  478. if (group != SlotGroups::Invalid)
  479. {
  480. LinearSlotGroupWidget* slotGroupWidget = FindCreateSlotGroupWidget(group);
  481. if (slotGroupWidget)
  482. {
  483. AZStd::vector< SlotLayoutInfo > inputSlots = slotGroupWidget->GetInputSlots();
  484. for (const SlotLayoutInfo& inputSlot : inputSlots)
  485. {
  486. NodeRequestBus::Event(GetEntityId(), &NodeRequests::RemoveSlot, inputSlot.m_slotId);
  487. }
  488. AZStd::vector< SlotLayoutInfo > outputSlots = slotGroupWidget->GetOutputSlots();
  489. for (const SlotLayoutInfo& outputSlot : outputSlots)
  490. {
  491. NodeRequestBus::Event(GetEntityId(), &NodeRequests::RemoveSlot, outputSlot.m_slotId);
  492. }
  493. }
  494. }
  495. }
  496. void GeneralSlotLayoutGraphicsWidget::OnStyleChanged()
  497. {
  498. UpdateStyles();
  499. update();
  500. }
  501. bool GeneralSlotLayoutGraphicsWidget::DisplaySlot(const AZ::EntityId& slotId)
  502. {
  503. bool needsUpdate = false;
  504. SlotGroup slotGroup = SlotGroups::Invalid;
  505. SlotRequestBus::EventResult(slotGroup, slotId, &SlotRequests::GetSlotGroup);
  506. LinearSlotGroupWidget* groupWidget = FindCreateSlotGroupWidget(slotGroup);
  507. if (groupWidget)
  508. {
  509. needsUpdate = groupWidget->IsEmpty();
  510. groupWidget->DisplaySlot(slotId);
  511. }
  512. return needsUpdate;
  513. }
  514. bool GeneralSlotLayoutGraphicsWidget::RemoveSlot(const AZ::EntityId& slotId)
  515. {
  516. bool needsUpdate = false;
  517. SlotGroup slotGroup = SlotGroups::Invalid;
  518. SlotRequestBus::EventResult(slotGroup, slotId, &SlotRequests::GetSlotGroup);
  519. LinearSlotGroupWidget* groupWidget = FindCreateSlotGroupWidget(slotGroup);
  520. if (groupWidget)
  521. {
  522. groupWidget->RemoveSlot(slotId);
  523. needsUpdate = groupWidget->IsEmpty();
  524. }
  525. return needsUpdate;
  526. }
  527. void GeneralSlotLayoutGraphicsWidget::ActivateSlots()
  528. {
  529. AZStd::vector<AZ::EntityId> slotIds;
  530. NodeRequestBus::EventResult(slotIds, m_nodeSlots.GetEntityId(), &NodeRequests::GetSlotIds);
  531. for (const AZ::EntityId& slotId : slotIds)
  532. {
  533. AZ::Entity* slot = nullptr;
  534. AZ::ComponentApplicationBus::BroadcastResult(slot, &AZ::ComponentApplicationRequests::FindEntity, slotId);
  535. AZ_Assert(slot, "A Slot (ID: %s) of Node (ID: %s) has no Entity!", slotId.ToString().data(), m_nodeSlots.GetEntityId().ToString().data());
  536. DisplaySlot(slotId);
  537. }
  538. }
  539. void GeneralSlotLayoutGraphicsWidget::ClearLayout()
  540. {
  541. // Clear out our previous configurations
  542. while (m_groupLayout->count() > 0)
  543. {
  544. m_groupLayout->removeAt(m_groupLayout->count() - 1);
  545. }
  546. }
  547. void GeneralSlotLayoutGraphicsWidget::UpdateLayout()
  548. {
  549. if (!m_addedToScene)
  550. {
  551. return;
  552. }
  553. ClearLayout();
  554. prepareGeometryChange();
  555. AZStd::set<SlotGroup, SlotGroupConfigurationComparator> slotOrdering(SlotGroupConfigurationComparator(&m_nodeSlots.m_slotGroupConfigurations));
  556. for (auto& mapPair : m_slotGroups)
  557. {
  558. if (!mapPair.second->IsEmpty())
  559. {
  560. const SlotGroupConfiguration& configuration = m_nodeSlots.m_slotGroupConfigurations[mapPair.first];
  561. if (configuration.m_visible)
  562. {
  563. slotOrdering.insert(mapPair.first);
  564. }
  565. else
  566. {
  567. // Fun with SceneFilter's.
  568. // If an object with a scene filter is removed from the scene
  569. // That scene filter gets destroyed or invalidated in some way.
  570. //
  571. // This means if we were to ever remove a data slot from the scene
  572. // and add it back on, we need to re-hook up everything.
  573. auto groupIter = m_slotGroups.find(mapPair.first);
  574. if (groupIter != m_slotGroups.end())
  575. {
  576. if (groupIter->second->scene() != nullptr)
  577. {
  578. groupIter->second->scene()->removeItem(groupIter->second);
  579. }
  580. }
  581. }
  582. }
  583. }
  584. for (auto& divider : m_dividers)
  585. {
  586. if (divider->isVisible())
  587. {
  588. divider->setVisible(false);
  589. }
  590. }
  591. int dividerCount = 0;
  592. bool needsDivider = false;
  593. for (const SlotGroup& slotGroup : slotOrdering)
  594. {
  595. if (needsDivider)
  596. {
  597. needsDivider = false;
  598. LayoutDividerWidget* dividerWidget = FindCreateDividerWidget(dividerCount);
  599. ++dividerCount;
  600. m_groupLayout->addItem(dividerWidget);
  601. dividerWidget->setVisible(true);
  602. }
  603. auto groupIter = m_slotGroups.find(slotGroup);
  604. if (groupIter != m_slotGroups.end())
  605. {
  606. needsDivider = m_nodeSlots.m_enableDividers;
  607. m_groupLayout->addItem(groupIter->second);
  608. }
  609. }
  610. RefreshDisplay();
  611. NodeUIRequestBus::Event(GetEntityId(), &NodeUIRequests::AdjustSize);
  612. }
  613. void GeneralSlotLayoutGraphicsWidget::UpdateStyles()
  614. {
  615. m_styleHelper.SetStyle(GetEntityId(), Styling::Elements::GeneralSlotLayout);
  616. prepareGeometryChange();
  617. qreal margin = m_styleHelper.GetAttribute(Styling::Attribute::Margin, 0.0);
  618. m_groupLayout->setContentsMargins(margin, margin, margin, margin);
  619. m_groupLayout->setSpacing(m_styleHelper.GetAttribute(Styling::Attribute::Spacing, 0.0));
  620. for (LayoutDividerWidget* divider : m_dividers)
  621. {
  622. divider->UpdateStyle(m_styleHelper);
  623. }
  624. for (auto& mapPair : m_slotGroups)
  625. {
  626. mapPair.second->UpdateStyle(m_styleHelper);
  627. }
  628. RefreshDisplay();
  629. }
  630. void GeneralSlotLayoutGraphicsWidget::RefreshDisplay()
  631. {
  632. updateGeometry();
  633. update();
  634. }
  635. GeneralSlotLayoutGraphicsWidget::LinearSlotGroupWidget* GeneralSlotLayoutGraphicsWidget::FindCreateSlotGroupWidget(SlotGroup slotType)
  636. {
  637. AZ_Warning("GraphCanvas", slotType != SlotGroups::Invalid, "Trying to Create a Slot Group for an Invalid slot group");
  638. LinearSlotGroupWidget* retVal = nullptr;
  639. if (slotType != SlotGroups::Invalid)
  640. {
  641. auto mapIter = m_slotGroups.find(slotType);
  642. if (mapIter != m_slotGroups.end())
  643. {
  644. retVal = mapIter->second;
  645. }
  646. else
  647. {
  648. auto configurationIter = m_nodeSlots.m_slotGroupConfigurations.find(slotType);
  649. if (configurationIter == m_nodeSlots.m_slotGroupConfigurations.end())
  650. {
  651. SlotGroupConfiguration groupConfiguration;
  652. groupConfiguration.m_layoutOrder = static_cast<int>(m_nodeSlots.m_slotGroupConfigurations.size());
  653. m_nodeSlots.m_slotGroupConfigurations[slotType] = groupConfiguration;
  654. }
  655. retVal = aznew LinearSlotGroupWidget(this);
  656. retVal->UpdateStyle(m_styleHelper);
  657. m_slotGroups[slotType] = retVal;
  658. }
  659. }
  660. return retVal;
  661. }
  662. GeneralSlotLayoutGraphicsWidget::LayoutDividerWidget* GeneralSlotLayoutGraphicsWidget::FindCreateDividerWidget(int index)
  663. {
  664. AZ_Error("GraphCanvas", index <= m_dividers.size(), "Invalid Divider Creation flow. Jumped the line in divider indexing.");
  665. LayoutDividerWidget* retVal = nullptr;
  666. while (index >= m_dividers.size())
  667. {
  668. // Create and configure a new divider
  669. LayoutDividerWidget* divider = aznew LayoutDividerWidget(this);
  670. divider->UpdateStyle(m_styleHelper);
  671. m_dividers.push_back(divider);
  672. }
  673. retVal = m_dividers[index];
  674. return retVal;
  675. }
  676. }