NodeGroupFrameComponent.cpp 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703
  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 <QCursor>
  9. #include <QGraphicsLayout>
  10. #include <QGraphicsSceneEvent>
  11. #include <QPainter>
  12. #include <QScopedValueRollback>
  13. #include <QTimer>
  14. #include <AzCore/Casting/numeric_cast.h>
  15. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  16. #include <Components/Nodes/Group/NodeGroupFrameComponent.h>
  17. #include <GraphCanvas/Components/Connections/ConnectionBus.h>
  18. #include <GraphCanvas/Components/GeometryBus.h>
  19. #include <GraphCanvas/Components/GridBus.h>
  20. #include <GraphCanvas/Components/LayerBus.h>
  21. #include <GraphCanvas/Components/PersistentIdBus.h>
  22. #include <GraphCanvas/Components/Nodes/Comment/CommentBus.h>
  23. #include <GraphCanvas/Editor/GraphCanvasProfiler.h>
  24. #include <GraphCanvas/GraphCanvasBus.h>
  25. #include <GraphCanvas/tools.h>
  26. #include <GraphCanvas/Styling/StyleHelper.h>
  27. #include <GraphCanvas/Utils/ConversionUtils.h>
  28. #include <GraphCanvas/Utils/GraphUtils.h>
  29. #include <GraphCanvas/Utils/QtVectorMath.h>
  30. namespace GraphCanvas
  31. {
  32. ////////////////////////////////////
  33. // NodeGroupFrameComponentSaveData
  34. ////////////////////////////////////
  35. NodeGroupFrameComponent::NodeGroupFrameComponentSaveData::NodeGroupFrameComponentSaveData()
  36. : m_color(AZ::Color::CreateZero())
  37. , m_displayHeight(-1)
  38. , m_displayWidth(-1)
  39. , m_enableAsBookmark(false)
  40. , m_shortcut(k_findShortcut)
  41. , m_isCollapsed(false)
  42. , m_callback(nullptr)
  43. {
  44. }
  45. NodeGroupFrameComponent::NodeGroupFrameComponentSaveData::NodeGroupFrameComponentSaveData(NodeGroupFrameComponent* nodeFrameComponent)
  46. : NodeGroupFrameComponentSaveData()
  47. {
  48. m_callback = nodeFrameComponent;
  49. }
  50. void NodeGroupFrameComponent::NodeGroupFrameComponentSaveData::operator=(const NodeGroupFrameComponentSaveData& other)
  51. {
  52. // Purposefully skipping over the callback.
  53. m_color = other.m_color;
  54. m_displayHeight = other.m_displayHeight;
  55. m_displayWidth = other.m_displayWidth;
  56. m_enableAsBookmark = other.m_enableAsBookmark;
  57. m_shortcut = other.m_shortcut;
  58. m_isCollapsed = other.m_isCollapsed;
  59. m_persistentGroupedIds = other.m_persistentGroupedIds;
  60. m_isNewGroup = other.m_isNewGroup;
  61. }
  62. void NodeGroupFrameComponent::NodeGroupFrameComponentSaveData::OnBookmarkStatusChanged()
  63. {
  64. if (m_callback)
  65. {
  66. m_callback->OnBookmarkStatusChanged();
  67. SignalDirty();
  68. }
  69. }
  70. void NodeGroupFrameComponent::NodeGroupFrameComponentSaveData::OnCollapsedStatusChanged()
  71. {
  72. if (m_callback)
  73. {
  74. if (m_isCollapsed)
  75. {
  76. m_callback->CollapseGroup();
  77. }
  78. else
  79. {
  80. m_callback->ExpandGroup();
  81. }
  82. }
  83. }
  84. ////////////////////////////
  85. // NodeGroupFrameComponent
  86. ////////////////////////////
  87. bool NodeGroupFrameComponentVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  88. {
  89. if (classElement.GetVersion() == 1)
  90. {
  91. AZ::Crc32 colorId = AZ_CRC("Color", 0x665648e9);
  92. AZ::Crc32 heightId = AZ_CRC("DisplayHeight", 0x7e251278);
  93. AZ::Crc32 widthId = AZ_CRC("DisplayWidth", 0x5a55d875);
  94. NodeGroupFrameComponent::NodeGroupFrameComponentSaveData saveData;
  95. AZ::SerializeContext::DataElementNode* dataNode = classElement.FindSubElement(colorId);
  96. if (dataNode)
  97. {
  98. dataNode->GetData(saveData.m_color);
  99. }
  100. dataNode = nullptr;
  101. dataNode = classElement.FindSubElement(heightId);
  102. if (dataNode)
  103. {
  104. dataNode->GetData(saveData.m_displayHeight);
  105. }
  106. dataNode = nullptr;
  107. dataNode = classElement.FindSubElement(widthId);
  108. if (dataNode)
  109. {
  110. dataNode->GetData(saveData.m_displayWidth);
  111. }
  112. classElement.RemoveElementByName(colorId);
  113. classElement.RemoveElementByName(heightId);
  114. classElement.RemoveElementByName(widthId);
  115. classElement.AddElementWithData(context, "SaveData", saveData);
  116. }
  117. return true;
  118. }
  119. bool NodeGroupFrameSaveDataVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  120. {
  121. if (classElement.GetVersion() < 4)
  122. {
  123. classElement.AddElementWithData(context, "IsNewGroup", false);
  124. }
  125. return true;
  126. }
  127. void NodeGroupFrameComponent::Reflect(AZ::ReflectContext* context)
  128. {
  129. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  130. if (serializeContext)
  131. {
  132. serializeContext->Class<NodeGroupFrameComponentSaveData, ComponentSaveData>()
  133. ->Version(4, &NodeGroupFrameSaveDataVersionConverter)
  134. ->Field("Color", &NodeGroupFrameComponentSaveData::m_color)
  135. ->Field("DisplayHeight", &NodeGroupFrameComponentSaveData::m_displayHeight)
  136. ->Field("DisplayWidth", &NodeGroupFrameComponentSaveData::m_displayWidth)
  137. ->Field("EnableAsBookmark", &NodeGroupFrameComponentSaveData::m_enableAsBookmark)
  138. ->Field("QuickIndex", &NodeGroupFrameComponentSaveData::m_shortcut)
  139. ->Field("Collapsed", &NodeGroupFrameComponentSaveData::m_isCollapsed)
  140. ->Field("PersistentGroupedId", &NodeGroupFrameComponentSaveData::m_persistentGroupedIds)
  141. ->Field("IsNewGroup", &NodeGroupFrameComponentSaveData::m_isNewGroup)
  142. ;
  143. serializeContext->Class<NodeGroupFrameComponent, GraphCanvasPropertyComponent>()
  144. ->Version(2, &NodeGroupFrameComponentVersionConverter)
  145. ->Field("SaveData", &NodeGroupFrameComponent::m_saveData)
  146. ->Field("RedirectedEndpoints", &NodeGroupFrameComponent::m_collapsedRedirectionEndpoints)
  147. ;
  148. AZ::EditContext* editContext = serializeContext->GetEditContext();
  149. if (editContext)
  150. {
  151. editContext->Class<NodeGroupFrameComponentSaveData>("NodeGroupFrameComponentSaveData", "Structure that stores all of the save information for a Node Group.")
  152. ->ClassElement(AZ::Edit::ClassElements::EditorData, "Properties")
  153. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  154. ->DataElement(AZ::Edit::UIHandlers::Default, &NodeGroupFrameComponentSaveData::m_enableAsBookmark, "Enable as Bookmark", "Toggles whether or not the Node Group is registered as a bookmark.")
  155. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &NodeGroupFrameComponentSaveData::OnBookmarkStatusChanged)
  156. ->DataElement(AZ::Edit::UIHandlers::Default, &NodeGroupFrameComponentSaveData::m_isCollapsed, "Collapse Group", "Toggles whether or not the specified Node Group is collapsed.")
  157. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &NodeGroupFrameComponentSaveData::OnCollapsedStatusChanged)
  158. ;
  159. editContext->Class<NodeGroupFrameComponent>("Node Group Frame", "A comment that applies to the visible area.")
  160. ->ClassElement(AZ::Edit::ClassElements::EditorData, "Properties")
  161. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  162. ->DataElement(AZ::Edit::UIHandlers::Default, &NodeGroupFrameComponent::m_saveData, "SaveData", "The modifiable information about this Node Group.")
  163. ;
  164. }
  165. }
  166. }
  167. NodeGroupFrameComponent::NodeGroupFrameComponent()
  168. : m_saveData(this)
  169. , m_displayLayout(nullptr)
  170. , m_frameWidget(nullptr)
  171. , m_titleWidget(nullptr)
  172. , m_blockWidget(nullptr)
  173. , m_needsDisplayStateHighlight(false)
  174. , m_needsManualHighlight(false)
  175. , m_enableSelectionManipulation(true)
  176. , m_ignoreDisplayStateChanges(false)
  177. , m_ignoreSubSlementPostionChanged(false)
  178. , m_isGroupAnimating(false)
  179. {
  180. }
  181. void NodeGroupFrameComponent::Init()
  182. {
  183. GraphCanvasPropertyComponent::Init();
  184. m_displayLayout = new QGraphicsLinearLayout(Qt::Vertical);
  185. m_displayLayout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  186. m_titleWidget = aznew NodeGroupFrameTitleWidget();
  187. m_blockWidget = aznew NodeGroupFrameBlockAreaWidget();
  188. m_frameWidget = AZStd::make_unique<NodeGroupFrameGraphicsWidget>(GetEntityId(), (*this));
  189. m_frameWidget->setLayout(m_displayLayout);
  190. m_displayLayout->setSpacing(0);
  191. m_displayLayout->setContentsMargins(0, 0, 0, 0);
  192. m_displayLayout->addItem(m_titleWidget);
  193. m_displayLayout->addItem(m_blockWidget);
  194. m_blockWidget->RegisterFrame(m_frameWidget.get());
  195. m_titleWidget->RegisterFrame(m_frameWidget.get());
  196. EntitySaveDataRequestBus::Handler::BusConnect(GetEntityId());
  197. }
  198. void NodeGroupFrameComponent::Activate()
  199. {
  200. GraphCanvasPropertyComponent::Activate();
  201. NodeNotificationBus::Handler::BusConnect(GetEntityId());
  202. StyleNotificationBus::Handler::BusConnect(GetEntityId());
  203. NodeGroupRequestBus::Handler::BusConnect(GetEntityId());
  204. BookmarkRequestBus::Handler::BusConnect(GetEntityId());
  205. BookmarkNotificationBus::Handler::BusConnect(GetEntityId());
  206. SceneMemberNotificationBus::MultiHandler::BusConnect(GetEntityId());
  207. NodeGroupRequestBus::Handler::BusConnect(GetEntityId());
  208. VisualNotificationBus::MultiHandler::BusConnect(GetEntityId());
  209. m_frameWidget->Activate();
  210. }
  211. void NodeGroupFrameComponent::Deactivate()
  212. {
  213. GraphCanvasPropertyComponent::Deactivate();
  214. m_frameWidget->Deactivate();
  215. VisualNotificationBus::MultiHandler::BusDisconnect();
  216. NodeGroupRequestBus::Handler::BusDisconnect();
  217. SceneMemberNotificationBus::MultiHandler::BusDisconnect();
  218. BookmarkNotificationBus::Handler::BusDisconnect();
  219. BookmarkRequestBus::Handler::BusDisconnect();
  220. NodeGroupRequestBus::Handler::BusDisconnect();
  221. StyleNotificationBus::Handler::BusDisconnect();
  222. NodeNotificationBus::Handler::BusDisconnect();
  223. SceneNotificationBus::Handler::BusDisconnect();
  224. AZ::SystemTickBus::Handler::BusDisconnect();
  225. }
  226. void NodeGroupFrameComponent::SetGroupSize(QRectF blockRectangle)
  227. {
  228. QScopedValueRollback<bool> allowMovement(m_frameWidget->m_allowMovement, false);
  229. QRectF titleSize = m_titleWidget->boundingRect();
  230. if (titleSize.isEmpty())
  231. {
  232. m_titleWidget->adjustSize();
  233. titleSize = m_titleWidget->boundingRect();
  234. }
  235. m_saveData.m_displayHeight = aznumeric_cast<float>(blockRectangle.height() + titleSize.height());
  236. m_saveData.m_displayWidth = aznumeric_cast<float>(AZ::GetMax(m_frameWidget->m_minimumSize.width(), blockRectangle.width()));
  237. SignalDirty();
  238. m_frameWidget->ResizeTo(m_saveData.m_displayHeight, m_saveData.m_displayWidth);
  239. m_frameWidget->adjustSize();
  240. QPointF position = blockRectangle.topLeft();
  241. if (m_frameWidget->IsSnappedToGrid())
  242. {
  243. position.setY(m_frameWidget->RoundToClosestStep(aznumeric_cast<int>(position.y() - titleSize.height()), m_frameWidget->GetGridYStep()));
  244. }
  245. else
  246. {
  247. position.setY(position.y() - titleSize.height());
  248. }
  249. // Signal Bounds changed needs to happen after the set position to deal with uncollapsing of a collapsed group.
  250. // Uncollapsing a group triggers the 'Drag' sense, so that will cancel out the bound change reactions if it happens
  251. // after the bounds change.
  252. GeometryRequestBus::Event(GetEntityId(), &GeometryRequests::SetPosition, AZ::Vector2(aznumeric_cast<float>(position.x()), aznumeric_cast<float>(position.y())));
  253. GeometryRequestBus::Event(GetEntityId(), &GeometryRequests::SignalBoundsChanged);
  254. }
  255. QRectF NodeGroupFrameComponent::GetGroupBoundingBox() const
  256. {
  257. return m_blockWidget->sceneBoundingRect();
  258. }
  259. AZ::Color NodeGroupFrameComponent::GetGroupColor() const
  260. {
  261. AZ::Color color;
  262. CommentRequestBus::EventResult(color, GetEntityId(), &CommentRequests::GetBackgroundColor);
  263. return color;
  264. }
  265. void NodeGroupFrameComponent::CollapseGroup()
  266. {
  267. if (!m_saveData.m_isCollapsed
  268. || !m_collapsedNodeId.IsValid())
  269. {
  270. bool isRestoring = m_saveData.m_isCollapsed;
  271. CommentUIRequestBus::Event(GetEntityId(), &CommentUIRequests::SetEditable, false);
  272. m_saveData.m_isCollapsed = true;
  273. CollapsedNodeGroupConfiguration groupedConfiguration;
  274. groupedConfiguration.m_nodeGroupId = GetEntityId();
  275. AZ::Entity* nodeGroup = nullptr;
  276. GraphCanvasRequestBus::BroadcastResult(nodeGroup, &GraphCanvasRequests::CreateCollapsedNodeGroupAndActivate, groupedConfiguration);
  277. GraphId graphId;
  278. SceneMemberRequestBus::EventResult(graphId, GetEntityId(), &SceneMemberRequests::GetScene);
  279. if (nodeGroup)
  280. {
  281. m_collapsedNodeId = nodeGroup->GetId();
  282. CollapsedNodeGroupNotificationBus::Handler::BusConnect(m_collapsedNodeId);
  283. AZ::Vector2 position = ConversionUtils::QPointToVector(m_frameWidget->sceneBoundingRect().center());
  284. GeometryRequestBus::Event(nodeGroup->GetId(), &GeometryRequests::SetPosition, position);
  285. // This needs to be called before it's added to the scene. Since the group collapses and generates the slots in it's OnAddedToScene
  286. if (!m_collapsedRedirectionEndpoints.empty())
  287. {
  288. CollapsedNodeGroupRequestBus::Event(m_collapsedNodeId, &CollapsedNodeGroupRequests::ForceEndpointRedirection, m_collapsedRedirectionEndpoints);
  289. m_collapsedRedirectionEndpoints.clear();
  290. }
  291. SceneRequestBus::Event(graphId, &SceneRequests::Add, nodeGroup->GetId(), false);
  292. SceneMemberNotificationBus::MultiHandler::BusConnect(m_collapsedNodeId);
  293. NodeGroupNotificationBus::Event(GetEntityId(), &NodeGroupNotifications::OnCollapsed, m_collapsedNodeId);
  294. // Want to add in the collapsed node id to maintain our selection information correctly.
  295. GraphCanvasPropertyBus::Event(GetEntityId(), &GraphCanvasPropertyInterface::AddBusId, m_collapsedNodeId);
  296. }
  297. else
  298. {
  299. m_saveData.m_isCollapsed = false;
  300. }
  301. if (m_collapsedNodeId.IsValid())
  302. {
  303. if (!isRestoring)
  304. {
  305. SignalDirty();
  306. GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestUndoPoint);
  307. }
  308. if (m_enableSelectionManipulation)
  309. {
  310. SceneMemberUIRequestBus::Event(m_collapsedNodeId, &SceneMemberUIRequests::SetSelected, true);
  311. }
  312. }
  313. else
  314. {
  315. m_saveData.m_isCollapsed = false;
  316. if (isRestoring)
  317. {
  318. SignalDirty();
  319. }
  320. }
  321. }
  322. }
  323. void NodeGroupFrameComponent::ExpandGroup()
  324. {
  325. if (m_saveData.m_isCollapsed || m_collapsedNodeId.IsValid())
  326. {
  327. if (m_collapsedNodeId.IsValid())
  328. {
  329. AZ::EntityId collapsedNodeId = m_collapsedNodeId;
  330. CollapsedNodeGroupRequestBus::Event(collapsedNodeId, &CollapsedNodeGroupRequests::ExpandGroup);
  331. GraphCanvasPropertyBus::Event(GetEntityId(), &GraphCanvasPropertyInterface::RemoveBusId, collapsedNodeId);
  332. }
  333. else
  334. {
  335. SignalExpanded();
  336. }
  337. }
  338. }
  339. void NodeGroupFrameComponent::UngroupGroup()
  340. {
  341. GraphId graphId;
  342. SceneMemberRequestBus::EventResult(graphId, GetEntityId(), &SceneMemberRequests::GetScene);
  343. {
  344. ScopedGraphUndoBlocker undoBlocker(graphId);
  345. if (m_saveData.m_isCollapsed)
  346. {
  347. ExpandGroup();
  348. }
  349. for (const AZ::EntityId& groupedElement : m_groupedElements)
  350. {
  351. OnElementUngrouped(groupedElement);
  352. }
  353. m_groupedElements.clear();
  354. AZStd::unordered_set< AZ::EntityId > deletionSet = { GetEntityId() };
  355. SceneRequestBus::Event(graphId, &SceneRequests::Delete, deletionSet);
  356. }
  357. GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestUndoPoint);
  358. }
  359. bool NodeGroupFrameComponent::IsCollapsed() const
  360. {
  361. return m_saveData.m_isCollapsed;
  362. }
  363. AZ::EntityId NodeGroupFrameComponent::GetCollapsedNodeId() const
  364. {
  365. return m_collapsedNodeId;
  366. }
  367. void NodeGroupFrameComponent::AddElementToGroup(const AZ::EntityId& groupableElement)
  368. {
  369. if (AddToGroupInternal(groupableElement))
  370. {
  371. UpdateSavedElements();
  372. }
  373. }
  374. void NodeGroupFrameComponent::AddElementsToGroup(const AZStd::unordered_set<AZ::EntityId>& groupableElements)
  375. {
  376. bool signalSave = false;
  377. for (auto groupableElement : groupableElements)
  378. {
  379. if (AddToGroupInternal(groupableElement))
  380. {
  381. signalSave = true;
  382. }
  383. }
  384. if (signalSave)
  385. {
  386. UpdateSavedElements();
  387. }
  388. }
  389. void NodeGroupFrameComponent::AddElementsVectorToGroup(const AZStd::vector<AZ::EntityId>& groupableElements)
  390. {
  391. bool signalSave = false;
  392. for (auto groupableElement : groupableElements)
  393. {
  394. if (AddToGroupInternal(groupableElement))
  395. {
  396. signalSave = true;
  397. }
  398. }
  399. if (signalSave)
  400. {
  401. UpdateSavedElements();
  402. }
  403. }
  404. void NodeGroupFrameComponent::RemoveElementFromGroup(const AZ::EntityId& groupableElement)
  405. {
  406. size_t eraseCount = m_groupedElements.erase(groupableElement);
  407. if (eraseCount > 0)
  408. {
  409. OnElementUngrouped(groupableElement);
  410. UpdateSavedElements();
  411. }
  412. }
  413. void NodeGroupFrameComponent::RemoveElementsFromGroup(const AZStd::unordered_set<AZ::EntityId>& groupableElements)
  414. {
  415. for (auto groupableElement : groupableElements)
  416. {
  417. size_t eraseCount = m_groupedElements.erase(groupableElement);
  418. if (eraseCount > 0)
  419. {
  420. OnElementUngrouped(groupableElement);
  421. }
  422. }
  423. UpdateSavedElements();
  424. }
  425. void NodeGroupFrameComponent::RemoveElementsVectorFromGroup(const AZStd::vector<AZ::EntityId>& groupableElements)
  426. {
  427. for (auto groupableElement : groupableElements)
  428. {
  429. size_t eraseCount = m_groupedElements.erase(groupableElement);
  430. if (eraseCount > 0)
  431. {
  432. OnElementUngrouped(groupableElement);
  433. }
  434. }
  435. UpdateSavedElements();
  436. }
  437. void NodeGroupFrameComponent::FindGroupedElements(AZStd::vector< NodeId >& groupedElements)
  438. {
  439. groupedElements.reserve(groupedElements.size() + m_groupedElements.size());
  440. for (const AZ::EntityId& entityId : m_groupedElements)
  441. {
  442. groupedElements.push_back(entityId);
  443. }
  444. }
  445. void NodeGroupFrameComponent::ResizeGroupToElements(bool growGroupOnly)
  446. {
  447. // 1 or 0 indicates whether to align to that direction or not.
  448. const int adjustVertical = 1;
  449. const int adjustHorizontal = 1;
  450. m_frameWidget->ResizeToGroup(adjustHorizontal, adjustVertical, growGroupOnly);
  451. }
  452. bool NodeGroupFrameComponent::IsInTitle(const QPointF& scenePos) const
  453. {
  454. return m_titleWidget->sceneBoundingRect().contains(scenePos);
  455. }
  456. void NodeGroupFrameComponent::AdjustTitleSize()
  457. {
  458. if (m_titleWidget)
  459. {
  460. m_titleWidget->adjustSize();
  461. }
  462. }
  463. void NodeGroupFrameComponent::OnCollapsed(const NodeId& collapsedNodeId)
  464. {
  465. const AZ::EntityId* busId = NodeGroupNotificationBus::GetCurrentBusId();
  466. if (busId)
  467. {
  468. m_groupedElements.insert(collapsedNodeId);
  469. OnElementGrouped(collapsedNodeId);
  470. size_t eraseCount = m_initializingGroups.erase((*busId));
  471. if (eraseCount != 0 && m_initializingGroups.empty())
  472. {
  473. RestoreCollapsedState();
  474. }
  475. }
  476. }
  477. void NodeGroupFrameComponent::OnExpanded()
  478. {
  479. const AZ::EntityId* busId = NodeGroupNotificationBus::GetCurrentBusId();
  480. if (busId)
  481. {
  482. auto collapsedNodeIter = m_collapsedGroupMapping.find((*busId));
  483. if (collapsedNodeIter != m_collapsedGroupMapping.end())
  484. {
  485. AZ::EntityId collapsedGroupId = collapsedNodeIter->second;
  486. // Erase this from the mapping, since at this point the collapsed node is deleted
  487. // but we still want the ungrouped node inside of our element.
  488. m_collapsedGroupMapping.erase(collapsedNodeIter);
  489. // Remove the collapsed node from the grouped
  490. m_groupedElements.erase(collapsedGroupId);
  491. OnElementUngrouped(collapsedGroupId);
  492. UpdateSavedElements();
  493. }
  494. }
  495. }
  496. void NodeGroupFrameComponent::OnNodeActivated()
  497. {
  498. const AZ::EntityId* busId = NodeNotificationBus::GetCurrentBusId();
  499. if (busId != nullptr)
  500. {
  501. if ((*busId) == GetEntityId())
  502. {
  503. QGraphicsLayout* layout = nullptr;
  504. NodeLayoutRequestBus::EventResult(layout, GetEntityId(), &NodeLayoutRequests::GetLayout);
  505. layout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  506. m_titleWidget->setLayout(layout);
  507. CommentRequestBus::Event(GetEntityId(), &CommentRequests::SetCommentMode, CommentMode::BlockComment);
  508. }
  509. }
  510. }
  511. void NodeGroupFrameComponent::OnAddedToScene(const AZ::EntityId& sceneId)
  512. {
  513. const AZ::EntityId* busId = NodeNotificationBus::GetCurrentBusId();
  514. if (busId != nullptr)
  515. {
  516. if ((*busId) == GetEntityId())
  517. {
  518. OnBookmarkStatusChanged();
  519. SceneNotificationBus::Handler::BusDisconnect();
  520. SceneNotificationBus::Handler::BusConnect(sceneId);
  521. const AZ::EntityId& entityId = GetEntityId();
  522. CommentNotificationBus::Handler::BusConnect(entityId);
  523. GeometryNotificationBus::MultiHandler::BusConnect(entityId);
  524. RootGraphicsItemNotificationBus::Handler::BusConnect(entityId);
  525. GeometryRequestBus::EventResult(m_previousPosition, entityId, &GeometryRequests::GetPosition);
  526. m_frameWidget->ResizeTo(m_saveData.m_displayHeight, m_saveData.m_displayWidth);
  527. AZ::Color backgroundColor;
  528. CommentRequestBus::EventResult(backgroundColor, entityId, &CommentRequests::GetBackgroundColor);
  529. OnBackgroundColorChanged(backgroundColor);
  530. if (m_saveData.m_enableAsBookmark)
  531. {
  532. BookmarkManagerRequestBus::Event(sceneId, &BookmarkManagerRequests::RegisterBookmark, entityId);
  533. SceneBookmarkRequestBus::Handler::BusConnect(sceneId);
  534. }
  535. m_saveData.RegisterIds(entityId, sceneId);
  536. SceneRequestBus::EventResult(m_editorId, sceneId, &SceneRequests::GetEditorId);
  537. }
  538. }
  539. }
  540. void NodeGroupFrameComponent::PreOnRemovedFromScene(const AZ::EntityId& /*sceneId*/)
  541. {
  542. const AZ::EntityId* busId = SceneMemberNotificationBus::GetCurrentBusId();
  543. if (busId != nullptr)
  544. {
  545. if ((*busId) == GetEntityId())
  546. {
  547. CommentUIRequestBus::Event(GetEntityId(), &CommentUIRequests::SetEditable, false);
  548. }
  549. }
  550. }
  551. void NodeGroupFrameComponent::OnRemovedFromScene(const AZ::EntityId& sceneId)
  552. {
  553. const AZ::EntityId* busId = SceneMemberNotificationBus::GetCurrentBusId();
  554. if (busId != nullptr)
  555. {
  556. if ((*busId) == GetEntityId())
  557. {
  558. bool isRegistered = false;
  559. BookmarkManagerRequestBus::EventResult(isRegistered, sceneId, &BookmarkManagerRequests::IsBookmarkRegistered, GetEntityId());
  560. if (isRegistered)
  561. {
  562. BookmarkManagerRequestBus::Event(sceneId, &BookmarkManagerRequests::UnregisterBookmark, GetEntityId());
  563. SceneBookmarkRequestBus::Handler::BusDisconnect(sceneId);
  564. }
  565. AZStd::vector< AZ::EntityId > memberIds;
  566. FindGroupedElements(memberIds);
  567. AZStd::unordered_set< AZ::EntityId > deletionIds;
  568. deletionIds.insert(memberIds.begin(), memberIds.end());
  569. SceneRequestBus::Event(sceneId, &SceneRequests::Delete, deletionIds);
  570. }
  571. }
  572. }
  573. void NodeGroupFrameComponent::OnSceneMemberAboutToSerialize(GraphSerialization& serializationTarget)
  574. {
  575. const AZ::EntityId* busId = SceneMemberNotificationBus::GetCurrentBusId();
  576. if (busId != nullptr)
  577. {
  578. if ((*busId) == GetEntityId())
  579. {
  580. AZStd::vector< AZ::EntityId > groupedElements;
  581. FindGroupedElements(groupedElements);
  582. AZStd::unordered_set< AZ::EntityId > memberIds;
  583. memberIds.insert(groupedElements.begin(), groupedElements.end());
  584. GraphUtils::ParseMembersForSerialization(serializationTarget, memberIds);
  585. }
  586. else if ((*busId) == m_collapsedNodeId)
  587. {
  588. // Groups we don't want to copy over the collapsed node. But instead we want to copy over
  589. // the source group(this object).
  590. //
  591. // Remove the collapsed node id. And add in the group id.
  592. serializationTarget.GetGraphData().m_nodes.erase(AzToolsFramework::GetEntity(m_collapsedNodeId));
  593. CollapsedNodeGroupRequestBus::EventResult(m_collapsedRedirectionEndpoints, m_collapsedNodeId, &CollapsedNodeGroupRequests::GetRedirectedEndpoints);
  594. AZStd::unordered_set< AZ::EntityId > memberIds = { GetEntityId() };
  595. GraphUtils::ParseMembersForSerialization(serializationTarget, memberIds);
  596. }
  597. }
  598. }
  599. void NodeGroupFrameComponent::OnSceneMemberDeserialized(const AZ::EntityId& graphId, const GraphSerialization& /*serializationTarget*/)
  600. {
  601. const AZ::EntityId* busId = SceneMemberNotificationBus::GetCurrentBusId();
  602. if (busId != nullptr)
  603. {
  604. if ((*busId) == GetEntityId())
  605. {
  606. EditorId editorId;
  607. SceneRequestBus::EventResult(editorId, graphId, &SceneRequests::GetEditorId);
  608. PersistentIdNotificationBus::Handler::BusConnect(editorId);
  609. if (m_saveData.m_enableAsBookmark)
  610. {
  611. AZ::EntityId conflictedId;
  612. BookmarkManagerRequestBus::EventResult(conflictedId, graphId, &BookmarkManagerRequests::FindBookmarkForShortcut, m_saveData.m_shortcut);
  613. if (conflictedId.IsValid() && m_saveData.m_shortcut > 0)
  614. {
  615. m_saveData.m_shortcut = k_findShortcut;
  616. }
  617. }
  618. }
  619. }
  620. }
  621. void NodeGroupFrameComponent::OnStyleChanged()
  622. {
  623. auto entityId = GetEntityId();
  624. m_titleWidget->RefreshStyle(entityId);
  625. m_blockWidget->RefreshStyle(entityId);
  626. m_frameWidget->RefreshStyle(entityId);
  627. QSizeF titleMinimumSize = m_titleWidget->minimumSize();
  628. QSizeF blockMinimumSize = m_blockWidget->minimumSize();
  629. QSizeF finalMin;
  630. finalMin.setWidth(AZ::GetMax(titleMinimumSize.width(), blockMinimumSize.width()));
  631. finalMin.setHeight(titleMinimumSize.height() + blockMinimumSize.height());
  632. m_frameWidget->SetResizableMinimum(finalMin);
  633. }
  634. void NodeGroupFrameComponent::OnPositionChanged(const AZ::EntityId& /*entityId*/, const AZ::Vector2& position)
  635. {
  636. const AZ::EntityId* sourceId = GeometryNotificationBus::GetCurrentBusId();
  637. if (sourceId && (*sourceId) == GetEntityId())
  638. {
  639. if (m_frameWidget->m_allowMovement)
  640. {
  641. SetupElementsForMove();
  642. if (!m_movingElements.empty())
  643. {
  644. QScopedValueRollback<bool> valueRollback(m_ignoreSubSlementPostionChanged, true);
  645. AZ::Vector2 delta = position - m_previousPosition;
  646. if (!delta.IsZero())
  647. {
  648. for (const AZ::EntityId& element : m_movingElements)
  649. {
  650. // Rout the position change through the graphics item to deal with animation
  651. RootGraphicsItemRequestBus::Event(element, &RootGraphicsItemRequests::OffsetBy, delta);
  652. }
  653. }
  654. }
  655. }
  656. m_previousPosition = position;
  657. }
  658. else if (!m_ignoreSubSlementPostionChanged)
  659. {
  660. AZ::SystemTickBus::Handler::BusConnect();
  661. }
  662. }
  663. void NodeGroupFrameComponent::OnBoundsChanged()
  664. {
  665. const AZ::EntityId* sourceId = GeometryNotificationBus::GetCurrentBusId();
  666. if (sourceId)
  667. {
  668. if ((*sourceId) != GetEntityId())
  669. {
  670. AZ::SystemTickBus::Handler::BusConnect();
  671. }
  672. }
  673. }
  674. void NodeGroupFrameComponent::WriteSaveData(EntitySaveDataContainer& saveDataContainer) const
  675. {
  676. NodeGroupFrameComponentSaveData* saveData = saveDataContainer.FindCreateSaveData<NodeGroupFrameComponentSaveData>();
  677. if (saveData)
  678. {
  679. (*saveData) = m_saveData;
  680. }
  681. }
  682. void NodeGroupFrameComponent::ReadSaveData(const EntitySaveDataContainer& saveDataContainer)
  683. {
  684. NodeGroupFrameComponentSaveData* saveData = saveDataContainer.FindSaveDataAs<NodeGroupFrameComponentSaveData>();
  685. if (saveData)
  686. {
  687. m_saveData = (*saveData);
  688. }
  689. }
  690. AZ::EntityId NodeGroupFrameComponent::GetBookmarkId() const
  691. {
  692. return GetEntityId();
  693. }
  694. void NodeGroupFrameComponent::RemoveBookmark()
  695. {
  696. m_saveData.m_enableAsBookmark = false;
  697. OnBookmarkStatusChanged();
  698. SignalDirty();
  699. }
  700. int NodeGroupFrameComponent::GetShortcut() const
  701. {
  702. return m_saveData.m_shortcut;
  703. }
  704. void NodeGroupFrameComponent::SetShortcut(int shortcut)
  705. {
  706. m_saveData.m_shortcut = shortcut;
  707. SignalDirty();
  708. }
  709. AZStd::string NodeGroupFrameComponent::GetBookmarkName() const
  710. {
  711. AZStd::string comment;
  712. CommentRequestBus::EventResult(comment, GetEntityId(), &CommentRequests::GetComment);
  713. return comment;
  714. }
  715. void NodeGroupFrameComponent::SetBookmarkName(const AZStd::string& bookmarkName)
  716. {
  717. CommentRequestBus::Event(GetEntityId(), &CommentRequests::SetComment, bookmarkName);
  718. }
  719. QRectF NodeGroupFrameComponent::GetBookmarkTarget() const
  720. {
  721. if (m_saveData.m_isCollapsed && m_collapsedNodeId.IsValid())
  722. {
  723. QGraphicsItem* graphicsItem = nullptr;
  724. SceneMemberUIRequestBus::EventResult(graphicsItem, m_collapsedNodeId, &SceneMemberUIRequests::GetRootGraphicsItem);
  725. if (graphicsItem)
  726. {
  727. return graphicsItem->sceneBoundingRect();
  728. }
  729. }
  730. return m_frameWidget->sceneBoundingRect();
  731. }
  732. QColor NodeGroupFrameComponent::GetBookmarkColor() const
  733. {
  734. AZ::Color backgroundColor;
  735. CommentRequestBus::EventResult(backgroundColor, GetEntityId(), &CommentRequests::GetBackgroundColor);
  736. return GraphCanvas::ConversionUtils::AZToQColor(backgroundColor);
  737. }
  738. void NodeGroupFrameComponent::OnBookmarkTriggered()
  739. {
  740. static const float k_gridSteps = 5.0f;
  741. AZ::EntityId graphId;
  742. SceneMemberRequestBus::EventResult(graphId, GetEntityId(), &SceneMemberRequests::GetScene);
  743. AZ::EntityId gridId;
  744. SceneRequestBus::EventResult(gridId, graphId, &SceneRequests::GetGrid);
  745. AZ::Vector2 minorPitch(0,0);
  746. GridRequestBus::EventResult(minorPitch, gridId, &GridRequests::GetMinorPitch);
  747. QRectF target = GetBookmarkTarget();
  748. AnimatedPulseConfiguration pulseConfiguration;
  749. pulseConfiguration.m_enableGradient = true;
  750. pulseConfiguration.m_drawColor = GetBookmarkColor();
  751. pulseConfiguration.m_durationSec = 1.0f;
  752. pulseConfiguration.m_zValue = m_frameWidget->zValue() - 1;
  753. for (QPointF currentPoint : { target.topLeft(), target.topRight(), target.bottomRight(), target.bottomLeft()} )
  754. {
  755. QPointF directionVector = currentPoint - target.center();
  756. directionVector = QtVectorMath::Normalize(directionVector);
  757. QPointF finalPoint(currentPoint.x() + directionVector.x() * minorPitch.GetX() * k_gridSteps, currentPoint.y() + directionVector.y() * minorPitch.GetY() * k_gridSteps);
  758. pulseConfiguration.m_controlPoints.emplace_back(currentPoint, finalPoint);
  759. }
  760. SceneRequestBus::Event(graphId, &SceneRequests::CreatePulse, pulseConfiguration);
  761. }
  762. void NodeGroupFrameComponent::OnCommentChanged(const AZStd::string&)
  763. {
  764. BookmarkNotificationBus::Event(GetEntityId(), &BookmarkNotifications::OnBookmarkNameChanged);
  765. }
  766. void NodeGroupFrameComponent::OnBackgroundColorChanged(const AZ::Color& color)
  767. {
  768. m_titleWidget->SetColor(color);
  769. m_blockWidget->SetColor(color);
  770. BookmarkNotificationBus::Event(GetEntityId(), &BookmarkNotifications::OnBookmarkColorChanged);
  771. }
  772. void NodeGroupFrameComponent::OnSceneMemberDragBegin()
  773. {
  774. m_ignoreSubSlementPostionChanged = true;
  775. // Order of operations. The selected element begins to move, before this signal happens[This signal happens in response to it being moved]. So if we get in here, disconnect from the bus in case
  776. // something already queued up a movement.
  777. AZ::SystemTickBus::Handler::BusDisconnect();
  778. if (m_frameWidget->IsSelected())
  779. {
  780. SetupElementsForMove();
  781. EnableGroupedDisplayState(true);
  782. }
  783. }
  784. void NodeGroupFrameComponent::OnSceneMemberDragComplete()
  785. {
  786. m_ignoreSubSlementPostionChanged = false;
  787. m_movingElements.clear();
  788. EnableGroupedDisplayState(false);
  789. }
  790. void NodeGroupFrameComponent::OnDragSelectStart()
  791. {
  792. m_frameWidget->SetUseTitleShape(true);
  793. // Work around for when the drag selection starts inside of the Node Group.
  794. m_frameWidget->setSelected(false);
  795. }
  796. void NodeGroupFrameComponent::OnDragSelectEnd()
  797. {
  798. m_frameWidget->SetUseTitleShape(false);
  799. }
  800. void NodeGroupFrameComponent::OnNodeRemoved(const AZ::EntityId& nodeId)
  801. {
  802. OnSceneMemberRemoved(nodeId);
  803. }
  804. void NodeGroupFrameComponent::OnSceneMemberRemoved(const AZ::EntityId& sceneMemberId)
  805. {
  806. auto groupElementIter = m_groupedElements.find(sceneMemberId);
  807. if (groupElementIter != m_groupedElements.end())
  808. {
  809. m_groupedElements.erase(groupElementIter);
  810. OnElementUngrouped(sceneMemberId);
  811. UpdateSavedElements();
  812. }
  813. }
  814. void NodeGroupFrameComponent::OnEntitiesDeserializationComplete(const GraphSerialization&)
  815. {
  816. RestoreCollapsedState();
  817. }
  818. void NodeGroupFrameComponent::OnGraphLoadComplete()
  819. {
  820. // Version Conversion for background color
  821. if (!m_saveData.m_color.IsZero())
  822. {
  823. CommentRequestBus::Event(GetEntityId(), &CommentRequests::SetBackgroundColor, m_saveData.m_color);
  824. m_saveData.m_color = AZ::Color::CreateZero();
  825. }
  826. ////
  827. ////
  828. // Version Conversion for free floating grouping to persistent ownership
  829. // Kind of janky check to see if we don't have anything persisted in our save, then do a spot check to see if we need to persist somethign.
  830. if (!m_saveData.m_isNewGroup)
  831. {
  832. m_saveData.m_isNewGroup = true;
  833. m_groupedElements.clear();
  834. // Adjust the size before calling the interior information.
  835. m_frameWidget->adjustSize();
  836. FindInteriorElements(m_groupedElements);
  837. UpdateSavedElements();
  838. }
  839. ////
  840. RemapGroupedPersistentIds();
  841. }
  842. void NodeGroupFrameComponent::PostOnGraphLoadComplete()
  843. {
  844. RestoreCollapsedState();
  845. }
  846. void NodeGroupFrameComponent::OnPersistentIdsRemapped(const AZStd::unordered_map<PersistentGraphMemberId, PersistentGraphMemberId>& persistentIdRemapping)
  847. {
  848. AZStd::vector< PersistentGraphMemberId > oldPersistentIds = AZStd::move(m_saveData.m_persistentGroupedIds);
  849. m_saveData.m_persistentGroupedIds.clear();
  850. m_saveData.m_persistentGroupedIds.reserve(oldPersistentIds.size());
  851. for (PersistentGraphMemberId oldPersistentId : oldPersistentIds)
  852. {
  853. auto remappedIter = persistentIdRemapping.find(oldPersistentId);
  854. if (remappedIter != persistentIdRemapping.end())
  855. {
  856. m_saveData.m_persistentGroupedIds.emplace_back(remappedIter->second);
  857. }
  858. }
  859. RemapGroupedPersistentIds();
  860. PersistentIdNotificationBus::Handler::BusDisconnect();
  861. }
  862. void NodeGroupFrameComponent::OnSystemTick()
  863. {
  864. // 1 or 0 indicates whether to align to that direction or not.
  865. const int adjustVertical = 1;
  866. const int adjustHorizontal = 1;
  867. // If we have something animating in us, we can adjust ourselves down.
  868. // Otherwise, we want to only grow in response to elements.
  869. m_frameWidget->ResizeToGroup(adjustHorizontal, adjustVertical, m_animatingElements.empty());
  870. AZ::SystemTickBus::Handler::BusDisconnect();
  871. }
  872. void NodeGroupFrameComponent::OnPositionAnimateBegin()
  873. {
  874. const AZ::EntityId* sourceId = VisualNotificationBus::GetCurrentBusId();
  875. if (sourceId)
  876. {
  877. if ((*sourceId) == GetEntityId())
  878. {
  879. m_isGroupAnimating = true;
  880. m_movingElements.clear();
  881. SetupElementsForMove();
  882. for (const auto& element : m_movingElements)
  883. {
  884. RootGraphicsItemRequestBus::Event(element, &RootGraphicsItemRequests::SignalGroupAnimationStart, GetEntityId());
  885. }
  886. }
  887. m_animatingElements.insert((*sourceId));
  888. m_frameWidget->SetSnapToGridEnabled(false);
  889. }
  890. }
  891. void NodeGroupFrameComponent::OnPositionAnimateEnd()
  892. {
  893. const AZ::EntityId* sourceId = VisualNotificationBus::GetCurrentBusId();
  894. if (sourceId)
  895. {
  896. if ((*sourceId) == GetEntityId())
  897. {
  898. for (const auto& element : m_movingElements)
  899. {
  900. RootGraphicsItemRequestBus::Event(element, &RootGraphicsItemRequests::SignalGroupAnimationEnd, GetEntityId());
  901. }
  902. m_isGroupAnimating = false;
  903. m_movingElements.clear();
  904. }
  905. m_animatingElements.erase((*sourceId));
  906. if (m_animatingElements.empty())
  907. {
  908. m_frameWidget->SetSnapToGridEnabled(true);
  909. AZ::SystemTickBus::Handler::BusConnect();
  910. }
  911. }
  912. }
  913. void NodeGroupFrameComponent::OnDisplayStateChanged(RootGraphicsItemDisplayState /*oldState*/, RootGraphicsItemDisplayState newState)
  914. {
  915. if (!m_ignoreDisplayStateChanges)
  916. {
  917. if (newState == RootGraphicsItemDisplayState::GroupHighlight
  918. || newState == RootGraphicsItemDisplayState::Inspection)
  919. {
  920. m_needsDisplayStateHighlight = true;
  921. }
  922. else
  923. {
  924. m_needsDisplayStateHighlight = false;
  925. }
  926. UpdateHighlightState();
  927. }
  928. }
  929. void NodeGroupFrameComponent::OnExpansionComplete()
  930. {
  931. CollapsedNodeGroupNotificationBus::Handler::BusDisconnect();
  932. m_collapsedNodeId.SetInvalid();
  933. SignalExpanded();
  934. }
  935. void NodeGroupFrameComponent::OnFrameResizeStart()
  936. {
  937. m_ignoreDisplayStateChanges = true;
  938. SetupHighlightElementsStateSetters();
  939. m_highlightDisplayStateStateSetter.SetState(RootGraphicsItemDisplayState::GroupHighlight);
  940. m_ignoreElementsOnResize.clear();
  941. AZ::EntityId groupId;
  942. GroupableSceneMemberRequestBus::EventResult(groupId, GetEntityId(), &GroupableSceneMemberRequests::GetGroupId);
  943. while (groupId.IsValid())
  944. {
  945. m_ignoreElementsOnResize.insert(groupId);
  946. AZ::EntityId parentGroup;
  947. GroupableSceneMemberRequestBus::EventResult(parentGroup, groupId, &GroupableSceneMemberRequests::GetGroupId);
  948. if (parentGroup == groupId)
  949. {
  950. break;
  951. }
  952. groupId = parentGroup;
  953. }
  954. }
  955. void NodeGroupFrameComponent::OnFrameResized()
  956. {
  957. AZ::EntityId sceneId;
  958. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  959. QRectF blockArea = GetGroupBoundary();
  960. AZStd::unordered_set< AZ::EntityId > removedElements;
  961. AZStd::unordered_set< AZ::EntityId > resizedGroupElements;
  962. FindInteriorElements(resizedGroupElements, Qt::ItemSelectionMode::IntersectsItemShape);
  963. for (auto currentElement : resizedGroupElements)
  964. {
  965. if (m_ignoreElementsOnResize.find(currentElement) != m_ignoreElementsOnResize.end())
  966. {
  967. continue;
  968. }
  969. bool isVisible = false;
  970. VisualRequestBus::EventResult(isVisible, currentElement, &VisualRequests::IsVisible);
  971. if (!isVisible)
  972. {
  973. continue;
  974. }
  975. if (GraphUtils::IsGroupableElement(currentElement))
  976. {
  977. AZ::EntityId groupId;
  978. GroupableSceneMemberRequestBus::EventResult(groupId, currentElement, &GroupableSceneMemberRequests::GetGroupId);
  979. // Anything in a group will be added into this when the group is absorbed
  980. if (!groupId.IsValid()
  981. || groupId == GetEntityId())
  982. {
  983. QGraphicsItem* graphicsItem = nullptr;
  984. SceneMemberUIRequestBus::EventResult(graphicsItem, currentElement, &SceneMemberUIRequests::GetRootGraphicsItem);
  985. if (graphicsItem)
  986. {
  987. QRectF boundingRect = graphicsItem->sceneBoundingRect();
  988. QRectF intersected = boundingRect.intersected(blockArea);
  989. if (intersected.height() > boundingRect.height() * 0.5f
  990. && intersected.width() > boundingRect.width() * 0.5f)
  991. {
  992. if (groupId != GetEntityId())
  993. {
  994. StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
  995. RootGraphicsItemRequestBus::EventResult(stateController, currentElement, &RootGraphicsItemRequests::GetDisplayStateStateController);
  996. m_highlightDisplayStateStateSetter.AddStateController(stateController);
  997. m_groupedElements.insert(currentElement);
  998. OnElementGrouped(currentElement);
  999. }
  1000. }
  1001. else if (m_groupedElements.find(currentElement) != m_groupedElements.end())
  1002. {
  1003. removedElements.insert(currentElement);
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. // Go over everything that might have been completely out of sized.
  1010. for (auto groupedElement : m_groupedElements)
  1011. {
  1012. if (resizedGroupElements.find(groupedElement) == resizedGroupElements.end())
  1013. {
  1014. removedElements.insert(groupedElement);
  1015. }
  1016. }
  1017. for (auto removedElement : removedElements)
  1018. {
  1019. StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
  1020. RootGraphicsItemRequestBus::EventResult(stateController, removedElement, &RootGraphicsItemRequests::GetDisplayStateStateController);
  1021. m_highlightDisplayStateStateSetter.RemoveStateController(stateController);
  1022. m_groupedElements.erase(removedElement);
  1023. OnElementUngrouped(removedElement);
  1024. }
  1025. }
  1026. void NodeGroupFrameComponent::OnFrameResizeEnd()
  1027. {
  1028. // Sanitize our group elements from our display.
  1029. UpdateSavedElements();
  1030. const bool growGroupOnly = true;
  1031. ResizeGroupToElements(growGroupOnly);
  1032. m_ignoreElementsOnResize.clear();
  1033. m_ignoreDisplayStateChanges = false;
  1034. }
  1035. EditorId NodeGroupFrameComponent::GetEditorId() const
  1036. {
  1037. return m_editorId;
  1038. }
  1039. void NodeGroupFrameComponent::RestoreCollapsedState()
  1040. {
  1041. if (m_saveData.m_isCollapsed)
  1042. {
  1043. m_frameWidget->adjustSize();
  1044. if (m_groupedElements.empty())
  1045. {
  1046. RemapGroupedPersistentIds();
  1047. }
  1048. bool canCollapseNode = true;
  1049. // Need to restore our collapsed states inward out(so any group that is contained within another group needs to collapse before I can collapse the owning group).
  1050. for (const AZ::EntityId& groupedElement : m_groupedElements)
  1051. {
  1052. if (GraphUtils::IsNodeGroup(groupedElement))
  1053. {
  1054. bool isCollapsed = false;
  1055. NodeGroupRequestBus::EventResult(isCollapsed, groupedElement, &NodeGroupRequests::IsCollapsed);
  1056. if (isCollapsed)
  1057. {
  1058. NodeId collapsedNodeId;
  1059. NodeGroupRequestBus::EventResult(collapsedNodeId, groupedElement, &NodeGroupRequests::GetCollapsedNodeId);
  1060. if (!collapsedNodeId.IsValid())
  1061. {
  1062. m_initializingGroups.insert(groupedElement);
  1063. canCollapseNode = false;
  1064. break;
  1065. }
  1066. else
  1067. {
  1068. m_groupedElements.insert(collapsedNodeId);
  1069. OnElementGrouped(collapsedNodeId);
  1070. }
  1071. }
  1072. }
  1073. }
  1074. if (canCollapseNode)
  1075. {
  1076. QScopedValueRollback<bool> manipulationBlocker(m_enableSelectionManipulation, false);
  1077. CollapseGroup();
  1078. }
  1079. }
  1080. }
  1081. void NodeGroupFrameComponent::TryAndRestoreCollapsedState()
  1082. {
  1083. if (m_saveData.m_isCollapsed)
  1084. {
  1085. bool canCollapse = true;
  1086. for (const AZ::EntityId& internalGroup : m_groupedGrouped)
  1087. {
  1088. NodeGroupRequests* nodeGroupRequests = NodeGroupRequestBus::FindFirstHandler(internalGroup);
  1089. if (nodeGroupRequests)
  1090. {
  1091. if (nodeGroupRequests->IsCollapsed())
  1092. {
  1093. if (!nodeGroupRequests->GetCollapsedNodeId().IsValid())
  1094. {
  1095. canCollapse = false;
  1096. break;
  1097. }
  1098. }
  1099. }
  1100. }
  1101. if (canCollapse)
  1102. {
  1103. RestoreCollapsedState();
  1104. }
  1105. }
  1106. }
  1107. void NodeGroupFrameComponent::FindInteriorElements(AZStd::unordered_set< AZ::EntityId >& interiorElements, Qt::ItemSelectionMode selectionMode)
  1108. {
  1109. AZ::EntityId sceneId;
  1110. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  1111. QRectF blockArea = GetGroupBoundary();
  1112. AZStd::vector< AZ::EntityId > elementList;
  1113. SceneRequestBus::EventResult(elementList, sceneId, &SceneRequests::GetEntitiesInRect, blockArea, selectionMode);
  1114. interiorElements.clear();
  1115. for (const AZ::EntityId& testElement : elementList)
  1116. {
  1117. if (GraphUtils::IsConnection(testElement) || testElement == GetEntityId())
  1118. {
  1119. continue;
  1120. }
  1121. GroupableSceneMemberRequests* groupableRequests = GroupableSceneMemberRequestBus::FindFirstHandler(testElement);
  1122. if (groupableRequests)
  1123. {
  1124. bool isVisible = true;
  1125. VisualRequestBus::EventResult(isVisible, testElement, &VisualRequests::IsVisible);
  1126. if (isVisible)
  1127. {
  1128. interiorElements.insert(testElement);
  1129. }
  1130. }
  1131. }
  1132. }
  1133. float NodeGroupFrameComponent::SetDisplayHeight(float height)
  1134. {
  1135. if (m_frameWidget && m_frameWidget->m_minimumSize.height() > height)
  1136. {
  1137. height = aznumeric_cast<float>(m_frameWidget->m_minimumSize.height());
  1138. }
  1139. m_saveData.m_displayHeight = height;
  1140. SignalDirty();
  1141. return height;
  1142. }
  1143. float NodeGroupFrameComponent::SetDisplayWidth(float width)
  1144. {
  1145. if (m_frameWidget && m_frameWidget->m_minimumSize.width() > width)
  1146. {
  1147. width = aznumeric_cast<float>(m_frameWidget->m_minimumSize.width());
  1148. }
  1149. m_saveData.m_displayWidth = width;
  1150. SignalDirty();
  1151. return width;
  1152. }
  1153. void NodeGroupFrameComponent::EnableInteriorHighlight(bool highlight)
  1154. {
  1155. m_needsManualHighlight = highlight;
  1156. UpdateHighlightState();
  1157. }
  1158. void NodeGroupFrameComponent::EnableGroupedDisplayState(bool enabled)
  1159. {
  1160. m_forcedGroupDisplayStateStateSetter.ResetStateSetter();
  1161. if (enabled)
  1162. {
  1163. SetupGroupedElementsStateSetters();
  1164. m_forcedGroupDisplayStateStateSetter.SetState(RootGraphicsItemDisplayState::GroupHighlight);
  1165. }
  1166. }
  1167. void NodeGroupFrameComponent::OnBookmarkStatusChanged()
  1168. {
  1169. AZ::EntityId sceneId;
  1170. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  1171. if (m_saveData.m_enableAsBookmark)
  1172. {
  1173. BookmarkManagerRequestBus::Event(sceneId, &BookmarkManagerRequests::RegisterBookmark, GetEntityId());
  1174. SceneBookmarkRequestBus::Handler::BusConnect(sceneId);
  1175. }
  1176. else
  1177. {
  1178. bool isRegistered = false;
  1179. BookmarkManagerRequestBus::EventResult(isRegistered, sceneId, &BookmarkManagerRequests::IsBookmarkRegistered, GetEntityId());
  1180. if (isRegistered)
  1181. {
  1182. BookmarkManagerRequestBus::Event(sceneId, &BookmarkManagerRequests::UnregisterBookmark, GetEntityId());
  1183. }
  1184. m_saveData.m_shortcut = k_findShortcut;
  1185. SceneBookmarkRequestBus::Handler::BusDisconnect();
  1186. }
  1187. }
  1188. void NodeGroupFrameComponent::UpdateSavedElements()
  1189. {
  1190. if (!m_saveData.m_isCollapsed)
  1191. {
  1192. m_saveData.m_persistentGroupedIds.clear();
  1193. for (AZ::EntityId groupedMemberId : m_groupedElements)
  1194. {
  1195. if (GraphUtils::IsCollapsedNodeGroup(groupedMemberId))
  1196. {
  1197. continue;
  1198. }
  1199. PersistentGraphMemberId graphMemberId = PersistentGraphMemberId::CreateNull();
  1200. PersistentMemberRequestBus::EventResult(graphMemberId, groupedMemberId, &PersistentMemberRequests::GetPersistentGraphMemberId);
  1201. if (!graphMemberId.IsNull())
  1202. {
  1203. m_saveData.m_persistentGroupedIds.emplace_back(graphMemberId);
  1204. }
  1205. }
  1206. SignalDirty();
  1207. }
  1208. }
  1209. void NodeGroupFrameComponent::RemapGroupedPersistentIds()
  1210. {
  1211. for (const AZ::EntityId& groupedElement : m_groupedElements)
  1212. {
  1213. OnElementUngrouped(groupedElement);
  1214. }
  1215. m_groupedElements.clear();
  1216. for (const PersistentGraphMemberId& persistentMemberId : m_saveData.m_persistentGroupedIds)
  1217. {
  1218. AZ::EntityId graphMemberId;
  1219. PersistentIdRequestBus::EventResult(graphMemberId, persistentMemberId, &PersistentIdRequests::MapToEntityId);
  1220. if (graphMemberId.IsValid())
  1221. {
  1222. m_groupedElements.insert(graphMemberId);
  1223. OnElementGrouped(graphMemberId);
  1224. if (GraphUtils::IsNodeGroup(graphMemberId))
  1225. {
  1226. bool isCollapsed = false;
  1227. NodeGroupRequestBus::EventResult(isCollapsed, graphMemberId, &NodeGroupRequests::IsCollapsed);
  1228. if (isCollapsed)
  1229. {
  1230. NodeId collapsedNodeId;
  1231. NodeGroupRequestBus::EventResult(collapsedNodeId, graphMemberId, &NodeGroupRequests::GetCollapsedNodeId);
  1232. if (collapsedNodeId.IsValid())
  1233. {
  1234. m_groupedElements.insert(collapsedNodeId);
  1235. OnElementGrouped(collapsedNodeId);
  1236. }
  1237. }
  1238. }
  1239. }
  1240. }
  1241. }
  1242. bool NodeGroupFrameComponent::AddToGroupInternal(const AZ::EntityId& groupableElement)
  1243. {
  1244. if (GraphUtils::IsGroupableElement(groupableElement) && groupableElement != GetEntityId())
  1245. {
  1246. auto insertResult = m_groupedElements.insert(groupableElement);
  1247. if (insertResult.second)
  1248. {
  1249. OnElementGrouped(groupableElement);
  1250. return true;
  1251. }
  1252. }
  1253. return false;
  1254. }
  1255. void NodeGroupFrameComponent::UpdateHighlightState()
  1256. {
  1257. bool isHighlighted = m_highlightDisplayStateStateSetter.HasState();
  1258. bool shouldHighlight = m_needsDisplayStateHighlight || m_needsManualHighlight;
  1259. if (isHighlighted != shouldHighlight)
  1260. {
  1261. if (shouldHighlight)
  1262. {
  1263. SetupHighlightElementsStateSetters();
  1264. m_highlightDisplayStateStateSetter.SetState(RootGraphicsItemDisplayState::GroupHighlight);
  1265. }
  1266. else
  1267. {
  1268. m_highlightDisplayStateStateSetter.ResetStateSetter();
  1269. }
  1270. }
  1271. }
  1272. void NodeGroupFrameComponent::SetupHighlightElementsStateSetters()
  1273. {
  1274. AZStd::vector< AZ::EntityId > highlightEntities;
  1275. FindGroupedElements(highlightEntities);
  1276. for (const AZ::EntityId& entityId : highlightEntities)
  1277. {
  1278. StateController<RootGraphicsItemDisplayState>* stateController = nullptr;
  1279. RootGraphicsItemRequestBus::EventResult(stateController, entityId, &RootGraphicsItemRequests::GetDisplayStateStateController);
  1280. m_highlightDisplayStateStateSetter.AddStateController(stateController);
  1281. }
  1282. }
  1283. void NodeGroupFrameComponent::SetupGroupedElementsStateSetters()
  1284. {
  1285. AZStd::vector< AZ::EntityId > groupedElements;
  1286. FindGroupedElements(groupedElements);
  1287. groupedElements.push_back(GetEntityId());
  1288. SubGraphParsingConfig config;
  1289. config.m_createNonConnectableSubGraph = true;
  1290. SubGraphParsingResult subGraphResult = GraphUtils::ParseSceneMembersIntoSubGraphs(groupedElements, config);
  1291. SetupSubGraphGroupedElementsStateSetters(subGraphResult.m_nonConnectableGraph);
  1292. for (const GraphSubGraph& subGraph : subGraphResult.m_subGraphs)
  1293. {
  1294. SetupSubGraphGroupedElementsStateSetters(subGraph);
  1295. }
  1296. }
  1297. void NodeGroupFrameComponent::SetupSubGraphGroupedElementsStateSetters(const GraphSubGraph& subGraph)
  1298. {
  1299. for (const AZ::EntityId& elementId : subGraph.m_containedNodes)
  1300. {
  1301. if (elementId == m_collapsedNodeId)
  1302. {
  1303. continue;
  1304. }
  1305. StateController<RootGraphicsItemDisplayState>* displayStateController = nullptr;
  1306. RootGraphicsItemRequestBus::EventResult(displayStateController, elementId, &RootGraphicsItemRequests::GetDisplayStateStateController);
  1307. m_forcedGroupDisplayStateStateSetter.AddStateController(displayStateController);
  1308. }
  1309. }
  1310. void NodeGroupFrameComponent::OnElementGrouped(const AZ::EntityId& groupableElement)
  1311. {
  1312. GroupableSceneMemberRequestBus::Event(groupableElement, &GroupableSceneMemberRequests::RegisterToGroup, GetEntityId());
  1313. GeometryNotificationBus::MultiHandler::BusConnect(groupableElement);
  1314. VisualNotificationBus::MultiHandler::BusConnect(groupableElement);
  1315. if (GraphUtils::IsNodeGroup(groupableElement))
  1316. {
  1317. m_groupedGrouped.insert(groupableElement);
  1318. NodeGroupNotificationBus::MultiHandler::BusConnect(groupableElement);
  1319. }
  1320. if (GraphUtils::IsCollapsedNodeGroup(groupableElement))
  1321. {
  1322. AZ::EntityId groupId;
  1323. CollapsedNodeGroupRequestBus::EventResult(groupId, groupableElement, &CollapsedNodeGroupRequests::GetSourceGroup);
  1324. if (groupId.IsValid())
  1325. {
  1326. m_collapsedGroupMapping[groupId] = groupableElement;
  1327. if (m_groupedElements.find(groupId) == m_groupedElements.end())
  1328. {
  1329. m_groupedElements.insert(groupId);
  1330. OnElementGrouped(groupId);
  1331. }
  1332. }
  1333. }
  1334. }
  1335. void NodeGroupFrameComponent::OnElementUngrouped(const AZ::EntityId& groupableElement)
  1336. {
  1337. GroupableSceneMemberRequestBus::Event(groupableElement, &GroupableSceneMemberRequests::UnregisterFromGroup, GetEntityId());
  1338. GeometryNotificationBus::MultiHandler::BusDisconnect(groupableElement);
  1339. VisualNotificationBus::MultiHandler::BusDisconnect(groupableElement);
  1340. size_t eraseCount = m_groupedGrouped.erase(groupableElement);
  1341. if (eraseCount > 0)
  1342. {
  1343. NodeGroupNotificationBus::MultiHandler::BusDisconnect(groupableElement);
  1344. }
  1345. if (GraphUtils::IsCollapsedNodeGroup(groupableElement))
  1346. {
  1347. AZ::EntityId groupId;
  1348. CollapsedNodeGroupRequestBus::EventResult(groupId, groupableElement, &CollapsedNodeGroupRequests::GetSourceGroup);
  1349. if (groupId.IsValid())
  1350. {
  1351. // If we don't erase anything from this map, that means we are coming from the ExpandedSignal
  1352. size_t eraseCount2 = m_collapsedGroupMapping.erase(groupId);
  1353. if (eraseCount2 > 0)
  1354. {
  1355. m_groupedElements.erase(groupId);
  1356. OnElementUngrouped(groupId);
  1357. }
  1358. }
  1359. }
  1360. }
  1361. void NodeGroupFrameComponent::SignalExpanded()
  1362. {
  1363. GraphId graphId;
  1364. SceneMemberRequestBus::EventResult(graphId, GetEntityId(), &SceneMemberRequests::GetScene);
  1365. m_saveData.m_isCollapsed = false;
  1366. SignalDirty();
  1367. NodeGroupNotificationBus::Event(GetEntityId(), &NodeGroupNotifications::OnExpanded);
  1368. GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestUndoPoint);
  1369. if (m_enableSelectionManipulation)
  1370. {
  1371. m_frameWidget->SetSelected(true);
  1372. }
  1373. }
  1374. void NodeGroupFrameComponent::SetupElementsForMove()
  1375. {
  1376. if (m_movingElements.empty())
  1377. {
  1378. AZ_Warning("Graph Canvas", m_movingElements.empty(), "Moving elements should be empty when scraping for new elements.");
  1379. m_movingElements = m_groupedElements;
  1380. if (!m_isGroupAnimating)
  1381. {
  1382. for (const AZ::EntityId& currentElement : m_groupedElements)
  1383. {
  1384. // We don't want to move anything that is selected, since in the drag move
  1385. // Qt will handle moving it already, so we don't want to double move it.
  1386. bool isSelected = false;
  1387. SceneMemberUIRequestBus::EventResult(isSelected, currentElement, &SceneMemberUIRequests::IsSelected);
  1388. if (isSelected)
  1389. {
  1390. m_movingElements.erase(currentElement);
  1391. }
  1392. }
  1393. }
  1394. // Go through and erase any group ids that are subsumed by a collapsed node id.
  1395. for (const auto& mappingPair : m_collapsedGroupMapping)
  1396. {
  1397. m_movingElements.erase(mappingPair.first);
  1398. }
  1399. }
  1400. }
  1401. void NodeGroupFrameComponent::SignalDirty()
  1402. {
  1403. if (!m_isGroupAnimating)
  1404. {
  1405. m_saveData.SignalDirty();
  1406. }
  1407. }
  1408. QRectF NodeGroupFrameComponent::GetGroupBoundary() const
  1409. {
  1410. QRectF blockArea = m_frameWidget->sceneBoundingRect();
  1411. // Need to convert this to our previous position
  1412. // just incase we are moving.
  1413. //
  1414. // If we aren't moving, this will be the same, so just a little slower then necessary.
  1415. blockArea.setX(m_previousPosition.GetX());
  1416. blockArea.setY(m_previousPosition.GetY());
  1417. blockArea.setWidth(m_frameWidget->RoundToClosestStep(aznumeric_cast<int>(blockArea.width()), m_frameWidget->GetGridXStep()));
  1418. blockArea.setHeight(m_frameWidget->RoundToClosestStep(aznumeric_cast<int>(blockArea.height()), m_frameWidget->GetGridYStep()));
  1419. // Want to adjust everything by half a step in each direction to get the elements that are directly on the edge of the frame widget
  1420. // without grabbing the elements that are a single step off the edge.
  1421. qreal adjustStepX = m_frameWidget->GetGridXStep() * 0.5f;
  1422. qreal adjustStepY = m_frameWidget->GetGridYStep() * 0.5f;
  1423. blockArea.adjust(-adjustStepX, -adjustStepY, adjustStepX, adjustStepY);
  1424. return blockArea;
  1425. }
  1426. //////////////////////////////
  1427. // NodeGroupFrameTitleWidget
  1428. //////////////////////////////
  1429. NodeGroupFrameTitleWidget::NodeGroupFrameTitleWidget()
  1430. : m_frameWidget(nullptr)
  1431. {
  1432. setAcceptHoverEvents(false);
  1433. setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
  1434. }
  1435. void NodeGroupFrameTitleWidget::RefreshStyle(const AZ::EntityId& parentId)
  1436. {
  1437. m_styleHelper.SetStyle(parentId, Styling::Elements::NodeGroup::Title);
  1438. update();
  1439. }
  1440. void NodeGroupFrameTitleWidget::SetColor(const AZ::Color& color)
  1441. {
  1442. m_color = ConversionUtils::AZToQColor(color);
  1443. update();
  1444. }
  1445. void NodeGroupFrameTitleWidget::RegisterFrame(NodeGroupFrameGraphicsWidget* frameWidget)
  1446. {
  1447. m_frameWidget = frameWidget;
  1448. }
  1449. void NodeGroupFrameTitleWidget::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent)
  1450. {
  1451. if (m_frameWidget)
  1452. {
  1453. if (m_frameWidget->m_adjustVertical != 0
  1454. || m_frameWidget->m_adjustHorizontal != 0)
  1455. {
  1456. mouseEvent->setAccepted(false);
  1457. return;
  1458. }
  1459. }
  1460. QGraphicsWidget::mousePressEvent(mouseEvent);
  1461. }
  1462. void NodeGroupFrameTitleWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  1463. {
  1464. GRAPH_CANVAS_DETAILED_PROFILE_FUNCTION();
  1465. QPen border = m_styleHelper.GetBorder();
  1466. border.setColor(m_color);
  1467. QBrush alphaBackground = m_styleHelper.GetBrush(Styling::Attribute::BackgroundColor);
  1468. QColor backgroundColor = m_color;
  1469. backgroundColor.setAlpha(alphaBackground.color().alpha());
  1470. QBrush background = QBrush(backgroundColor);
  1471. if (border.style() != Qt::NoPen || background.color().alpha() > 0)
  1472. {
  1473. qreal cornerRadius = m_styleHelper.GetAttribute(Styling::Attribute::BorderRadius, 5.0);
  1474. border.setJoinStyle(Qt::PenJoinStyle::MiterJoin); // sharp corners
  1475. painter->setPen(border);
  1476. QRectF bounds = boundingRect();
  1477. // Ensure the bounds are large enough to draw the full radius
  1478. // Even in our smaller section
  1479. if (bounds.height() < 2.0 * cornerRadius)
  1480. {
  1481. bounds.setHeight(2.0 * cornerRadius);
  1482. }
  1483. qreal halfBorder = border.widthF() / 2.;
  1484. QRectF adjustedBounds = bounds.marginsRemoved(QMarginsF(halfBorder, halfBorder, halfBorder, halfBorder));
  1485. painter->save();
  1486. painter->setClipRect(bounds);
  1487. QPainterPath path;
  1488. path.setFillRule(Qt::WindingFill);
  1489. // Moving the bottom bounds off the bottom, so we can't see them(mostly to avoid double drawing over the same region)
  1490. adjustedBounds.setHeight(adjustedBounds.height() + border.widthF() + cornerRadius);
  1491. // -1.0 because the rounding is a little bit short(for some reason), so I subtract one and let it overshoot a smidge.
  1492. path.addRoundedRect(adjustedBounds, cornerRadius - 1.0, cornerRadius - 1.0);
  1493. painter->fillPath(path, background);
  1494. painter->drawPath(path.simplified());
  1495. painter->restore();
  1496. }
  1497. QGraphicsWidget::paint(painter, option, widget);
  1498. }
  1499. QVariant NodeGroupFrameTitleWidget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
  1500. {
  1501. if (m_frameWidget)
  1502. {
  1503. VisualNotificationBus::Event(m_frameWidget->GetEntityId(), &VisualNotifications::OnItemChange, m_frameWidget->GetEntityId(), change, value);
  1504. }
  1505. return QGraphicsWidget::itemChange(change, value);
  1506. }
  1507. //////////////////////////////////
  1508. // NodeGroupFrameBlockAreaWidget
  1509. //////////////////////////////////
  1510. NodeGroupFrameBlockAreaWidget::NodeGroupFrameBlockAreaWidget()
  1511. {
  1512. setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  1513. }
  1514. void NodeGroupFrameBlockAreaWidget::RegisterFrame(NodeGroupFrameGraphicsWidget* frame)
  1515. {
  1516. m_frameWidget = frame;
  1517. }
  1518. void NodeGroupFrameBlockAreaWidget::RefreshStyle(const AZ::EntityId& parentId)
  1519. {
  1520. m_styleHelper.SetStyle(parentId, Styling::Elements::NodeGroup::BlockArea);
  1521. update();
  1522. }
  1523. void NodeGroupFrameBlockAreaWidget::SetColor(const AZ::Color& color)
  1524. {
  1525. m_color = ConversionUtils::AZToQColor(color);
  1526. update();
  1527. }
  1528. void NodeGroupFrameBlockAreaWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  1529. {
  1530. QPen border = m_styleHelper.GetBorder();
  1531. border.setColor(m_color);
  1532. QBrush alphaBackground = m_styleHelper.GetBrush(Styling::Attribute::BackgroundColor);
  1533. QColor backgroundColor = m_color;
  1534. backgroundColor.setAlpha(alphaBackground.color().alpha());
  1535. QBrush background = QBrush(backgroundColor);
  1536. if (border.style() != Qt::NoPen || background.color().alpha() > 0)
  1537. {
  1538. qreal cornerRadius = m_styleHelper.GetAttribute(Styling::Attribute::BorderRadius, 5.0);
  1539. border.setJoinStyle(Qt::PenJoinStyle::MiterJoin); // sharp corners
  1540. painter->setPen(border);
  1541. QRectF bounds = boundingRect();
  1542. // Ensure the bounds are large enough to draw the full radius
  1543. // Even in our smaller section
  1544. if (bounds.height() < 2.0 * cornerRadius)
  1545. {
  1546. bounds.setHeight(2.0 * cornerRadius);
  1547. }
  1548. painter->save();
  1549. painter->setClipRect(bounds);
  1550. qreal halfBorder = border.widthF() / 2.;
  1551. QRectF adjustedBounds = bounds.marginsRemoved(QMarginsF(halfBorder, halfBorder, halfBorder, halfBorder));
  1552. // Moving the tops bounds off the top, so we can't see them(mostly to avoid double drawing over the same region)
  1553. adjustedBounds.setY(adjustedBounds.y() - AZ::GetMax(border.widthF(), cornerRadius));
  1554. QPainterPath path;
  1555. path.setFillRule(Qt::WindingFill);
  1556. // -1.0 because the rounding is a little bit short(for some reason), so I subtract one and let it overshoot a smidge.
  1557. path.addRoundedRect(adjustedBounds, cornerRadius - 1.0, cornerRadius - 1.0);
  1558. painter->fillPath(path, background);
  1559. painter->drawPath(path.simplified());
  1560. int numLines = 3;
  1561. border.setWidth(1);
  1562. painter->setPen(border);
  1563. qreal halfPenWidth = border.width() * 0.5f;
  1564. qreal spacing = 3;
  1565. qreal initialSpacing = 0;
  1566. QPointF bottomPoint = bounds.bottomRight();
  1567. QPointF offsetPointHorizontal = bottomPoint;
  1568. offsetPointHorizontal.setX(offsetPointHorizontal.x() - (initialSpacing));
  1569. QPointF offsetPointVertical = bottomPoint;
  1570. offsetPointVertical.setY(offsetPointVertical.y() - (initialSpacing));
  1571. for (int i = 0; i < numLines; ++i)
  1572. {
  1573. offsetPointHorizontal.setX(offsetPointHorizontal.x() - (spacing + halfPenWidth));
  1574. offsetPointVertical.setY(offsetPointVertical.y() - (spacing + halfPenWidth));
  1575. painter->drawLine(offsetPointHorizontal, offsetPointVertical);
  1576. offsetPointHorizontal.setX(offsetPointHorizontal.x() - (halfPenWidth));
  1577. offsetPointVertical.setY(offsetPointVertical.y() - (halfPenWidth));
  1578. }
  1579. painter->restore();
  1580. }
  1581. QGraphicsWidget::paint(painter, option, widget);
  1582. }
  1583. /////////////////////////////////
  1584. // NodeGroupFrameGraphicsWidget
  1585. /////////////////////////////////
  1586. NodeGroupFrameGraphicsWidget::NodeGroupFrameGraphicsWidget(const AZ::EntityId& entityKey, NodeGroupFrameComponent& nodeFrameComponent)
  1587. : NodeFrameGraphicsWidget(entityKey)
  1588. , m_nodeFrameComponent(nodeFrameComponent)
  1589. , m_useTitleShape(false)
  1590. , m_allowCommentReaction(false)
  1591. , m_allowMovement(false)
  1592. , m_resizeComment(false)
  1593. , m_allowDraw(true)
  1594. , m_adjustVertical(0)
  1595. , m_adjustHorizontal(0)
  1596. , m_overTitleWidget(false)
  1597. , m_isSelected(false)
  1598. , m_enableHighlight(false)
  1599. {
  1600. setAcceptHoverEvents(true);
  1601. setCacheMode(QGraphicsItem::CacheMode::NoCache);
  1602. }
  1603. void NodeGroupFrameGraphicsWidget::RefreshStyle(const AZ::EntityId& styleEntity)
  1604. {
  1605. m_borderStyle.SetStyle(styleEntity, Styling::Elements::NodeGroup::Border);
  1606. }
  1607. void NodeGroupFrameGraphicsWidget::SetResizableMinimum(const QSizeF& minimumSize)
  1608. {
  1609. m_resizableMinimum = minimumSize;
  1610. UpdateMinimumSize();
  1611. // Weird case. The maximum size of this needs to be set.
  1612. // Otherwise the text widget will force it to grow a bit.
  1613. // This gets set naturally when you resize the element, but
  1614. // not when one gets newly created. To catch this,
  1615. // we'll just check if we don't have a reasonable maximum width set
  1616. // and then just set ourselves to the minimum size that is passed in.
  1617. if (maximumWidth() == QWIDGETSIZE_MAX)
  1618. {
  1619. ResizeTo(aznumeric_cast<float>(minimumSize.height()), aznumeric_cast<float>(minimumSize.width()));
  1620. }
  1621. }
  1622. void NodeGroupFrameGraphicsWidget::SetUseTitleShape(bool enable)
  1623. {
  1624. m_useTitleShape = enable;
  1625. }
  1626. void NodeGroupFrameGraphicsWidget::OnActivated()
  1627. {
  1628. SceneMemberNotificationBus::Handler::BusConnect(GetEntityId());
  1629. }
  1630. QPainterPath NodeGroupFrameGraphicsWidget::GetOutline() const
  1631. {
  1632. QPainterPath path;
  1633. path.addRect(sceneBoundingRect());
  1634. return path;
  1635. }
  1636. void NodeGroupFrameGraphicsWidget::hoverEnterEvent(QGraphicsSceneHoverEvent* hoverEvent)
  1637. {
  1638. NodeFrameGraphicsWidget::hoverEnterEvent(hoverEvent);
  1639. QPointF point = hoverEvent->scenePos();
  1640. UpdateCursor(point);
  1641. m_allowDraw = m_nodeFrameComponent.m_titleWidget->sceneBoundingRect().contains(point);
  1642. m_overTitleWidget = m_allowDraw;
  1643. UpdateHighlightState();
  1644. }
  1645. void NodeGroupFrameGraphicsWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* hoverEvent)
  1646. {
  1647. NodeFrameGraphicsWidget::hoverMoveEvent(hoverEvent);
  1648. QPointF point = hoverEvent->scenePos();
  1649. UpdateCursor(point);
  1650. bool allowDraw = m_nodeFrameComponent.m_titleWidget->sceneBoundingRect().contains(point);
  1651. if (allowDraw != m_allowDraw)
  1652. {
  1653. m_overTitleWidget = allowDraw;
  1654. m_allowDraw = allowDraw;
  1655. update();
  1656. }
  1657. UpdateHighlightState();
  1658. }
  1659. void NodeGroupFrameGraphicsWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent* hoverEvent)
  1660. {
  1661. NodeFrameGraphicsWidget::hoverLeaveEvent(hoverEvent);
  1662. ResetCursor();
  1663. m_adjustHorizontal = 0;
  1664. m_adjustVertical = 0;
  1665. m_allowDraw = true;
  1666. m_overTitleWidget = false;
  1667. UpdateHighlightState();
  1668. }
  1669. void NodeGroupFrameGraphicsWidget::mousePressEvent(QGraphicsSceneMouseEvent* pressEvent)
  1670. {
  1671. if (m_adjustHorizontal != 0 || m_adjustVertical != 0)
  1672. {
  1673. pressEvent->accept();
  1674. m_allowCommentReaction = true;
  1675. m_resizeComment = true;
  1676. AZ::EntityId sceneId;
  1677. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  1678. SceneRequestBus::Event(sceneId, &SceneRequests::ClearSelection);
  1679. SetSelected(true);
  1680. m_nodeFrameComponent.OnFrameResizeStart();
  1681. }
  1682. else if (m_nodeFrameComponent.m_titleWidget->sceneBoundingRect().contains(pressEvent->scenePos()))
  1683. {
  1684. pressEvent->accept();
  1685. NodeFrameGraphicsWidget::mousePressEvent(pressEvent);
  1686. }
  1687. else
  1688. {
  1689. pressEvent->setAccepted(false);
  1690. }
  1691. }
  1692. void NodeGroupFrameGraphicsWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent)
  1693. {
  1694. if (m_resizeComment)
  1695. {
  1696. QScopedValueRollback<bool> allowMovement(m_allowMovement, false);
  1697. mouseEvent->accept();
  1698. QPointF point = mouseEvent->scenePos();
  1699. QPointF anchorPoint = scenePos();
  1700. double halfBorder = (m_style.GetAttribute(Styling::Attribute::BorderWidth, 1.0) * 0.5f);
  1701. QSizeF originalSize = boundingRect().size();
  1702. qreal newWidth = originalSize.width();
  1703. qreal newHeight = originalSize.height();
  1704. if (m_adjustVertical < 0)
  1705. {
  1706. newHeight += anchorPoint.y() - point.y();
  1707. }
  1708. else if (m_adjustVertical > 0)
  1709. {
  1710. newHeight += point.y() - (anchorPoint.y() + boundingRect().height() - halfBorder);
  1711. }
  1712. if (m_adjustHorizontal < 0)
  1713. {
  1714. newWidth += anchorPoint.x() - point.x();
  1715. }
  1716. else if (m_adjustHorizontal > 0)
  1717. {
  1718. newWidth += point.x() - (anchorPoint.x() + boundingRect().width() - halfBorder);
  1719. }
  1720. QSizeF minimumSize = m_style.GetMinimumSize();
  1721. if (newWidth < m_minimumSize.width())
  1722. {
  1723. newWidth = minimumSize.width();
  1724. }
  1725. if (newHeight < m_minimumSize.height())
  1726. {
  1727. newHeight = minimumSize.height();
  1728. }
  1729. if (IsResizedToGrid())
  1730. {
  1731. int width = static_cast<int>(newWidth);
  1732. newWidth = RoundToClosestStep(width, GetGridXStep());
  1733. int height = static_cast<int>(newHeight);
  1734. newHeight = RoundToClosestStep(height, GetGridYStep());
  1735. }
  1736. newWidth = m_nodeFrameComponent.SetDisplayWidth(aznumeric_cast<float>(newWidth));
  1737. newHeight = m_nodeFrameComponent.SetDisplayHeight(aznumeric_cast<float>(newHeight));
  1738. qreal widthDelta = newWidth - originalSize.width();
  1739. qreal heightDelta = newHeight - originalSize.height();
  1740. prepareGeometryChange();
  1741. QPointF reposition(0, 0);
  1742. if (m_adjustHorizontal < 0)
  1743. {
  1744. reposition.setX(-widthDelta);
  1745. }
  1746. if (m_adjustVertical < 0)
  1747. {
  1748. reposition.setY(-heightDelta);
  1749. }
  1750. prepareGeometryChange();
  1751. setPos(scenePos() + reposition);
  1752. setMinimumSize(newWidth, newHeight);
  1753. setPreferredSize(newWidth, newHeight);
  1754. setMaximumSize(newWidth, newHeight);
  1755. adjustSize();
  1756. updateGeometry();
  1757. update();
  1758. m_nodeFrameComponent.OnFrameResized();
  1759. }
  1760. else
  1761. {
  1762. NodeFrameGraphicsWidget::mouseMoveEvent(mouseEvent);
  1763. }
  1764. }
  1765. void NodeGroupFrameGraphicsWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* releaseEvent)
  1766. {
  1767. if (m_resizeComment)
  1768. {
  1769. releaseEvent->accept();
  1770. m_resizeComment = false;
  1771. m_allowCommentReaction = false;
  1772. m_nodeFrameComponent.OnFrameResizeEnd();
  1773. GraphId graphId;
  1774. SceneMemberRequestBus::EventResult(graphId, GetEntityId(), &SceneMemberRequests::GetScene);
  1775. GraphModelRequestBus::Event(graphId, &GraphModelRequests::RequestUndoPoint);
  1776. }
  1777. else
  1778. {
  1779. NodeFrameGraphicsWidget::mouseReleaseEvent(releaseEvent);
  1780. }
  1781. }
  1782. bool NodeGroupFrameGraphicsWidget::sceneEventFilter(QGraphicsItem*, QEvent* event)
  1783. {
  1784. switch (event->type())
  1785. {
  1786. case QEvent::GraphicsSceneResize:
  1787. {
  1788. QGraphicsSceneResizeEvent* resizeEvent = static_cast<QGraphicsSceneResizeEvent*>(event);
  1789. OnCommentSizeChanged(resizeEvent->oldSize(), resizeEvent->newSize());
  1790. break;
  1791. }
  1792. default:
  1793. break;
  1794. }
  1795. return false;
  1796. }
  1797. void NodeGroupFrameGraphicsWidget::OnEditBegin()
  1798. {
  1799. m_allowCommentReaction = true;
  1800. }
  1801. void NodeGroupFrameGraphicsWidget::OnEditEnd()
  1802. {
  1803. m_allowCommentReaction = false;
  1804. }
  1805. void NodeGroupFrameGraphicsWidget::OnCommentSizeChanged(const QSizeF& oldSize, const QSizeF& newSize)
  1806. {
  1807. if (m_allowCommentReaction)
  1808. {
  1809. QScopedValueRollback<bool> allowMovement(m_allowMovement, false);
  1810. qreal originalHeight = boundingRect().height();
  1811. qreal newHeight = boundingRect().height() + (newSize.height() - oldSize.height());
  1812. if (newHeight < m_minimumSize.height())
  1813. {
  1814. newHeight = m_minimumSize.height();
  1815. }
  1816. qreal heightDelta = newHeight - originalHeight;
  1817. if (IsResizedToGrid())
  1818. {
  1819. // Check if we have enough space to grow down into the block widget without eating into a full square
  1820. // basically use the bit of a fuzzy space where both the header and the block merge.
  1821. //
  1822. // If we can, just expand down, otherwise then we want to grow up a tick.
  1823. qreal frameHeight = m_nodeFrameComponent.m_blockWidget->boundingRect().height();
  1824. if (heightDelta >= 0 && GrowToNextStep(aznumeric_cast<int>(frameHeight - heightDelta), GetGridYStep()) > frameHeight)
  1825. {
  1826. heightDelta = 0;
  1827. newHeight = originalHeight;
  1828. }
  1829. else
  1830. {
  1831. int height = static_cast<int>(newHeight);
  1832. newHeight = GrowToNextStep(height, GetGridYStep());
  1833. heightDelta = newHeight - originalHeight;
  1834. }
  1835. }
  1836. QPointF reposition(0, -heightDelta);
  1837. prepareGeometryChange();
  1838. setPos(scenePos() + reposition);
  1839. updateGeometry();
  1840. setMinimumHeight(newHeight);
  1841. setPreferredHeight(newHeight);
  1842. setMaximumHeight(newHeight);
  1843. m_nodeFrameComponent.SetDisplayHeight(aznumeric_cast<float>(newHeight));
  1844. adjustSize();
  1845. }
  1846. }
  1847. void NodeGroupFrameGraphicsWidget::OnCommentFontReloadBegin()
  1848. {
  1849. m_allowCommentReaction = true;
  1850. }
  1851. void NodeGroupFrameGraphicsWidget::OnCommentFontReloadEnd()
  1852. {
  1853. m_allowCommentReaction = false;
  1854. }
  1855. void NodeGroupFrameGraphicsWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* mouseEvent)
  1856. {
  1857. if (m_adjustHorizontal != 0
  1858. || m_adjustVertical != 0)
  1859. {
  1860. mouseEvent->accept();
  1861. ResizeToGroup(m_adjustHorizontal, m_adjustVertical);
  1862. AZ::EntityId sceneId;
  1863. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  1864. GraphModelRequestBus::Event(sceneId, &GraphModelRequests::RequestUndoPoint);
  1865. }
  1866. else
  1867. {
  1868. bool collapseOnDoubleClick = false;
  1869. AssetEditorSettingsRequestBus::EventResult(collapseOnDoubleClick, m_nodeFrameComponent.GetEditorId(), &AssetEditorSettingsRequests::IsGroupDoubleClickCollapseEnabled);
  1870. if (collapseOnDoubleClick)
  1871. {
  1872. if (m_nodeFrameComponent.m_titleWidget->sceneBoundingRect().contains(mouseEvent->scenePos()))
  1873. {
  1874. NodeGroupRequestBus::Event(GetEntityId(), &NodeGroupRequests::CollapseGroup);
  1875. }
  1876. else
  1877. {
  1878. NodeFrameGraphicsWidget::mouseDoubleClickEvent(mouseEvent);
  1879. mouseEvent->accept();
  1880. NodeGroupRequestBus::Event(GetEntityId(), &NodeGroupRequests::CollapseGroup);
  1881. }
  1882. }
  1883. }
  1884. }
  1885. void NodeGroupFrameGraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  1886. {
  1887. if (isSelected() || m_allowDraw)
  1888. {
  1889. QPen border = m_borderStyle.GetBorder();
  1890. painter->setPen(border);
  1891. painter->drawRect(boundingRect());
  1892. }
  1893. QGraphicsWidget::paint(painter, option, widget);
  1894. }
  1895. QPainterPath NodeGroupFrameGraphicsWidget::shape() const
  1896. {
  1897. // We want to use the title shape for determinig things like selection range with a drag select.
  1898. // But we need to use the full shape for things like mouse events.
  1899. if (m_useTitleShape)
  1900. {
  1901. QPainterPath path;
  1902. path.addRect(m_nodeFrameComponent.m_titleWidget->boundingRect());
  1903. return path;
  1904. }
  1905. else
  1906. {
  1907. return NodeFrameGraphicsWidget::shape();
  1908. }
  1909. }
  1910. QVariant NodeGroupFrameGraphicsWidget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
  1911. {
  1912. QVariant retVal = NodeFrameGraphicsWidget::itemChange(change, value);
  1913. if (change == QGraphicsItem::ItemSelectedChange)
  1914. {
  1915. m_isSelected = value.toBool();
  1916. UpdateHighlightState();
  1917. }
  1918. return retVal;
  1919. }
  1920. void NodeGroupFrameGraphicsWidget::OnMemberSetupComplete()
  1921. {
  1922. m_allowMovement = true;
  1923. CommentNotificationBus::Handler::BusConnect(GetEntityId());
  1924. }
  1925. void NodeGroupFrameGraphicsWidget::ResizeToGroup(int adjustHorizontal, int adjustVertical, bool growOnly)
  1926. {
  1927. QScopedValueRollback<bool> allowMovement(m_allowMovement, false);
  1928. QRectF blockBoundingRect = m_nodeFrameComponent.m_blockWidget->sceneBoundingRect();
  1929. QRectF calculatedBounds;
  1930. // Default grid step to something non-zero so we have some gap
  1931. AZ::EntityId sceneId;
  1932. SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
  1933. AZ::Vector2 gridStep = GraphUtils::FindMinorStep(sceneId);
  1934. QRectF searchBoundingRect = sceneBoundingRect();
  1935. searchBoundingRect.adjust(-gridStep.GetX() * 0.5f, -gridStep.GetY() * 0.5f, gridStep.GetX() * 0.5f, gridStep.GetY() * 0.5f);
  1936. for (AZ::EntityId groupedElement : m_nodeFrameComponent.m_groupedElements)
  1937. {
  1938. // Don't want to resize to connections.
  1939. // And don't want to include ourselves in this calculation
  1940. if (ConnectionRequestBus::FindFirstHandler(groupedElement) != nullptr || groupedElement == GetEntityId())
  1941. {
  1942. continue;
  1943. }
  1944. QGraphicsItem* graphicsItem = nullptr;
  1945. SceneMemberUIRequestBus::EventResult(graphicsItem, groupedElement, &SceneMemberUIRequests::GetRootGraphicsItem);
  1946. if (graphicsItem == nullptr || !graphicsItem->isVisible())
  1947. {
  1948. continue;
  1949. }
  1950. if (calculatedBounds.isEmpty())
  1951. {
  1952. calculatedBounds = graphicsItem->sceneBoundingRect();
  1953. }
  1954. else
  1955. {
  1956. calculatedBounds = calculatedBounds.united(graphicsItem->sceneBoundingRect());
  1957. }
  1958. }
  1959. if (!calculatedBounds.isEmpty())
  1960. {
  1961. // When we are in 'grow' only mode we don't want to add in extra padding, since that will be compounded. So we'll apply that padding once we decide which bound to use.
  1962. if (!growOnly)
  1963. {
  1964. calculatedBounds.adjust(-gridStep.GetX(), -gridStep.GetY(), gridStep.GetX(), gridStep.GetY());
  1965. }
  1966. if (adjustHorizontal != 0)
  1967. {
  1968. if (growOnly)
  1969. {
  1970. int left = static_cast<int>(blockBoundingRect.left());
  1971. if (left >= calculatedBounds.left())
  1972. {
  1973. left = static_cast<int>(calculatedBounds.left() - gridStep.GetX());
  1974. }
  1975. int right = static_cast<int>(blockBoundingRect.right());
  1976. if (right <= calculatedBounds.right())
  1977. {
  1978. right = static_cast<int>(calculatedBounds.right() + gridStep.GetX());
  1979. }
  1980. blockBoundingRect.setX(left);
  1981. blockBoundingRect.setWidth(right - left);
  1982. }
  1983. else
  1984. {
  1985. blockBoundingRect.setX(calculatedBounds.x());
  1986. blockBoundingRect.setWidth(calculatedBounds.width());
  1987. }
  1988. }
  1989. if (adjustVertical != 0)
  1990. {
  1991. if (growOnly)
  1992. {
  1993. int top = static_cast<int>(blockBoundingRect.top());
  1994. if (top >= calculatedBounds.top())
  1995. {
  1996. top = static_cast<int>(calculatedBounds.top() - gridStep.GetY());
  1997. }
  1998. int bottom = static_cast<int>(blockBoundingRect.bottom());
  1999. if (bottom <= calculatedBounds.bottom())
  2000. {
  2001. bottom = static_cast<int>(calculatedBounds.bottom() + gridStep.GetY());
  2002. }
  2003. blockBoundingRect.setY(top);
  2004. blockBoundingRect.setHeight(bottom - top);
  2005. }
  2006. else
  2007. {
  2008. blockBoundingRect.setY(calculatedBounds.y());
  2009. blockBoundingRect.setHeight(calculatedBounds.height());
  2010. }
  2011. }
  2012. m_nodeFrameComponent.SetGroupSize(blockBoundingRect);
  2013. }
  2014. }
  2015. void NodeGroupFrameGraphicsWidget::UpdateHighlightState()
  2016. {
  2017. SetHighlightState(m_overTitleWidget || m_isSelected);
  2018. }
  2019. void NodeGroupFrameGraphicsWidget::SetHighlightState(bool highlightState)
  2020. {
  2021. if (highlightState != m_enableHighlight)
  2022. {
  2023. m_enableHighlight = highlightState;
  2024. m_nodeFrameComponent.EnableInteriorHighlight(m_enableHighlight);
  2025. }
  2026. }
  2027. void NodeGroupFrameGraphicsWidget::ResizeTo(float height, float width)
  2028. {
  2029. prepareGeometryChange();
  2030. if (height >= 0)
  2031. {
  2032. setMinimumHeight(height);
  2033. setPreferredHeight(height);
  2034. setMaximumHeight(height);
  2035. }
  2036. if (width >= 0)
  2037. {
  2038. setMinimumWidth(width);
  2039. setPreferredWidth(width);
  2040. setMaximumWidth(width);
  2041. }
  2042. updateGeometry();
  2043. }
  2044. void NodeGroupFrameGraphicsWidget::OnDeactivated()
  2045. {
  2046. CommentNotificationBus::Handler::BusDisconnect();
  2047. }
  2048. void NodeGroupFrameGraphicsWidget::UpdateMinimumSize()
  2049. {
  2050. QSizeF styleMinimum = m_style.GetMinimumSize();
  2051. m_minimumSize.setWidth(AZ::GetMax(styleMinimum.width(), m_resizableMinimum.width()));
  2052. m_minimumSize.setHeight(AZ::GetMax(styleMinimum.height(), m_resizableMinimum.height()));
  2053. if (IsResizedToGrid())
  2054. {
  2055. m_minimumSize.setWidth(GrowToNextStep(static_cast<int>(m_minimumSize.width()), GetGridXStep()));
  2056. m_minimumSize.setHeight(GrowToNextStep(static_cast<int>(m_minimumSize.height()), GetGridYStep()));
  2057. }
  2058. prepareGeometryChange();
  2059. if (minimumHeight() < m_minimumSize.height())
  2060. {
  2061. setMinimumHeight(m_minimumSize.height());
  2062. setPreferredHeight(m_minimumSize.height());
  2063. setMaximumHeight(m_minimumSize.height());
  2064. // Fix for a timing hole in the start-up process.
  2065. //
  2066. // Save size is set, but not used. But then the style refreshed, which causes
  2067. // this to be recalculated which stomps on the save data.
  2068. if (m_nodeFrameComponent.m_saveData.m_displayHeight < m_minimumSize.height())
  2069. {
  2070. m_nodeFrameComponent.SetDisplayHeight(aznumeric_cast<float>(m_minimumSize.height()));
  2071. }
  2072. }
  2073. if (minimumWidth() < m_minimumSize.width())
  2074. {
  2075. setMinimumWidth(m_minimumSize.width());
  2076. setPreferredWidth(m_minimumSize.width());
  2077. setMaximumWidth(m_minimumSize.width());
  2078. // Fix for a timing hole in the start-up process.
  2079. //
  2080. // Save size is set, but not used. But then the style refreshed, which causes
  2081. // this to be recalculated which stomps on the save data.
  2082. if (m_nodeFrameComponent.m_saveData.m_displayWidth < m_minimumSize.width())
  2083. {
  2084. m_nodeFrameComponent.SetDisplayWidth(aznumeric_cast<float>(m_minimumSize.width()));
  2085. }
  2086. }
  2087. prepareGeometryChange();
  2088. updateGeometry();
  2089. update();
  2090. }
  2091. void NodeGroupFrameGraphicsWidget::ResetCursor()
  2092. {
  2093. setCursor(Qt::ArrowCursor);
  2094. }
  2095. void NodeGroupFrameGraphicsWidget::UpdateCursor(QPointF cursorPoint)
  2096. {
  2097. qreal border = m_style.GetAttribute(Styling::Attribute::BorderWidth, 1.0);
  2098. border = AZStd::GetMax(10.0, border);
  2099. QPointF topLeft = scenePos();
  2100. topLeft.setX(topLeft.x() + border);
  2101. topLeft.setY(topLeft.y() + border);
  2102. QPointF bottomRight = scenePos() + QPointF(boundingRect().width(), boundingRect().height());
  2103. bottomRight.setX(bottomRight.x() - border);
  2104. bottomRight.setY(bottomRight.y() - border);
  2105. m_adjustVertical = 0;
  2106. m_adjustHorizontal = 0;
  2107. if (cursorPoint.x() < topLeft.x())
  2108. {
  2109. m_adjustHorizontal = -1;
  2110. }
  2111. else if (cursorPoint.x() >= bottomRight.x())
  2112. {
  2113. m_adjustHorizontal = 1;
  2114. }
  2115. if (cursorPoint.y() < topLeft.y())
  2116. {
  2117. m_adjustVertical = -1;
  2118. }
  2119. else if (cursorPoint.y() >= bottomRight.y())
  2120. {
  2121. m_adjustVertical = 1;
  2122. }
  2123. if (m_adjustHorizontal == 0 && m_adjustVertical == 0)
  2124. {
  2125. ResetCursor();
  2126. }
  2127. else if (m_adjustHorizontal == m_adjustVertical)
  2128. {
  2129. setCursor(Qt::SizeFDiagCursor);
  2130. }
  2131. else if (m_adjustVertical != 0 && m_adjustHorizontal != 0)
  2132. {
  2133. setCursor(Qt::SizeBDiagCursor);
  2134. }
  2135. else if (m_adjustVertical != 0)
  2136. {
  2137. setCursor(Qt::SizeVerCursor);
  2138. }
  2139. else
  2140. {
  2141. setCursor(Qt::SizeHorCursor);
  2142. }
  2143. }
  2144. }