SWwiseBrowser.cpp 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. /*------------------------------------------------------------------------------------
  16. SWwiseBrowser.cpp
  17. ------------------------------------------------------------------------------------*/
  18. #include "SWwiseBrowser.h"
  19. #include "IDesktopPlatform.h"
  20. #include "ISettingsModule.h"
  21. #include "Async/Async.h"
  22. #include "AkSettingsPerUser.h"
  23. #include "DesktopPlatformModule.h"
  24. #include "Async/Async.h"
  25. #include "EditorDirectories.h"
  26. #include "Framework/Application/SlateApplication.h"
  27. #include "Framework/Commands/GenericCommands.h"
  28. #include "Framework/MultiBox/MultiBoxBuilder.h"
  29. #include "Misc/MessageDialog.h"
  30. #include "Misc/ScopedSlowTask.h"
  31. #include "Widgets/Images/SLayeredImage.h"
  32. #include "Widgets/Input/SHyperlink.h"
  33. #include "Widgets/Input/SComboButton.h"
  34. #include "Widgets/Input/SSearchBox.h"
  35. #include "Widgets/Input/SComboButton.h"
  36. #include "Widgets/Layout/SSeparator.h"
  37. #include "Widgets/Layout/SSpacer.h"
  38. #include "AkAudioBankGenerationHelpers.h"
  39. #include "AkAudioModule.h"
  40. #include "AkAudioStyle.h"
  41. #include "AkSettings.h"
  42. #include "AkSettingsPerUser.h"
  43. #include "WwiseUnrealHelper.h"
  44. #if !UE_5_0_OR_LATER
  45. #include "EditorFontGlyphs.h"
  46. #endif
  47. #include "FSoundPlayingColumn.h"
  48. #include "IAudiokineticTools.h"
  49. #include "AssetManagement/AkAssetDatabase.h"
  50. #include "Wwise/WwiseProjectDatabase.h"
  51. #include "WwiseBrowser/WwiseAssetDragDropOp.h"
  52. #include "WwiseBrowser/WwiseBrowserHelpers.h"
  53. #include "WwiseBrowser/WwiseBrowserViewCommands.h"
  54. #include "SWwiseBrowserTreeView.h"
  55. #include "SoundBankStatusColumn.h"
  56. #include "WwiseBrowserTreeColumn.h"
  57. #include "WwiseStatusColumn.h"
  58. #include "WwiseUEAssetStatusColumn.h"
  59. #include "DataSource/WwiseBrowserDataSource.h"
  60. #include "AkWaapiUMG/Components/AkBoolPropertyToControlCustomization.h"
  61. #include "Wwise/WwiseReconcile.h"
  62. #include "Widgets/SWwiseReconcile.h"
  63. #define LOCTEXT_NAMESPACE "AkAudio"
  64. const FName SWwiseBrowser::WwiseBrowserTabName = "WwiseBrowser";
  65. namespace SWwiseBrowser_Helper
  66. {
  67. const FName DirectoryWatcherModuleName = "DirectoryWatcher";
  68. }
  69. namespace FilterMenuTitles
  70. {
  71. FText GetMenuTitle(ESoundBankStatusFilter Filter)
  72. {
  73. switch (Filter)
  74. {
  75. case NewInWwise:
  76. return LOCTEXT("NewInWwise", "New In Wwise");
  77. case DeletedInWwise:
  78. return LOCTEXT("DeletedInWwise", "Deleted In Wwise");
  79. case RenamedInWwise:
  80. return LOCTEXT("RenamedInWwise", "Renamed In Wwise");
  81. case NotInWwise:
  82. return LOCTEXT("NotInWwiseOrSoundBank", "Not In Wwise or SoundBank");
  83. case MovedInWwise:
  84. return LOCTEXT("MovedInWwise", "Moved In Wwise");
  85. case UpToDate:
  86. return LOCTEXT("SoundBankUpToDate", "SoundBank Up To Date");
  87. }
  88. return FText();
  89. }
  90. FText GetMenuTooltip(ESoundBankStatusFilter Filter)
  91. {
  92. switch (Filter)
  93. {
  94. case NewInWwise:
  95. return LOCTEXT("NewInWwise_Tooltip", "Filter the New in Wwise Items.");
  96. case DeletedInWwise:
  97. return LOCTEXT("DeletedInWwise_Tooltip", "Filter the Deleted Items in Wwise.");
  98. case RenamedInWwise:
  99. return LOCTEXT("RenamedInWwise_Tooltip", "Filter the Renamed Items in Wwise.");
  100. case NotInWwise:
  101. return LOCTEXT("NotInWwiseOrSoundBank_Tooltip", "Filter the Items not in Wwise or in SoundBank.");
  102. case MovedInWwise:
  103. return LOCTEXT("MovedInWwise_Tooltip", "Filter the Items in different locations in Wwise and in SoundBank.");
  104. case UpToDate:
  105. return LOCTEXT("SoundBankUpToDate_Tooltip", "Filter the Up to date Wwise Items.");
  106. }
  107. return FText();
  108. }
  109. FText GetMenuTitle(EUAssetStatusFilter Filter)
  110. {
  111. switch (Filter)
  112. {
  113. case UAssetMissing:
  114. return LOCTEXT("UAssetMissing", "UAsset Missing");
  115. case NotInSoundBankOrUnreal:
  116. return LOCTEXT("NotInSoundBankOrUnreal", "Not in SoundBank or Unreal");
  117. case UAssetOrphaned:
  118. return LOCTEXT("UAssetOrphaned", "UAsset Orphaned");
  119. case MultipleUAssets:
  120. return LOCTEXT("UAssetMultiple", "Multiple UAssets");
  121. case RenamedInSoundBank:
  122. return LOCTEXT("RenamedInSoundBank", "Renamed In SoundBank");
  123. case UAssetNeedsUpdate:
  124. return LOCTEXT("UAssetNeedsUpdate", "UAsset Needs Update");
  125. case UAssetUpToDate:
  126. return LOCTEXT("UAssetUpToDate", "UAsset Up to Date");
  127. }
  128. return FText();
  129. }
  130. FText GetMenuTooltip(EUAssetStatusFilter Filter)
  131. {
  132. switch (Filter)
  133. {
  134. case UAssetMissing:
  135. return LOCTEXT("UAssetMissing_Tooltip", "Filter the Missing UAssets.");
  136. case NotInSoundBankOrUnreal:
  137. return LOCTEXT("NotInSoundBankOrUnreal_Tooltip", "Filter the UAssets not in SoundBanks or Unreal.");
  138. case UAssetOrphaned:
  139. return LOCTEXT("UAssetOrphaned_Tooltip", "Filter UAssets with no counterpart in Wwise.");
  140. case MultipleUAssets:
  141. return LOCTEXT("UAssetMultiple_Tooltip", "Filter Wwise items with multiple UAssets.");
  142. case RenamedInSoundBank:
  143. return LOCTEXT("UAssetOrphaned_Tooltip", "Filter UAssets with different names in the SoundBank.");
  144. case UAssetNeedsUpdate:
  145. return LOCTEXT("UAssetNeedsUpdate_Tooltip", "Filter UAssets with different Guid or ShortId in the SoundBank.");
  146. case UAssetUpToDate:
  147. return LOCTEXT("UAssetUpToDate_Tooltip", "Filter UAssets that are up to date with Wwise.");
  148. }
  149. return FText();
  150. }
  151. FText GetMenuTitle(EWwiseTypeFilter Filter)
  152. {
  153. switch (Filter)
  154. {
  155. case AcousticTexture:
  156. return LOCTEXT("AcousticTexture", "Acoustic Texture");
  157. case Effects:
  158. return LOCTEXT("Effects", "Effects");
  159. case Events:
  160. return LOCTEXT("Events", "Events");
  161. case GameParameters:
  162. return LOCTEXT("GameParameters", "GameParameters");
  163. case MasterMixerHierarchy:
  164. return LOCTEXT("MasterMixerHierarchy", "Master Mixer Hierarchy (Bus)");
  165. case State:
  166. return LOCTEXT("States", "States");
  167. case Switch:
  168. return LOCTEXT("Switches", "Switches");
  169. case Trigger:
  170. return LOCTEXT("Triggers", "Triggers");
  171. }
  172. return FText();
  173. }
  174. FText GetMenuTooltip(EWwiseTypeFilter Filter)
  175. {
  176. switch (Filter)
  177. {
  178. case AcousticTexture:
  179. return LOCTEXT("AcousticTexture_Tooltip", "Filter Wwise Acoustic Texture Types.");
  180. case Effects:
  181. return LOCTEXT("Effects_Tooltip", "Filter Wwise Effect Types.");
  182. case Events:
  183. return LOCTEXT("Events_Tooltip", "Filter Wwise Event Types.");
  184. case GameParameters:
  185. return LOCTEXT("GameParameters_Tooltip", "Filter Wwise Game Parameter Types.");
  186. case MasterMixerHierarchy:
  187. return LOCTEXT("MasterMixerHierarchy_Tooltip", "Filter Wwise Bus Types.");
  188. case State:
  189. return LOCTEXT("State_Tooltip", "Filter Wwise State Types.");
  190. case Switch:
  191. return LOCTEXT("Switch_Tooltip", "Filter Wwise Switch Types.");
  192. case Trigger:
  193. return LOCTEXT("Trigger_Tooltip", "Filter Wwise Trigger Types.");
  194. }
  195. return FText();
  196. }
  197. }
  198. SWwiseBrowser::SWwiseBrowser(): CommandList(MakeShared<FUICommandList>())
  199. {
  200. AllowTreeViewDelegates = true;
  201. DataSource = MakeUnique<FWwiseBrowserDataSource>();
  202. Transport = MakeUnique<WaapiPlaybackTransport>();
  203. DataSource->WwiseBrowserDataSourceRefreshed.BindLambda([this]()
  204. {
  205. AsyncTask(ENamedThreads::Type::GameThread, [this]
  206. {
  207. this->ConstructTree();
  208. });
  209. });
  210. DataSource->WwiseSelectionChange.BindRaw(this, &SWwiseBrowser::UpdateWaapiSelection);
  211. DataSource->WwiseExpansionChange.BindRaw(this, &SWwiseBrowser::ExpandItems);
  212. }
  213. void SWwiseBrowser::CreateWwiseBrowserCommands()
  214. {
  215. const FWwiseBrowserViewCommands& Commands = FWwiseBrowserViewCommands::Get();
  216. FUICommandList& ActionList = *CommandList;
  217. // Action to start playing an event from the Wwise Browser.
  218. ActionList.MapAction(
  219. Commands.RequestPlayWwiseItem,
  220. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandlePlayWwiseItemCommandExecute),
  221. FCanExecuteAction::CreateSP(this, &SWwiseBrowser::HandlePlayOrStopWwiseItemCanExecute));
  222. // Action to stop all playing Wwise item (event).
  223. ActionList.MapAction(
  224. Commands.RequestStopAllWwiseItem,
  225. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleStopAllWwiseItemCommandExecute));
  226. // Action to explore an item (workunit) in the containing folder.
  227. ActionList.MapAction(
  228. Commands.RequestExploreWwiseItem,
  229. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleExploreWwiseItemCommandExecute),
  230. FCanExecuteAction::CreateSP(this, &SWwiseBrowser::HandleExploreWwiseItemCanExecute));
  231. // Action find an item in the Wwise Project Explorer
  232. ActionList.MapAction(
  233. Commands.RequestFindInProjectExplorerWwiseItem,
  234. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleFindInProjectExplorerWwiseItemCommandExecute),
  235. FCanExecuteAction::CreateSP(this, &SWwiseBrowser::HandleFindInProjectExplorerWwiseItemCanExecute));
  236. // Action to find the Unreal asset in the Content Browser that maps to this item
  237. ActionList.MapAction(
  238. Commands.RequestFindInContentBrowser,
  239. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleFindInContentBrowserCommandExecute),
  240. FCanExecuteAction::CreateSP(this, &SWwiseBrowser::HandleFindInContentBrowserCanExecute));
  241. // Action to refresh the Browser
  242. ActionList.MapAction(
  243. Commands.RequestRefreshWwiseBrowser,
  244. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleRefreshWwiseBrowserCommandExecute));
  245. // Action for importing the selected items from the Wwise Browser.
  246. ActionList.MapAction(
  247. Commands.RequestImportWwiseItem,
  248. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleImportWwiseItemCommandExecute));
  249. // Action for reconciling the selected items from the Wwise Browser.
  250. ActionList.MapAction(
  251. Commands.RequestReconcileWwiseItem,
  252. FExecuteAction::CreateSP(this, &SWwiseBrowser::HandleReconcileWwiseItemCommandExecute));
  253. }
  254. TSharedPtr<SWidget> SWwiseBrowser::MakeWwiseBrowserContextMenu()
  255. {
  256. const FWwiseBrowserViewCommands& Commands = FWwiseBrowserViewCommands::Get();
  257. // Build up the menu
  258. FMenuBuilder MenuBuilder(true, CommandList);
  259. {
  260. MenuBuilder.BeginSection("WwiseBrowserTransport", LOCTEXT("MenuHeader", "WwiseBrowser"));
  261. {
  262. MenuBuilder.AddMenuEntry(Commands.RequestPlayWwiseItem);
  263. MenuBuilder.AddMenuEntry(Commands.RequestStopAllWwiseItem);
  264. }
  265. MenuBuilder.EndSection();
  266. MenuBuilder.BeginSection("WwiseBrowserFindOptions", LOCTEXT("ExploreMenuHeader", "Explore"));
  267. {
  268. MenuBuilder.AddMenuEntry(Commands.RequestFindInProjectExplorerWwiseItem);
  269. MenuBuilder.AddMenuEntry(Commands.RequestFindInContentBrowser);
  270. MenuBuilder.AddMenuEntry(Commands.RequestExploreWwiseItem);
  271. }
  272. MenuBuilder.EndSection();
  273. MenuBuilder.BeginSection("WwiseBrowserRefreshAll", LOCTEXT("RefreshHeader", "Refresh"));
  274. {
  275. MenuBuilder.AddMenuEntry(Commands.RequestRefreshWwiseBrowser);
  276. }
  277. MenuBuilder.EndSection();
  278. MenuBuilder.BeginSection("WwiseBrowserImport", LOCTEXT("ImportHeader", "Import"));
  279. {
  280. MenuBuilder.AddMenuEntry(Commands.RequestImportWwiseItem);
  281. }
  282. MenuBuilder.EndSection();
  283. {
  284. MenuBuilder.AddMenuEntry(Commands.RequestReconcileWwiseItem);
  285. }
  286. MenuBuilder.EndSection();
  287. }
  288. return MenuBuilder.MakeWidget();
  289. }
  290. void SWwiseBrowser::HandlePlayWwiseItemCommandExecute()
  291. {
  292. TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  293. int32 TransportID = -1;
  294. for (auto WwiseTreeItem : SelectedItems)
  295. {
  296. bool bPlaying = Transport->IsPlaying(WwiseTreeItem->ItemId);
  297. if (WwiseTreeItem->bWaapiRefExists)
  298. {
  299. TransportID = Transport->FindOrAdd(WwiseTreeItem->ItemId);
  300. }
  301. if(TransportID >= 0 && !bPlaying)
  302. {
  303. Transport->TogglePlay(TransportID);
  304. }
  305. if(bPlaying)
  306. {
  307. Transport->Remove(WwiseTreeItem->ItemId);
  308. }
  309. }
  310. }
  311. bool SWwiseBrowser::HandlePlayOrStopWwiseItemCanExecute()
  312. {
  313. if (IsWaapiAvailable() != EWwiseConnectionStatus::Connected)
  314. {
  315. return false;
  316. }
  317. TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  318. if (SelectedItems.Num() == 0)
  319. {
  320. return false;
  321. }
  322. for (auto SelectedItem: SelectedItems)
  323. {
  324. if (!SelectedItem->bWaapiRefExists)
  325. {
  326. return false;
  327. }
  328. if (SelectedItem->IsNotOfType({ EWwiseItemType::Event, EWwiseItemType::Sound, EWwiseItemType::BlendContainer, EWwiseItemType::SwitchContainer, EWwiseItemType::RandomSequenceContainer }))
  329. {
  330. return false;
  331. }
  332. }
  333. return true;
  334. }
  335. void SWwiseBrowser::HandleStopWwiseItemCommandExecute()
  336. {
  337. TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  338. int32 TransportID = -1;
  339. for (auto WwiseTreeItem : SelectedItems)
  340. {
  341. if (WwiseTreeItem->bWaapiRefExists)
  342. {
  343. TransportID = Transport->FindOrAdd(WwiseTreeItem->ItemId);
  344. }
  345. Transport->Stop(TransportID);
  346. }
  347. }
  348. void SWwiseBrowser::HandleStopAllWwiseItemCommandExecute()
  349. {
  350. Transport->StopAndDestroyAll();
  351. }
  352. void SWwiseBrowser::HandleExploreWwiseItemCommandExecute()
  353. {
  354. FWwiseTreeItemPtr SelectedItem = TreeViewPtr->GetSelectedItems()[0];
  355. FString WorkUnitPath = DataSource->GetItemWorkUnitPath(SelectedItem);
  356. FPlatformProcess::ExploreFolder(*WorkUnitPath);
  357. }
  358. bool SWwiseBrowser::HandleExploreWwiseItemCanExecute()
  359. {
  360. return TreeViewPtr->GetSelectedItems().Num() == 1 && IsWaapiAvailable() == EWwiseConnectionStatus::Connected;
  361. }
  362. void SWwiseBrowser::HandleFindInProjectExplorerWwiseItemCommandExecute()
  363. {
  364. TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  365. DataSource->SelectInWwiseProjectExplorer(SelectedItems);
  366. }
  367. bool SWwiseBrowser::HandleFindInProjectExplorerWwiseItemCanExecute()
  368. {
  369. return TreeViewPtr->GetSelectedItems().Num() >= 1 && IsWaapiAvailable() == EWwiseConnectionStatus::Connected;
  370. }
  371. bool SWwiseBrowser::HandleFindInContentBrowserCanExecute()
  372. {
  373. TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  374. for (const auto& Asset : SelectedItems)
  375. {
  376. if (Asset->IsOfType({ EWwiseItemType::Event,
  377. EWwiseItemType::Bus,
  378. EWwiseItemType::AuxBus,
  379. EWwiseItemType::AcousticTexture,
  380. EWwiseItemType::State,
  381. EWwiseItemType::Switch,
  382. EWwiseItemType::GameParameter,
  383. EWwiseItemType::Trigger,
  384. EWwiseItemType::EffectShareSet
  385. }))
  386. {
  387. return true;
  388. }
  389. }
  390. return false;
  391. }
  392. void SWwiseBrowser::HandleFindInContentBrowserCommandExecute()
  393. {
  394. TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  395. TArray<FAssetData> AssetsToSync;
  396. for (const auto& Asset : SelectedItems)
  397. {
  398. AssetsToSync.Append(Asset->Assets);
  399. }
  400. if (AssetsToSync.Num())
  401. {
  402. GEditor->SyncBrowserToObjects(AssetsToSync);
  403. }
  404. }
  405. void SWwiseBrowser::HandleRefreshWwiseBrowserCommandExecute()
  406. {
  407. DataSource->ConstructTree();
  408. }
  409. SWwiseBrowser::~SWwiseBrowser()
  410. {
  411. RootItems.Empty();
  412. SearchBoxFilter->OnChanged().RemoveAll(this);
  413. DataSource->WwiseSelectionChange.Unbind();
  414. DataSource->WwiseExpansionChange.Unbind();
  415. }
  416. void SWwiseBrowser::Construct(const FArguments& InArgs)
  417. {
  418. FGenericCommands::Register();
  419. FWwiseBrowserViewCommands::Register();
  420. CreateWwiseBrowserCommands();
  421. SearchBoxFilter = MakeShareable(new StringFilter(StringFilter::FItemToStringArray::CreateSP(this, &SWwiseBrowser::PopulateSearchStrings)));
  422. SearchBoxFilter->OnChanged().AddSP(this, &SWwiseBrowser::OnTextFilterUpdated);
  423. HeaderRowWidget =
  424. SNew(SHeaderRow)
  425. .CanSelectGeneratedColumn(true);
  426. #if UE_5_0_OR_LATER
  427. TSharedPtr<SLayeredImage> FilterImage = SNew(SLayeredImage)
  428. .Image(FAkAppStyle::Get().GetBrush("Icons.Filter"))
  429. .ColorAndOpacity(FSlateColor::UseForeground());
  430. #if UE_5_1_OR_LATER
  431. // Badge the filter icon if there are filters active
  432. FilterImage->AddLayer(TAttribute<const FSlateBrush*>(this, &SWwiseBrowser::GetFilterBadgeIcon));
  433. #endif
  434. #endif
  435. SetupColumns(*HeaderRowWidget);
  436. ChildSlot
  437. [
  438. SNew(SBorder)
  439. .Padding(7.f)
  440. .BorderImage(FAkAppStyle::Get().GetBrush("ToolPanel.GroupBorder"))
  441. [
  442. SNew(SOverlay)
  443. // Browser
  444. + SOverlay::Slot()
  445. .VAlign(VAlign_Fill)
  446. [
  447. SNew(SVerticalBox)
  448. // Search
  449. + SVerticalBox::Slot()
  450. .AutoHeight()
  451. .Padding(0, 1, 0, 3)
  452. [
  453. SNew(SHorizontalBox)
  454. + SHorizontalBox::Slot()
  455. .AutoWidth()
  456. [
  457. InArgs._SearchContent.Widget
  458. ]
  459. + SHorizontalBox::Slot()
  460. .AutoWidth()
  461. .HAlign(HAlign_Left)
  462. [
  463. SNew(SComboButton)
  464. #if UE_5_0_OR_LATER
  465. .ComboButtonStyle(FAkAppStyle::Get(), "SimpleComboButton")
  466. #else
  467. .ComboButtonStyle(FEditorStyle::Get(), "GenericFilters.ComboButtonStyle")
  468. .ForegroundColor(FLinearColor::White)
  469. #endif
  470. .ToolTipText(LOCTEXT("Browser_AddFilterToolTip", "Add filters to the Wwise Browser."))
  471. .OnGetMenuContent(this, &SWwiseBrowser::MakeAddFilterMenu)
  472. .ButtonContent()
  473. [
  474. SNew(SHorizontalBox)
  475. + SHorizontalBox::Slot()
  476. .AutoWidth()
  477. [
  478. #if UE_5_0_OR_LATER
  479. FilterImage.ToSharedRef()
  480. #else
  481. SNew(STextBlock)
  482. .TextStyle(FEditorStyle::Get(), "GenericFilters.TextStyle")
  483. .Font(FEditorStyle::Get().GetFontStyle("FontAwesome.9"))
  484. .Text(FText::FromString(FString(TEXT("\xf0b0"))) /*fa-filter*/)
  485. #endif
  486. ]
  487. ]
  488. ]
  489. + SHorizontalBox::Slot()
  490. .FillWidth(1.0f)
  491. [
  492. SNew(SSearchBox)
  493. .HintText(LOCTEXT("WwiseBrowserSearchTooltip", "Search..."))
  494. .OnTextChanged(this, &SWwiseBrowser::OnSearchBoxChanged)
  495. .SelectAllTextWhenFocused(false)
  496. .DelayChangeNotificationsWhileTyping(true)
  497. ]
  498. + SHorizontalBox::Slot()
  499. .AutoWidth()
  500. [
  501. SNew(SBox)
  502. .Padding(FMargin(5.0f,0.0f,20.0f,0.0f))
  503. [
  504. SNew(SButton)
  505. .ToolTipText(LOCTEXT("WwiseBrowserRefresh", "Refresh the Wwise Browser"))
  506. .ButtonStyle(FAkAudioStyle::Get(), "AudiokineticTools.HoverHintOnly")
  507. .OnClicked(this, &SWwiseBrowser::OnRefreshClicked)
  508. .VAlign(VAlign_Center)
  509. [
  510. #if UE_5_0_OR_LATER
  511. SNew(SImage)
  512. .Image(FAkAppStyle::Get().GetBrush("Icons.Refresh"))
  513. #else
  514. SNew(STextBlock)
  515. .Font(FEditorStyle::Get().GetFontStyle("FontAwesome.11"))
  516. .Text(FEditorFontGlyphs::Repeat)
  517. .ColorAndOpacity(FLinearColor::White)
  518. #endif
  519. ]
  520. ]
  521. ]
  522. + SHorizontalBox::Slot()
  523. .AutoWidth()
  524. [
  525. SNew(SButton)
  526. .Text(LOCTEXT("AkBrowserGenerate", "Generate SoundBanks..."))
  527. .VAlign(VAlign_Center)
  528. .OnClicked(this, &SWwiseBrowser::OnGenerateSoundBanksClicked)
  529. ]
  530. + SHorizontalBox::Slot()
  531. .Padding(FMargin(20.0f,0.0f,0.0f,0.0f))
  532. .AutoWidth()
  533. [
  534. SNew(SButton)
  535. .ToolTipText(LOCTEXT("Reconcile_Tooltip", "Reconcile Selected."))
  536. .ButtonStyle(FAkAudioStyle::Get(), "AudiokineticTools.HoverHintOnly")
  537. .OnClicked(this, &SWwiseBrowser::OnReconcileClicked)
  538. [
  539. SNew(SImage)
  540. .Image(FAkAppStyle::Get().GetBrush("Graph.Node.Loop"))
  541. ]
  542. ]
  543. ]
  544. // Tree
  545. + SVerticalBox::Slot()
  546. .FillHeight(1.f)
  547. [
  548. SAssignNew(TreeViewPtr, SWwiseBrowserTreeView, StaticCastSharedRef<SWwiseBrowser>(AsShared()))
  549. .TreeItemsSource(&RootItems).Visibility(this, &SWwiseBrowser::IsWarningNotVisible)
  550. .OnGenerateRow(this, &SWwiseBrowser::GenerateRow)
  551. .ItemHeight(18)
  552. .SelectionMode(InArgs._SelectionMode)
  553. .OnSelectionChanged(this, &SWwiseBrowser::TreeSelectionChanged)
  554. .OnExpansionChanged(this, &SWwiseBrowser::TreeExpansionChanged)
  555. .OnGetChildren(this, &SWwiseBrowser::GetChildrenForTree)
  556. .OnContextMenuOpening(this, &SWwiseBrowser::MakeWwiseBrowserContextMenu)
  557. .ClearSelectionOnClick(false)
  558. .HeaderRow(HeaderRowWidget)
  559. .OnMouseButtonDoubleClick(this, &SWwiseBrowser::OnTreeItemDoubleClicked)
  560. ]
  561. //Footer
  562. + SVerticalBox::Slot()
  563. .AutoHeight()
  564. .Padding(0.f, 6.f, 0.f, 0.f)
  565. [
  566. SNew(SVerticalBox)
  567. + SVerticalBox::Slot()
  568. .VAlign(VAlign_Center)
  569. [
  570. SNew(SVerticalBox)
  571. + SVerticalBox::Slot()
  572. .VAlign(VAlign_Center)
  573. .AutoHeight()
  574. [
  575. SNew(SBorder)
  576. .BorderImage(FCoreStyle::Get().GetBrush("ToolPanel.GroupBorder"))
  577. [
  578. SNew(SHorizontalBox)
  579. + SHorizontalBox::Slot()
  580. [
  581. SNew(STextBlock)
  582. .Text(this, &SWwiseBrowser::GetConnectionStatusText)
  583. .Visibility(this, &SWwiseBrowser::IsWarningNotVisible)
  584. ]
  585. + SHorizontalBox::Slot()
  586. [
  587. SNew(STextBlock)
  588. .Text(this, &SWwiseBrowser::GetSoundBanksLocationText)
  589. .ColorAndOpacity(this, &SWwiseBrowser::GetSoundBanksLocationTextColor)
  590. ]
  591. ]
  592. ]
  593. ]
  594. ]
  595. ]
  596. // Empty Browser
  597. + SOverlay::Slot()
  598. .VAlign(VAlign_Center)
  599. .HAlign(HAlign_Center)
  600. [
  601. SNew(SVerticalBox)
  602. + SVerticalBox::Slot()
  603. .VAlign(VAlign_Center)
  604. .HAlign(HAlign_Center)
  605. .AutoHeight()
  606. [
  607. SNew(STextBlock)
  608. .Visibility(this, &SWwiseBrowser::IsWarningVisible)
  609. .AutoWrapText(true)
  610. .Justification(ETextJustify::Center)
  611. .Text(this, &SWwiseBrowser::GetWarningText)
  612. ]
  613. + SVerticalBox::Slot()
  614. .VAlign(VAlign_Center)
  615. .HAlign(HAlign_Center)
  616. .AutoHeight()
  617. [
  618. SNew(SButton)
  619. .Text(LOCTEXT("AkBrowserOpenSettings", "Open Wwise Integration Settings"))
  620. .Visibility(this, &SWwiseBrowser::IsWarningVisible)
  621. .OnClicked(this, &SWwiseBrowser::OnOpenSettingsClicked)
  622. ]
  623. + SVerticalBox::Slot()
  624. .VAlign(VAlign_Center)
  625. .HAlign(HAlign_Center)
  626. .AutoHeight()
  627. ]
  628. ]
  629. ];
  630. InitialParse();
  631. }
  632. TSharedRef<SWidget> SWwiseBrowser::MakeAddFilterMenu()
  633. {
  634. FMenuBuilder MenuBuilder(/*bInShouldCloseWindowAfterMenuSelection=*/false, nullptr);
  635. MenuBuilder.BeginSection("SoundBankStatusFilters", LOCTEXT("SoundBankStatusFilters", "SoundBank Status Filters"));
  636. {
  637. for (int i = 0; i < NumberOfSoundBankStatus; i++)
  638. {
  639. ESoundBankStatusFilter Status = (ESoundBankStatusFilter)i;
  640. MenuBuilder.AddMenuEntry(
  641. FilterMenuTitles::GetMenuTitle(Status),
  642. FilterMenuTitles::GetMenuTooltip(Status),
  643. FSlateIcon(),
  644. FUIAction(FExecuteAction::CreateSP(this, &SWwiseBrowser::SoundBankFilterExecute, Status),
  645. FCanExecuteAction::CreateLambda([] { return true; }),
  646. FIsActionChecked::CreateSP(this, &SWwiseBrowser::SoundBankFilterIsChecked, Status)),
  647. NAME_None,
  648. EUserInterfaceActionType::ToggleButton
  649. );
  650. }
  651. MenuBuilder.AddMenuEntry(
  652. LOCTEXT("SoundBankNotUpToDate", "SoundBank Not Up to Date"),
  653. LOCTEXT("SoundBankNotUpToDate_Tooltip", "Activate all filters of this section that is not \"SoundBank Up to Date\""),
  654. FSlateIcon(),
  655. FUIAction(FExecuteAction::CreateSP(this, &SWwiseBrowser::SoundBankNotUpToDateExecute)),
  656. NAME_None,
  657. EUserInterfaceActionType::Button
  658. );
  659. }
  660. MenuBuilder.EndSection();
  661. MenuBuilder.BeginSection("UAssetStatusFilters", LOCTEXT("UAssetStatusFilters", "UAsset Status Filters"));
  662. {
  663. for(int i = 0; i < NumberOfUAssetStatus; i++)
  664. {
  665. EUAssetStatusFilter Status = (EUAssetStatusFilter)i;
  666. MenuBuilder.AddMenuEntry(
  667. FilterMenuTitles::GetMenuTitle(Status),
  668. FilterMenuTitles::GetMenuTooltip(Status),
  669. FSlateIcon(),
  670. FUIAction(FExecuteAction::CreateSP(this, &SWwiseBrowser::UAssetFilterExecute, Status),
  671. FCanExecuteAction::CreateLambda([] { return true; }),
  672. FIsActionChecked::CreateSP(this, &SWwiseBrowser::UAssetFilterIsChecked, Status)),
  673. NAME_None,
  674. EUserInterfaceActionType::ToggleButton
  675. );
  676. }
  677. MenuBuilder.AddMenuEntry(
  678. LOCTEXT("UAssetNotUpToDate", "UAsset Not Up to Date"),
  679. LOCTEXT("UAssetNotUpToDate_Tooltip", "Activate all filters of this section that is not \"UAsset Up to Date\""),
  680. FSlateIcon(),
  681. FUIAction(FExecuteAction::CreateSP(this, &SWwiseBrowser::UAssetNotUpToDateExecute)),
  682. NAME_None,
  683. EUserInterfaceActionType::Button
  684. );
  685. }
  686. MenuBuilder.EndSection();
  687. MenuBuilder.BeginSection("TypeFilters", LOCTEXT("TypeFilters", "Type Filters"));
  688. {
  689. for (int i = 0; i < NumberOfWwiseTypes; i++)
  690. {
  691. EWwiseTypeFilter Type = (EWwiseTypeFilter)i;
  692. MenuBuilder.AddMenuEntry(
  693. FilterMenuTitles::GetMenuTitle(Type),
  694. FilterMenuTitles::GetMenuTooltip(Type),
  695. FSlateIcon(),
  696. FUIAction(FExecuteAction::CreateSP(this, &SWwiseBrowser::WwiseTypeFilterExecute, Type),
  697. FCanExecuteAction::CreateLambda([] { return true; }),
  698. FIsActionChecked::CreateSP(this, &SWwiseBrowser::WwiseTypeFilterIsChecked, Type)),
  699. NAME_None,
  700. EUserInterfaceActionType::ToggleButton
  701. );
  702. }
  703. }
  704. MenuBuilder.EndSection();
  705. MenuBuilder.BeginSection("RemoveFilters", LOCTEXT("RemoveFilters", "Remove Filters"));
  706. {
  707. MenuBuilder.AddMenuEntry(
  708. LOCTEXT("Remove_Title", "Remove All Filters"),
  709. LOCTEXT("Remove_Tooltip", "Removes all selected filters."),
  710. FSlateIcon(),
  711. FUIAction(FExecuteAction::CreateSP(this, &SWwiseBrowser::RemoveFiltersExecute),
  712. FCanExecuteAction::CreateLambda([] { return true; })),
  713. NAME_None,
  714. EUserInterfaceActionType::Button
  715. );
  716. }
  717. return MenuBuilder.MakeWidget();
  718. }
  719. const FSlateBrush* SWwiseBrowser::GetFilterBadgeIcon() const
  720. {
  721. if (!SoundBankStatusFilter.AreFiltersOff())
  722. {
  723. return FAkAppStyle::Get().GetBrush("Icons.BadgeModified");
  724. }
  725. if (!UAssetStatusFilter.AreFiltersOff())
  726. {
  727. return FAkAppStyle::Get().GetBrush("Icons.BadgeModified");
  728. }
  729. if (!WwiseTypeFilter.AreFiltersOff())
  730. {
  731. return FAkAppStyle::Get().GetBrush("Icons.BadgeModified");
  732. }
  733. return nullptr;
  734. }
  735. void SWwiseBrowser::SoundBankFilterExecute(ESoundBankStatusFilter Filter)
  736. {
  737. SoundBankStatusFilter.bFilters[Filter] = !SoundBankStatusFilter.bFilters[Filter];
  738. OnFilterUpdated();
  739. }
  740. bool SWwiseBrowser::SoundBankFilterIsChecked(ESoundBankStatusFilter Filter)
  741. {
  742. return SoundBankStatusFilter.bFilters[Filter];
  743. }
  744. void SWwiseBrowser::UAssetFilterExecute(EUAssetStatusFilter Filter)
  745. {
  746. UAssetStatusFilter.bFilters[Filter] = !UAssetStatusFilter.bFilters[Filter];
  747. OnFilterUpdated();
  748. }
  749. bool SWwiseBrowser::UAssetFilterIsChecked(EUAssetStatusFilter Filter)
  750. {
  751. return UAssetStatusFilter.bFilters[Filter];
  752. }
  753. void SWwiseBrowser::WwiseTypeFilterExecute(EWwiseTypeFilter Filter)
  754. {
  755. WwiseTypeFilter.bFilters[Filter] = !WwiseTypeFilter.bFilters[Filter];
  756. OnFilterUpdated();
  757. }
  758. bool SWwiseBrowser::WwiseTypeFilterIsChecked(EWwiseTypeFilter Filter)
  759. {
  760. return WwiseTypeFilter.bFilters[Filter];
  761. }
  762. void SWwiseBrowser::RemoveFiltersExecute()
  763. {
  764. bool bShouldUpdate = false;
  765. for (auto& bFilter : WwiseTypeFilter.bFilters)
  766. {
  767. if(bFilter)
  768. {
  769. bShouldUpdate = true;
  770. bFilter = false;
  771. }
  772. }
  773. for(auto& bFilter : SoundBankStatusFilter.bFilters)
  774. {
  775. if (bFilter)
  776. {
  777. bShouldUpdate = true;
  778. bFilter = false;
  779. }
  780. }
  781. for(auto& bFilter : UAssetStatusFilter.bFilters)
  782. {
  783. if (bFilter)
  784. {
  785. bShouldUpdate = true;
  786. bFilter = false;
  787. }
  788. }
  789. if(bShouldUpdate)
  790. {
  791. OnFilterUpdated();
  792. }
  793. }
  794. void SWwiseBrowser::SoundBankNotUpToDateExecute()
  795. {
  796. bool bShouldUpdate = false;
  797. for (int i = 0; i < ESoundBankStatusFilter::UpToDate; i++)
  798. {
  799. if (!SoundBankStatusFilter.bFilters[i])
  800. {
  801. SoundBankStatusFilter.bFilters[i] = true;
  802. bShouldUpdate = true;
  803. }
  804. }
  805. if (SoundBankStatusFilter.bFilters[ESoundBankStatusFilter::UpToDate])
  806. {
  807. SoundBankStatusFilter.bFilters[ESoundBankStatusFilter::UpToDate] = false;
  808. bShouldUpdate = true;
  809. }
  810. if (bShouldUpdate)
  811. {
  812. OnFilterUpdated();
  813. }
  814. }
  815. void SWwiseBrowser::UAssetNotUpToDateExecute()
  816. {
  817. bool bShouldUpdate = false;
  818. for (int i = 0; i < EUAssetStatusFilter::UAssetUpToDate; i++)
  819. {
  820. if (!UAssetStatusFilter.bFilters[i])
  821. {
  822. UAssetStatusFilter.bFilters[i] = true;
  823. bShouldUpdate = true;
  824. }
  825. }
  826. if (UAssetStatusFilter.bFilters[EUAssetStatusFilter::UAssetUpToDate])
  827. {
  828. UAssetStatusFilter.bFilters[EUAssetStatusFilter::UAssetUpToDate] = false;
  829. bShouldUpdate = true;
  830. }
  831. if (bShouldUpdate)
  832. {
  833. OnFilterUpdated();
  834. }
  835. }
  836. void SWwiseBrowser::ForceRefresh()
  837. {
  838. if(!GetProjectName().IsEmpty())
  839. {
  840. DataSource->ConstructTree();
  841. }
  842. }
  843. void SWwiseBrowser::InitialParse()
  844. {
  845. if(!GetProjectName().IsEmpty())
  846. {
  847. DataSource->ConstructTree();
  848. ConstructTree();
  849. TreeViewPtr->RequestTreeRefresh();
  850. ExpandFirstLevel();
  851. }
  852. }
  853. FText SWwiseBrowser::GetProjectName() const
  854. {
  855. return DataSource->GetProjectName();
  856. }
  857. FText SWwiseBrowser::GetConnectedWwiseProjectName() const
  858. {
  859. return DataSource->GetConnectedWwiseProjectName();
  860. }
  861. EWwiseConnectionStatus SWwiseBrowser::IsWaapiAvailable() const
  862. {
  863. return DataSource->GetWaapiConnectionStatus();
  864. }
  865. EVisibility SWwiseBrowser::IsWarningVisible() const
  866. {
  867. // Also need to check if WAAPI available
  868. return GetProjectName().IsEmpty() ? EVisibility::Visible : EVisibility::Hidden;
  869. }
  870. EVisibility SWwiseBrowser::IsWarningNotVisible() const
  871. {
  872. return GetProjectName().IsEmpty() ? EVisibility::Hidden : EVisibility::Visible;
  873. }
  874. EVisibility SWwiseBrowser::IsItemPlaying(FGuid ItemId) const
  875. {
  876. return Transport->IsPlaying(ItemId) ? EVisibility::Visible : EVisibility::Hidden;
  877. }
  878. FText SWwiseBrowser::GetWarningText() const
  879. {
  880. if (auto AkSettings = GetMutableDefault<UAkSettings>())
  881. {
  882. if (AkSettings->RootOutputPath.Path.IsEmpty())
  883. {
  884. const FText WarningText = LOCTEXT("BrowserSoundBanksFolderEmpty", "Generated SoundBanks Folder in Wwise Integration settings is empty.\nThis folder should match the \"Root Output Path\" in the Wwise Project's SoundBanks settings.");
  885. return WarningText;
  886. }
  887. }
  888. FString soundBankDirectory = WwiseUnrealHelper::GetSoundBankDirectory();
  889. const FText WarningText = FText::FormatOrdered(LOCTEXT("BrowserMissingSoundBanks", "SoundBank metadata was not found at path specified by \"Generated SoundBanks Folder\" setting: {0}.\nThis folder should match the \"Root Output Path\" in the Wwise Project's SoundBanks settings.\nEnsure the folders match, and that SoundBanks and JSON metadata are generated.\nPress the \"Refresh\" button to re-parse the generated metadata."), FText::FromString(soundBankDirectory));
  890. return WarningText;
  891. }
  892. FText SWwiseBrowser::GetConnectionStatusText() const
  893. {
  894. switch(IsWaapiAvailable())
  895. {
  896. case Connected:
  897. return FText::Format(LOCTEXT("WwiseConnected", "Connected to Wwise Project: {0}"), GetProjectName());
  898. case SettingDisabled:
  899. return LOCTEXT("WwiseSettingDisabled", "Not Connected to Wwise. Only objects on disk shown. Enable \"Auto Connect to Waapi\" in the Wwise User Settings to see the Wwise project in the Browser.");
  900. case WrongProjectOpened:
  901. return LOCTEXT("WwiseWrongProject", "Not Connected to Wwise. Only objects on disk shown. The wrong Wwise project is opened.");
  902. case WwiseNotOpen:
  903. default:
  904. return LOCTEXT("WwiseNotConnected", "Not Connected to Wwise. Only objects on disk shown. Open Wwise to see the Wwise project in the Browser.");
  905. }
  906. }
  907. FText SWwiseBrowser::GetSoundBanksLocationText() const
  908. {
  909. FString RootOutputPath = TEXT("Root Output Path");
  910. UAkSettingsPerUser* UserSettings = GetMutableDefault<UAkSettingsPerUser>();
  911. if(UserSettings && !UserSettings->RootOutputPathOverride.Path.IsEmpty())
  912. {
  913. RootOutputPath = TEXT("Root Output Path Override");
  914. }
  915. return FText::Format(LOCTEXT("RootOutputPath", "{0}: {1}"), FText::FromString(RootOutputPath), FText::FromString(WwiseUnrealHelper::GetSoundBankDirectory()));
  916. }
  917. FSlateColor SWwiseBrowser::GetSoundBanksLocationTextColor() const
  918. {
  919. UAkSettingsPerUser* UserSettings = GetMutableDefault<UAkSettingsPerUser>();
  920. if(UserSettings && !UserSettings->RootOutputPathOverride.Path.IsEmpty())
  921. {
  922. return FLinearColor(1.f, 0.33f, 0);
  923. }
  924. return FLinearColor::Gray;
  925. }
  926. FReply SWwiseBrowser::OnOpenSettingsClicked()
  927. {
  928. FModuleManager::LoadModuleChecked<ISettingsModule>("Settings").ShowViewer(FName("Project"), FName("Wwise"), FName("Integration"));
  929. return FReply::Handled();
  930. }
  931. FReply SWwiseBrowser::OnRefreshClicked()
  932. {
  933. if (FModuleManager::Get().IsModuleLoaded("AudiokineticTools"))
  934. {
  935. UE_LOG(LogAudiokineticTools, Verbose, TEXT("SWwiseBrowser::OnRefreshClicked: Reloading project data."));
  936. FModuleManager::Get().GetModuleChecked<IAudiokineticTools>(FName("AudiokineticTools")).RefreshWwiseProject();
  937. }
  938. ForceRefresh();
  939. return FReply::Handled();
  940. }
  941. FReply SWwiseBrowser::OnGenerateSoundBanksClicked()
  942. {
  943. UE_LOG(LogAudiokineticTools, Verbose, TEXT("SWwiseBrowser::OnGenerateSoundBanksClicked: Opening Generate SoundBanks Window."));
  944. AkAudioBankGenerationHelper::CreateGenerateSoundDataWindow();
  945. return FReply::Handled();
  946. }
  947. FReply SWwiseBrowser::OnReconcileClicked()
  948. {
  949. if(IsWarningVisible() == EVisibility::Hidden)
  950. {
  951. UE_LOG(LogAudiokineticTools, Verbose, TEXT("SWwiseBrowser::OnReconcileClicked: Opening Reconcile Window."));
  952. CreateReconcileTab();
  953. }
  954. else if(EAppReturnType::Yes == FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("NoSoundBanksReconcile", "SoundBanks must be generated before reconciliation. Generate SoundBanks now?")))
  955. {
  956. AkAudioBankGenerationHelper::CreateGenerateSoundDataWindow();
  957. }
  958. return FReply::Handled();
  959. }
  960. void SWwiseBrowser::OnTreeItemDoubleClicked(FWwiseTreeItemPtr TreeItem)
  961. {
  962. if (TreeItem->IsBrowserType())
  963. {
  964. HandleFindInContentBrowserCommandExecute();
  965. }
  966. else if (TreeItem->IsFolder() && TreeItem->GetChildren().Num() > 0)
  967. {
  968. ExpandItem(TreeItem, !TreeViewPtr->IsItemExpanded(TreeItem));
  969. }
  970. }
  971. void SWwiseBrowser::ConstructTree()
  972. {
  973. UE_LOG(LogAudiokineticTools, Verbose, TEXT("SWwiseBrowser::ConstructTree: Rebuilding Wwise Browser Tree"));
  974. RootItems.Empty(EWwiseItemType::LastWwiseBrowserType - EWwiseItemType::Event + 1);
  975. for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType + 1; ++i)
  976. {
  977. FWwiseTreeItemPtr NewRoot = DataSource->GetTreeRootForType(static_cast<EWwiseItemType::Type>(i));
  978. RootItems.Add(NewRoot);
  979. }
  980. RestoreTreeExpansion(RootItems);
  981. TreeViewPtr->RequestTreeRefresh();
  982. }
  983. void SWwiseBrowser::ExpandFirstLevel()
  984. {
  985. // Expand root items and first-level work units.
  986. for(int32 i = 0; i < RootItems.Num(); i++)
  987. {
  988. ExpandItem(RootItems[i], true);
  989. }
  990. }
  991. void SWwiseBrowser::ExpandParents(FWwiseTreeItemPtr Item)
  992. {
  993. if(Item->Parent.IsValid())
  994. {
  995. ExpandParents(Item->Parent.Pin());
  996. ExpandItem(Item->Parent.Pin(), true);
  997. }
  998. }
  999. TSharedRef<ITableRow> SWwiseBrowser::GenerateRow( FWwiseTreeItemPtr TreeItem, const TSharedRef<STableViewBase>& OwnerTable )
  1000. {
  1001. check(TreeItem.IsValid());
  1002. TSharedRef<SWwiseBrowserTreeRow> NewRow = SNew(SWwiseBrowserTreeRow, TreeViewPtr.ToSharedRef(), SharedThis(this)).
  1003. Item(TreeItem);
  1004. TreeItem->TreeRow = NewRow;
  1005. return NewRow;
  1006. }
  1007. void SWwiseBrowser::GetChildrenForTree(FWwiseTreeItemPtr TreeItem, TArray< FWwiseTreeItemPtr >& OutChildren)
  1008. {
  1009. if (TreeItem)
  1010. {
  1011. if(TreeItem->ChildCountInWwise)
  1012. {
  1013. if (!LastExpandedPaths.Contains(TreeItem->FolderPath))
  1014. {
  1015. DataSource->ClearEmptyChildren(TreeItem);
  1016. // We add a placeholder item if the children exist, but are not loaded (e.g. for WAAPI). This should never be visible
  1017. if (!TreeItem->GetChildren().Num())
  1018. {
  1019. FWwiseTreeItemPtr EmptyTreeItem = MakeShared<FWwiseTreeItem>(FString::Format(TEXT("Expansion placeholder for {0} "), { TreeItem->FolderPath }), "", nullptr, EWwiseItemType::None, FGuid());
  1020. EmptyTreeItem->Parent = TreeItem;
  1021. TreeItem->AddChild(EmptyTreeItem);
  1022. }
  1023. }
  1024. else
  1025. {
  1026. ExpandItem(TreeItem, true);
  1027. }
  1028. }
  1029. OutChildren = TreeItem->GetChildren();
  1030. }
  1031. }
  1032. FReply SWwiseBrowser::OnDragDetected(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
  1033. {
  1034. return DoDragDetected(MouseEvent, TreeViewPtr->GetSelectedItems());
  1035. }
  1036. FReply SWwiseBrowser::DoDragDetected(const FPointerEvent& MouseEvent, const TArray<FWwiseTreeItemPtr>& SelectedItems)
  1037. {
  1038. if (!MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
  1039. {
  1040. return FReply::Unhandled();
  1041. }
  1042. if (SelectedItems.Num() == 0)
  1043. {
  1044. return FReply::Unhandled();
  1045. }
  1046. UE_LOG(LogAudiokineticTools, Verbose, TEXT("SWwiseBrowser::OnDragDetected: User drag operation started."));
  1047. auto AkSettings = GetMutableDefault<UAkSettings>();
  1048. const FString DefaultPath = AkSettings->DefaultAssetCreationPath;
  1049. TArray<WwiseBrowserHelpers::WwiseBrowserAssetPayload> DragAssets;
  1050. TSet<FGuid> SeenGuids;
  1051. bool bAllItemsCanBeCreated = true;
  1052. for (auto& WwiseTreeItem : SelectedItems)
  1053. {
  1054. if (!WwiseTreeItem->ItemId.IsValid() && !WwiseTreeItem->IsFolder())
  1055. {
  1056. UE_LOG(LogAudiokineticTools, Error, TEXT("Cannot drag selected Wwise asset: %s does not have a valid ID"), *(WwiseTreeItem->FolderPath));
  1057. continue;
  1058. }
  1059. if(!WwiseBrowserHelpers::CanCreateAsset(WwiseTreeItem))
  1060. {
  1061. bAllItemsCanBeCreated = false;
  1062. }
  1063. WwiseBrowserHelpers::FindOrCreateAssetsRecursive(WwiseTreeItem,DragAssets,SeenGuids, WwiseBrowserHelpers::EAssetCreationMode::Transient);
  1064. }
  1065. if (DragAssets.Num() == 0 && bAllItemsCanBeCreated)
  1066. {
  1067. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to find or create Wwise asset '%s'%s in Browser operation"),
  1068. *(SelectedItems[0]->FolderPath), SelectedItems.Num() > 1 ? TEXT(" and others"): TEXT(""));
  1069. return FReply::Unhandled();
  1070. }
  1071. return FReply::Handled().BeginDragDrop(FWwiseAssetDragDropOp::New(DragAssets));
  1072. }
  1073. void SWwiseBrowser::ImportWwiseAssets(const TArray<FWwiseTreeItemPtr>& SelectedItems, const FString& PackagePath)
  1074. {
  1075. UE_LOG(LogAudiokineticTools, Verbose, TEXT("SWwiseBrowser::ImportWwiseAssets: Creating %d assets in %s."), SelectedItems.Num(), *PackagePath);
  1076. TArray<WwiseBrowserHelpers::WwiseBrowserAssetPayload> AssetsToImport;
  1077. TSet<FGuid> SeenGuids;
  1078. for(auto WwiseTreeItem: SelectedItems)
  1079. {
  1080. WwiseBrowserHelpers::FindOrCreateAssetsRecursive(WwiseTreeItem, AssetsToImport, SeenGuids,
  1081. WwiseBrowserHelpers::EAssetCreationMode::InPackage, PackagePath);
  1082. }
  1083. WwiseBrowserHelpers::SaveSelectedAssets(AssetsToImport, PackagePath,
  1084. WwiseBrowserHelpers::EAssetCreationMode::InPackage, WwiseBrowserHelpers::EAssetDuplicationMode::DoDuplication);
  1085. }
  1086. FReply SWwiseBrowser::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
  1087. {
  1088. const FKey KeyPressed = InKeyEvent.GetKey();
  1089. if (KeyPressed == EKeys::SpaceBar)
  1090. {
  1091. // Play the wwise item.
  1092. if (HandlePlayOrStopWwiseItemCanExecute())
  1093. {
  1094. HandlePlayWwiseItemCommandExecute();
  1095. return FReply::Handled();
  1096. }
  1097. }
  1098. else if (KeyPressed == EKeys::F5)
  1099. { // Populates the Wwise Browser.
  1100. HandleRefreshWwiseBrowserCommandExecute();
  1101. return FReply::Handled();
  1102. }
  1103. else if ((KeyPressed == EKeys::One) && InKeyEvent.IsControlDown() && InKeyEvent.IsShiftDown())
  1104. {
  1105. // Finds the specified object in the Project Explorer (Sync Group 1).
  1106. if (HandleFindInProjectExplorerWwiseItemCanExecute())
  1107. {
  1108. HandleFindInProjectExplorerWwiseItemCommandExecute();
  1109. return FReply::Handled();
  1110. }
  1111. }
  1112. return FReply::Unhandled();
  1113. }
  1114. void SWwiseBrowser::PopulateSearchStrings(const FString& FolderName, OUT TArray< FString >& OutSearchStrings) const
  1115. {
  1116. OutSearchStrings.Add(FolderName);
  1117. }
  1118. void SWwiseBrowser::OnSearchBoxChanged(const FText& InSearchText)
  1119. {
  1120. SearchBoxFilter->SetRawFilterText(InSearchText);
  1121. }
  1122. void SWwiseBrowser::SetItemVisibility(FWwiseTreeItemPtr Item, bool IsVisible)
  1123. {
  1124. if (Item.IsValid())
  1125. {
  1126. if (IsVisible)
  1127. {
  1128. // Propagate visibility to parents.
  1129. SetItemVisibility(Item->Parent.Pin(), IsVisible);
  1130. }
  1131. Item->IsVisible = IsVisible;
  1132. if (Item->TreeRow.IsValid())
  1133. {
  1134. TSharedRef<SWidget> wid = Item->TreeRow.Pin()->AsWidget();
  1135. wid->SetVisibility(IsVisible ? EVisibility::Visible : EVisibility::Collapsed);
  1136. }
  1137. }
  1138. }
  1139. void SWwiseBrowser::SaveCurrentTreeExpansion()
  1140. {
  1141. TSet<FWwiseTreeItemPtr> ExpandedItemSet;
  1142. TreeViewPtr->GetExpandedItems(ExpandedItemSet);
  1143. LastExpandedPaths.Empty();
  1144. for (const auto& Item : ExpandedItemSet)
  1145. {
  1146. if (Item.IsValid())
  1147. {
  1148. // Keep track of the last paths that we broadcasted for expansion reasons when filtering
  1149. LastExpandedPaths.Add(Item->FolderPath);
  1150. }
  1151. }
  1152. }
  1153. void SWwiseBrowser::RestoreTreeExpansion(const TArray< FWwiseTreeItemPtr >& Items)
  1154. {
  1155. TSet<FWwiseTreeItemPtr> ExpandedItemSet;
  1156. TreeViewPtr->GetExpandedItems(ExpandedItemSet);
  1157. LastExpandedPaths.Empty();
  1158. for (const auto& Item : ExpandedItemSet)
  1159. {
  1160. if (Item.IsValid())
  1161. {
  1162. // Keep track of the last paths that we broadcasted for expansion reasons when filtering
  1163. LastExpandedPaths.Add(Item->FolderPath);
  1164. }
  1165. }
  1166. }
  1167. void SWwiseBrowser::TreeSelectionChanged( FWwiseTreeItemPtr TreeItem, ESelectInfo::Type SelectInfo )
  1168. {
  1169. if (AllowTreeViewDelegates)
  1170. {
  1171. const TArray<FWwiseTreeItemPtr> SelectedItems = TreeViewPtr->GetSelectedItems();
  1172. LastSelectedPaths.Empty();
  1173. for (int32 ItemIdx = 0; ItemIdx < SelectedItems.Num(); ++ItemIdx)
  1174. {
  1175. const FWwiseTreeItemPtr Item = SelectedItems[ItemIdx];
  1176. if (Item.IsValid())
  1177. {
  1178. LastSelectedPaths.Add(Item->FolderPath);
  1179. }
  1180. }
  1181. const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
  1182. if (AkSettingsPerUser && AkSettingsPerUser->AutoSyncSelection &&
  1183. DataSource->GetWaapiConnectionStatus() == Connected && SelectInfo != ESelectInfo::Direct)
  1184. {
  1185. DataSource->HandleFindWwiseItemInProjectExplorerCommandExecute(SelectedItems);
  1186. }
  1187. }
  1188. }
  1189. void SWwiseBrowser::TreeExpansionChanged( FWwiseTreeItemPtr TreeItem, bool bIsExpanded )
  1190. {
  1191. auto Items = TreeViewPtr->GetSelectedItems();
  1192. if (bIsExpanded)
  1193. {
  1194. // If we have a filter applied, it is assumed that everything is loaded
  1195. if (!IsFiltering())
  1196. {
  1197. TArray<FWwiseTreeItemPtr> OutChildren;
  1198. }
  1199. }
  1200. // If the item is not expanded we don't need to request the server to get any information(the children are hidden).
  1201. else
  1202. {
  1203. LastExpandedPaths.Remove(TreeItem->FolderPath);
  1204. return;
  1205. }
  1206. LastExpandedPaths.Add(TreeItem->FolderPath);
  1207. TreeViewPtr->SetSelectedItems(Items);
  1208. }
  1209. void SWwiseBrowser::ExpandItem(FWwiseTreeItemPtr TreeItem, bool bShouldExpand)
  1210. {
  1211. TreeViewPtr->SetItemExpansion(TreeItem, bShouldExpand);
  1212. TreeItem->IsExpanded = bShouldExpand;
  1213. }
  1214. void SWwiseBrowser::ExpandItem(FWwiseTreeItemPtr WaapiTreeItem)
  1215. {
  1216. if(auto TreeItem = GetTreeItemFromWaapiItem(WaapiTreeItem))
  1217. {
  1218. LastExpandedPaths.Add(TreeItem->FolderPath);
  1219. ExpandItem(TreeItem, true);
  1220. }
  1221. }
  1222. bool SWwiseBrowser::IsItemExpanded(FWwiseTreeItemPtr TreeItem)
  1223. {
  1224. return TreeViewPtr->IsItemExpanded(TreeItem);
  1225. }
  1226. void SWwiseBrowser::GetTreeItemsFromWaapi(const TArray<TSharedPtr<FWwiseTreeItem>>& WaapiTreeItems, TArray<TSharedPtr<FWwiseTreeItem>>& TreeItems)
  1227. {
  1228. for(auto& WaapiTreeItem : WaapiTreeItems)
  1229. {
  1230. if(auto TreeItem = GetTreeItemFromWaapiItem(WaapiTreeItem))
  1231. {
  1232. TreeItems.Add(TreeItem);
  1233. }
  1234. }
  1235. }
  1236. FWwiseTreeItemPtr SWwiseBrowser::GetTreeItemFromWaapiItem(FWwiseTreeItemPtr WaapiTreeItem)
  1237. {
  1238. for (auto& RootItem : RootItems)
  1239. {
  1240. if (auto ResultTreeItem = RootItem->FindItemRecursive(WaapiTreeItem))
  1241. {
  1242. return ResultTreeItem;
  1243. }
  1244. if (auto ResultTreeItem = RootItem->FindItemRecursive(WaapiTreeItem->FolderPath))
  1245. {
  1246. return ResultTreeItem;
  1247. }
  1248. }
  1249. return FWwiseTreeItemPtr();
  1250. }
  1251. void SWwiseBrowser::ExpandItems(const TArray<FWwiseTreeItemPtr>& Items)
  1252. {
  1253. for(auto& Item : Items)
  1254. {
  1255. ExpandItem(Item, true);
  1256. }
  1257. }
  1258. void SWwiseBrowser::UpdateWaapiSelection(const TArray<TSharedPtr<FWwiseTreeItem>>& WaapiTreeItems)
  1259. {
  1260. TArray<TSharedPtr<FWwiseTreeItem>> TreeItems;
  1261. GetTreeItemsFromWaapi(WaapiTreeItems, TreeItems);
  1262. TreeViewPtr->RequestTreeRefresh();
  1263. if (TreeItems.Num() > 0)
  1264. {
  1265. TreeViewPtr->ClearSelection();
  1266. TreeViewPtr->SetSelectedItems(TreeItems);
  1267. TreeViewPtr->RequestScrollIntoView(TreeItems[0]);
  1268. }
  1269. AllowTreeViewDelegates = true;
  1270. }
  1271. void SWwiseBrowser::HandleImportWwiseItemCommandExecute() const
  1272. {
  1273. // If not prompting individual files, prompt the user to select a target directory.
  1274. IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
  1275. if (DesktopPlatform)
  1276. {
  1277. FString LastWwiseImportPath = FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_IMPORT);
  1278. FString FolderName;
  1279. const FString Title = NSLOCTEXT("UnrealEd", "ChooseADirectory", "Choose A Directory").ToString();
  1280. const bool bFolderSelected = DesktopPlatform->OpenDirectoryDialog(
  1281. FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
  1282. Title,
  1283. LastWwiseImportPath,
  1284. FolderName
  1285. );
  1286. if (bFolderSelected)
  1287. {
  1288. if (!FPaths::IsUnderDirectory(FolderName, FPaths::ProjectContentDir()))
  1289. {
  1290. const FText FailReason = FText::FormatOrdered(LOCTEXT("CannotImportWwiseItem", "Cannot import into {0}. Folder must be in content directory."), FText::FromString(FolderName));
  1291. FMessageDialog::Open(EAppMsgType::Ok, FailReason);
  1292. UE_LOG(LogAudiokineticTools, Error, TEXT("%s"), *FailReason.ToString());
  1293. return;
  1294. }
  1295. FPaths::MakePathRelativeTo(FolderName, *FPaths::ProjectContentDir());
  1296. FString PackagePath = TEXT("/Game");
  1297. if (!FolderName.IsEmpty())
  1298. {
  1299. PackagePath = PackagePath / FolderName;
  1300. }
  1301. FEditorDirectories::Get().SetLastDirectory(ELastDirectory::GENERIC_IMPORT, PackagePath);
  1302. ImportWwiseAssets(TreeViewPtr->GetSelectedItems(), PackagePath);
  1303. }
  1304. }
  1305. }
  1306. void SWwiseBrowser::HandleReconcileWwiseItemCommandExecute() const
  1307. {
  1308. CreateReconcileTab();
  1309. }
  1310. void SWwiseBrowser::SetupColumns(SHeaderRow& HeaderRow)
  1311. {
  1312. Columns.Empty();
  1313. HeaderRow.ClearColumns();
  1314. auto SoundColumn = MakeShared<FSoundPlayingColumn>(*this);
  1315. auto WwiseObjectsColumn = MakeShared<FWwiseBrowserTreeColumn>(*this);
  1316. auto WwiseStatusColumn = MakeShared<FWwiseStatusColumn>(*this);
  1317. auto WwiseUEAssetStatusColumn = MakeShared<FWwiseUEAssetStatusColumn>();
  1318. auto SoundBankStatusColumn = MakeShared<FSoundBankStatusColumn>();
  1319. auto SoundArgs = SoundColumn->ConstructHeaderRowColumn();
  1320. auto WwiseObjectArgs = WwiseObjectsColumn->ConstructHeaderRowColumn();
  1321. auto WwiseStatusArgs = WwiseStatusColumn->ConstructHeaderRowColumn();
  1322. auto WwiseUEAssetStatusArgs = WwiseUEAssetStatusColumn->ConstructHeaderRowColumn();
  1323. auto SoundBankStatusArgs = SoundBankStatusColumn->ConstructHeaderRowColumn();
  1324. Columns.Add(SoundArgs._ColumnId, SoundColumn);
  1325. Columns.Add(WwiseObjectArgs._ColumnId, WwiseObjectsColumn);
  1326. Columns.Add(WwiseStatusArgs._ColumnId, WwiseStatusColumn);
  1327. Columns.Add(WwiseUEAssetStatusArgs._ColumnId, WwiseUEAssetStatusColumn);
  1328. Columns.Add(SoundBankStatusArgs._ColumnId, SoundBankStatusColumn);
  1329. HeaderRow.AddColumn(SoundArgs);
  1330. HeaderRowWidget->AddColumn(WwiseObjectArgs);
  1331. HeaderRowWidget->AddColumn(WwiseStatusArgs);
  1332. HeaderRowWidget->AddColumn(WwiseUEAssetStatusArgs);
  1333. HeaderRowWidget->AddColumn(SoundBankStatusArgs);
  1334. }
  1335. void SWwiseBrowser::OnTextFilterUpdated()
  1336. {
  1337. if (GetFilterText().IsEmpty())
  1338. {
  1339. bIsFilterApplied = false;
  1340. }
  1341. DataSource->ApplyTextFilter(SearchBoxFilter);
  1342. }
  1343. void SWwiseBrowser::OnFilterUpdated()
  1344. {
  1345. if (RootItems.Num() == 0)
  1346. {
  1347. return;
  1348. }
  1349. ApplyFilter();
  1350. TreeViewPtr->RequestTreeRefresh();
  1351. }
  1352. void SWwiseBrowser::ApplyFilter()
  1353. {
  1354. AllowTreeViewDelegates = false;
  1355. if (!bIsFilterApplied)
  1356. {
  1357. SaveCurrentTreeExpansion();
  1358. }
  1359. DataSource->ApplyFilter(SoundBankStatusFilter, UAssetStatusFilter, WwiseTypeFilter);
  1360. RootItems.Empty();
  1361. for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType + 1; ++i)
  1362. {
  1363. FWwiseTreeItemPtr NewRoot = DataSource->GetTreeRootForType(static_cast<EWwiseItemType::Type>(i));
  1364. RootItems.Add(NewRoot);
  1365. }
  1366. bIsFilterApplied = true;
  1367. AllowTreeViewDelegates = true;
  1368. }
  1369. bool SWwiseBrowser::IsFiltering()
  1370. {
  1371. return !GetFilterText().IsEmpty();
  1372. }
  1373. FText SWwiseBrowser::GetFilterText()
  1374. {
  1375. return SearchBoxFilter.IsValid() ? SearchBoxFilter->GetRawFilterText(): FText();
  1376. }
  1377. FString SWwiseBrowser::GetFilterString()
  1378. {
  1379. return GetFilterText().ToString();
  1380. }
  1381. TAttribute<FText> SWwiseBrowser::GetFilterHighlightText() const
  1382. {
  1383. return SearchBoxFilter.IsValid() ? SearchBoxFilter->GetRawFilterText(): FText();
  1384. }
  1385. void SWwiseBrowser::CreateReconcileTab() const
  1386. {
  1387. auto SelectedItems = TreeViewPtr->GetSelectedItems();
  1388. //Nothing items are selected, Select everything
  1389. if(SelectedItems.Num() == 0)
  1390. {
  1391. SelectedItems = RootItems;
  1392. }
  1393. TArray<FWwiseReconcileItem> ReconcileItems;
  1394. if (auto WwiseReconcile = FWwiseReconcile::Get())
  1395. {
  1396. WwiseReconcile->ConvertWwiseItemTypeToReconcileItem(SelectedItems, ReconcileItems);
  1397. if (ReconcileItems.Num() == 0)
  1398. {
  1399. FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("NoReconcile", "Selected Items do not need to be reconciled."));
  1400. return;
  1401. }
  1402. auto Window = SNew(SWindow)
  1403. .Title(LOCTEXT("AkAudioWwiseReconcileTabTitle", "Reconcile Unreal Assets"))
  1404. .SizingRule(ESizingRule::UserSized)
  1405. .MinWidth(850)
  1406. .MinHeight(400)
  1407. .ClientSize(FVector2D(1100.f, 400.f));
  1408. auto ReconcileWindow = SNew(SWwiseReconcile, ReconcileItems, Window);
  1409. Window->SetContent(ReconcileWindow);
  1410. Window->SetAsModalWindow();
  1411. GEditor->EditorAddModalWindow(Window);
  1412. }
  1413. else
  1414. {
  1415. UE_LOG(LogAudiokineticTools, Error, TEXT("Failed to get Wwise Reconcile Module."));
  1416. }
  1417. }
  1418. #undef LOCTEXT_NAMESPACE