ScriptCanvasNodePaletteDockWidget.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  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 <QLineEdit>
  9. #include <QMenu>
  10. #include <QSignalBlocker>
  11. #include <QScrollBar>
  12. #include <QBoxLayout>
  13. #include <QPainter>
  14. #include <QEvent>
  15. #include <QCoreApplication>
  16. #include <QCompleter>
  17. #include <QHeaderView>
  18. #include <QScopedValueRollback>
  19. #include <AzCore/Asset/AssetManager.h>
  20. #include <AzCore/Component/ComponentApplication.h>
  21. #include <AzCore/Interface/Interface.h>
  22. #include <AzCore/RTTI/BehaviorContext.h>
  23. #include <AzCore/Serialization/EditContext.h>
  24. #include <AzCore/Serialization/SerializeContext.h>
  25. #include <AzCore/UserSettings/UserSettings.h>
  26. #include <AzCore/std/containers/map.h>
  27. #include <AzFramework/Gem/GemInfo.h>
  28. #include <AzFramework/StringFunc/StringFunc.h>
  29. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  30. #include <AzToolsFramework/AssetBrowser/Entries/ProductAssetBrowserEntry.h>
  31. #include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
  32. #include <AzToolsFramework/AssetEditor/AssetEditorUtils.h>
  33. #include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
  34. #include <AzQtComponents/Utilities/DesktopUtilities.h>
  35. #include <Editor/Assets/ScriptCanvasAssetHelpers.h>
  36. #include <Editor/Components/IconComponent.h>
  37. #include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
  38. #include <Editor/GraphCanvas/GraphCanvasEditorNotificationBusId.h>
  39. #include <Editor/Include/ScriptCanvas/Bus/EditorScriptCanvasBus.h>
  40. #include <Editor/Include/ScriptCanvas/Bus/RequestBus.h>
  41. #include <Editor/Nodes/NodeUtils.h>
  42. #include <Editor/Settings.h>
  43. #include <Editor/Translation/TranslationHelper.h>
  44. #include <Editor/View/Widgets/NodePalette/EBusNodePaletteTreeItemTypes.h>
  45. #include <Editor/View/Widgets/NodePalette/FunctionNodePaletteTreeItemTypes.h>
  46. #include <Editor/View/Widgets/NodePalette/GeneralNodePaletteTreeItemTypes.h>
  47. #include <Editor/View/Widgets/NodePalette/NodePaletteModel.h>
  48. #include <Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.h>
  49. #include <Editor/View/Widgets/NodePalette/SpecializedNodePaletteTreeItemTypes.h>
  50. #include <Editor/View/Widgets/NodePalette/VariableNodePaletteTreeItemTypes.h>
  51. #include <Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h>
  52. #include <Editor/View/Widgets/ui_ScriptCanvasNodePaletteToolbar.h>
  53. #include <GraphCanvas/Widgets/NodePalette/NodePaletteTreeView.h>
  54. #include <GraphCanvas/Widgets/NodePalette/NodePaletteWidget.h>
  55. #include <GraphCanvas/Widgets/NodePalette/TreeItems/NodePaletteTreeItem.h>
  56. #include <ScriptCanvas/Asset/SubgraphInterfaceAsset.h>
  57. #include <ScriptCanvas/Core/Attributes.h>
  58. #include <ScriptCanvas/Core/SubgraphInterfaceUtility.h>
  59. #include <ScriptCanvas/Data/DataRegistry.h>
  60. #include <ScriptCanvas/Libraries/Core/GetVariable.h>
  61. #include <ScriptCanvas/Libraries/Core/Method.h>
  62. #include <ScriptCanvas/Libraries/Core/SetVariable.h>
  63. #include <ScriptCanvas/Libraries/Libraries.h>
  64. #include <ScriptCanvas/Utils/NodeUtils.h>
  65. #include <ScriptEvents/ScriptEventsAsset.h>
  66. namespace ScriptCanvasEditor
  67. {
  68. namespace Widget
  69. {
  70. //////////////////////
  71. // NodePaletteWidget
  72. //////////////////////
  73. GraphCanvas::NodePaletteTreeItem* NodePaletteWidget::ExternalCreateNodePaletteRoot(const NodePaletteModel& nodePaletteModel, AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* assetModel)
  74. {
  75. ScriptCanvasRootPaletteTreeItem* root = aznew ScriptCanvasRootPaletteTreeItem(nodePaletteModel, assetModel);
  76. {
  77. GraphCanvas::NodePaletteTreeItem* variablesRoot = root->CreateChildNode<LocalVariablesListNodePaletteTreeItem>("Variables");
  78. root->RegisterCategoryNode(variablesRoot, "Variables");
  79. GraphCanvas::NodePaletteTreeItem* customEventRoot = root->GetCategoryNode("Script Events");
  80. customEventRoot->SetAllowPruneOnEmpty(true);
  81. GraphCanvas::NodePaletteTreeItem* globalFunctionRoot = root->GetCategoryNode("User Functions");
  82. globalFunctionRoot->SetAllowPruneOnEmpty(true);
  83. }
  84. const NodePaletteModel::NodePaletteRegistry& nodeRegistry = nodePaletteModel.GetNodeRegistry();
  85. for (const auto& registryPair : nodeRegistry)
  86. {
  87. const NodePaletteModelInformation* modelInformation = registryPair.second;
  88. GraphCanvas::GraphCanvasTreeItem* parentItem = root->GetCategoryNode(modelInformation->m_categoryPath.c_str());
  89. GraphCanvas::NodePaletteTreeItem* createdItem = nullptr;
  90. if (auto customModelInformation = azrtti_cast<const CustomNodeModelInformation*>(modelInformation))
  91. {
  92. createdItem = parentItem->CreateChildNode<CustomNodePaletteTreeItem>(*customModelInformation);
  93. createdItem->SetToolTip(QString(customModelInformation->m_toolTip.c_str()));
  94. }
  95. else if (auto methodNodeModelInformation = azrtti_cast<const MethodNodeModelInformation*>(modelInformation))
  96. {
  97. createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::ClassMethodEventPaletteTreeItem>(methodNodeModelInformation->m_classMethod, methodNodeModelInformation->m_methodName, methodNodeModelInformation->m_isOverload, methodNodeModelInformation->m_propertyStatus);
  98. }
  99. else if (auto globalMethodNodeModelInformation = azrtti_cast<const GlobalMethodNodeModelInformation*>(modelInformation);
  100. globalMethodNodeModelInformation != nullptr)
  101. {
  102. createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::GlobalMethodEventPaletteTreeItem>(
  103. *globalMethodNodeModelInformation);
  104. }
  105. else if (auto ebusHandlerNodeModelInformation = azrtti_cast<const EBusHandlerNodeModelInformation*>(modelInformation))
  106. {
  107. if (!azrtti_istypeof<const ScriptEventHandlerNodeModelInformation*>(ebusHandlerNodeModelInformation))
  108. {
  109. createdItem = parentItem->CreateChildNode<EBusHandleEventPaletteTreeItem>(ebusHandlerNodeModelInformation->m_busName, ebusHandlerNodeModelInformation->m_eventName, ebusHandlerNodeModelInformation->m_busId, ebusHandlerNodeModelInformation->m_eventId);
  110. }
  111. }
  112. else if (auto ebusSenderNodeModelInformation = azrtti_cast<const EBusSenderNodeModelInformation*>(modelInformation))
  113. {
  114. if (!azrtti_istypeof<const ScriptEventSenderNodeModelInformation*>(ebusSenderNodeModelInformation))
  115. {
  116. createdItem = parentItem->CreateChildNode<ScriptCanvasEditor::EBusSendEventPaletteTreeItem>(ebusSenderNodeModelInformation->m_busName, ebusSenderNodeModelInformation->m_eventName, ebusSenderNodeModelInformation->m_busId, ebusSenderNodeModelInformation->m_eventId, ebusSenderNodeModelInformation->m_isOverload, ebusSenderNodeModelInformation->m_propertyStatus);
  117. }
  118. }
  119. if (createdItem)
  120. {
  121. modelInformation->PopulateTreeItem((*createdItem));
  122. }
  123. }
  124. root->PruneEmptyNodes();
  125. return root;
  126. }
  127. ////////////////////////////////////
  128. // ScriptCanvasRootPaletteTreeItem
  129. ////////////////////////////////////
  130. ScriptCanvasRootPaletteTreeItem::ScriptCanvasRootPaletteTreeItem(const NodePaletteModel& nodePaletteModel, AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* assetModel)
  131. : GraphCanvas::NodePaletteTreeItem("root", ScriptCanvasEditor::AssetEditorId)
  132. , m_assetModel(assetModel)
  133. , m_categorizer(nodePaletteModel)
  134. {
  135. UpgradeNotificationsBus::Handler::BusConnect();
  136. if (m_assetModel)
  137. {
  138. TraverseTree();
  139. ConnectLambdas();
  140. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  141. }
  142. }
  143. ScriptCanvasRootPaletteTreeItem::~ScriptCanvasRootPaletteTreeItem()
  144. {
  145. DisconnectLambdas();
  146. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  147. AZ::Data::AssetBus::MultiHandler::BusDisconnect();
  148. UpgradeNotificationsBus::Handler::BusDisconnect();
  149. }
  150. void ScriptCanvasRootPaletteTreeItem::ConnectLambdas()
  151. {
  152. {
  153. auto connection = QObject::connect(m_assetModel, &QAbstractItemModel::rowsInserted, [this](const QModelIndex& parentIndex, int first, int last) { this->OnRowsInserted(parentIndex, first, last); });
  154. m_lambdaConnections.emplace_back(connection);
  155. }
  156. {
  157. auto connection = QObject::connect(m_assetModel, &QAbstractItemModel::rowsAboutToBeRemoved, [this](const QModelIndex& parentIndex, int first, int last) { this->OnRowsAboutToBeRemoved(parentIndex, first, last); });
  158. m_lambdaConnections.emplace_back(connection);
  159. }
  160. }
  161. void ScriptCanvasRootPaletteTreeItem::DisconnectLambdas()
  162. {
  163. for (auto connection : m_lambdaConnections)
  164. {
  165. QObject::disconnect(connection);
  166. }
  167. }
  168. void ScriptCanvasRootPaletteTreeItem::RegisterCategoryNode(GraphCanvas::GraphCanvasTreeItem* treeItem, const char* subCategory, GraphCanvas::NodePaletteTreeItem* parentRoot)
  169. {
  170. if (parentRoot == nullptr)
  171. {
  172. parentRoot = this;
  173. }
  174. m_categorizer.RegisterCategoryNode(treeItem, subCategory, parentRoot);
  175. }
  176. // Given a category path (e.g. "My/Category") and a parent node, creates the necessary intermediate
  177. // nodes under the given parent and returns the leaf tree item under the given category path.
  178. GraphCanvas::NodePaletteTreeItem* ScriptCanvasRootPaletteTreeItem::GetCategoryNode(const char* categoryPath, GraphCanvas::NodePaletteTreeItem* parentRoot)
  179. {
  180. if (parentRoot)
  181. {
  182. return static_cast<GraphCanvas::NodePaletteTreeItem*>(m_categorizer.GetCategoryNode(categoryPath, parentRoot));
  183. }
  184. else
  185. {
  186. return static_cast<GraphCanvas::NodePaletteTreeItem*>(m_categorizer.GetCategoryNode(categoryPath, this));
  187. }
  188. }
  189. void ScriptCanvasRootPaletteTreeItem::PruneEmptyNodes()
  190. {
  191. m_categorizer.PruneEmptyNodes();
  192. }
  193. void ScriptCanvasRootPaletteTreeItem::SetActiveScriptCanvasId(const ScriptCanvas::ScriptCanvasId& scriptCanvasId)
  194. {
  195. ScriptCanvas::GraphRequestBus::EventResult(m_previousAssetId, scriptCanvasId, &ScriptCanvas::GraphRequests::GetAssetId);
  196. for (auto functionTreePair : m_globalFunctionTreeItems)
  197. {
  198. functionTreePair.second->SetEnabled(true);
  199. }
  200. }
  201. void ScriptCanvasRootPaletteTreeItem::OnRowsInserted(const QModelIndex& parentIndex, int first, int last)
  202. {
  203. for (int i = first; i <= last; ++i)
  204. {
  205. QModelIndex modelIndex = m_assetModel->index(i, 0, parentIndex);
  206. QModelIndex sourceIndex = m_assetModel->mapToSource(modelIndex);
  207. AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = reinterpret_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  208. ProcessAsset(entry);
  209. }
  210. }
  211. void ScriptCanvasRootPaletteTreeItem::OnRowsAboutToBeRemoved(const QModelIndex& parentIndex, int first, int last)
  212. {
  213. for (int i = first; i <= last; ++i)
  214. {
  215. QModelIndex modelIndex = m_assetModel->index(first, 0, parentIndex);
  216. QModelIndex sourceIndex = m_assetModel->mapToSource(modelIndex);
  217. const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = reinterpret_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  218. if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Product)
  219. {
  220. const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* productEntry = azrtti_cast<const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry*>(entry);
  221. const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
  222. auto scriptEventElementIter = m_scriptEventElementTreeItems.find(assetId);
  223. if (scriptEventElementIter != m_scriptEventElementTreeItems.end())
  224. {
  225. scriptEventElementIter->second->DetachItem();
  226. delete scriptEventElementIter->second;
  227. m_scriptEventElementTreeItems.erase(scriptEventElementIter);
  228. }
  229. else
  230. {
  231. auto globalFunctionElementIter = m_globalFunctionTreeItems.find(assetId);
  232. if (globalFunctionElementIter != m_globalFunctionTreeItems.end())
  233. {
  234. globalFunctionElementIter->second->SetError("Graph has errors or has been deleted");
  235. }
  236. }
  237. }
  238. }
  239. PruneEmptyNodes();
  240. }
  241. void ScriptCanvasRootPaletteTreeItem::TraverseTree(QModelIndex index)
  242. {
  243. QModelIndex sourceIndex = m_assetModel->mapToSource(index);
  244. AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry = reinterpret_cast<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>(sourceIndex.internalPointer());
  245. ProcessAsset(entry);
  246. int rowCount = m_assetModel->rowCount(index);
  247. for (int i = 0; i < rowCount; ++i)
  248. {
  249. QModelIndex nextIndex = m_assetModel->index(i, 0, index);
  250. TraverseTree(nextIndex);
  251. }
  252. }
  253. void ScriptCanvasRootPaletteTreeItem::ProcessAsset(AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
  254. {
  255. if (entry)
  256. {
  257. if (entry->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Product)
  258. {
  259. const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry* productEntry = static_cast<const AzToolsFramework::AssetBrowser::ProductAssetBrowserEntry*>(entry);
  260. const auto entryType = productEntry->GetAssetType();
  261. if (entryType == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
  262. {
  263. const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
  264. auto elementIter = m_globalFunctionTreeItems.find(assetId);
  265. if (elementIter == m_globalFunctionTreeItems.end())
  266. {
  267. RequestAssetLoad(assetId, productEntry->GetAssetType());
  268. }
  269. else
  270. {
  271. if (elementIter->second->HasError())
  272. {
  273. m_pendingAssets.erase(assetId);
  274. RequestAssetLoad(assetId, productEntry->GetAssetType());
  275. }
  276. }
  277. }
  278. else if (entryType == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
  279. {
  280. const AZ::Data::AssetId& assetId = productEntry->GetAssetId();
  281. auto elementIter = m_scriptEventElementTreeItems.find(assetId.m_guid);
  282. if (elementIter == m_scriptEventElementTreeItems.end())
  283. {
  284. RequestAssetLoad(assetId, productEntry->GetAssetType());
  285. }
  286. }
  287. }
  288. }
  289. }
  290. void ScriptCanvasRootPaletteTreeItem::OnSystemTick()
  291. {
  292. AZ::SystemTickBus::Handler::BusDisconnect();
  293. while (!m_requestQueue.empty())
  294. {
  295. const auto entry = m_requestQueue.front();
  296. m_requestQueue.pop();
  297. if (m_pendingAssets.find(entry.first) == m_pendingAssets.end())
  298. {
  299. AZ::Data::AssetBus::MultiHandler::BusConnect(entry.first);
  300. m_pendingAssets[entry.first] = AZ::Data::AssetManager::Instance().GetAsset(entry.first, entry.second, AZ::Data::AssetLoadBehavior::Default);
  301. }
  302. }
  303. }
  304. void ScriptCanvasRootPaletteTreeItem::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
  305. {
  306. auto scriptEventIter = m_scriptEventElementTreeItems.find(assetId.m_guid);
  307. if (scriptEventIter != m_scriptEventElementTreeItems.end())
  308. {
  309. RequestAssetLoad(assetId, azrtti_typeid<ScriptEvents::ScriptEventsAsset>());
  310. }
  311. else
  312. {
  313. auto functionIter = m_globalFunctionTreeItems.find(assetId);
  314. if (functionIter != m_globalFunctionTreeItems.end())
  315. {
  316. RequestAssetLoad(assetId, azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>());
  317. }
  318. }
  319. }
  320. void ScriptCanvasRootPaletteTreeItem::OnCatalogAssetAdded(const AZ::Data::AssetId&)
  321. {
  322. }
  323. void ScriptCanvasRootPaletteTreeItem::OnCatalogAssetRemoved(const AZ::Data::AssetId&, const AZ::Data::AssetInfo&)
  324. {
  325. }
  326. void ScriptCanvasRootPaletteTreeItem::OnUpgradeStart()
  327. {
  328. DisconnectLambdas();
  329. // Disconnect from the AssetCatalogEventBus during the upgrade to avoid overlap
  330. // in asset processing
  331. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  332. }
  333. void ScriptCanvasRootPaletteTreeItem::OnUpgradeCancelled()
  334. {
  335. if (!AzFramework::AssetCatalogEventBus::Handler::BusIsConnected())
  336. {
  337. ConnectLambdas();
  338. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  339. TraverseTree();
  340. }
  341. }
  342. void ScriptCanvasRootPaletteTreeItem::RequestAssetLoad(AZ::Data::AssetId assetId, AZ::Data::AssetType assetType)
  343. {
  344. // Delay handling loads until the top of the next tick in case we are handling this on an asset callback thread to avoid potential deadlocks.
  345. AZ::SystemTickBus::Handler::BusConnect();
  346. m_requestQueue.emplace(AZStd::make_pair(assetId, assetType));
  347. }
  348. void ScriptCanvasRootPaletteTreeItem::OnAssetError(AZ::Data::Asset<AZ::Data::AssetData> asset)
  349. {
  350. // mark the function on error... if possible
  351. AZ::Data::AssetId assetId = asset.GetId();
  352. m_pendingAssets.erase(assetId);
  353. }
  354. void ScriptCanvasRootPaletteTreeItem::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
  355. {
  356. using namespace AzFramework;
  357. AZ::Data::AssetId assetId = asset.GetId();
  358. m_pendingAssets.erase(assetId);
  359. if (asset.GetType() == azrtti_typeid<ScriptEvents::ScriptEventsAsset>())
  360. {
  361. if (m_scriptEventElementTreeItems.find(assetId) == m_scriptEventElementTreeItems.end())
  362. {
  363. ScriptEvents::ScriptEventsAsset* data = asset.GetAs<ScriptEvents::ScriptEventsAsset>();
  364. if (data)
  365. {
  366. GraphCanvas::NodePaletteTreeItem* categoryRoot = GetCategoryNode(data->m_definition.GetCategory().c_str());
  367. ScriptEventsPaletteTreeItem* treeItem = categoryRoot->CreateChildNode<ScriptEventsPaletteTreeItem>(asset);
  368. if (treeItem)
  369. {
  370. m_scriptEventElementTreeItems[assetId] = treeItem;
  371. }
  372. }
  373. }
  374. }
  375. else if (asset.GetType() == azrtti_typeid<ScriptCanvas::SubgraphInterfaceAsset>())
  376. {
  377. // We only need to add
  378. auto treePaletteIter = m_globalFunctionTreeItems.find(asset->GetId());
  379. if (treePaletteIter == m_globalFunctionTreeItems.end())
  380. {
  381. ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
  382. if (!data)
  383. {
  384. return;
  385. }
  386. if (!data->m_interfaceData.m_interface.HasAnyFunctionality())
  387. {
  388. // check for deleting the old entry
  389. return;
  390. }
  391. auto assetInfo = AssetHelpers::GetSourceInfoByProductId(assetId, asset.GetType());
  392. if (!assetInfo.m_assetId.IsValid())
  393. {
  394. return;
  395. }
  396. CreateFunctionPaletteItem(asset, assetInfo);
  397. treePaletteIter = m_globalFunctionTreeItems.find(asset->GetId());
  398. if (treePaletteIter != m_globalFunctionTreeItems.end())
  399. {
  400. treePaletteIter->second->ClearError();
  401. }
  402. m_monitoredAssets.emplace(asset->GetId(), asset);
  403. }
  404. else
  405. {
  406. RequestBuildChildrenFromSubgraphInterface(treePaletteIter->second, asset);
  407. treePaletteIter->second->ClearError();
  408. }
  409. }
  410. }
  411. void ScriptCanvasRootPaletteTreeItem::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
  412. {
  413. OnAssetReady(asset);
  414. }
  415. bool ScriptCanvasRootPaletteTreeItem::HasAssetTreeItem(AZ::Data::AssetId assetId) const
  416. {
  417. return m_scriptEventElementTreeItems.find(assetId) != m_scriptEventElementTreeItems.end()
  418. || m_globalFunctionTreeItems.find(assetId) != m_globalFunctionTreeItems.end();
  419. }
  420. void ScriptCanvasRootPaletteTreeItem::CreateFunctionPaletteItem(AZ::Data::Asset<AZ::Data::AssetData> asset, const AZ::Data::AssetInfo& assetInfo)
  421. {
  422. ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
  423. if (!data)
  424. {
  425. return;
  426. }
  427. const ScriptCanvas::Grammar::SubgraphInterface& graphInterface = data->m_interfaceData.m_interface;
  428. if (!graphInterface.HasAnyFunctionality())
  429. {
  430. return;
  431. }
  432. AZStd::string name;
  433. AzFramework::StringFunc::Path::GetFileName(assetInfo.m_relativePath.c_str(), name);
  434. AZStd::string category = "User Functions";
  435. AZStd::string relativePath;
  436. if (AzFramework::StringFunc::Path::GetFolderPath(assetInfo.m_relativePath.c_str(), relativePath))
  437. {
  438. AZStd::to_lower(relativePath.begin(), relativePath.end());
  439. auto stripPathStart = [&](const AZStd::string root)
  440. {
  441. if (relativePath.starts_with(root))
  442. {
  443. relativePath = relativePath.substr(root.size(), relativePath.size() - root.size());
  444. }
  445. };
  446. stripPathStart("scriptcanvas/functions");
  447. stripPathStart("scriptcanvas");
  448. stripPathStart("/");
  449. category.append("/");
  450. category.append(relativePath);
  451. }
  452. NodePaletteTreeItem* categoryRoot = GetCategoryNode(category.c_str());
  453. auto functionCategory = categoryRoot->CreateChildNode<NodePaletteTreeItem>(name.c_str(), ScriptCanvasEditor::AssetEditorId);
  454. RequestBuildChildrenFromSubgraphInterface(functionCategory, asset);
  455. m_globalFunctionTreeItems[asset->GetId()] = functionCategory;
  456. categoryRoot->SetEnabled(true);
  457. }
  458. void ScriptCanvasRootPaletteTreeItem::RequestBuildChildrenFromSubgraphInterface(NodePaletteTreeItem* functionCategory, AZ::Data::Asset<AZ::Data::AssetData> asset)
  459. {
  460. functionCategory->ClearChildren();
  461. ScriptCanvas::SubgraphInterfaceAsset* data = asset.GetAs<ScriptCanvas::SubgraphInterfaceAsset>();
  462. if (!data)
  463. {
  464. return;
  465. }
  466. const ScriptCanvas::Grammar::SubgraphInterface& graphInterface = data->m_interfaceData.m_interface;
  467. if (!graphInterface.HasAnyFunctionality())
  468. {
  469. return;
  470. }
  471. auto parent = functionCategory;
  472. parent->SetEnabled(true);
  473. if (graphInterface.IsUserNodeable())
  474. {
  475. AZStd::string name = functionCategory->GetName().toUtf8().constData();
  476. parent = parent->CreateChildNode<FunctionPaletteTreeItem>(name.c_str(), ScriptCanvas::Grammar::MakeFunctionSourceIdNodeable(), asset);
  477. parent->SetEnabled(true);
  478. }
  479. if (graphInterface.IsMarkedPure())
  480. {
  481. for (auto& in : graphInterface.GetIns())
  482. {
  483. auto childNode = parent->CreateChildNode<FunctionPaletteTreeItem>(in.displayName.c_str(), in.sourceID, asset);
  484. childNode->SetEnabled(true);
  485. }
  486. }
  487. else
  488. {
  489. auto& ins = graphInterface.GetIns();
  490. AZStd::vector<const ScriptCanvas::Grammar::In*> onNodeIns;
  491. AZStd::vector<const ScriptCanvas::Grammar::In*> pureIns;
  492. auto pureParent = functionCategory;
  493. for (auto& in : ins)
  494. {
  495. if (in.isPure)
  496. {
  497. pureIns.push_back(&in);
  498. }
  499. else
  500. {
  501. onNodeIns.push_back(&in);
  502. }
  503. }
  504. if (!onNodeIns.empty())
  505. {
  506. parent->SetEnabled(true);
  507. for (auto in : onNodeIns)
  508. {
  509. auto childNode = parent->CreateChildNode<NodePaletteTreeItem>(in->displayName.c_str(), ScriptCanvasEditor::AssetEditorId);
  510. childNode->SetEnabled(true);
  511. }
  512. }
  513. if (!pureIns.empty())
  514. {
  515. parent = pureParent->CreateChildNode<NodePaletteTreeItem>("Pure Functions", ScriptCanvasEditor::AssetEditorId);
  516. parent->SetEnabled(true);
  517. for (auto in : pureIns)
  518. {
  519. auto childNode = parent->CreateChildNode<FunctionPaletteTreeItem>(in->displayName.c_str(), in->sourceID, asset);
  520. childNode->SetEnabled(true);
  521. }
  522. }
  523. }
  524. }
  525. //////////////////////////////////
  526. // ScriptCanvasNodePaletteConfig
  527. //////////////////////////////////
  528. ScriptCanvasNodePaletteConfig::ScriptCanvasNodePaletteConfig(const NodePaletteModel& nodePaletteModel, AzToolsFramework::AssetBrowser::AssetBrowserFilterModel* assetModel, bool isInContextMenu)
  529. : m_nodePaletteModel(nodePaletteModel)
  530. , m_assetModel(assetModel)
  531. {
  532. m_editorId = ScriptCanvasEditor::AssetEditorId;
  533. m_mimeType = NodePaletteDockWidget::GetMimeType();
  534. m_isInContextMenu = isInContextMenu;
  535. m_allowArrowKeyNavigation = isInContextMenu;
  536. m_saveIdentifier = m_isInContextMenu ? "ScriptCanvas" : "ScriptCanvas_ContextMenu";
  537. m_rootTreeItem = Widget::NodePaletteWidget::ExternalCreateNodePaletteRoot(nodePaletteModel, assetModel);
  538. }
  539. ScriptCanvasNodePaletteConfig::~ScriptCanvasNodePaletteConfig()
  540. {
  541. }
  542. //////////////////////////
  543. // NodePaletteDockWidget
  544. //////////////////////////
  545. NodePaletteDockWidget::NodePaletteDockWidget(const QString& windowLabel, QWidget* parent, const ScriptCanvasNodePaletteConfig& paletteConfig)
  546. : GraphCanvas::NodePaletteDockWidget(parent, windowLabel, paletteConfig)
  547. , m_assetModel(paletteConfig.m_assetModel)
  548. , m_nodePaletteModel(paletteConfig.m_nodePaletteModel)
  549. , m_nextCycleAction(nullptr)
  550. , m_previousCycleAction(nullptr)
  551. , m_ignoreSelectionChanged(false)
  552. {
  553. GraphCanvas::NodePaletteTreeView* treeView = GetTreeView();
  554. treeView->setContextMenuPolicy(Qt::ContextMenuPolicy::ActionsContextMenu);
  555. if (!paletteConfig.m_isInContextMenu)
  556. {
  557. QMenu* creationMenu = new QMenu();
  558. auto scriptEventAction = creationMenu->addAction("New Script Event");
  559. QObject::connect(scriptEventAction, &QAction::triggered, this, &NodePaletteDockWidget::OnNewCustomEvent);
  560. m_newCustomEvent = new QToolButton(this);
  561. m_newCustomEvent->setIcon(QIcon(":/ScriptCanvasEditorResources/Resources/add.png"));
  562. m_newCustomEvent->setToolTip("Click to create a new Script Event or Function");
  563. m_newCustomEvent->setPopupMode(QToolButton::ToolButtonPopupMode::InstantPopup);
  564. m_newCustomEvent->setMenu(creationMenu);
  565. //
  566. AddSearchCustomizationWidget(m_newCustomEvent);
  567. {
  568. m_nextCycleAction = new QAction(treeView);
  569. m_nextCycleAction->setText(tr("Next Instance in Graph"));
  570. m_nextCycleAction->setShortcut(QKeySequence(Qt::Key_F8));
  571. treeView->addAction(m_nextCycleAction);
  572. QObject::connect(m_nextCycleAction, &QAction::triggered, this, &NodePaletteDockWidget::CycleToNextNode);
  573. }
  574. {
  575. m_previousCycleAction = new QAction(treeView);
  576. m_previousCycleAction->setText(tr("Previous Instance in Graph"));
  577. m_previousCycleAction->setShortcut(QKeySequence(Qt::Key_F7));
  578. treeView->addAction(m_previousCycleAction);
  579. QObject::connect(m_previousCycleAction, &QAction::triggered, this, &NodePaletteDockWidget::CycleToPreviousNode);
  580. }
  581. QObject::connect(treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &NodePaletteDockWidget::OnTreeSelectionChanged);
  582. QObject::connect(treeView, &GraphCanvas::NodePaletteTreeView::OnTreeItemDoubleClicked, this, &NodePaletteDockWidget::HandleTreeItemDoubleClicked);
  583. {
  584. m_openTranslationData = new QAction(treeView);
  585. m_openTranslationData->setText("Explore Translation Data");
  586. treeView->addAction(m_openTranslationData);
  587. QObject::connect(m_openTranslationData, &QAction::triggered, this, &NodePaletteDockWidget::OpenTranslationData);
  588. }
  589. {
  590. m_generateTranslation = new QAction(treeView);
  591. m_generateTranslation->setText("Generate Translation");
  592. treeView->addAction(m_generateTranslation);
  593. QObject::connect(m_generateTranslation, &QAction::triggered, this, &NodePaletteDockWidget::GenerateTranslation);
  594. }
  595. }
  596. ConfigureSearchCustomizationMargins(QMargins(0, 0, 0, 0), 0);
  597. GraphCanvas::AssetEditorNotificationBus::Handler::BusConnect(ScriptCanvasEditor::AssetEditorId);
  598. }
  599. NodePaletteDockWidget::~NodePaletteDockWidget()
  600. {
  601. GraphCanvas::AssetEditorNotificationBus::Handler::BusDisconnect();
  602. GraphCanvas::SceneNotificationBus::Handler::BusDisconnect();
  603. }
  604. void NodePaletteDockWidget::OnNewCustomEvent()
  605. {
  606. AzToolsFramework::AssetEditor::AssetEditorRequestsBus::Broadcast(&AzToolsFramework::AssetEditor::AssetEditorRequests::CreateNewAsset, azrtti_typeid<ScriptEvents::ScriptEventsAsset>(), AZ::Uuid::CreateNull());
  607. }
  608. void NodePaletteDockWidget::OnActiveGraphChanged(const GraphCanvas::GraphId& graphCanvasGraphId)
  609. {
  610. GraphCanvas::SceneNotificationBus::Handler::BusDisconnect();
  611. GraphCanvas::SceneNotificationBus::Handler::BusConnect(graphCanvasGraphId);
  612. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  613. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphCanvasGraphId);
  614. static_cast<ScriptCanvasRootPaletteTreeItem*>(ModTreeRoot())->SetActiveScriptCanvasId(scriptCanvasId);
  615. }
  616. void NodePaletteDockWidget::OnSelectionChanged()
  617. {
  618. if (m_ignoreSelectionChanged)
  619. {
  620. return;
  621. }
  622. m_cyclingHelper.Clear();
  623. GetTreeView()->selectionModel()->clearSelection();
  624. }
  625. GraphCanvas::GraphCanvasTreeItem* NodePaletteDockWidget::CreatePaletteRoot() const
  626. {
  627. return NodePaletteWidget::ExternalCreateNodePaletteRoot(m_nodePaletteModel, m_assetModel);
  628. }
  629. void NodePaletteDockWidget::OnTreeSelectionChanged(const QItemSelection&, const QItemSelection&)
  630. {
  631. ClearCycleTarget();
  632. AZStd::unordered_set< ScriptCanvas::VariableId > variableSet;
  633. QModelIndexList indexList = GetTreeView()->selectionModel()->selectedRows();
  634. if (indexList.size() == 1)
  635. {
  636. QSortFilterProxyModel* filterModel = static_cast<QSortFilterProxyModel*>(GetTreeView()->model());
  637. for (const QModelIndex& index : indexList)
  638. {
  639. QModelIndex sourceIndex = filterModel->mapToSource(index);
  640. GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast<GraphCanvas::NodePaletteTreeItem*>(sourceIndex.internalPointer());
  641. ParseCycleTargets(nodePaletteItem);
  642. }
  643. }
  644. }
  645. void NodePaletteDockWidget::AddCycleTarget(ScriptCanvas::NodeTypeIdentifier cyclingIdentifier)
  646. {
  647. if (cyclingIdentifier == ScriptCanvas::NodeTypeIdentifier(0))
  648. {
  649. return;
  650. }
  651. m_cyclingIdentifiers.insert(cyclingIdentifier);
  652. m_cyclingHelper.Clear();
  653. if (m_nextCycleAction)
  654. {
  655. m_nextCycleAction->setEnabled(true);
  656. m_previousCycleAction->setEnabled(true);
  657. m_openTranslationData->setEnabled(true);
  658. }
  659. }
  660. void NodePaletteDockWidget::ClearCycleTarget()
  661. {
  662. m_cyclingIdentifiers.clear();
  663. m_cyclingHelper.Clear();
  664. if (m_nextCycleAction)
  665. {
  666. m_nextCycleAction->setEnabled(false);
  667. m_previousCycleAction->setEnabled(false);
  668. m_openTranslationData->setEnabled(false);
  669. }
  670. }
  671. void NodePaletteDockWidget::CycleToNextNode()
  672. {
  673. ConfigureHelper();
  674. m_cyclingHelper.CycleToNextNode();
  675. }
  676. void NodePaletteDockWidget::CycleToPreviousNode()
  677. {
  678. ConfigureHelper();
  679. m_cyclingHelper.CycleToPreviousNode();
  680. }
  681. void NodePaletteDockWidget::HandleTreeItemDoubleClicked(GraphCanvas::GraphCanvasTreeItem* treeItem)
  682. {
  683. ParseCycleTargets(treeItem);
  684. CycleToNextNode();
  685. }
  686. void NodePaletteDockWidget::NavigateToTranslationFile(GraphCanvas::NodePaletteTreeItem* nodePaletteItem)
  687. {
  688. if (nodePaletteItem)
  689. {
  690. AZ::IO::Path filePath = nodePaletteItem->GetTranslationDataPath();
  691. AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
  692. if (fileIO && !filePath.empty() && fileIO->Exists(filePath.c_str()))
  693. {
  694. AzQtComponents::ShowFileOnDesktop(filePath.c_str());
  695. }
  696. }
  697. }
  698. void NodePaletteDockWidget::GenerateTranslation()
  699. {
  700. QModelIndexList indexList = GetTreeView()->selectionModel()->selectedRows();
  701. QSortFilterProxyModel* filterModel = static_cast<QSortFilterProxyModel*>(GetTreeView()->model());
  702. for (const QModelIndex& index : indexList)
  703. {
  704. QModelIndex sourceIndex = filterModel->mapToSource(index);
  705. GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast<GraphCanvas::NodePaletteTreeItem*>(sourceIndex.internalPointer());
  706. nodePaletteItem->GenerateTranslationData();
  707. }
  708. if (indexList.size() == 1)
  709. {
  710. QModelIndex sourceIndex = filterModel->mapToSource(indexList[0]);
  711. if (sourceIndex.isValid())
  712. {
  713. GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast<GraphCanvas::NodePaletteTreeItem*>(sourceIndex.internalPointer());
  714. NavigateToTranslationFile(nodePaletteItem);
  715. }
  716. }
  717. }
  718. void NodePaletteDockWidget::OpenTranslationData()
  719. {
  720. QModelIndexList indexList = GetTreeView()->selectionModel()->selectedRows();
  721. if (indexList.size() == 1)
  722. {
  723. QSortFilterProxyModel* filterModel = static_cast<QSortFilterProxyModel*>(GetTreeView()->model());
  724. for (const QModelIndex& index : indexList)
  725. {
  726. QModelIndex sourceIndex = filterModel->mapToSource(index);
  727. GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast<GraphCanvas::NodePaletteTreeItem*>(sourceIndex.internalPointer());
  728. NavigateToTranslationFile(nodePaletteItem);
  729. }
  730. }
  731. }
  732. void NodePaletteDockWidget::ConfigureHelper()
  733. {
  734. if (!m_cyclingHelper.IsConfigured() && !m_cyclingIdentifiers.empty())
  735. {
  736. ScriptCanvas::ScriptCanvasId scriptCanvasId;
  737. GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetActiveScriptCanvasId);
  738. AZ::EntityId graphCanvasGraphId;
  739. GeneralRequestBus::BroadcastResult(graphCanvasGraphId, &GeneralRequests::GetActiveGraphCanvasGraphId);
  740. m_cyclingHelper.SetActiveGraph(graphCanvasGraphId);
  741. AZStd::vector<GraphCanvas::NodeId> cyclingNodes;
  742. AZStd::vector<NodeIdPair> completeNodePairs;
  743. for (ScriptCanvas::NodeTypeIdentifier nodeTypeIdentifier : m_cyclingIdentifiers)
  744. {
  745. AZStd::vector<NodeIdPair> nodePairs;
  746. EditorGraphRequestBus::EventResult(nodePairs, scriptCanvasId, &EditorGraphRequests::GetNodesOfType, nodeTypeIdentifier);
  747. cyclingNodes.reserve(cyclingNodes.size() + nodePairs.size());
  748. completeNodePairs.reserve(completeNodePairs.size() + nodePairs.size());
  749. for (const auto& nodeIdPair : nodePairs)
  750. {
  751. cyclingNodes.emplace_back(nodeIdPair.m_graphCanvasId);
  752. completeNodePairs.emplace_back(nodeIdPair);
  753. }
  754. }
  755. m_cyclingHelper.SetNodes(cyclingNodes);
  756. {
  757. // Clean-up Selection to maintain the 'single' selection state throughout the editor
  758. QScopedValueRollback<bool> ignoreSelection(m_ignoreSelectionChanged, true);
  759. GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::ClearSelection);
  760. }
  761. EditorGraphRequestBus::Event(scriptCanvasId, &EditorGraphRequests::HighlightNodes, completeNodePairs);
  762. }
  763. }
  764. void NodePaletteDockWidget::ParseCycleTargets(GraphCanvas::GraphCanvasTreeItem* treeItem)
  765. {
  766. AZStd::vector< ScriptCanvas::NodeTypeIdentifier > nodeTypeIdentifiers = NodeIdentifierFactory::ConstructNodeIdentifiers(treeItem);
  767. for (auto nodeTypeIdentifier : nodeTypeIdentifiers)
  768. {
  769. AddCycleTarget(nodeTypeIdentifier);
  770. }
  771. }
  772. }
  773. }
  774. #include <Editor/View/Widgets/moc_ScriptCanvasNodePaletteDockWidget.cpp>