3
0

ScriptCanvasContextMenus.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  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 <QApplication>
  9. #include <QClipboard>
  10. #include <QFileDialog>
  11. #include <QInputDialog>
  12. #include <QMessageBox>
  13. #include <QMimeData>
  14. #include <QVBoxLayout>
  15. #include <AzCore/UserSettings/UserSettings.h>
  16. #include <AzQtComponents/Components/Widgets/FileDialog.h>
  17. #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  18. #include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
  19. #include <Editor/Nodes/NodeCreateUtils.h>
  20. #include <Editor/Nodes/NodeUtils.h>
  21. #include <Editor/View/Widgets/NodePalette/VariableNodePaletteTreeItemTypes.h>
  22. #include <Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h>
  23. #include <Editor/View/Widgets/VariablePanel/GraphVariablesTableView.h>
  24. #include <Editor/View/Widgets/VariablePanel/VariableConfigurationWidget.h>
  25. #include <GraphCanvas/Components/GridBus.h>
  26. #include <GraphCanvas/Components/NodeDescriptors/FunctionDefinitionNodeDescriptorComponent.h>
  27. #include <GraphCanvas/Components/Nodes/Comment/CommentBus.h>
  28. #include <GraphCanvas/Components/Nodes/Group/NodeGroupBus.h>
  29. #include <GraphCanvas/Components/Nodes/NodeBus.h>
  30. #include <GraphCanvas/Components/Nodes/NodeTitleBus.h>
  31. #include <GraphCanvas/Components/SceneBus.h>
  32. #include <GraphCanvas/Components/ViewBus.h>
  33. #include <GraphCanvas/Components/VisualBus.h>
  34. #include <GraphCanvas/Editor/EditorTypes.h>
  35. #include <GraphCanvas/GraphCanvasBus.h>
  36. #include <GraphCanvas/Types/Endpoint.h>
  37. #include <GraphCanvas/Utils/ConversionUtils.h>
  38. #include <GraphCanvas/Utils/NodeNudgingController.h>
  39. #include <GraphCanvas/Widgets/EditorContextMenu/ContextMenuActions/SceneMenuActions/SceneContextMenuActions.h>
  40. #include <ScriptCanvas/Bus/EditorScriptCanvasBus.h>
  41. #include <ScriptCanvas/Bus/NodeIdPair.h>
  42. #include <ScriptCanvas/Bus/RequestBus.h>
  43. #include <ScriptCanvas/Core/GraphBus.h>
  44. #include <ScriptCanvas/Core/GraphSerialization.h>
  45. #include <ScriptCanvas/Core/Node.h>
  46. #include <ScriptCanvas/Core/NodeBus.h>
  47. #include <ScriptCanvas/Core/ScriptCanvasBus.h>
  48. #include <ScriptCanvas/Core/Slot.h>
  49. #include <ScriptCanvas/Grammar/ParsingUtilitiesScriptEventExtension.h>
  50. #include <ScriptCanvas/GraphCanvas/MappingBus.h>
  51. #include <ScriptCanvas/Libraries/Core/FunctionDefinitionNode.h>
  52. #include <ScriptCanvas/Libraries/Core/Method.h>
  53. #include <ScriptEvents/ScriptEventsBus.h>
  54. #include "ScriptCanvasContextMenus.h"
  55. #include "Settings.h"
  56. namespace ScriptCanvasEditor
  57. {
  58. ////////////////////////////
  59. // EndpointSelectionAction
  60. ////////////////////////////
  61. EndpointSelectionAction::EndpointSelectionAction(const GraphCanvas::Endpoint& proposedEndpoint)
  62. : QAction(nullptr)
  63. , m_endpoint(proposedEndpoint)
  64. {
  65. AZStd::string name;
  66. GraphCanvas::SlotRequestBus::EventResult(name, proposedEndpoint.GetSlotId(), &GraphCanvas::SlotRequests::GetName);
  67. AZStd::string tooltip;
  68. GraphCanvas::SlotRequestBus::EventResult(tooltip, proposedEndpoint.GetSlotId(), &GraphCanvas::SlotRequests::GetTooltip);
  69. setText(name.c_str());
  70. setToolTip(tooltip.c_str());
  71. }
  72. const GraphCanvas::Endpoint& EndpointSelectionAction::GetEndpoint() const
  73. {
  74. return m_endpoint;
  75. }
  76. ////////////////////////////////////
  77. // RemoveUnusedVariablesMenuAction
  78. ////////////////////////////////////
  79. RemoveUnusedVariablesMenuAction::RemoveUnusedVariablesMenuAction(QObject* parent)
  80. : SceneContextMenuAction("Variables", parent)
  81. {
  82. setToolTip("Removes all of the unused variables from the active graph");
  83. }
  84. void RemoveUnusedVariablesMenuAction::RefreshAction([[maybe_unused]] const GraphCanvas::GraphId& graphId, [[maybe_unused]] const AZ::EntityId& targetId)
  85. {
  86. setEnabled(true);
  87. }
  88. bool RemoveUnusedVariablesMenuAction::IsInSubMenu() const
  89. {
  90. return true;
  91. }
  92. AZStd::string RemoveUnusedVariablesMenuAction::GetSubMenuPath() const
  93. {
  94. return "Remove Unused";
  95. }
  96. GraphCanvas::ContextMenuAction::SceneReaction RemoveUnusedVariablesMenuAction::TriggerAction(const GraphCanvas::GraphId& graphId, [[maybe_unused]] const AZ::Vector2& scenePos)
  97. {
  98. GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::RemoveUnusedNodes);
  99. return SceneReaction::PostUndo;
  100. }
  101. ///////////////////////////////
  102. // SlotManipulationMenuAction
  103. ///////////////////////////////
  104. SlotManipulationMenuAction::SlotManipulationMenuAction(AZStd::string_view actionName, QObject* parent)
  105. : GraphCanvas::ContextMenuAction(actionName, parent)
  106. {
  107. }
  108. ScriptCanvas::Slot* SlotManipulationMenuAction::GetScriptCanvasSlot(const GraphCanvas::Endpoint& endpoint)
  109. {
  110. GraphCanvas::GraphId graphId;
  111. GraphCanvas::SceneMemberRequestBus::EventResult(graphId, endpoint.GetNodeId(), &GraphCanvas::SceneMemberRequests::GetScene);
  112. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  113. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphId);
  114. ScriptCanvas::Endpoint scriptCanvasEndpoint;
  115. {
  116. AZStd::any* userData = nullptr;
  117. GraphCanvas::SlotRequestBus::EventResult(userData, endpoint.GetSlotId(), &GraphCanvas::SlotRequests::GetUserData);
  118. ScriptCanvas::SlotId scriptCanvasSlotId = (userData && userData->is<ScriptCanvas::SlotId>()) ? *AZStd::any_cast<ScriptCanvas::SlotId>(userData) : ScriptCanvas::SlotId();
  119. userData = nullptr;
  120. GraphCanvas::NodeRequestBus::EventResult(userData, endpoint.GetNodeId(), &GraphCanvas::NodeRequests::GetUserData);
  121. AZ::EntityId scriptCanvasNodeId = (userData && userData->is<AZ::EntityId>()) ? *AZStd::any_cast<AZ::EntityId>(userData) : AZ::EntityId();
  122. scriptCanvasEndpoint = ScriptCanvas::Endpoint(scriptCanvasNodeId, scriptCanvasSlotId);
  123. }
  124. ScriptCanvas::Slot* scriptCanvasSlot = nullptr;
  125. ScriptCanvas::GraphRequestBus::EventResult(scriptCanvasSlot, scriptCanvasId, &ScriptCanvas::GraphRequests::FindSlot, scriptCanvasEndpoint);
  126. return scriptCanvasSlot;
  127. }
  128. /////////////////////////////////////////
  129. // ConvertVariableNodeToReferenceAction
  130. /////////////////////////////////////////
  131. ConvertVariableNodeToReferenceAction::ConvertVariableNodeToReferenceAction(QObject* parent)
  132. : GraphCanvas::ContextMenuAction("Convert to References", parent)
  133. {
  134. }
  135. GraphCanvas::ActionGroupId ConvertVariableNodeToReferenceAction::GetActionGroupId() const
  136. {
  137. return AZ_CRC("VariableConversion", 0x157beab0);
  138. }
  139. void ConvertVariableNodeToReferenceAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
  140. {
  141. bool hasMultipleSelection = false;
  142. GraphCanvas::SceneRequestBus::EventResult(hasMultipleSelection, graphId, &GraphCanvas::SceneRequests::HasMultipleSelection);
  143. m_targetId = targetId;
  144. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  145. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphId);
  146. bool canConvertNode = false;
  147. EditorGraphRequestBus::EventResult(canConvertNode, scriptCanvasId, &EditorGraphRequests::CanConvertVariableNodeToReference, m_targetId);
  148. // This item is added only when it's valid
  149. setEnabled(canConvertNode && !hasMultipleSelection);
  150. }
  151. GraphCanvas::ContextMenuAction::SceneReaction ConvertVariableNodeToReferenceAction::TriggerAction(const GraphCanvas::GraphId& graphId, [[maybe_unused]] const AZ::Vector2& scenePos)
  152. {
  153. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  154. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphId);
  155. bool convertedNode = false;
  156. EditorGraphRequestBus::EventResult(convertedNode, scriptCanvasId, &EditorGraphRequests::ConvertVariableNodeToReference, m_targetId);
  157. if (convertedNode)
  158. {
  159. return SceneReaction::PostUndo;
  160. }
  161. return SceneReaction::Nothing;
  162. }
  163. /////////////////////////////////////////
  164. // ConvertReferenceToVariableNodeAction
  165. /////////////////////////////////////////
  166. ConvertReferenceToVariableNodeAction::ConvertReferenceToVariableNodeAction(QObject* parent)
  167. : SlotManipulationMenuAction("Convert to Variable Node", parent)
  168. {
  169. }
  170. GraphCanvas::ActionGroupId ConvertReferenceToVariableNodeAction::GetActionGroupId() const
  171. {
  172. return AZ_CRC("VariableConversion", 0x157beab0);
  173. }
  174. void ConvertReferenceToVariableNodeAction::RefreshAction([[maybe_unused]] const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
  175. {
  176. m_targetId = targetId;
  177. bool enableAction = false;
  178. if (GraphCanvas::GraphUtils::IsSlot(m_targetId))
  179. {
  180. GraphCanvas::SlotType slotType = GraphCanvas::SlotTypes::Invalid;
  181. GraphCanvas::SlotRequestBus::EventResult(slotType, m_targetId, &GraphCanvas::SlotRequests::GetSlotType);
  182. if (slotType == GraphCanvas::SlotTypes::DataSlot)
  183. {
  184. GraphCanvas::DataSlotRequestBus::EventResult(enableAction, m_targetId, &GraphCanvas::DataSlotRequests::CanConvertToValue);
  185. if (enableAction)
  186. {
  187. GraphCanvas::DataSlotType valueType = GraphCanvas::DataSlotType::Unknown;
  188. GraphCanvas::DataSlotRequestBus::EventResult(valueType, m_targetId, &GraphCanvas::DataSlotRequests::GetDataSlotType);
  189. enableAction = (valueType == GraphCanvas::DataSlotType::Reference);
  190. if (enableAction)
  191. {
  192. GraphCanvas::Endpoint endpoint;
  193. GraphCanvas::SlotRequestBus::EventResult(endpoint, m_targetId, &GraphCanvas::SlotRequests::GetEndpoint);
  194. ScriptCanvas::Slot* slot = GetScriptCanvasSlot(endpoint);
  195. enableAction = slot->GetVariableReference().IsValid();
  196. }
  197. }
  198. }
  199. }
  200. setEnabled(enableAction);
  201. }
  202. GraphCanvas::ContextMenuAction::SceneReaction ConvertReferenceToVariableNodeAction::TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos)
  203. {
  204. GraphCanvas::Endpoint endpoint;
  205. GraphCanvas::SlotRequestBus::EventResult(endpoint, m_targetId, &GraphCanvas::SlotRequests::GetEndpoint);
  206. GraphCanvas::ConnectionType connectionType = GraphCanvas::CT_Invalid;
  207. GraphCanvas::SlotRequestBus::EventResult(connectionType, m_targetId, &GraphCanvas::SlotRequests::GetConnectionType);
  208. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  209. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphId);
  210. ScriptCanvas::Slot* scriptCanvasSlot = GetScriptCanvasSlot(endpoint);
  211. if (scriptCanvasSlot == nullptr
  212. || !scriptCanvasSlot->IsVariableReference())
  213. {
  214. return SceneReaction::Nothing;
  215. }
  216. // Store the variable then convert the slot to a value for the next step.
  217. ScriptCanvas::VariableId variableId = scriptCanvasSlot->GetVariableReference();
  218. GraphCanvas::DataSlotRequestBus::Event(m_targetId, &GraphCanvas::DataSlotRequests::ConvertToValue);
  219. AZ::EntityId createdNodeId;
  220. if (connectionType == GraphCanvas::CT_Input)
  221. {
  222. CreateGetVariableNodeMimeEvent createMimeEvent(variableId);
  223. createdNodeId = createMimeEvent.CreateSplicingNode(graphId);
  224. }
  225. else if (connectionType == GraphCanvas::CT_Output)
  226. {
  227. CreateSetVariableNodeMimeEvent createMimeEvent(variableId);
  228. createdNodeId = createMimeEvent.CreateSplicingNode(graphId);
  229. }
  230. if (!createdNodeId.IsValid())
  231. {
  232. return SceneReaction::Nothing;
  233. }
  234. GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::AddNode, createdNodeId, scenePos, false);
  235. GraphCanvas::CreateConnectionsBetweenConfig createConnectionBetweenConfig;
  236. createConnectionBetweenConfig.m_connectionType = GraphCanvas::CreateConnectionsBetweenConfig::CreationType::SingleConnection;
  237. createConnectionBetweenConfig.m_createModelConnections = true;
  238. GraphCanvas::GraphUtils::CreateConnectionsBetween({ endpoint }, createdNodeId, createConnectionBetweenConfig);
  239. if (!createConnectionBetweenConfig.m_createdConnections.empty())
  240. {
  241. GraphCanvas::Endpoint otherEndpoint;
  242. GraphCanvas::ConnectionRequestBus::EventResult(otherEndpoint, (*createConnectionBetweenConfig.m_createdConnections.begin()), &GraphCanvas::ConnectionRequests::FindOtherEndpoint, endpoint);
  243. if (otherEndpoint.IsValid())
  244. {
  245. GraphCanvas::GraphUtils::AlignSlotForConnection(otherEndpoint, endpoint);
  246. }
  247. }
  248. AZStd::vector<AZ::EntityId> slotIds;
  249. GraphCanvas::NodeRequestBus::EventResult(slotIds, endpoint.GetNodeId(), &GraphCanvas::NodeRequests::GetSlotIds);
  250. GraphCanvas::ConnectionSpliceConfig spliceConfig;
  251. spliceConfig.m_allowOpportunisticConnections = false;
  252. bool connectedExecution = false;
  253. AZStd::vector< GraphCanvas::Endpoint > validInputSlots;
  254. for (auto slotId : slotIds)
  255. {
  256. GraphCanvas::SlotRequests* slotRequests = GraphCanvas::SlotRequestBus::FindFirstHandler(slotId);
  257. if (slotRequests == nullptr)
  258. {
  259. continue;
  260. }
  261. GraphCanvas::SlotType slotType = slotRequests->GetSlotType();
  262. if (slotType == GraphCanvas::SlotTypes::ExecutionSlot)
  263. {
  264. GraphCanvas::ConnectionType testConnectionType = slotRequests->GetConnectionType();
  265. // We only want to connect to things going in the same direction as we are.
  266. if (testConnectionType == connectionType)
  267. {
  268. validInputSlots.emplace_back(endpoint.GetNodeId(), slotId);
  269. AZStd::vector< AZ::EntityId > connectionIds = slotRequests->GetConnections();
  270. for (const AZ::EntityId& connectionId : connectionIds)
  271. {
  272. if (GraphCanvas::GraphUtils::SpliceNodeOntoConnection(createdNodeId, connectionId, spliceConfig))
  273. {
  274. connectedExecution = true;
  275. }
  276. }
  277. }
  278. }
  279. if (!connectedExecution)
  280. {
  281. GraphCanvas::CreateConnectionsBetweenConfig fallbackConnectionConfig;
  282. fallbackConnectionConfig.m_connectionType = GraphCanvas::CreateConnectionsBetweenConfig::CreationType::SinglePass;
  283. fallbackConnectionConfig.m_createModelConnections = true;
  284. GraphCanvas::GraphUtils::CreateConnectionsBetween(validInputSlots, createdNodeId, fallbackConnectionConfig);
  285. }
  286. }
  287. GraphCanvas::NodeNudgingController nudgingController;
  288. nudgingController.SetGraphId(graphId);
  289. nudgingController.StartNudging({ createdNodeId });
  290. nudgingController.FinalizeNudging();
  291. GraphCanvas::AnimatedPulseConfiguration animatedPulseConfig;
  292. animatedPulseConfig.m_enableGradient = true;
  293. animatedPulseConfig.m_drawColor = QColor(255, 255, 255);
  294. animatedPulseConfig.m_durationSec = 0.25f;
  295. GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::CreatePulseAroundSceneMember, createdNodeId, 4, animatedPulseConfig);
  296. return SceneReaction::PostUndo;
  297. }
  298. //////////////////////////////////
  299. // ExposeExecutionSlotMenuAction
  300. //////////////////////////////////
  301. ExposeSlotMenuAction::ExposeSlotMenuAction(QObject* parent)
  302. : GraphCanvas::SlotContextMenuAction("Expose", parent)
  303. {
  304. }
  305. void ExposeSlotMenuAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
  306. {
  307. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  308. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphId);
  309. GraphCanvas::NodeId nodeId;
  310. GraphCanvas::SlotRequestBus::EventResult(nodeId, targetId, &GraphCanvas::SlotRequests::GetNode);
  311. bool canExposeSlot = false;
  312. EditorGraphRequestBus::EventResult(canExposeSlot, scriptCanvasId, &EditorGraphRequests::CanExposeEndpoint, GraphCanvas::Endpoint(nodeId, targetId ));
  313. setEnabled(canExposeSlot);
  314. }
  315. void ExposeSlotMenuAction::CreateNodeling(const GraphCanvas::GraphId& graphId, AZ::EntityId scriptCanvasGraphId, GraphCanvas::GraphId slotId, const AZ::Vector2& scenePos, GraphCanvas::ConnectionType connectionType)
  316. {
  317. GraphCanvas::NodeId nodeId;
  318. GraphCanvas::SlotRequestBus::EventResult(nodeId, slotId, &GraphCanvas::SlotRequests::GetNode);
  319. // Set the connection type for the node opposite of what it actually is because we're interested in the connection type of the node we're
  320. // exposing, not the type of the slot we just created
  321. ScriptCanvas::ConnectionType scriptCanvasConnectionType = (connectionType == GraphCanvas::CT_Input) ? ScriptCanvas::ConnectionType::Input : ScriptCanvas::ConnectionType::Output;
  322. bool isInput = (scriptCanvasConnectionType == ScriptCanvas::ConnectionType::Output);
  323. NodeIdPair nodePair = ScriptCanvasEditor::Nodes::CreateFunctionDefinitionNode(scriptCanvasGraphId, isInput);
  324. GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::AddNode, nodePair.m_graphCanvasId, scenePos, false);
  325. GraphCanvas::Endpoint graphCanvasEndpoint;
  326. GraphCanvas::SlotRequestBus::EventResult(graphCanvasEndpoint, slotId, &GraphCanvas::SlotRequests::GetEndpoint);
  327. // Find the execution "nodeling"
  328. ScriptCanvas::Nodes::Core::FunctionDefinitionNode* nodeling = ScriptCanvasEditor::Nodes::GetNode<ScriptCanvas::Nodes::Core::FunctionDefinitionNode>(scriptCanvasGraphId, nodePair);
  329. // Configure the Execution node
  330. AZStd::string nodeTitle;
  331. GraphCanvas::NodeTitleRequestBus::EventResult(nodeTitle, nodeId, &GraphCanvas::NodeTitleRequests::GetTitle);
  332. AZStd::string name;
  333. GraphCanvas::SlotRequestBus::EventResult(name, slotId, &GraphCanvas::SlotRequests::GetName);
  334. AZStd::string fullTitle = AZStd::string::format("%s : %s", nodeTitle.c_str(), name.c_str());
  335. nodeling->SetDisplayName(fullTitle);
  336. // Set the node title, subtitle, tooltip
  337. GraphCanvas::NodeTitleRequestBus::Event(nodePair.m_graphCanvasId, &GraphCanvas::NodeTitleRequests::SetTitle, fullTitle);
  338. GraphCanvas::NodeRequestBus::Event(nodePair.m_graphCanvasId, &GraphCanvas::NodeRequests::SetTooltip, name);
  339. ScriptCanvas::SlotDescriptor descriptor;
  340. descriptor.m_slotType = ScriptCanvas::SlotTypeDescriptor::Execution;
  341. descriptor.m_connectionType = scriptCanvasConnectionType;
  342. auto descriptorSlots = nodeling->GetAllSlotsByDescriptor(descriptor);
  343. // There should only be a single slot
  344. AZ_Assert(descriptorSlots.size() == 1, "Nodeling should only create one of each execution slot type.");
  345. const ScriptCanvas::Slot* slot = descriptorSlots.front();
  346. GraphCanvas::SlotId graphCanvasSlotId;
  347. SlotMappingRequestBus::EventResult(graphCanvasSlotId, nodePair.m_graphCanvasId, &SlotMappingRequests::MapToGraphCanvasId, slot->GetId());
  348. GraphCanvas::Endpoint fixedEndpoint(nodeId, slotId);
  349. // Automatically connect to the slot that was exposed
  350. AZ::EntityId connectionId;
  351. GraphCanvas::SlotRequestBus::EventResult(connectionId, graphCanvasSlotId, &GraphCanvas::SlotRequests::CreateConnectionWithEndpoint, fixedEndpoint);
  352. if (connectionId.IsValid())
  353. {
  354. GraphCanvas::Endpoint executionEndpoint(nodePair.m_graphCanvasId, graphCanvasSlotId);
  355. GraphCanvas::GraphUtils::AlignSlotForConnection(executionEndpoint, fixedEndpoint);
  356. }
  357. else
  358. {
  359. AZStd::unordered_set<AZ::EntityId> deletionSet = { nodePair.m_graphCanvasId };
  360. GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::Delete, deletionSet);
  361. }
  362. }
  363. GraphCanvas::ContextMenuAction::SceneReaction ExposeSlotMenuAction::TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos)
  364. {
  365. // Go to Execution node and allow it to be renamed
  366. // Make sure this stuff is restored on serialization
  367. ScriptCanvas::ScriptCanvasId scriptCanvasGraphId;
  368. GeneralRequestBus::BroadcastResult(scriptCanvasGraphId, &GeneralRequests::GetScriptCanvasId, graphId);
  369. const GraphCanvas::SlotId& slotId = GetTargetId();
  370. GraphCanvas::ConnectionType connectionType;
  371. GraphCanvas::SlotRequestBus::EventResult(connectionType, slotId, &GraphCanvas::SlotRequests::GetConnectionType);
  372. GraphCanvas::SlotType slotType;
  373. GraphCanvas::SlotRequestBus::EventResult(slotType, slotId, &GraphCanvas::SlotRequests::GetSlotType);
  374. // Will create an Execution node and connect it to this slot, nothing if the slot is already connected (the option shouldn't show)
  375. if (slotType == GraphCanvas::SlotTypes::ExecutionSlot && connectionType == GraphCanvas::CT_Input)
  376. {
  377. AZ::Vector2 spawnPosition = scenePos + AZ::Vector2(-200, 0);
  378. CreateNodeling(graphId, scriptCanvasGraphId, slotId, spawnPosition, GraphCanvas::CT_Output);
  379. }
  380. else if (slotType == GraphCanvas::SlotTypes::ExecutionSlot && connectionType == GraphCanvas::CT_Output)
  381. {
  382. AZ::Vector2 spawnPosition = scenePos + AZ::Vector2(200, 0);
  383. CreateNodeling(graphId, scriptCanvasGraphId, slotId, spawnPosition, GraphCanvas::CT_Input);
  384. }
  385. else if (slotType == GraphCanvas::SlotTypes::DataSlot)
  386. {
  387. const AZ::EntityId& slotId2 = GetTargetId();
  388. const GraphCanvas::GraphId& graphId2 = GetGraphId();
  389. GraphCanvas::Endpoint endpoint;
  390. GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId2, &GraphCanvas::SlotRequests::GetEndpoint);
  391. bool promotedElement = false;
  392. GraphCanvas::GraphModelRequestBus::EventResult(promotedElement, graphId2, &GraphCanvas::GraphModelRequests::PromoteToVariableAction, endpoint, false);
  393. if (promotedElement)
  394. {
  395. ScriptCanvas::Endpoint scEndpoint;
  396. EditorGraphRequestBus::EventResult(scEndpoint, scriptCanvasGraphId, &EditorGraphRequests::ConvertToScriptCanvasEndpoint, endpoint);
  397. if (scEndpoint.IsValid())
  398. {
  399. ScriptCanvas::Slot* slot = nullptr;
  400. ScriptCanvas::GraphRequestBus::EventResult(slot, scriptCanvasGraphId, &ScriptCanvas::GraphRequests::FindSlot, scEndpoint);
  401. if (slot && slot->IsVariableReference())
  402. {
  403. ScriptCanvas::GraphVariable* variable = slot->GetVariable();
  404. if (variable)
  405. {
  406. variable->SetScope(ScriptCanvas::VariableFlags::Scope::Function);
  407. }
  408. }
  409. }
  410. }
  411. }
  412. return GraphCanvas::ContextMenuAction::SceneReaction::PostUndo;
  413. }
  414. //////////////////////////////////
  415. // SetDataSlotTypeMenuAction
  416. //////////////////////////////////
  417. SetDataSlotTypeMenuAction::SetDataSlotTypeMenuAction(QObject* parent)
  418. : GraphCanvas::SlotContextMenuAction("Set Slot Type", parent)
  419. {
  420. }
  421. void SetDataSlotTypeMenuAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
  422. {
  423. ScriptCanvas::Slot* slot = GetSlot(graphId, targetId);
  424. bool isEnabled = slot && slot->IsUserAdded() && slot->GetDescriptor().IsData();
  425. setEnabled(isEnabled);
  426. }
  427. GraphCanvas::ContextMenuAction::SceneReaction SetDataSlotTypeMenuAction::TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos)
  428. {
  429. ScriptCanvas::Slot* slot = GetSlot(graphId, GetTargetId());
  430. if (!slot)
  431. {
  432. return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
  433. }
  434. auto variable = slot->GetVariable();
  435. if (!variable)
  436. {
  437. return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
  438. }
  439. ScriptCanvas::ScriptCanvasId scriptCanvasGraphId;
  440. GeneralRequestBus::BroadcastResult(scriptCanvasGraphId, &GeneralRequests::GetScriptCanvasId, graphId);
  441. if (!scriptCanvasGraphId.IsValid())
  442. {
  443. return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
  444. }
  445. VariablePaletteRequests::VariableConfigurationInput selectedSlotSetup;
  446. selectedSlotSetup.m_changeVariableType = true;
  447. selectedSlotSetup.m_graphVariable = variable;
  448. selectedSlotSetup.m_currentName = slot->GetName();
  449. selectedSlotSetup.m_currentType = slot->GetDataType();
  450. QPoint scenePoint(static_cast<int>(scenePos.GetX()), static_cast<int>(scenePos.GetY()));
  451. VariablePaletteRequests::VariableConfigurationOutput output;
  452. VariablePaletteRequestBus::BroadcastResult(output, &VariablePaletteRequests::ShowVariableConfigurationWidget
  453. , selectedSlotSetup, scenePoint);
  454. bool changed = false;
  455. if (output.m_actionIsValid)
  456. {
  457. if ((output.m_nameChanged && !output.m_name.empty()) || (output.m_typeChanged && output.m_type.IsValid()))
  458. {
  459. GeneralRequestBus::Broadcast(&GeneralRequests::PostUndoPoint, scriptCanvasGraphId);
  460. GraphCanvas::ScopedGraphUndoBlocker undoBlocker(graphId);
  461. if ((output.m_nameChanged && !output.m_name.empty()))
  462. {
  463. variable->SetVariableName(output.m_name);
  464. }
  465. if (output.m_typeChanged && output.m_type.IsValid())
  466. {
  467. variable->ModDatum().SetType(output.m_type, ScriptCanvas::Datum::TypeChange::Forced);
  468. ScriptCanvas::GraphRequestBus::Event(scriptCanvasGraphId, &ScriptCanvas::GraphRequests::RefreshVariableReferences
  469. , variable->GetVariableId());
  470. }
  471. changed = true;
  472. }
  473. }
  474. return changed ? GraphCanvas::ContextMenuAction::SceneReaction::PostUndo : GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
  475. }
  476. bool SetDataSlotTypeMenuAction::IsSupportedSlotType(const AZ::EntityId& slotId)
  477. {
  478. GraphCanvas::Endpoint endpoint;
  479. GraphCanvas::SlotRequestBus::EventResult(endpoint, slotId, &GraphCanvas::SlotRequests::GetEndpoint);
  480. const ScriptCanvas::Slot* slot = SlotManipulationMenuAction::GetScriptCanvasSlot(endpoint);
  481. if (slot)
  482. {
  483. if (slot->GetDescriptor().IsData())
  484. {
  485. return true;
  486. }
  487. }
  488. return false;
  489. }
  490. ScriptCanvas::Slot* SetDataSlotTypeMenuAction::GetSlot(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
  491. {
  492. ScriptCanvas::ScriptCanvasId scriptCanvasGraphId;
  493. GeneralRequestBus::BroadcastResult(scriptCanvasGraphId, &GeneralRequests::GetScriptCanvasId, graphId);
  494. GraphCanvas::Endpoint endpoint;
  495. GraphCanvas::SlotRequestBus::EventResult(endpoint, targetId, &GraphCanvas::SlotRequests::GetEndpoint);
  496. ScriptCanvas::Endpoint scEndpoint;
  497. EditorGraphRequestBus::EventResult(scEndpoint, scriptCanvasGraphId, &EditorGraphRequests::ConvertToScriptCanvasEndpoint, endpoint);
  498. ScriptCanvas::Slot* slot = nullptr;
  499. ScriptCanvas::NodeRequestBus::EventResult(slot, scEndpoint.GetNodeId(), &ScriptCanvas::NodeRequests::GetSlot, scEndpoint.GetSlotId());
  500. return slot;
  501. }
  502. //////////////////////////////////
  503. // CreateAzEventHandlerSlotMenuAction
  504. //////////////////////////////////
  505. CreateAzEventHandlerSlotMenuAction::CreateAzEventHandlerSlotMenuAction(QObject* parent)
  506. : SlotContextMenuAction("Create event handler", parent)
  507. {
  508. }
  509. void CreateAzEventHandlerSlotMenuAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetId)
  510. {
  511. m_methodWithAzEventReturn = FindBehaviorMethodWithAzEventReturn(graphId, targetId);
  512. if (m_methodWithAzEventReturn)
  513. {
  514. // Store the GraphCanvas endpoint corresponding to the supplied slot
  515. GraphCanvas::SlotRequestBus::Event(targetId, [this](GraphCanvas::SlotRequests* slotRequests)
  516. {
  517. m_methodNodeAzEventEndpoint = slotRequests->GetEndpoint();
  518. });
  519. setEnabled(true);
  520. return;
  521. }
  522. setEnabled(false);
  523. }
  524. GraphCanvas::ContextMenuAction::SceneReaction CreateAzEventHandlerSlotMenuAction::TriggerAction(const GraphCanvas::GraphId& graphId, const AZ::Vector2& scenePos)
  525. {
  526. if (m_methodWithAzEventReturn)
  527. {
  528. ScriptCanvas::ScriptCanvasId scriptCanvasGraphId;
  529. GeneralRequestBus::BroadcastResult(scriptCanvasGraphId, &GeneralRequests::GetScriptCanvasId, graphId);
  530. // Retrieve the MethodNodeScriptCanvasId and pass that in to the CreateAzEventHandlerNode function to enforce
  531. // the restricted node contract
  532. AZ::EntityId methodNodeScriptCanvasId;
  533. auto GetScriptCanvasNodeId = [&methodNodeScriptCanvasId](GraphCanvas::NodeRequests* nodeRequests)
  534. {
  535. if (auto scNodeId = AZStd::any_cast<AZ::EntityId>(nodeRequests->GetUserData());
  536. scNodeId != nullptr)
  537. {
  538. methodNodeScriptCanvasId = *scNodeId;
  539. }
  540. };
  541. GraphCanvas::NodeRequestBus::Event(m_methodNodeAzEventEndpoint.GetNodeId(), GetScriptCanvasNodeId);
  542. NodeIdPair nodePair = Nodes::CreateAzEventHandlerNode(*m_methodWithAzEventReturn, scriptCanvasGraphId,
  543. methodNodeScriptCanvasId);
  544. if (nodePair.m_graphCanvasId.IsValid())
  545. {
  546. // Add newly created GraphCanvas node to the GraphCanvas scene
  547. GraphCanvas::SceneRequestBus::Event(graphId, &GraphCanvas::SceneRequests::AddNode, nodePair.m_graphCanvasId, scenePos, false);
  548. // Connect the AZ::Event<Params...> data output from the MethodNode to newly created AzEventHandler node data input slot of the same type
  549. GraphCanvas::CreateConnectionsBetweenConfig createConnectionBetweenConfig;
  550. createConnectionBetweenConfig.m_connectionType = GraphCanvas::CreateConnectionsBetweenConfig::CreationType::SingleConnection;
  551. createConnectionBetweenConfig.m_createModelConnections = true;
  552. GraphCanvas::GraphUtils::CreateConnectionsBetween({ m_methodNodeAzEventEndpoint }, nodePair.m_graphCanvasId, createConnectionBetweenConfig);
  553. if (!createConnectionBetweenConfig.m_createdConnections.empty())
  554. {
  555. GraphCanvas::Endpoint otherEndpoint;
  556. GraphCanvas::ConnectionRequestBus::EventResult(otherEndpoint, *createConnectionBetweenConfig.m_createdConnections.begin(),
  557. &GraphCanvas::ConnectionRequests::FindOtherEndpoint, m_methodNodeAzEventEndpoint);
  558. if (otherEndpoint.IsValid())
  559. {
  560. // This will connect the execution output slot from the MethodNode to the Connect input slot
  561. // on our newly created AzEventHandler node
  562. auto opportunisticConnections = GraphCanvas::GraphUtils::CreateOpportunisticConnectionsBetween(m_methodNodeAzEventEndpoint, otherEndpoint);
  563. createConnectionBetweenConfig.m_createdConnections.insert(opportunisticConnections.begin(), opportunisticConnections.end());
  564. // Update the AzEventHandler node position to not overlap over the MethodNode
  565. GraphCanvas::GraphUtils::AlignSlotForConnection(otherEndpoint, m_methodNodeAzEventEndpoint);
  566. }
  567. // Disable the flags on the connections we created with the AZ::Event Handler node (e.g. selectable/movable)
  568. // so that the user can't delete them
  569. for (auto connectionId : createConnectionBetweenConfig.m_createdConnections)
  570. {
  571. GraphCanvas::ConnectionUIRequestBus::Event(connectionId, &GraphCanvas::ConnectionUIRequests::SetGraphicsItemFlags, QGraphicsItem::GraphicsItemFlags());
  572. }
  573. }
  574. return GraphCanvas::ContextMenuAction::SceneReaction::PostUndo;
  575. }
  576. }
  577. return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
  578. }
  579. const AZ::BehaviorMethod* CreateAzEventHandlerSlotMenuAction::FindBehaviorMethodWithAzEventReturn(const GraphCanvas::GraphId& graphId, AZ::EntityId targetId)
  580. {
  581. const AZ::BehaviorMethod* methodWithAzEventReturn{};
  582. if (GraphCanvas::GraphUtils::IsSlot(targetId))
  583. {
  584. // Extract the GraphCanvas Slot Type and complete endpoint from using the targetId
  585. GraphCanvas::SlotType slotType = GraphCanvas::SlotTypes::Invalid;
  586. GraphCanvas::Endpoint endpoint;
  587. auto GetGraphCanvasEndpoint = [&slotType, &endpoint](GraphCanvas::SlotRequests* slotRequests)
  588. {
  589. slotType = slotRequests->GetSlotType();
  590. endpoint = slotRequests->GetEndpoint();
  591. };
  592. GraphCanvas::SlotRequestBus::Event(targetId, GetGraphCanvasEndpoint);
  593. // A slot that exposes the context menu to create an AZ::Event must be a data slot
  594. if (slotType != GraphCanvas::SlotTypes::DataSlot)
  595. {
  596. return nullptr;
  597. }
  598. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  599. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphId);
  600. ScriptCanvas::SlotId scriptCanvasSlotId;
  601. auto GetScriptCanvasSlotId = [&scriptCanvasSlotId](GraphCanvas::SlotRequests* slotRequests)
  602. {
  603. if (auto scSlotId = AZStd::any_cast<ScriptCanvas::SlotId>(slotRequests->GetUserData());
  604. scSlotId != nullptr)
  605. {
  606. scriptCanvasSlotId = *scSlotId;
  607. }
  608. };
  609. GraphCanvas::SlotRequestBus::Event(endpoint.GetSlotId(), GetScriptCanvasSlotId);
  610. AZ::EntityId scriptCanvasNodeId;
  611. auto GetScriptCanvasNodeId = [&scriptCanvasNodeId](GraphCanvas::NodeRequests* nodeRequests)
  612. {
  613. if (auto scNodeId = AZStd::any_cast<AZ::EntityId>(nodeRequests->GetUserData());
  614. scNodeId != nullptr)
  615. {
  616. scriptCanvasNodeId = *scNodeId;
  617. }
  618. };
  619. GraphCanvas::NodeRequestBus::Event(endpoint.GetNodeId(), GetScriptCanvasNodeId);
  620. const AZ::BehaviorMethod* candidateMethod{};
  621. auto GetMethodFromNode = [&candidateMethod, &scriptCanvasNodeId, scriptCanvasSlotId](ScriptCanvas::GraphRequests* graphRequests)
  622. {
  623. ScriptCanvas::Slot* scriptCanvasSlot = graphRequests->FindSlot(ScriptCanvas::Endpoint{ scriptCanvasNodeId, scriptCanvasSlotId });
  624. ScriptCanvas::Node* scriptCanvasNode = scriptCanvasSlot ? scriptCanvasSlot->GetNode() : nullptr;
  625. if (auto methodNode = azrtti_cast<ScriptCanvas::Nodes::Core::Method*>(scriptCanvasNode); methodNode != nullptr)
  626. {
  627. candidateMethod = methodNode->GetMethod();
  628. }
  629. };
  630. ScriptCanvas::GraphRequestBus::Event(scriptCanvasId, GetMethodFromNode);
  631. if (candidateMethod)
  632. {
  633. auto MethodReturnsValidAzEvent = [&methodWithAzEventReturn, &candidateMethod](AZ::ComponentApplicationRequests* requests)
  634. {
  635. if (AZ::BehaviorContext* behaviorContext = requests->GetBehaviorContext(); behaviorContext != nullptr)
  636. {
  637. if (AZ::ValidateAzEventDescription(*behaviorContext, *candidateMethod))
  638. {
  639. methodWithAzEventReturn = candidateMethod;
  640. }
  641. }
  642. };
  643. AZ::ComponentApplicationBus::Broadcast(MethodReturnsValidAzEvent);
  644. }
  645. }
  646. return methodWithAzEventReturn;
  647. }
  648. /////////////////////
  649. // SceneContextMenu
  650. /////////////////////
  651. SceneContextMenu::SceneContextMenu(const NodePaletteModel& paletteModel, AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* assetModel)
  652. : GraphCanvas::SceneContextMenu(ScriptCanvasEditor::AssetEditorId)
  653. {
  654. auto userSettings = AZ::UserSettings::CreateFind<EditorSettings::ScriptCanvasEditorSettings>(AZ_CRC("ScriptCanvasPreviewSettings", 0x1c5a2965), AZ::UserSettings::CT_LOCAL);
  655. if (userSettings)
  656. {
  657. m_userNodePaletteWidth = userSettings->m_sceneContextMenuNodePaletteWidth;
  658. }
  659. const bool inContextMenu = true;
  660. Widget::ScriptCanvasNodePaletteConfig paletteConfig(paletteModel, assetModel, inContextMenu);
  661. AddNodePaletteMenuAction(paletteConfig);
  662. }
  663. void SceneContextMenu::ResetSourceSlotFilter()
  664. {
  665. m_nodePalette->ResetSourceSlotFilter();
  666. }
  667. void SceneContextMenu::FilterForSourceSlot(const AZ::EntityId& scriptCanvasGraphId, const AZ::EntityId& sourceSlotId)
  668. {
  669. m_nodePalette->FilterForSourceSlot(scriptCanvasGraphId, sourceSlotId);
  670. }
  671. void SceneContextMenu::OnRefreshActions(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetMemberId)
  672. {
  673. GraphCanvas::SceneContextMenu::OnRefreshActions(graphId, targetMemberId);
  674. // Don't want to overly manipulate the state. So we only modify this when we know we want to turn it on.
  675. if (GraphVariablesTableView::HasCopyVariableData())
  676. {
  677. m_editorActionsGroup.SetPasteEnabled(true);
  678. }
  679. }
  680. void SceneContextMenu::SetupDisplayForProposal()
  681. {
  682. // Disabling all of the actions here for the proposal.
  683. // Allows a certain 'visual consistency' in using the same menu while
  684. // not providing any unusable options.
  685. m_editorActionsGroup.SetCutEnabled(false);
  686. m_editorActionsGroup.SetCopyEnabled(false);
  687. m_editorActionsGroup.SetPasteEnabled(false);
  688. m_editorActionsGroup.SetDeleteEnabled(false);
  689. m_editorActionsGroup.SetDuplicateEnabled(false);
  690. m_graphCanvasConstructGroups.SetAddBookmarkEnabled(false);
  691. m_graphCanvasConstructGroups.SetCommentsEnabled(false);
  692. m_nodeGroupPresets.SetEnabled(false);
  693. m_alignmentActionsGroups.SetEnabled(false);
  694. }
  695. //////////////////////////
  696. // ConnectionContextMenu
  697. //////////////////////////
  698. ConnectionContextMenu::ConnectionContextMenu(const NodePaletteModel& nodePaletteModel, AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* assetModel)
  699. : GraphCanvas::ConnectionContextMenu(ScriptCanvasEditor::AssetEditorId)
  700. {
  701. const bool inContextMenu = true;
  702. Widget::ScriptCanvasNodePaletteConfig paletteConfig(nodePaletteModel, assetModel, inContextMenu);
  703. AddNodePaletteMenuAction(paletteConfig);
  704. }
  705. void ConnectionContextMenu::OnRefreshActions(const GraphCanvas::GraphId& graphId, const AZ::EntityId& targetMemberId)
  706. {
  707. GraphCanvas::ConnectionContextMenu::OnRefreshActions(graphId, targetMemberId);
  708. m_connectionId = targetMemberId;
  709. // TODO: Filter nodes.
  710. }
  711. //////////////////////////
  712. // RenameFunctionDefinitionNodeAction
  713. //////////////////////////
  714. RenameFunctionDefinitionNodeAction::RenameFunctionDefinitionNodeAction(NodeDescriptorComponent* descriptor, QObject* parent)
  715. : NodeContextMenuAction("Rename Function", parent)
  716. , m_descriptor(descriptor)
  717. {}
  718. void RenameFunctionDefinitionNodeAction::RefreshAction(const GraphCanvas::GraphId& graphId, const AZ::EntityId& /*targetId*/)
  719. {
  720. AZStd::vector<AZ::EntityId> selectedNodes;
  721. GraphCanvas::SceneRequestBus::EventResult(selectedNodes, graphId, &GraphCanvas::SceneRequests::GetSelectedNodes);
  722. setEnabled(selectedNodes.size() == 1);
  723. }
  724. GraphCanvas::ContextMenuAction::SceneReaction RenameFunctionDefinitionNodeAction::TriggerAction(const GraphCanvas::GraphId&, const AZ::Vector2&)
  725. {
  726. if (FunctionDefinitionNodeDescriptorComponent::RenameDialog(azrtti_cast<FunctionDefinitionNodeDescriptorComponent*>(m_descriptor)))
  727. {
  728. return GraphCanvas::ContextMenuAction::SceneReaction::PostUndo;
  729. }
  730. return GraphCanvas::ContextMenuAction::SceneReaction::Nothing;
  731. }
  732. #include "Editor/View/Windows/moc_ScriptCanvasContextMenus.cpp"
  733. }