ConnectionVisualComponent.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  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 <qevent.h>
  9. #include <QtMath>
  10. #include <QPainter>
  11. #include <QGraphicsSceneContextMenuEvent>
  12. #include <QStyle>
  13. #include <QStyleOption>
  14. #include <qglobal.h>
  15. #include <Components/Connections/ConnectionVisualComponent.h>
  16. #include <GraphCanvas/Components/GeometryBus.h>
  17. #include <GraphCanvas/Components/Slots/SlotBus.h>
  18. #include <GraphCanvas/Components/VisualBus.h>
  19. #include <GraphCanvas/Editor/GraphCanvasProfiler.h>
  20. #include <GraphCanvas/tools.h>
  21. #include <GraphCanvas/Styling/definitions.h>
  22. namespace GraphCanvas
  23. {
  24. //////////////////////////////
  25. // ConnectionVisualComponent
  26. //////////////////////////////
  27. void ConnectionVisualComponent::Reflect(AZ::ReflectContext* context)
  28. {
  29. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  30. if (serializeContext)
  31. {
  32. serializeContext->Class<ConnectionVisualComponent, AZ::Component>()
  33. ->Version(1)
  34. ;
  35. }
  36. }
  37. ConnectionVisualComponent::ConnectionVisualComponent()
  38. {
  39. }
  40. void ConnectionVisualComponent::Init()
  41. {
  42. CreateConnectionVisual();
  43. }
  44. void ConnectionVisualComponent::Activate()
  45. {
  46. if (m_connectionGraphicsItem)
  47. {
  48. m_connectionGraphicsItem->Activate();
  49. }
  50. VisualRequestBus::Handler::BusConnect(GetEntityId());
  51. SceneMemberUIRequestBus::Handler::BusConnect(GetEntityId());
  52. }
  53. void ConnectionVisualComponent::Deactivate()
  54. {
  55. VisualRequestBus::Handler::BusDisconnect();
  56. SceneMemberUIRequestBus::Handler::BusDisconnect();
  57. if (m_connectionGraphicsItem)
  58. {
  59. m_connectionGraphicsItem->Deactivate();
  60. }
  61. }
  62. QGraphicsItem* ConnectionVisualComponent::AsGraphicsItem()
  63. {
  64. return m_connectionGraphicsItem.get();
  65. }
  66. bool ConnectionVisualComponent::Contains(const AZ::Vector2&) const
  67. {
  68. return false;
  69. }
  70. void ConnectionVisualComponent::SetVisible(bool visible)
  71. {
  72. m_connectionGraphicsItem->setVisible(visible);
  73. }
  74. bool ConnectionVisualComponent::IsVisible() const
  75. {
  76. return m_connectionGraphicsItem->isVisible();
  77. }
  78. QGraphicsItem* ConnectionVisualComponent::GetRootGraphicsItem()
  79. {
  80. return m_connectionGraphicsItem.get();
  81. }
  82. QGraphicsLayoutItem* ConnectionVisualComponent::GetRootGraphicsLayoutItem()
  83. {
  84. return nullptr;
  85. }
  86. void ConnectionVisualComponent::SetSelected(bool selected)
  87. {
  88. m_connectionGraphicsItem->setSelected(selected);
  89. }
  90. bool ConnectionVisualComponent::IsSelected() const
  91. {
  92. return m_connectionGraphicsItem->isSelected();
  93. }
  94. QPainterPath ConnectionVisualComponent::GetOutline() const
  95. {
  96. return m_connectionGraphicsItem->path();
  97. }
  98. void ConnectionVisualComponent::SetZValue(qreal zValue)
  99. {
  100. m_connectionGraphicsItem->setZValue(zValue);
  101. }
  102. qreal ConnectionVisualComponent::GetZValue() const
  103. {
  104. return aznumeric_cast<int>(m_connectionGraphicsItem->zValue());
  105. }
  106. void ConnectionVisualComponent::CreateConnectionVisual()
  107. {
  108. m_connectionGraphicsItem = AZStd::make_unique<ConnectionGraphicsItem>(GetEntityId());
  109. }
  110. ////////////////////////////
  111. // ConnectionGraphicsItem
  112. ////////////////////////////
  113. qreal ConnectionGraphicsItem::VectorLength(QPointF vectorPoint)
  114. {
  115. return qSqrt(vectorPoint.x() * vectorPoint.x() + vectorPoint.y() * vectorPoint.y());
  116. }
  117. ConnectionGraphicsItem::ConnectionGraphicsItem(const AZ::EntityId& connectionEntityId)
  118. : RootGraphicsItem(connectionEntityId)
  119. , m_trackMove(false)
  120. , m_moveSource(false)
  121. , m_curveType(Styling::ConnectionCurveType::Straight)
  122. , m_offset(0.0)
  123. , m_connectionEntityId(connectionEntityId)
  124. {
  125. setFlags(ItemIsSelectable | ItemIsFocusable);
  126. setData(GraphicsItemName, QStringLiteral("DefaultConnectionVisual/%1").arg(static_cast<AZ::u64>(GetEntityId()), 16, 16, QChar('0')));
  127. }
  128. void ConnectionGraphicsItem::Activate()
  129. {
  130. AZStd::string tooltip;
  131. ConnectionRequestBus::EventResult(tooltip, GetEntityId(), &ConnectionRequests::GetTooltip);
  132. setToolTip(Tools::qStringFromUtf8(tooltip));
  133. ConnectionNotificationBus::Handler::BusConnect(GetEntityId());
  134. StyleNotificationBus::Handler::BusConnect(GetEntityId());
  135. AZ::EntityId sourceId;
  136. ConnectionRequestBus::EventResult(sourceId, GetConnectionEntityId(), &ConnectionRequests::GetSourceSlotId);
  137. OnSourceSlotIdChanged(AZ::EntityId(), sourceId);
  138. AZ::EntityId targetId;
  139. ConnectionRequestBus::EventResult(targetId, GetConnectionEntityId(), &ConnectionRequests::GetTargetSlotId);
  140. OnTargetSlotIdChanged(AZ::EntityId(), targetId);
  141. ConnectionUIRequestBus::Handler::BusConnect(GetConnectionEntityId());
  142. SceneMemberNotificationBus::Handler::BusConnect(GetConnectionEntityId());
  143. OnStyleChanged();
  144. UpdateConnectionPath();
  145. OnActivate();
  146. }
  147. void ConnectionGraphicsItem::Deactivate()
  148. {
  149. SceneMemberNotificationBus::Handler::BusDisconnect();
  150. ConnectionUIRequestBus::Handler::BusDisconnect();
  151. ConnectionNotificationBus::Handler::BusDisconnect();
  152. StyleNotificationBus::Handler::BusDisconnect();
  153. VisualNotificationBus::MultiHandler::BusDisconnect();
  154. }
  155. void ConnectionGraphicsItem::RefreshStyle()
  156. {
  157. m_style.SetStyle(GetEntityId());
  158. UpdatePen();
  159. }
  160. const Styling::StyleHelper& ConnectionGraphicsItem::GetStyle() const
  161. {
  162. return m_style;
  163. }
  164. void ConnectionGraphicsItem::UpdateOffset()
  165. {
  166. auto currentTime = AZStd::chrono::steady_clock::now();
  167. auto currentDuration = currentTime.time_since_epoch();
  168. AZStd::chrono::milliseconds currentUpdate = AZStd::chrono::duration_cast<AZStd::chrono::milliseconds>(currentDuration);
  169. float delta = (currentUpdate - m_lastUpdate).count() * 0.001f;
  170. m_lastUpdate = currentUpdate;
  171. // This works for all default dash/dot patterns, for now
  172. static const double offsetReset = 24.0;
  173. // TODO: maybe calculate this based on an "animation-speed" attribute?
  174. // For now. 1.35 resets per second?
  175. m_offset += offsetReset * 1.35f * delta;
  176. if (m_offset >= offsetReset)
  177. {
  178. m_offset -= offsetReset;
  179. }
  180. QPen currentPen = pen();
  181. currentPen.setDashOffset(-m_offset);
  182. setPen(currentPen);
  183. }
  184. QRectF ConnectionGraphicsItem::GetBoundingRect() const
  185. {
  186. return boundingRect();
  187. }
  188. void ConnectionGraphicsItem::OnSourceSlotIdChanged(const AZ::EntityId& oldSlotId, const AZ::EntityId& newSlotId)
  189. {
  190. if (oldSlotId.IsValid())
  191. {
  192. VisualNotificationBus::MultiHandler::BusDisconnect(oldSlotId);
  193. }
  194. if (newSlotId.IsValid())
  195. {
  196. VisualNotificationBus::MultiHandler::BusConnect(newSlotId);
  197. }
  198. UpdateConnectionPath();
  199. }
  200. void ConnectionGraphicsItem::OnTargetSlotIdChanged(const AZ::EntityId& oldSlotId, const AZ::EntityId& newSlotId)
  201. {
  202. if (oldSlotId.IsValid())
  203. {
  204. VisualNotificationBus::MultiHandler::BusDisconnect(oldSlotId);
  205. }
  206. if (newSlotId.IsValid())
  207. {
  208. VisualNotificationBus::MultiHandler::BusConnect(newSlotId);
  209. }
  210. UpdateConnectionPath();
  211. }
  212. void ConnectionGraphicsItem::OnTooltipChanged(const AZStd::string& tooltip)
  213. {
  214. setToolTip(Tools::qStringFromUtf8(tooltip));
  215. }
  216. void ConnectionGraphicsItem::OnStyleChanged()
  217. {
  218. RefreshStyle();
  219. bool animate = m_style.GetAttribute(Styling::Attribute::LineStyle, Qt::SolidLine) != Qt::SolidLine;
  220. if (animate)
  221. {
  222. if (!AZ::SystemTickBus::Handler::BusIsConnected())
  223. {
  224. auto currentTime = AZStd::chrono::steady_clock::now();
  225. auto currentDuration = currentTime.time_since_epoch();
  226. m_lastUpdate = AZStd::chrono::duration_cast<AZStd::chrono::milliseconds>(currentDuration);
  227. AZ::SystemTickBus::Handler::BusConnect();
  228. }
  229. }
  230. else if (AZ::SystemTickBus::Handler::BusIsConnected())
  231. {
  232. AZ::SystemTickBus::Handler::BusDisconnect();
  233. }
  234. setOpacity(m_style.GetAttribute(Styling::Attribute::Opacity, 1.0f));
  235. UpdateConnectionPath();
  236. }
  237. void ConnectionGraphicsItem::OnSystemTick()
  238. {
  239. UpdateOffset();
  240. }
  241. void ConnectionGraphicsItem::OnItemChange(const AZ::EntityId& /*entityId*/, QGraphicsItem::GraphicsItemChange change, const QVariant& /*value*/)
  242. {
  243. switch (change)
  244. {
  245. case QGraphicsItem::ItemScenePositionHasChanged:
  246. {
  247. UpdateConnectionPath();
  248. break;
  249. }
  250. }
  251. }
  252. void ConnectionGraphicsItem::UpdateConnectionPath()
  253. {
  254. AZ::EntityId sourceId;
  255. ConnectionRequestBus::EventResult(sourceId, GetConnectionEntityId(), &ConnectionRequests::GetSourceSlotId);
  256. AZ::EntityId targetId;
  257. ConnectionRequestBus::EventResult(targetId, GetConnectionEntityId(), &ConnectionRequests::GetTargetSlotId);
  258. QPointF start;
  259. ConnectionRequestBus::EventResult(start, GetEntityId(), &ConnectionRequests::GetSourcePosition);
  260. QPointF startJutDirection;
  261. SlotUIRequestBus::EventResult(startJutDirection, sourceId, &SlotUIRequests::GetJutDirection);
  262. QPointF end;
  263. ConnectionRequestBus::EventResult(end, GetEntityId(), &ConnectionRequests::GetTargetPosition);
  264. QPointF endJutDirection;
  265. SlotUIRequestBus::EventResult(endJutDirection, targetId, &SlotUIRequests::GetJutDirection);
  266. if (!sourceId.IsValid())
  267. {
  268. startJutDirection = -endJutDirection;
  269. }
  270. else if (!targetId.IsValid())
  271. {
  272. endJutDirection = -startJutDirection;
  273. }
  274. bool loopback = false;
  275. float nodeHeight = 0;
  276. AZ::Vector2 nodePos(0, 0);
  277. if (end.isNull())
  278. {
  279. end = start;
  280. }
  281. else
  282. {
  283. // Determine if this connection is from and to the same node (self-connection)
  284. AZ::EntityId sourceNode;
  285. SlotRequestBus::EventResult(sourceNode, sourceId, &SlotRequestBus::Events::GetNode);
  286. AZ::EntityId targetNode;
  287. SlotRequestBus::EventResult(targetNode, targetId, &SlotRequestBus::Events::GetNode);
  288. loopback = sourceNode == targetNode;
  289. if (loopback)
  290. {
  291. QGraphicsItem* rootVisual = nullptr;
  292. SceneMemberUIRequestBus::EventResult(rootVisual, sourceNode, &SceneMemberUIRequests::GetRootGraphicsItem);
  293. if (rootVisual)
  294. {
  295. nodeHeight = aznumeric_cast<float>(rootVisual->boundingRect().height());
  296. }
  297. GeometryRequestBus::EventResult(nodePos, sourceNode, &GeometryRequestBus::Events::GetPosition);
  298. }
  299. }
  300. ConnectionType connectionType = ConnectionType::CT_Invalid;
  301. SlotRequestBus::EventResult(connectionType, sourceId, &SlotRequests::GetConnectionType);
  302. QPainterPath path = QPainterPath(start);
  303. if (m_curveType == Styling::ConnectionCurveType::Curved)
  304. {
  305. // Scale the control points based on the length of the line to make sure the curve looks pretty
  306. QPointF offset = (end - start);
  307. QPointF midVector = (start + end) / 2.0 - start;
  308. // Mathemagic to make the curvature look nice
  309. qreal magnitude = 0;
  310. if (offset.x() < 0)
  311. {
  312. magnitude = AZ::GetMax(qSqrt(VectorLength(offset)) * 5, qFabs(offset.x()) * 0.25f);
  313. }
  314. else
  315. {
  316. magnitude = AZ::GetMax(qSqrt(VectorLength(offset)) * 5, offset.x() * 0.5f);
  317. }
  318. magnitude = AZ::GetClamp(magnitude, (qreal) 10.0f, qMax(VectorLength(midVector), (qreal) 10.0f));
  319. // Makes the line come out horizontally from the start and end points
  320. QPointF offsetStart = start + startJutDirection * magnitude;
  321. QPointF offsetEnd = end + endJutDirection * magnitude;
  322. if (!loopback)
  323. {
  324. path.cubicTo(offsetStart, offsetEnd, end);
  325. }
  326. else
  327. {
  328. // Make the connection wrap around the node,
  329. // leaving some space between the connection and the node
  330. qreal heightOffset = (qreal)nodePos.GetY() + nodeHeight + 20.0f;
  331. path.cubicTo(offsetStart, { offsetStart.x(), heightOffset }, { start.x(), heightOffset });
  332. path.lineTo({ end.x(), heightOffset });
  333. path.cubicTo({ offsetEnd.x(), heightOffset }, offsetEnd, end);
  334. }
  335. }
  336. else
  337. {
  338. float connectionJut = m_style.GetAttribute(Styling::Attribute::ConnectionJut, 0.0f);
  339. QPointF startOffset = start + startJutDirection * connectionJut;
  340. QPointF endOffset = end + endJutDirection * connectionJut;
  341. path.lineTo(startOffset);
  342. path.lineTo(endOffset);
  343. path.lineTo(end);
  344. }
  345. setPath(path);
  346. update();
  347. OnPathChanged();
  348. ConnectionVisualNotificationBus::Event(GetEntityId(), &ConnectionVisualNotifications::OnConnectionPathUpdated);
  349. }
  350. void ConnectionGraphicsItem::SetAltDeletionEnabled(bool enabled)
  351. {
  352. SetAllowQuickDeletion(enabled);
  353. }
  354. void ConnectionGraphicsItem::SetGraphicsItemFlags(QGraphicsItem::GraphicsItemFlags flags)
  355. {
  356. setFlags(flags);
  357. }
  358. void ConnectionGraphicsItem::OnSceneMemberHidden()
  359. {
  360. AZ::EntityId sourceId;
  361. ConnectionRequestBus::EventResult(sourceId, GetConnectionEntityId(), &ConnectionRequests::GetSourceSlotId);
  362. VisualNotificationBus::MultiHandler::BusDisconnect(sourceId);
  363. AZ::EntityId targetId;
  364. ConnectionRequestBus::EventResult(targetId, GetConnectionEntityId(), &ConnectionRequests::GetTargetSlotId);
  365. VisualNotificationBus::MultiHandler::BusDisconnect(targetId);
  366. }
  367. void ConnectionGraphicsItem::OnSceneMemberShown()
  368. {
  369. AZ::EntityId sourceId;
  370. ConnectionRequestBus::EventResult(sourceId, GetConnectionEntityId(), &ConnectionRequests::GetSourceSlotId);
  371. VisualNotificationBus::MultiHandler::BusConnect(sourceId);
  372. AZ::EntityId targetId;
  373. ConnectionRequestBus::EventResult(targetId, GetConnectionEntityId(), &ConnectionRequests::GetTargetSlotId);
  374. VisualNotificationBus::MultiHandler::BusConnect(targetId);
  375. UpdateConnectionPath();
  376. }
  377. void ConnectionGraphicsItem::OnSceneSet(const GraphId& graphId)
  378. {
  379. m_editorId = EditorId();
  380. SceneRequestBus::EventResult(m_editorId, graphId, &SceneRequests::GetEditorId);
  381. AssetEditorSettingsNotificationBus::Handler::BusDisconnect();
  382. AssetEditorSettingsNotificationBus::Handler::BusConnect(m_editorId);
  383. UpdateCurveStyle();
  384. }
  385. void ConnectionGraphicsItem::OnSettingsChanged()
  386. {
  387. UpdateCurveStyle();
  388. }
  389. const AZ::EntityId& ConnectionGraphicsItem::GetConnectionEntityId() const
  390. {
  391. return m_connectionEntityId;
  392. }
  393. AZ::EntityId ConnectionGraphicsItem::GetSourceSlotEntityId() const
  394. {
  395. AZ::EntityId sourceId;
  396. ConnectionRequestBus::EventResult(sourceId, GetConnectionEntityId(), &ConnectionRequests::GetSourceSlotId);
  397. return sourceId;
  398. }
  399. AZ::EntityId ConnectionGraphicsItem::GetTargetSlotEntityId() const
  400. {
  401. AZ::EntityId targetId;
  402. ConnectionRequestBus::EventResult(targetId, GetConnectionEntityId(), &ConnectionRequests::GetTargetSlotId);
  403. return targetId;
  404. }
  405. EditorId ConnectionGraphicsItem::GetEditorId() const
  406. {
  407. return m_editorId;
  408. }
  409. void ConnectionGraphicsItem::UpdateCurveStyle()
  410. {
  411. Styling::ConnectionCurveType oldType = m_curveType;
  412. m_curveType = GetCurveStyle();
  413. if (m_curveType != oldType)
  414. {
  415. UpdateConnectionPath();
  416. }
  417. }
  418. Styling::ConnectionCurveType ConnectionGraphicsItem::GetCurveStyle() const
  419. {
  420. Styling::ConnectionCurveType curveStyle = Styling::ConnectionCurveType::Straight;
  421. AssetEditorSettingsRequestBus::EventResult(curveStyle, GetEditorId(), &AssetEditorSettingsRequests::GetConnectionCurveType);
  422. return curveStyle;
  423. }
  424. void ConnectionGraphicsItem::UpdatePen()
  425. {
  426. QPen pen = m_style.GetPen(Styling::Attribute::LineWidth, Styling::Attribute::LineStyle, Styling::Attribute::LineColor, Styling::Attribute::CapStyle);
  427. setPen(pen);
  428. }
  429. void ConnectionGraphicsItem::OnActivate()
  430. {
  431. }
  432. void ConnectionGraphicsItem::OnDeactivate()
  433. {
  434. }
  435. void ConnectionGraphicsItem::OnPathChanged()
  436. {
  437. }
  438. QPainterPath ConnectionGraphicsItem::shape() const
  439. {
  440. // Creates a "selectable area" around the connection
  441. QPainterPathStroker stroker;
  442. qreal padding = m_style.GetAttribute(Styling::Attribute::LineSelectionPadding, 0);
  443. stroker.setWidth(padding);
  444. return stroker.createStroke(path());
  445. }
  446. void ConnectionGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent)
  447. {
  448. if (mouseEvent->button() == Qt::MouseButton::LeftButton)
  449. {
  450. m_trackMove = false;
  451. if (GetDisplayState() == RootGraphicsItemDisplayState::Inspection)
  452. {
  453. const QPainterPath painterPath = path();
  454. QPointF clickPoint = mouseEvent->scenePos();
  455. QPointF startPoint = painterPath.pointAtPercent(0);
  456. QPointF endPoint = painterPath.pointAtPercent(1);
  457. float distanceToSource = aznumeric_cast<float>((clickPoint - startPoint).manhattanLength());
  458. float distanceToTarget = aznumeric_cast<float>((clickPoint - endPoint).manhattanLength());
  459. float maxDistance = m_style.GetAttribute(Styling::Attribute::ConnectionDragMaximumDistance, 100.0f);
  460. float dragPercentage = m_style.GetAttribute(Styling::Attribute::ConnectionDragPercent, 0.1f);
  461. float acceptanceDistance = AZStd::GetMin(maxDistance, aznumeric_cast<float>(painterPath.length() * dragPercentage));
  462. if (distanceToSource < acceptanceDistance)
  463. {
  464. m_trackMove = true;
  465. m_moveSource = true;
  466. m_initialPoint = mouseEvent->scenePos();
  467. }
  468. else if (distanceToTarget < acceptanceDistance)
  469. {
  470. m_trackMove = true;
  471. m_moveSource = false;
  472. m_initialPoint = mouseEvent->scenePos();
  473. }
  474. }
  475. else
  476. {
  477. RootGraphicsItem<QGraphicsPathItem>::mousePressEvent(mouseEvent);
  478. }
  479. }
  480. else
  481. {
  482. RootGraphicsItem<QGraphicsPathItem>::mousePressEvent(mouseEvent);
  483. }
  484. }
  485. void ConnectionGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent)
  486. {
  487. if (m_trackMove)
  488. {
  489. float maxDistance = m_style.GetAttribute(Styling::Attribute::ConnectionDragMoveBuffer, 0.0f);
  490. float distanceFromInitial = aznumeric_cast<float>((m_initialPoint - mouseEvent->scenePos()).manhattanLength());
  491. if (distanceFromInitial > maxDistance)
  492. {
  493. m_trackMove = false;
  494. if (m_moveSource)
  495. {
  496. ConnectionRequestBus::Event(GetEntityId(), &ConnectionRequests::StartSourceMove);
  497. }
  498. else
  499. {
  500. ConnectionRequestBus::Event(GetEntityId(), &ConnectionRequests::StartTargetMove);
  501. }
  502. }
  503. }
  504. else
  505. {
  506. RootGraphicsItem<QGraphicsPathItem>::mouseMoveEvent(mouseEvent);
  507. }
  508. }
  509. void ConnectionGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent)
  510. {
  511. // Handle the case where we clicked but didn't drag.
  512. // So we want to select ourselves.
  513. if (mouseEvent->button() == Qt::MouseButton::LeftButton && shape().contains(mouseEvent->scenePos()))
  514. {
  515. if ((mouseEvent->modifiers() & Qt::KeyboardModifier::ControlModifier) == 0)
  516. {
  517. AZ::EntityId sceneId;
  518. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  519. SceneRequestBus::Event(sceneId, &SceneRequests::ClearSelection);
  520. setSelected(true);
  521. }
  522. else
  523. {
  524. setSelected(!isSelected());
  525. }
  526. m_trackMove = false;
  527. }
  528. else
  529. {
  530. RootGraphicsItem<QGraphicsPathItem>::mouseReleaseEvent(mouseEvent);
  531. }
  532. }
  533. void ConnectionGraphicsItem::focusOutEvent(QFocusEvent* focusEvent)
  534. {
  535. if (m_trackMove)
  536. {
  537. m_trackMove = false;
  538. }
  539. RootGraphicsItem<QGraphicsPathItem>::focusOutEvent(focusEvent);
  540. }
  541. void ConnectionGraphicsItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget /*= nullptr*/)
  542. {
  543. GRAPH_CANVAS_DETAILED_PROFILE_FUNCTION();
  544. bool showDefaultSelector = m_style.GetAttribute(Styling::Attribute::ConnectionDefaultMarquee, false);
  545. if (!showDefaultSelector)
  546. {
  547. // Remove the selected state to get rid of the marquee outline
  548. QStyleOptionGraphicsItem myoption = (*option);
  549. myoption.state &= !QStyle::State_Selected;
  550. QGraphicsPathItem::paint(painter, &myoption, widget);
  551. }
  552. else
  553. {
  554. QGraphicsPathItem::paint(painter, option, widget);
  555. }
  556. }
  557. }