123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998 |
- /*******************************************************************************
- The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
- Technology released in source code form as part of the game integration package.
- The content of this file may not be used without valid licenses to the
- AUDIOKINETIC Wwise Technology.
- Note that the use of the game engine is subject to the Unreal(R) Engine End User
- License Agreement at https://www.unrealengine.com/en-US/eula/unreal
-
- License Usage
-
- Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
- this file in accordance with the end user license agreement provided with the
- software or, alternatively, in accordance with the terms contained
- in a written agreement between you and Audiokinetic Inc.
- Copyright (c) 2023 Audiokinetic Inc.
- *******************************************************************************/
- /*------------------------------------------------------------------------------------
- SWaapiPicker.cpp
- ------------------------------------------------------------------------------------*/
- /*------------------------------------------------------------------------------------
- includes.
- ------------------------------------------------------------------------------------*/
- #include "WaapiPicker/SWaapiPicker.h"
- #include "WaapiPicker/SWaapiPickerRow.h"
- #include "WaapiPicker/WaapiPickerViewCommands.h"
- #include "AkWaapiUtils.h"
- #include "AkAudioStyle.h"
- #include "AkSettings.h"
- #include "AkSettingsPerUser.h"
- #include "AkAudioDevice.h"
- #include "AkUnrealHelper.h"
- #include "Widgets/Images/SImage.h"
- #include "Widgets/Input/SHyperlink.h"
- #include "Widgets/Input/SButton.h"
- #include "Widgets/Input/SSearchBox.h"
- #include "Widgets/Layout/SSpacer.h"
- #include "Widgets/Layout/SSeparator.h"
- #include "Widgets/Text/SInlineEditableTextBlock.h"
- #include "Framework/Application/SlateApplication.h"
- #include "Framework/Commands/UICommandList.h"
- #include "Framework/Commands/GenericCommands.h"
- #include "Framework/MultiBox/MultiBoxBuilder.h"
- #include "Misc/ScopedSlowTask.h"
- #include "HAL/PlatformProcess.h"
- #include "Async/Async.h"
- #if WITH_EDITOR
- #include "DesktopPlatformModule.h"
- #include "Editor/UnrealEd/Public/EditorDirectories.h"
- #include "IDesktopPlatform.h"
- #endif
- /*------------------------------------------------------------------------------------
- Defines
- ------------------------------------------------------------------------------------*/
- #define LOCTEXT_NAMESPACE "AkAudio"
- DECLARE_CYCLE_STAT(TEXT("WaapiPicker - ConstructTree"), STAT_WaapiPickerConstructTree, STATGROUP_Audio);
- DECLARE_CYCLE_STAT(TEXT("WaapiPicker - TreeExpansionChanged"), STAT_WaapiPickerTreeExpansionChanged, STATGROUP_Audio);
- /*------------------------------------------------------------------------------------
- Statics and Globals
- ------------------------------------------------------------------------------------*/
- const FName SWaapiPicker::WaapiPickerTabName = FName("WaapiPicker");
- const FText SWaapiPicker::ModalWarning = LOCTEXT("WaapiModalOpened", "Wwise currently has a modal window opened. Please close it to use WAAPI functionality.");
- static inline void CallWaapiGetProjectNamePath(FString& ProjectName, FString& ProjectPath)
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- return;
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> OfType = MakeShared<FJsonObject>();
- OfType->SetArrayField(WwiseWaapiHelper::OF_TYPE, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(WwiseWaapiHelper::PROJECT) });
- Args->SetObjectField(WwiseWaapiHelper::FROM, OfType);
- }
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- {
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::FILEPATH),
- });
- }
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> outJsonResult;
- if (waapiClient->Call(ak::wwise::core::object::get, Args, Options, outJsonResult))
- {
- // Recover the information from the Json object Result and use it to get the item id.
- TArray<TSharedPtr<FJsonValue>> StructJsonArray = outJsonResult->GetArrayField(WwiseWaapiHelper::RETURN);
- if (StructJsonArray.Num())
- {
- auto Path = StructJsonArray[0]->AsObject()->GetStringField(WwiseWaapiHelper::FILEPATH);
- ProjectPath = FPaths::GetPath(Path);
- ProjectName = FPaths::GetCleanFilename(Path);
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to get the project name"));
- }
- }
- #endif
- }
- inline TSharedPtr<FWwiseTreeItem> SWaapiPicker::FindItemFromPath(const TSharedPtr<FWwiseTreeItem>& ParentItem, const FString& CurrentItemPath)
- {
- // We get the element to create in an array and loop over it to create them.
- TArray<FString> itemPathArray;
- CurrentItemPath.ParseIntoArray(itemPathArray, *WwiseWaapiHelper::BACK_SLASH);
- TSharedPtr<FWwiseTreeItem> PreviousItem = ParentItem;
- for (int i = 1; i < itemPathArray.Num(); i++)
- {
- TSharedPtr<FWwiseTreeItem> ChildItem = PreviousItem->GetChild(itemPathArray[i]);
- if (!ChildItem.IsValid())
- {
- return TSharedPtr<FWwiseTreeItem>(NULL);
- }
- PreviousItem = ChildItem;
- }
- return PreviousItem;
- }
- inline void SWaapiPicker::FindAndCreateItems(TSharedPtr<FWwiseTreeItem> CurrentItem)
- {
- LastExpandedItems.Add(CurrentItem->ItemId);
- FString LastPathVisited = CurrentItem->FolderPath;
- LastPathVisited.RemoveFromEnd(WwiseWaapiHelper::BACK_SLASH + CurrentItem->DisplayName);
- TSharedPtr<FWwiseTreeItem> RootItem = GetRootItem(CurrentItem->FolderPath);
- if (CurrentItem->FolderPath == RootItem->FolderPath)
- {
- return;
- }
- else if (LastPathVisited == RootItem->FolderPath)
- {
- CurrentItem->Parent = RootItem->Parent.Pin();
- RootItem->AddChild(CurrentItem);
- return;
- }
- TSharedPtr<FWwiseTreeItem> ParentItem = FindItemFromPath(RootItem, LastPathVisited);
- if (ParentItem.IsValid())
- {
- CurrentItem->Parent = ParentItem->Parent.Pin();
- ParentItem->AddChild(CurrentItem);
- }
- else
- {
- TSharedPtr<FJsonObject> Result;
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "PATH".
- if (CallWaapiGetInfoFrom(WwiseWaapiHelper::PATH, LastPathVisited, Result, {}))
- {
- // Recover the information from the Json object Result and use it to construct the tree item.
- TSharedPtr<FWwiseTreeItem> NewRootItem = ConstructWwiseTreeItem(Result->GetArrayField(WwiseWaapiHelper::RETURN)[0]);
- CurrentItem->Parent = NewRootItem;
- NewRootItem->AddChild(CurrentItem);
- FindAndCreateItems(NewRootItem);
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to get information from path : %s"), *LastPathVisited);
- }
- }
- }
- inline TSharedPtr<FWwiseTreeItem> SWaapiPicker::GetRootItem(const FString& InFullPath)
- {
- for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType; ++i)
- {
- if (InFullPath.StartsWith(RootItems[i]->FolderPath))
- {
- return RootItems[i];
- }
- }
- return {};
- }
- bool SWaapiPicker::CallWaapiGetInfoFrom(const FString& inFromField, const FString& inFromString, TSharedPtr<FJsonObject>& outJsonResult, const TArray<TransformStringField>& TransformFields)
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- return false;
- #if AK_SUPPORT_WAAPI
- // Construct the arguments Json object : Getting infos "from - a specific id/path"
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> from = MakeShared<FJsonObject>();
- from->SetArrayField(inFromField, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(inFromString) });
- Args->SetObjectField(WwiseWaapiHelper::FROM, from);
- // In case we would recover the children of the object that have the id : ID or the path : PATH, then we set isGetChildren to true.
- if (TransformFields.Num())
- {
- TArray<TSharedPtr<FJsonValue>> transform;
- for (auto TransformValue : TransformFields)
- {
- TSharedPtr<FJsonObject> insideTransform = MakeShared<FJsonObject>();
- TArray<TSharedPtr<FJsonValue>> JsonArray;
- for (auto TransformStringValueArg : TransformValue.valueStringArgs)
- {
- JsonArray.Add(MakeShared<FJsonValueString>(TransformStringValueArg));
- }
- for (auto TransformNumberValueArg : TransformValue.valueNumberArgs)
- {
- JsonArray.Add(MakeShared<FJsonValueNumber>(TransformNumberValueArg));
- }
- insideTransform->SetArrayField(TransformValue.keyArg, JsonArray);
- transform.Add(MakeShared<FJsonValueObject>(insideTransform));
- }
- Args->SetArrayField(WwiseWaapiHelper::TRANSFORM, transform);
- }
- }
- // Construct the Options Json object : Getting specific infos to construct the wwise tree item "id - name - type - childrenCount - path - parent"
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::ID),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::TYPE),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::CHILDREN_COUNT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PATH),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::WORKUNIT_TYPE),
- });
- // Request data from Wwise using WAAPI
- return waapiClient->Call(ak::wwise::core::object::get, Args, Options, outJsonResult);
- #endif
- return false;
- }
- TSharedPtr<FWwiseTreeItem> SWaapiPicker::ConstructWwiseTreeItem(const TSharedPtr<FJsonValue>& InJsonItem)
- {
- return ConstructWwiseTreeItem(InJsonItem->AsObject());
- }
- TSharedPtr<FWwiseTreeItem> SWaapiPicker::ConstructWwiseTreeItem(const TSharedPtr<FJsonObject>& ItemInfoObj)
- {
- static const FString ValidPaths[] = {
- EWwiseItemType::FolderNames[EWwiseItemType::Event],
- EWwiseItemType::FolderNames[EWwiseItemType::AuxBus],
- EWwiseItemType::FolderNames[EWwiseItemType::ActorMixer],
- EWwiseItemType::FolderNames[EWwiseItemType::GameParameter],
- EWwiseItemType::FolderNames[EWwiseItemType::State],
- EWwiseItemType::FolderNames[EWwiseItemType::Switch],
- EWwiseItemType::FolderNames[EWwiseItemType::Trigger],
- EWwiseItemType::FolderNames[EWwiseItemType::AcousticTexture],
- EWwiseItemType::FolderNames[EWwiseItemType::EffectShareSet]
- };
- static auto isValidPath = [](const FString& input, const auto& source) -> bool {
- for (const auto& item : source)
- {
- if (input.StartsWith(WwiseWaapiHelper::BACK_SLASH + item))
- {
- return true;
- }
- }
- return false;
- };
- const FString itemTypeString = ItemInfoObj->GetStringField(WwiseWaapiHelper::TYPE);
- auto itemType = EWwiseItemType::FromString(itemTypeString);
- if (itemType == EWwiseItemType::None)
- {
- return {};
- }
- const FString itemPath = ItemInfoObj->GetStringField(WwiseWaapiHelper::PATH);
- if (isValidPath(itemPath, ValidPaths))
- {
- const FString itemIdString = ItemInfoObj->GetStringField(WwiseWaapiHelper::ID);
- FGuid in_ItemId = FGuid::NewGuid();
- FGuid::ParseExact(itemIdString, EGuidFormats::DigitsWithHyphensInBraces, in_ItemId);
- const FString itemName = ItemInfoObj->GetStringField(WwiseWaapiHelper::NAME);
- if (itemName.IsEmpty())
- {
- return {};
- }
- const uint32_t ItemChildrenCount = ItemInfoObj->GetNumberField(WwiseWaapiHelper::CHILDREN_COUNT);
- if (itemType == EWwiseItemType::StandaloneWorkUnit)
- {
- FString WorkUnitType;
- if (ItemInfoObj->TryGetStringField(WwiseWaapiHelper::WORKUNIT_TYPE, WorkUnitType) && WorkUnitType == "FOLDER")
- {
- itemType = EWwiseItemType::PhysicalFolder;
- }
- }
- TSharedPtr<FWwiseTreeItem> treeItem = MakeShared<FWwiseTreeItem>(itemName, itemPath, nullptr, itemType, in_ItemId);
- if ((itemType != EWwiseItemType::Event) && (itemType != EWwiseItemType::Sound))
- {
- treeItem->ChildCountInWwise = ItemChildrenCount;
- }
- return treeItem;
- }
- return {};
- }
- /*------------------------------------------------------------------------------------
- Implementation
- ------------------------------------------------------------------------------------*/
- SWaapiPicker::SWaapiPicker() : CommandList(MakeShared<FUICommandList>())
- {
- AllowTreeViewDelegates = true;
- isPickerVisible = FAkWaapiClient::IsProjectLoaded();
- }
- void SWaapiPicker::RemoveClientCallbacks()
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (waapiClient == nullptr)
- return;
- if (ProjectLoadedHandle.IsValid())
- {
- waapiClient->OnProjectLoaded.Remove(ProjectLoadedHandle);
- ProjectLoadedHandle.Reset();
- }
- if (ConnectionLostHandle.IsValid())
- {
- waapiClient->OnConnectionLost.Remove(ConnectionLostHandle);
- ConnectionLostHandle.Reset();
- }
- UnsubscribeWaapiCallbacks();
- }
- SWaapiPicker::~SWaapiPicker()
- {
- RootItems.Empty();
- RemoveClientCallbacks();
- if (auto waapiClient = FAkWaapiClient::Get())
- {
- waapiClient->OnClientBeginDestroy.Remove(ClientBeginDestroyHandle);
- }
- StopAndDestroyAllTransports();
- }
- void SWaapiPicker::Construct(const FArguments& InArgs)
- {
- OnDragDetected = InArgs._OnDragDetected;
- OnSelectionChanged = InArgs._OnSelectionChanged;
- OnGenerateSoundBanksClicked = InArgs._OnGenerateSoundBanksClicked;
- OnRefreshClicked = InArgs._OnRefreshClicked;
- OnImportWwiseAssetsClicked = InArgs._OnImportWwiseAssetsClicked;
- CallWaapiGetProjectNamePath(ProjectName, ProjectFolder);
- bRestrictContextMenu = InArgs._RestrictContextMenu;
- if (InArgs._FocusSearchBoxWhenOpened)
- {
- RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateSP(this, &SWaapiPicker::SetFocusPostConstruct));
- }
- FGenericCommands::Register();
- FWaapiPickerViewCommands::Register();
- CreateWaapiPickerCommands();
- SearchBoxFilter = MakeShared<StringFilter>(StringFilter::FItemToStringArray::CreateSP(this, &SWaapiPicker::PopulateSearchStrings));
- SearchBoxFilter->OnChanged().AddSP(this, &SWaapiPicker::FilterUpdated);
- if (auto* settings = GetMutableDefault<UAkSettings>())
- {
- settings->bRequestRefresh = false;
- }
-
- ChildSlot
- [
- SNew(SBorder)
- .Padding(4)
- .BorderImage(FAkAudioStyle::GetBrush("AudiokineticTools.GroupBorder"))
- [
- SNew(SOverlay)
- // Picker
- + SOverlay::Slot()
- .VAlign(VAlign_Fill)
- [
- SNew(SVerticalBox)
- .Visibility(this, &SWaapiPicker::isPickerAllowed)
- // Search
- + SVerticalBox::Slot()
- .AutoHeight()
- .Padding(0, 1, 0, 3)
- [
- SNew(SHorizontalBox)
- + SHorizontalBox::Slot()
- .AutoWidth()
- [
- InArgs._SearchContent.Widget
- ]
- + SHorizontalBox::Slot()
- .FillWidth(1.0f)
- [
- SAssignNew(SearchBoxPtr,SSearchBox)
- .HintText( LOCTEXT( "WaapiPickerSearchHint", "Search Wwise Item" ) )
- .ToolTipText(LOCTEXT("WaapiPickerSearchTooltip", "Type here to search for a Wwise asset"))
- .OnTextChanged( this, &SWaapiPicker::OnSearchBoxChanged )
- .SelectAllTextWhenFocused(false)
- .DelayChangeNotificationsWhileTyping(true)
- ]
- ]
- // Tree title
- +SVerticalBox::Slot()
- .AutoHeight()
- [
- SNew(SHorizontalBox)
- + SHorizontalBox::Slot()
- .AutoWidth()
- .Padding(3.0f)
- [
- SNew(SImage)
- .Image(FAkAudioStyle::GetBrush(EWwiseItemType::Project))
- ]
- + SHorizontalBox::Slot()
- .AutoWidth()
- .Padding(0,0,3,0)
- [
- SNew(STextBlock)
- .Font(FAkAudioStyle::GetFontStyle("ContentBrowser.SourceTitleFont") )
- .Text( this, &SWaapiPicker::GetProjectName )
- .Visibility(InArgs._ShowTreeTitle ? EVisibility::Visible : EVisibility::Collapsed)
- ]
- + SHorizontalBox::Slot()
- .FillWidth(1)
- [
- SNew( SSpacer )
- ]
- + SHorizontalBox::Slot()
- .AutoWidth()
- [
- SNew(SButton)
- .Text(LOCTEXT("AkPickerRefresh", "Refresh"))
- .OnClicked(this, &SWaapiPicker::OnRefreshButtonClicked)
- ]
- + SHorizontalBox::Slot()
- .AutoWidth()
- [
- SNew(SButton)
- .Text(LOCTEXT("AkPickerGenerateSoundData", "Generate SoundBanks..."))
- .OnClicked(this, &SWaapiPicker::OnGenerateSoundBanksButtonClicked)
- .Visibility(InArgs._ShowGenerateSoundBanksButton ? EVisibility::Visible : EVisibility::Collapsed)
- ]
- ]
- // Separator
- +SVerticalBox::Slot()
- .AutoHeight()
- .Padding(0, 0, 0, 1)
- [
- SNew(SSeparator)
- .Visibility( ( InArgs._ShowSeparator) ? EVisibility::Visible : EVisibility::Collapsed )
- ]
-
- // Tree
- +SVerticalBox::Slot()
- .FillHeight(1.f)
- [
- SAssignNew(TreeViewPtr, STreeView< TSharedPtr<FWwiseTreeItem> >)
- .TreeItemsSource(&RootItems)
- .OnGenerateRow( this, &SWaapiPicker::GenerateRow )
- //.OnItemScrolledIntoView( this, &SPathView::TreeItemScrolledIntoView )
- .ItemHeight(18)
- .SelectionMode(InArgs._SelectionMode)
- .OnSelectionChanged(this, &SWaapiPicker::TreeSelectionChanged)
- .OnExpansionChanged(this, &SWaapiPicker::TreeExpansionChanged)
- .OnGetChildren( this, &SWaapiPicker::GetChildrenForTree )
- .OnContextMenuOpening(this, &SWaapiPicker::MakeWaapiPickerContextMenu)
- .ClearSelectionOnClick(false)
- ]
- ]
- // Empty Picker
- + SOverlay::Slot()
- .VAlign(VAlign_Center)
- .HAlign(HAlign_Center)
- [
- SNew(SVerticalBox)
- + SVerticalBox::Slot()
- .VAlign(VAlign_Center)
- .HAlign(HAlign_Center)
- .AutoHeight()
- [
- SNew(STextBlock)
- .Visibility(this, &SWaapiPicker::isWarningVisible)
- .AutoWrapText(true)
- .Justification(ETextJustify::Center)
- .Text(this, &SWaapiPicker::GetWarningText)
- ]
- + SVerticalBox::Slot()
- .VAlign(VAlign_Center)
- .HAlign(HAlign_Center)
- .AutoHeight()
- [
- SNew(SHyperlink)
- .Visibility(this, &SWaapiPicker::isWarningVisible)
- .Text(LOCTEXT("WaapiDucumentation", "For more informaton, please Visit Waapi Documentation."))
- .ToolTipText(LOCTEXT("WaapiDucumentationTooltip", "Opens Waapi documentation in a new browser window"))
- .OnNavigate_Lambda([] { FPlatformProcess::LaunchURL(*FString("https://www.audiokinetic.com/library/?source=SDK&id=waapi.html"), nullptr, nullptr); })
- ]
- ]
- ]
- ];
- ConstructTree();
- ExpandFirstLevel();
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- return;
- ProjectLoadedHandle = waapiClient->OnProjectLoaded.AddSP(this, &SWaapiPicker::OnProjectLoadedCallback);
- ConnectionLostHandle = waapiClient->OnConnectionLost.AddSP(this, &SWaapiPicker::OnConnectionLostCallback);
- ClientBeginDestroyHandle = waapiClient->OnClientBeginDestroy.AddSP(this, &SWaapiPicker::RemoveClientCallbacks);
- SubscribeWaapiCallbacks();
- }
- void SWaapiPicker::OnProjectLoadedCallback()
- {
- /* Construct the tree when we have the same project */
- isPickerVisible = true;
- isModalActiveInWwise = false;
- SubscribeWaapiCallbacks();
- CallWaapiGetProjectNamePath(ProjectName, ProjectFolder);
- ConstructTree();
- }
- void SWaapiPicker::OnConnectionLostCallback()
- {
- /* Empty the tree when we have different projects */
- isPickerVisible = false;
- UnsubscribeWaapiCallbacks();
- ConstructTree();
- }
- EVisibility SWaapiPicker::isPickerAllowed() const
- {
- return (isPickerVisible && !isModalActiveInWwise) ? EVisibility::Visible : EVisibility::Hidden;
- }
- EVisibility SWaapiPicker::isWarningVisible() const
- {
- return (isPickerVisible && !isModalActiveInWwise) ? EVisibility::Hidden : EVisibility::Visible;
- }
- FText SWaapiPicker::GetWarningText() const
- {
- const FText NotConnected = LOCTEXT("EmptyWaapiTree", "Could not establish a WAAPI connection; WAAPI picker is disabled. Please enable WAAPI in your Wwise settings, or use the Wwise Picker.");
- return isModalActiveInWwise ? ModalWarning : NotConnected;
- }
- void SWaapiPicker::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
- {
- auto* waapiClient = FAkWaapiClient::Get();
- auto AkSettings = GetMutableDefault<UAkSettings>();
- bool NeedRefresh = AkSettings->bRequestRefresh;
- if (isModalActiveInWwise && waapiClient)
- {
- #if AK_SUPPORT_WAAPI
- TSharedRef<FJsonObject> Args = MakeShareable(new FJsonObject());
- TSharedRef<FJsonObject> Options = MakeShareable(new FJsonObject());
- TSharedPtr<FJsonObject> Result = MakeShareable(new FJsonObject());
- waapiClient->Call(ak::wwise::core::getInfo, Args, Options, Result, 10, true);
- if (Result->GetStringField(TEXT("uri")) != TEXT("ak.wwise.locked"))
- {
- NeedRefresh = true;
- isModalActiveInWwise = false;
- }
- #endif
- }
- if (NeedRefresh)
- {
- ConstructTree();
- AkSettings->bRequestRefresh = false;
- }
- }
- FText SWaapiPicker::GetProjectName() const
- {
- return FText::FromString(ProjectName);
- }
- FReply SWaapiPicker::OnRefreshButtonClicked()
- {
- ConstructTree();
- OnRefreshClicked.ExecuteIfBound();
- return FReply::Handled();
- }
- FReply SWaapiPicker::OnGenerateSoundBanksButtonClicked()
- {
- OnGenerateSoundBanksClicked.ExecuteIfBound();
- return FReply::Handled();
- }
- void SWaapiPicker::ConstructTree()
- {
- if (FAkWaapiClient::IsProjectLoaded())
- {
- if (ConstructTreeTask.IsValid() && !ConstructTreeTask->IsComplete())
- {
- if (auto AkSettings = GetMutableDefault<UAkSettings>())
- {
- AkSettings->bRequestRefresh = true;
- }
- return;
- }
- FString CurrentFilterText = SearchBoxFilter.IsValid() ? SearchBoxFilter->GetRawFilterText().ToString() : TEXT("");
- if (!CurrentFilterText.IsEmpty())
- {
- FilterUpdated();
- return;
- }
- ConstructTreeTask = FFunctionGraphTask::CreateAndDispatchWhenReady([sharedThis = SharedThis(this)]
- {
- {
- FScopeLock autoLock(&sharedThis->RootItemsLock);
- sharedThis->RootItems.Empty(EWwiseItemType::LastWwiseBrowserType - EWwiseItemType::Event + 1);
- }
- auto PopulateTask = FFunctionGraphTask::CreateAndDispatchWhenReady([sharedThis]
- {
- for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType; ++i)
- {
- FGuid in_ItemId = FGuid::NewGuid();
- TSharedPtr<FJsonObject> Result;
- uint32_t ItemChildrenCount = 0;
- FString Path = WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[i];
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "PATH".
- if (sharedThis->CallWaapiGetInfoFrom(WwiseWaapiHelper::PATH, Path, Result, {}))
- {
- // Recover the information from the Json object Result and use it to get the item id.
- const TSharedPtr<FJsonObject>& ItemInfoObj = Result->GetArrayField(WwiseWaapiHelper::RETURN)[0]->AsObject();
- const FString ItemIdString = ItemInfoObj->GetStringField(WwiseWaapiHelper::ID);
- Path = ItemInfoObj->GetStringField(WwiseWaapiHelper::PATH);
- ItemChildrenCount = ItemInfoObj->GetNumberField(WwiseWaapiHelper::CHILDREN_COUNT);
- FGuid::ParseExact(ItemIdString, EGuidFormats::DigitsWithHyphensInBraces, in_ItemId);
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to get information from id : %s"), *Path);
- if (Result->GetStringField(TEXT("uri")) == TEXT("ak.wwise.locked"))
- {
- UE_LOG(LogAkAudio, Warning, TEXT("%s"), *ModalWarning.ToString());
- sharedThis->isModalActiveInWwise = true;
- }
- else if (auto AkSettings = GetMutableDefault<UAkSettings>())
- {
- AkSettings->bRequestRefresh = true;
- }
- return;
- }
- // Create a new tree item and add it the root list.
- TSharedPtr<FWwiseTreeItem> NewRootParent = MakeShared<FWwiseTreeItem>(EWwiseItemType::BrowserDisplayNames[i], Path, nullptr, EWwiseItemType::PhysicalFolder, in_ItemId);
- NewRootParent->ChildCountInWwise = ItemChildrenCount;
- {
- FScopeLock autoLock(&sharedThis->RootItemsLock);
- sharedThis->RootItems.Add(NewRootParent);
- }
- }
- }, GET_STATID(STAT_WaapiPickerConstructTree), nullptr, ENamedThreads::AnyThread);
- FTaskGraphInterface::Get().WaitUntilTaskCompletes(PopulateTask);
- FFunctionGraphTask::CreateAndDispatchWhenReady( [sharedThis]
- {
- sharedThis->AllowTreeViewDelegates = true;
- sharedThis->ExpandFirstLevel();
- sharedThis->RestoreTreeExpansion(sharedThis->RootItems);
- sharedThis->TreeViewPtr->RequestTreeRefresh();
- }, GET_STATID(STAT_WaapiPickerConstructTree), nullptr, ENamedThreads::GameThread);
- }, GET_STATID(STAT_WaapiPickerConstructTree), nullptr, ENamedThreads::AnyThread);
- }
- }
- void SWaapiPicker::ExpandFirstLevel()
- {
- // Expand root items and first-level work units.
- for (int32 i = 0; i < RootItems.Num(); i++)
- {
- TreeViewPtr->SetItemExpansion(RootItems[i], true);
- }
- }
- void SWaapiPicker::ExpandParents(TSharedPtr<FWwiseTreeItem> Item)
- {
- if (Item->Parent.IsValid())
- {
- ExpandParents(Item->Parent.Pin());
- TreeViewPtr->SetItemExpansion(Item->Parent.Pin(), true);
- }
- }
- TSharedRef<ITableRow> SWaapiPicker::GenerateRow(TSharedPtr<FWwiseTreeItem> TreeItem, const TSharedRef<STableViewBase>& OwnerTable)
- {
- check(TreeItem.IsValid());
- EVisibility RowVisibility = TreeItem->IsVisible ? EVisibility::Visible : EVisibility::Collapsed;
- TSharedPtr<ITableRow> NewRow = SNew(STableRow< TSharedPtr<FWwiseTreeItem> >, OwnerTable)
- .OnDragDetected(this, &SWaapiPicker::HandleOnDragDetected)
- .Visibility(RowVisibility)
- [
- SNew(SWaapiPickerRow)
- .WaapiPickerItem(TreeItem)
- .HighlightText(this, &SWaapiPicker::GetHighlightText)
- .IsSelected(this, &SWaapiPicker::IsTreeItemSelected, TreeItem)
- ];
- TreeItem->TreeRow = NewRow;
- return NewRow.ToSharedRef();
- }
- void SWaapiPicker::GetChildrenForTree(TSharedPtr< FWwiseTreeItem > TreeItem, TArray< TSharedPtr<FWwiseTreeItem> >& OutChildren)
- {
- // In case the item is "unexpanded" and have children (in the Wwise tree), we need to add a default item to show the arrow that says, this item have children.
- FString CurrentFilterText = SearchBoxFilter->GetRawFilterText().ToString();
- if (!TreeItem->ChildCountInWwise)
- {
- // This is useful in case when the item contains elements that are being moved to an other path and the item
- // has no longer children and was expanded, so we need to remove it form the expansion items list.
- LastExpandedItems.Remove(TreeItem->ItemId);
- }
- else if (CurrentFilterText.IsEmpty())
- {
- if (!LastExpandedItems.Contains(TreeItem->ItemId))
- {
- TreeItem->EmptyChildren();
- TSharedPtr<FWwiseTreeItem> emptyTreeItem = MakeShared<FWwiseTreeItem>(WwiseWaapiHelper::NAME, WwiseWaapiHelper::PATH, nullptr, EWwiseItemType::PhysicalFolder, FGuid::NewGuid());
- TreeItem->AddChild(emptyTreeItem);
- }
- else
- {
- // Update the item expansion to be visible in the tree, since it is being expanded by the user.
- TreeViewPtr->SetItemExpansion(TreeItem, true);
- }
- }
- OutChildren = TreeItem->GetChildren();
- }
- FReply SWaapiPicker::HandleOnDragDetected(const FGeometry& Geometry, const FPointerEvent& MouseEvent)
- {
- // Refresh the contents
- if (OnDragDetected.IsBound())
- {
- return OnDragDetected.Execute(Geometry, MouseEvent);
- }
- return FReply::Unhandled();
- }
- void SWaapiPicker::PopulateSearchStrings(const FString& FolderName, OUT TArray< FString >& OutSearchStrings) const
- {
- OutSearchStrings.Add(FolderName);
- }
- void SWaapiPicker::OnSearchBoxChanged(const FText& InSearchText)
- {
- SearchBoxFilter->SetRawFilterText(InSearchText);
- }
- FText SWaapiPicker::GetHighlightText() const
- {
- return SearchBoxFilter->GetRawFilterText();
- }
- void SWaapiPicker::FilterUpdated()
- {
- FScopedSlowTask SlowTask(2.f, LOCTEXT("AK_PopulatingPicker", "Populating Waapi Picker..."));
- SlowTask.MakeDialog();
- if (RootItems.Num())
- {
- ApplyFilter();
- }
- TreeViewPtr->RequestTreeRefresh();
- }
- void SWaapiPicker::SetItemVisibility(TSharedPtr<FWwiseTreeItem> Item, bool IsVisible)
- {
- if (!Item.IsValid())
- return;
- if (IsVisible)
- {
- // Propagate visibility to parents.
- SetItemVisibility(Item->Parent.Pin(), IsVisible);
- }
- Item->IsVisible = IsVisible;
- if (Item->TreeRow.IsValid())
- {
- TSharedRef<SWidget> wid = Item->TreeRow.Pin()->AsWidget();
- wid->SetVisibility(IsVisible ? EVisibility::Visible : EVisibility::Collapsed);
- }
- }
- void SWaapiPicker::ApplyFilter()
- {
- for (int i = EWwiseItemType::Event; i <= EWwiseItemType::LastWwiseBrowserType; ++i)
- {
- RootItems[i]->EmptyChildren();
- }
- static TSet<FGuid> LastExpandedItemsBeforFilter;
- AllowTreeViewDelegates = false;
- FString CurrentFilterText = SearchBoxFilter->GetRawFilterText().ToString();
- if (CurrentFilterText.IsEmpty())
- {
- // Recover the last expanded items before filtering.
- LastExpandedItems.Empty();
- LastExpandedItems = LastExpandedItemsBeforFilter;
- LastExpandedItemsBeforFilter.Empty();
- AllowTreeViewDelegates = true;
- ConstructTree();
- return;
- }
- if (!LastExpandedItemsBeforFilter.Num())
- {
- // We preserve the last expanded items to re-expand the tree as it was in non filtering mode.
- LastExpandedItemsBeforFilter = LastExpandedItems;
- LastExpandedItems.Empty();
- }
- TSharedPtr<FJsonObject> Result;
- if (CallWaapiGetInfoFrom(WwiseWaapiHelper::SEARCH, CurrentFilterText, Result,
- {
- { WwiseWaapiHelper::WHERE , { WwiseWaapiHelper::NAMECONTAINS, CurrentFilterText }, {} },
- { WwiseWaapiHelper::RANGE, {}, { 0, 2000 * CurrentFilterText.Len() } }
- }))
- {
- // Recover the information from the Json object Result and use it to construct the tree item.
- TArray<TSharedPtr<FJsonValue>> SearchResultArray = Result->GetArrayField(WwiseWaapiHelper::RETURN);
- if (SearchResultArray.Num())
- {
- // The map contains each path and the correspondent object of the search result.
- TMap < FString, TSharedPtr<FWwiseTreeItem>> SearchedResultTreeItem;
- for (int i = 0; i < SearchResultArray.Num(); i++)
- {
- // Fill the map with the path-object elements.
- TSharedPtr<FWwiseTreeItem> NewRootChild = ConstructWwiseTreeItem(SearchResultArray[i]);
- if (NewRootChild.IsValid())
- {
- FindAndCreateItems(NewRootChild);
- }
- }
- }
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to get information from item search : %s"), *CurrentFilterText);
- }
- RestoreTreeExpansion(RootItems);
- AllowTreeViewDelegates = true;
- }
- void SWaapiPicker::RestoreTreeExpansion(const TArray< TSharedPtr<FWwiseTreeItem> >& Items)
- {
- for (int i = 0; i < Items.Num(); i++)
- {
- if (LastExpandedItems.Contains(Items[i]->ItemId))
- {
- TreeViewPtr->SetItemExpansion(Items[i], true);
- }
- RestoreTreeExpansion(Items[i]->GetChildren());
- }
- }
- void SWaapiPicker::TreeSelectionChanged(TSharedPtr< FWwiseTreeItem > TreeItem, ESelectInfo::Type /*SelectInfo*/)
- {
- if (AllowTreeViewDelegates)
- {
- auto& SelectedItems = GetSelectedItems();
- LastSelectedItems.Empty();
- for (int32 ItemIdx = 0; ItemIdx < SelectedItems.Num(); ++ItemIdx)
- {
- auto& Item = SelectedItems[ItemIdx];
- if (Item.IsValid())
- {
- LastSelectedItems.Add(Item->ItemId);
- }
- }
- const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
- if (AkSettingsPerUser && AkSettingsPerUser->AutoSyncSelection)
- {
- HandleFindWwiseItemInProjectExplorerCommandExecute();
- }
- OnSelectionChanged.ExecuteIfBound(TreeItem, ESelectInfo::OnMouseClick);
- }
- }
- void SWaapiPicker::TreeExpansionChanged(TSharedPtr< FWwiseTreeItem > TreeItem, bool bIsExpanded)
- {
- if (!AllowTreeViewDelegates)
- {
- if (bIsExpanded)
- TreeItem->SortChildren();
- return;
- }
- // If the item is not expanded we don't need to request the server to get any information(the children are hidden).
- if (!bIsExpanded)
- {
- LastExpandedItems.Remove(TreeItem->ItemId);
- return;
- }
- LastExpandedItems.Add(TreeItem->ItemId);
- FString CurrentFilterText = SearchBoxFilter->GetRawFilterText().ToString();
- if (!CurrentFilterText.IsEmpty())
- return;
- const FString itemIdStringField = TreeItem->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
- FFunctionGraphTask::CreateAndDispatchWhenReady([sharedThis = SharedThis(this), TreeItem, itemIdStringField]
- {
- TSharedPtr<FJsonObject> Result;
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "ID".
- if (!sharedThis->CallWaapiGetInfoFrom(WwiseWaapiHelper::ID, itemIdStringField, Result, { { WwiseWaapiHelper::SELECT, { WwiseWaapiHelper::CHILDREN }, {} } }))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to get information from id : %s"), *itemIdStringField);
- return;
- }
- FFunctionGraphTask::CreateAndDispatchWhenReady([sharedThis, Result, TreeItem]
- {
- // The tree view might have been destroyed between scheduling and running this task
- // Recover the information from the Json object Result and use it to construct the tree item.
- TArray<TSharedPtr<FJsonValue>> StructJsonArray = Result->GetArrayField(WwiseWaapiHelper::RETURN);
- /** If the item have just one child and we are expanding it, this means that we need to construct the children list.
- * In case the the number of children gotten form Wwise is not the same of the item, this means that there is some children added/removed,
- * so we also need to construct the new list.
- */
- if ((TreeItem->GetChildren().Num() == 1) || (TreeItem->GetChildren().Num() != StructJsonArray.Num()))
- {
- TreeItem->EmptyChildren();
- for (int i = 0; i < StructJsonArray.Num(); i++)
- {
- TSharedPtr<FWwiseTreeItem> NewRootChild = sharedThis->ConstructWwiseTreeItem(StructJsonArray[i]);
- if (NewRootChild.IsValid())
- {
- TreeItem->AddChild(NewRootChild);
- }
- }
- TreeItem->SortChildren();
- sharedThis->TreeViewPtr->RequestTreeRefresh();
- }
- }, GET_STATID(STAT_WaapiPickerTreeExpansionChanged), nullptr, ENamedThreads::GameThread);
- }, GET_STATID(STAT_WaapiPickerTreeExpansionChanged));
- }
- bool SWaapiPicker::IsTreeItemSelected(TSharedPtr<FWwiseTreeItem> TreeItem) const
- {
- return TreeViewPtr->IsItemSelected(TreeItem);
- }
- TSharedPtr<SWidget> SWaapiPicker::MakeWaapiPickerContextMenu()
- {
- const FWaapiPickerViewCommands& Commands = FWaapiPickerViewCommands::Get();
- // Build up the menu
- FMenuBuilder MenuBuilder(true, CommandList);
- {
- MenuBuilder.BeginSection("WaapiPickerCreate", LOCTEXT("MenuHeader", "WaapiPicker"));
- {
- MenuBuilder.AddMenuEntry(Commands.RequestPlayWwiseItem);
- MenuBuilder.AddMenuEntry(Commands.RequestStopAllWwiseItem);
- }
- MenuBuilder.EndSection();
- MenuBuilder.BeginSection("WaapiPickerEdit", LOCTEXT("EditMenuHeader", "Edit"));
- {
- MenuBuilder.AddMenuEntry(Commands.RequestRenameWwiseItem);
- MenuBuilder.AddMenuEntry(Commands.RequestDeleteWwiseItem);
- }
- MenuBuilder.EndSection();
- if (!bRestrictContextMenu)
- {
- MenuBuilder.BeginSection("WaapiPickerExplore", LOCTEXT("ExploreMenuHeader", "Explore"));
- {
- MenuBuilder.AddMenuEntry(Commands.RequestExploreWwiseItem);
- MenuBuilder.AddMenuEntry(Commands.RequestFindInProjectExplorerWwisetem);
- }
- MenuBuilder.EndSection();
- }
- MenuBuilder.BeginSection("WaapiPickerRefreshAll");
- {
- MenuBuilder.AddMenuEntry(Commands.RequestRefreshWaapiPicker);
- }
- MenuBuilder.EndSection();
- MenuBuilder.BeginSection("WaapiPickerImport");
- {
- MenuBuilder.AddMenuEntry(Commands.RequestImportWwiseItem);
- }
- MenuBuilder.EndSection();
- }
- return MenuBuilder.MakeWidget();
- }
- void SWaapiPicker::CreateWaapiPickerCommands()
- {
- const FWaapiPickerViewCommands& Commands = FWaapiPickerViewCommands::Get();
- FUICommandList& ActionList = *CommandList;
- // Action for rename a Wwise item.
- ActionList.MapAction(Commands.RequestRenameWwiseItem,
- FExecuteAction::CreateRaw(this, &SWaapiPicker::HandleRenameWwiseItemCommandExecute),
- FCanExecuteAction::CreateRaw(this, &SWaapiPicker::HandleRenameWwiseItemCommandCanExecute));
- // Action to play a Wwise item (event).
- ActionList.MapAction(Commands.RequestPlayWwiseItem,
- FExecuteAction::CreateRaw(this, &SWaapiPicker::HandlePlayWwiseItemCommandExecute),
- FCanExecuteAction::CreateRaw(this, &SWaapiPicker::HandlePlayWwiseItemCommandCanExecute));
- // Action to stop all playing Wwise item (event).
- ActionList.MapAction(Commands.RequestStopAllWwiseItem,
- FExecuteAction::CreateSP(this, &SWaapiPicker::StopAndDestroyAllTransports));
- // Action for rename a Wwise item.
- ActionList.MapAction(Commands.RequestDeleteWwiseItem,
- FExecuteAction::CreateRaw(this, &SWaapiPicker::HandleDeleteWwiseItemCommandExecute),
- FCanExecuteAction::CreateRaw(this, &SWaapiPicker::HandleDeleteWwiseItemCommandCanExecute));
- // Explore an item in the containing folder.
- ActionList.MapAction(Commands.RequestExploreWwiseItem,
- FExecuteAction::CreateRaw(this, &SWaapiPicker::HandleExploreWwiseItemCommandExecute),
- FCanExecuteAction::CreateRaw(this, &SWaapiPicker::HandleWwiseCommandCanExecute));
- // Explore an item in the containing folder.
- ActionList.MapAction(Commands.RequestFindInProjectExplorerWwisetem,
- FExecuteAction::CreateRaw(this, &SWaapiPicker::HandleFindWwiseItemInProjectExplorerCommandExecute),
- FCanExecuteAction::CreateRaw(this, &SWaapiPicker::HandleWwiseCommandCanExecute));
- // Action for refresh the Waapi Picker.
- ActionList.MapAction(Commands.RequestRefreshWaapiPicker,
- FExecuteAction::CreateSP(this, &SWaapiPicker::HandleRefreshWaapiPickerCommandExecute));
- // Action for undo last action in the Waapi Picker.
- ActionList.MapAction(
- FGenericCommands::Get().Undo,
- FExecuteAction::CreateSP(this, &SWaapiPicker::HandleUndoWaapiPickerCommandExecute));
- // Action for redo last action in the Waapi Picker.
- ActionList.MapAction(
- FGenericCommands::Get().Redo,
- FExecuteAction::CreateSP(this, &SWaapiPicker::HandleRedoWaapiPickerCommandExecute));
- // Action for importing the selected items from the Waapi Picker.
- ActionList.MapAction(
- Commands.RequestImportWwiseItem,
- FExecuteAction::CreateSP(this, &SWaapiPicker::HandleImportWwiseItemCommandExecute));
- }
- bool SWaapiPicker::HandleRenameWwiseItemCommandCanExecute() const
- {
- auto& SelectedItems = GetSelectedItems();
- return SelectedItems.Num() == 1 && SelectedItems[0]->IsNotOfType({ EWwiseItemType::PhysicalFolder, EWwiseItemType::StandaloneWorkUnit, EWwiseItemType::NestedWorkUnit });
- }
- void SWaapiPicker::HandleRenameWwiseItemCommandExecute() const
- {
- auto& SelectedItems = GetSelectedItems();
- if (SelectedItems.Num())
- {
- TSharedPtr<ITableRow> TableRow = TreeViewPtr->WidgetFromItem(SelectedItems[0]);
- // If the Wwise item is selected but not visible, we scroll it into the view.
- if (!TableRow.IsValid())
- {
- TreeViewPtr->RequestScrollIntoView(SelectedItems[0]);
- return;
- }
- // Get the right Row to enter in editing mode.
- TSharedPtr<STableRow< TSharedPtr<FWwiseTreeItem>> > TableRowItem = StaticCastSharedPtr<STableRow< TSharedPtr<FWwiseTreeItem>>>(TableRow);
- if (TableRowItem.IsValid())
- {
- TSharedPtr<SWidget> RowContent = TableRowItem->GetContent();
- TSharedPtr<SWaapiPickerRow> ItemWidget = StaticCastSharedPtr<SWaapiPickerRow>(RowContent);
- if (ItemWidget.IsValid())
- {
- ItemWidget->EnterEditingMode();
- }
- }
- }
- }
- bool SWaapiPicker::HandlePlayWwiseItemCommandCanExecute() const
- {
- auto& SelectedItems = GetSelectedItems();
- if (SelectedItems.Num() == 0)
- return false;
- for (int32 i = 0; i < SelectedItems.Num(); ++i)
- {
- if (SelectedItems[i]->IsNotOfType({ EWwiseItemType::Event, EWwiseItemType::Sound, EWwiseItemType::BlendContainer, EWwiseItemType::SwitchContainer, EWwiseItemType::RandomSequenceContainer }))
- return false;
- }
- return true;
- }
- int32 SWaapiPicker::CreateTransport(const FGuid& in_ItemId)
- {
- const FString itemIdStringField = in_ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
- TSharedPtr<FJsonObject> Result;
- int32 transportID = -1;
- #if AK_SUPPORT_WAAPI
- if (SWaapiPickerRow::CallWaapiExecuteUri(ak::wwise::core::transport::create, { { WwiseWaapiHelper::OBJECT, itemIdStringField } }, Result))
- {
- transportID = Result->GetIntegerField(WwiseWaapiHelper::TRANSPORT);
- uint64 subscriptionID = SubscribeToTransportStateChanged(transportID);
- ItemToTransport.Add(in_ItemId, TransportInfo(transportID, subscriptionID));
- }
- #endif
- return transportID;
- }
- void SWaapiPicker::DestroyTransport(const FGuid& in_itemID)
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- return;
- if (!ItemToTransport.Contains(in_itemID))
- return;
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetNumberField(WwiseWaapiHelper::TRANSPORT, ItemToTransport[in_itemID].TransportID);
- TSharedPtr<FJsonObject> Result;
- if (ItemToTransport[in_itemID].SubscriptionID != 0)
- waapiClient->Unsubscribe(ItemToTransport[in_itemID].SubscriptionID, Result);
- #if AK_SUPPORT_WAAPI
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- if (waapiClient->Call(ak::wwise::core::transport::destroy, Args, Options, Result))
- ItemToTransport.Remove(in_itemID);
- #endif
- }
- void SWaapiPicker::TogglePlayStop(int32 in_transportID)
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to connect to localhost"));
- return;
- }
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::ACTION, WwiseWaapiHelper::PLAYSTOP);
- Args->SetNumberField(WwiseWaapiHelper::TRANSPORT, in_transportID);
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- if (!waapiClient->Call(ak::wwise::core::transport::executeAction, Args, Options, Result))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to trigger playback"));
- }
- #endif
- }
- void SWaapiPicker::StopTransport(int32 in_transportID)
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- return;
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::ACTION, WwiseWaapiHelper::STOP);
- Args->SetNumberField(WwiseWaapiHelper::TRANSPORT, in_transportID);
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- if (!waapiClient->Call(ak::wwise::core::transport::executeAction, Args, Options, Result))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Cannot stop event."));
- }
- #endif
- }
- void SWaapiPicker::HandleStateChanged(TSharedPtr<FJsonObject> in_UEJsonObject)
- {
- const FString newState = in_UEJsonObject->GetStringField(WwiseWaapiHelper::STATE);
- FGuid itemID;
- FGuid::Parse(in_UEJsonObject->GetStringField(WwiseWaapiHelper::OBJECT), itemID);
- const int32 transportID = in_UEJsonObject->GetNumberField(WwiseWaapiHelper::TRANSPORT);
- if (newState == WwiseWaapiHelper::STOPPED)
- {
- DestroyTransport(itemID);
- }
- else if (newState == WwiseWaapiHelper::PLAYING && !ItemToTransport.Contains(itemID))
- {
- ItemToTransport.Add(itemID, TransportInfo(transportID, 0));
- }
- }
- uint64 SWaapiPicker::SubscribeToTransportStateChanged(int32 TransportID)
- {
- auto WaapiClient = FAkWaapiClient::Get();
- if (!WaapiClient)
- return 0;
- auto WampEventCallback = WampEventCallback::CreateLambda(
- [sharedThis = SharedThis(this)](uint64_t ID, TSharedPtr<FJsonObject> UEJsonObject)
- {
- AsyncTask(ENamedThreads::GameThread, [sharedThis, UEJsonObject]
- {
- sharedThis->HandleStateChanged(UEJsonObject);
- });
- });
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetNumberField(WwiseWaapiHelper::TRANSPORT, TransportID);
- TSharedPtr<FJsonObject> OutJsonResult;
- uint64 SubscriptionID = 0;
- #if AK_SUPPORT_WAAPI
- WaapiClient->Subscribe(ak::wwise::core::transport::stateChanged, Options, WampEventCallback, SubscriptionID, OutJsonResult);
- #endif
- return SubscriptionID;
- }
- void SWaapiPicker::HandlePlayWwiseItemCommandExecute()
- {
- auto& SelectedItems = GetSelectedItems();
- // Loop to play all selected items.
- for (int32 i = 0; i < SelectedItems.Num(); ++i)
- {
- const FGuid& ItemId = SelectedItems[i]->ItemId;
- int32 transportID = -1;
- if (ItemToTransport.Contains(ItemId))
- {
- transportID = ItemToTransport[ItemId].TransportID;
- }
- else
- {
- transportID = CreateTransport(ItemId);
- }
- TogglePlayStop(transportID);
- }
- }
- void SWaapiPicker::StopAndDestroyAllTransports()
- {
- for (auto iter = ItemToTransport.CreateIterator(); iter; ++iter)
- {
- StopTransport(iter->Value.TransportID);
- DestroyTransport(iter->Key);
- }
- ItemToTransport.Empty();
- }
- bool SWaapiPicker::HandleDeleteWwiseItemCommandCanExecute() const
- {
- auto& SelectedItems = GetSelectedItems();
- if ((SelectedItems.Num() > 0) &&
- !(TreeViewPtr->IsItemSelected(RootItems[EWwiseItemType::Event]) || TreeViewPtr->IsItemSelected(RootItems[EWwiseItemType::AuxBus])
- || TreeViewPtr->IsItemSelected(RootItems[EWwiseItemType::ActorMixer]) || TreeViewPtr->IsItemSelected(RootItems[EWwiseItemType::AcousticTexture])))
- {
- for (int32 i = 0; i < SelectedItems.Num(); ++i)
- {
- if (SelectedItems[i]->IsOfType({ EWwiseItemType::PhysicalFolder, EWwiseItemType::StandaloneWorkUnit, EWwiseItemType::NestedWorkUnit }))
- return false;
- }
- return true;
- }
- return false;
- }
- void SWaapiPicker::HandleDeleteWwiseItemCommandExecute()
- {
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- SWaapiPickerRow::CallWaapiExecuteUri(ak::wwise::core::undo::beginGroup, {}, Result);
- auto& SelectedItems = GetSelectedItems();
- for (int32 i = 0; i < SelectedItems.Num(); ++i)
- {
- const FString itemIdStringField = SelectedItems[i]->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
- SWaapiPickerRow::CallWaapiExecuteUri(ak::wwise::core::object::delete_, { { WwiseWaapiHelper::OBJECT, itemIdStringField } }, Result);
- }
- SWaapiPickerRow::CallWaapiExecuteUri(ak::wwise::core::undo::endGroup, { {WwiseWaapiHelper::DISPLAY_NAME, WwiseWaapiHelper::DELETE_ITEMS} }, Result);
- ConstructTree();
- #endif
- }
- void SWaapiPicker::HandleExploreWwiseItemCommandExecute() const
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to connect to localhost"));
- return;
- }
- auto& SelectedItems = GetSelectedItems();
- if (SelectedItems.Num() == 0)
- return;
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- {
- TSharedPtr<FJsonObject> from = MakeShared<FJsonObject>();
- from->SetArrayField(WwiseWaapiHelper::PATH, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(SelectedItems[0]->FolderPath) });
- Args->SetObjectField(WwiseWaapiHelper::FROM, from);
- }
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>> { MakeShared<FJsonValueString>(WwiseWaapiHelper::FILEPATH) });
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> outJsonResult;
- if (!waapiClient->Call(ak::wwise::core::object::get, Args, Options, outJsonResult))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Call Failed"));
- return;
- }
- auto Path = outJsonResult->GetArrayField(WwiseWaapiHelper::RETURN)[0]->AsObject()->GetStringField(WwiseWaapiHelper::FILEPATH);
- FPlatformProcess::ExploreFolder(*Path);
- #endif
- }
- bool SWaapiPicker::HandleWwiseCommandCanExecute() const
- {
- return GetSelectedItems().Num() == 1;
- }
- void SWaapiPicker::HandleFindWwiseItemInProjectExplorerCommandExecute() const
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to connect to localhost"));
- return;
- }
- auto& SelectedItems = GetSelectedItems();
- if (SelectedItems.Num() == 0)
- return;
- TSharedRef<FJsonObject> Args = MakeShared<FJsonObject>();
- Args->SetStringField(WwiseWaapiHelper::COMMAND, WwiseWaapiHelper::FIND_IN_PROJECT_EXPLORER);
- TArray<TSharedPtr<FJsonValue>> SelectedObjects;
- for (auto selectedItem : SelectedItems)
- {
- SelectedObjects.Add(MakeShared<FJsonValueString>(selectedItem->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces)));
- }
- Args->SetArrayField(WwiseWaapiHelper::OBJECTS, SelectedObjects);
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- if (!waapiClient->Call(ak::wwise::ui::commands::execute, Args, Options, Result))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Call Failed"));
- }
- #endif
- }
- void SWaapiPicker::HandleRefreshWaapiPickerCommandExecute()
- {
- ConstructTree();
- }
- void SWaapiPicker::HandleUndoWaapiPickerCommandExecute() const
- {
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- SWaapiPickerRow::CallWaapiExecuteUri(ak::wwise::ui::commands::execute, { {WwiseWaapiHelper::COMMAND, WwiseWaapiHelper::UNDO} }, Result);
- #endif
- }
- void SWaapiPicker::HandleImportWwiseItemCommandExecute() const
- {
- #if WITH_EDITOR
- const FString& PackagePath = "/Game";
- FString LastWwiseImportPath = FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_IMPORT);
- const FString& ContentFolder = AkUnrealHelper::GetContentDirectory();
- FString FolderName;
- // If not prompting individual files, prompt the user to select a target directory.
- IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
- if (DesktopPlatform)
- {
- const FString Title = NSLOCTEXT("UnrealEd", "ChooseADirectory", "Choose A Directory").ToString();
- const bool bFolderSelected = DesktopPlatform->OpenDirectoryDialog(
- FSlateApplication::Get().FindBestParentWindowHandleForDialogs(nullptr),
- Title,
- LastWwiseImportPath,
- FolderName
- );
- if (bFolderSelected)
- {
- FEditorDirectories::Get().SetLastDirectory(ELastDirectory::GENERIC_IMPORT, LastWwiseImportPath);
- FPaths::MakePathRelativeTo(FolderName, *FPaths::ProjectContentDir());
- OnImportWwiseAssetsClicked.ExecuteIfBound(PackagePath / FolderName);
- }
- }
- #endif // WITH_EDITOR
- }
- void SWaapiPicker::HandleRedoWaapiPickerCommandExecute() const
- {
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> Result;
- SWaapiPickerRow::CallWaapiExecuteUri(ak::wwise::ui::commands::execute, { {WwiseWaapiHelper::COMMAND, WwiseWaapiHelper::REDO} }, Result);
- #endif
- }
- FReply SWaapiPicker::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyboardEvent)
- {
- const FKey KeyPressed = InKeyboardEvent.GetKey();
- if ((KeyPressed == EKeys::SpaceBar))
- {
- // Play the wwise item.
- if (HandlePlayWwiseItemCommandCanExecute())
- {
- HandlePlayWwiseItemCommandExecute();
- return FReply::Handled();
- }
- }
- else if (KeyPressed == EKeys::F2)
- {
- // Rename key : Rename selected Wwise item.
- if (HandleRenameWwiseItemCommandCanExecute())
- {
- HandleRenameWwiseItemCommandExecute();
- return FReply::Handled();
- }
- }
- else if (KeyPressed == EKeys::Delete)
- {
- // Delete key : Delete selected Wwise item(s).
- if (HandleDeleteWwiseItemCommandCanExecute())
- {
- HandleDeleteWwiseItemCommandExecute();
- return FReply::Handled();
- }
- }
- else if (KeyPressed == EKeys::F5)
- { // Populates the Waapi Picker.
- HandleRefreshWaapiPickerCommandExecute();
- return FReply::Handled();
- }
- else if ((KeyPressed == EKeys::Z) && InKeyboardEvent.IsControlDown())
- {
- // Undo
- HandleUndoWaapiPickerCommandExecute();
- return FReply::Handled();
- }
- else if ((KeyPressed == EKeys::Y) && InKeyboardEvent.IsControlDown())
- {
- // Redo
- HandleRedoWaapiPickerCommandExecute();
- return FReply::Handled();
- }
- else if (!bRestrictContextMenu && (KeyPressed == EKeys::One) && InKeyboardEvent.IsControlDown() && InKeyboardEvent.IsShiftDown())
- {
- // Finds the specified object in the Project Explorer (Sync Group 1).
- if (HandleWwiseCommandCanExecute())
- {
- HandleFindWwiseItemInProjectExplorerCommandExecute();
- return FReply::Handled();
- }
- }
- return FReply::Unhandled();
- }
- const TArray<TSharedPtr<FWwiseTreeItem>> SWaapiPicker::GetSelectedItems() const
- {
- return TreeViewPtr->GetSelectedItems();
- }
- const FString SWaapiPicker::GetSearchText() const
- {
- return SearchBoxFilter->GetRawFilterText().ToString();
- }
- const void SWaapiPicker::SetSearchText(const FString& newText)
- {
- SearchBoxPtr->SetText(FText::FromString(newText));
- }
- EActiveTimerReturnType SWaapiPicker::SetFocusPostConstruct(double InCurrentTime, float InDeltaTime)
- {
- FWidgetPath WidgetToFocusPath;
- FSlateApplication::Get().GeneratePathToWidgetUnchecked(SearchBoxPtr.ToSharedRef(), WidgetToFocusPath);
- FSlateApplication::Get().SetKeyboardFocus(WidgetToFocusPath, EFocusCause::SetDirectly);
- return EActiveTimerReturnType::Stop;
- }
- void SWaapiPicker::SubscribeWaapiCallbacks()
- {
- struct SubscriptionData
- {
- const char* Uri;
- WampEventCallback Callback;
- uint64* SubscriptionId;
- };
- #if AK_SUPPORT_WAAPI
- const SubscriptionData Subscriptions[] = {
- {ak::wwise::core::object::nameChanged, WampEventCallback::CreateSP(this, &SWaapiPicker::OnWaapiRenamed), &WaapiSubscriptionIds.Renamed},
- {ak::wwise::core::object::childAdded, WampEventCallback::CreateSP(this, &SWaapiPicker::OnWaapiChildAdded), &WaapiSubscriptionIds.ChildAdded},
- {ak::wwise::core::object::childRemoved, WampEventCallback::CreateSP(this, &SWaapiPicker::OnWaapiChildRemoved), &WaapiSubscriptionIds.ChildRemoved},
- {ak::wwise::ui::selectionChanged, WampEventCallback::CreateSP(this, &SWaapiPicker::OnWwiseSelectionChanged), &WaapiSubscriptionIds.SelectionChanged},
- };
- #endif
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- return;
- }
- TSharedRef<FJsonObject> Options = MakeShared<FJsonObject>();
- Options->SetArrayField(WwiseWaapiHelper::RETURN, TArray<TSharedPtr<FJsonValue>>
- {
- MakeShared<FJsonValueString>(WwiseWaapiHelper::ID),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::NAME),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::TYPE),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::CHILDREN_COUNT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PATH),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::PARENT),
- MakeShared<FJsonValueString>(WwiseWaapiHelper::WORKUNIT_TYPE),
- });
- TSharedPtr<FJsonObject> Result;
- #if AK_SUPPORT_WAAPI
- for (auto& SubscriptionData : Subscriptions)
- {
- if (*SubscriptionData.SubscriptionId == 0)
- {
- waapiClient->Subscribe(SubscriptionData.Uri,
- Options,
- SubscriptionData.Callback,
- *SubscriptionData.SubscriptionId,
- Result
- );
- }
- }
- #endif
- }
- void SWaapiPicker::UnsubscribeWaapiCallbacks()
- {
- auto waapiClient = FAkWaapiClient::Get();
- if (!waapiClient)
- {
- return;
- }
- auto doUnsubscribe = [waapiClient](uint64& subscriptionId) {
- if (subscriptionId > 0)
- {
- TSharedPtr<FJsonObject> Result;
- waapiClient->Unsubscribe(subscriptionId, Result);
- subscriptionId = 0;
- }
- };
- doUnsubscribe(WaapiSubscriptionIds.Renamed);
- doUnsubscribe(WaapiSubscriptionIds.ChildAdded);
- doUnsubscribe(WaapiSubscriptionIds.ChildRemoved);
- doUnsubscribe(WaapiSubscriptionIds.SelectionChanged);
- }
- TSharedPtr<FWwiseTreeItem> SWaapiPicker::FindTreeItemFromJsonObject(const TSharedPtr<FJsonObject>& ObjectJson, const FString& OverrideLastPart)
- {
- FString objectPath;
- if (!ObjectJson->TryGetStringField(WwiseWaapiHelper::PATH, objectPath))
- {
- return {};
- }
- FString stringId;
- if (!ObjectJson->TryGetStringField(WwiseWaapiHelper::ID, stringId))
- {
- return {};
- }
- FGuid id;
- FGuid::ParseExact(stringId, EGuidFormats::DigitsWithHyphensInBraces, id);
- TArray<FString> pathParts;
- objectPath.ParseIntoArray(pathParts, *WwiseWaapiHelper::BACK_SLASH);
- if (pathParts.Num() == 0)
- {
- return {};
- }
- if (!OverrideLastPart.IsEmpty())
- {
- pathParts[pathParts.Num() - 1] = OverrideLastPart;
- }
- TSharedPtr<FWwiseTreeItem> treeItem;
- TArray<TSharedPtr<FWwiseTreeItem>>* children = &RootItems;
- FString folderPath;
- for (auto& part : pathParts)
- {
- folderPath += FString::Printf(TEXT("%s%s"), *WwiseWaapiHelper::BACK_SLASH, *part);
- bool found = false;
- for (auto& item : *children)
- {
- if (item->ItemId == id)
- {
- return item;
- }
- if (item->FolderPath == folderPath)
- {
- treeItem = item;
- children = treeItem->GetChildrenMutable();
- found = true;
- }
- }
- if (!found)
- {
- return {};
- }
- }
- if (treeItem.IsValid() && treeItem->ItemId != id)
- {
- return {};
- }
- return treeItem;
- }
- void SWaapiPicker::OnWaapiRenamed(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- FString oldName;
- if (Response->TryGetStringField(WwiseWaapiHelper::OLD_NAME, oldName) && oldName.IsEmpty())
- {
- const TSharedPtr<FJsonObject>* objectJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::OBJECT, objectJsonPtr))
- {
- return;
- }
- auto& objectJson = *objectJsonPtr;
- FString stringId;
- if (!objectJson->TryGetStringField(WwiseWaapiHelper::ID, stringId))
- {
- return;
- }
- FGuid id;
- FGuid::ParseExact(stringId, EGuidFormats::DigitsWithHyphensInBraces, id);
- if (auto pendingIt = pendingTreeItems.Find(id))
- {
- CreateTreeItemWaapi(*pendingIt, objectJson);
- pendingTreeItems.Remove(id);
- AsyncTask(ENamedThreads::GameThread, [sharedThis = SharedThis(this)]
- {
- sharedThis->TreeViewPtr->RequestTreeRefresh();
- });
- }
- return;
- }
- const TSharedPtr<FJsonObject>* objectJsonPtr = nullptr;
- if (Response->TryGetObjectField(WwiseWaapiHelper::OBJECT, objectJsonPtr))
- {
- TSharedPtr<FJsonObject> objectJson = *objectJsonPtr;
- auto treeItem = FindTreeItemFromJsonObject(*objectJsonPtr, oldName);
- if (treeItem)
- {
- Response->TryGetStringField(WwiseWaapiHelper::NEW_NAME, treeItem->DisplayName);
- objectJson->TryGetStringField(WwiseWaapiHelper::PATH, treeItem->FolderPath);
- if (treeItem->Parent.IsValid())
- {
- treeItem->Parent.Pin()->SortChildren();
- }
- AsyncTask(ENamedThreads::GameThread, [sharedThis = SharedThis(this)]
- {
- sharedThis->TreeViewPtr->RequestTreeRefresh();
- });
- }
- }
- }
- template<typename ActionFunctor>
- void SWaapiPicker::HandleOnWaapiChildResponse(TSharedPtr<FJsonObject> Response, const ActionFunctor& Action)
- {
- const TSharedPtr<FJsonObject>* parentJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::PARENT, parentJsonPtr))
- {
- return;
- }
- const TSharedPtr<FJsonObject>* childJsonPtr = nullptr;
- if (!Response->TryGetObjectField(WwiseWaapiHelper::CHILD, childJsonPtr))
- {
- return;
- }
- FString childName;
- if (childJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::NAME, childName) && childName.IsEmpty())
- {
- auto parentTreeItem = FindTreeItemFromJsonObject(*parentJsonPtr);
- FString childStringId;
- childJsonPtr->Get()->TryGetStringField(WwiseWaapiHelper::ID, childStringId);
- FGuid childId;
- FGuid::ParseExact(childStringId, EGuidFormats::DigitsWithHyphensInBraces, childId);
- if (parentTreeItem && childId.IsValid())
- {
- pendingTreeItems.Add(childId, parentTreeItem);
- return;
- }
- }
- auto parentTreeItem = FindTreeItemFromJsonObject(*parentJsonPtr);
- if (parentTreeItem)
- {
- Action(parentTreeItem, *childJsonPtr);
- AsyncTask(ENamedThreads::GameThread, [sharedThis = SharedThis(this)]
- {
- sharedThis->TreeViewPtr->RequestTreeRefresh();
- });
- }
- }
- void SWaapiPicker::OnWaapiChildAdded(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- HandleOnWaapiChildResponse(Response,
- [sharedThis = SharedThis(this)](const TSharedPtr<FWwiseTreeItem>& parentTreeItem, const TSharedPtr<FJsonObject>& childJson)
- {
- sharedThis->CreateTreeItemWaapi(parentTreeItem, childJson);
- });
- }
- void SWaapiPicker::CreateTreeItemWaapi(const TSharedPtr<FWwiseTreeItem>& parentTreeItem, const TSharedPtr<FJsonObject>& childJson)
- {
- if (!parentTreeItem)
- {
- return;
- }
- auto newChild = ConstructWwiseTreeItem(childJson);
- if (newChild && parentTreeItem)
- {
- parentTreeItem->AddChild(newChild);
- parentTreeItem->SortChildren();
- ++parentTreeItem->ChildCountInWwise;
- if (parentTreeItem->TreeRow.IsValid() && parentTreeItem->TreeRow.Pin()->IsItemExpanded())
- {
- LastExpandedItems.Add(parentTreeItem->ItemId);
- }
- }
- }
- void SWaapiPicker::OnWaapiChildRemoved(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- HandleOnWaapiChildResponse(Response,
- [sharedThis=SharedThis(this)](const TSharedPtr<FWwiseTreeItem>& ParentTreeItem, const TSharedPtr<FJsonObject>& ChildJson)
- {
- auto StringId = ChildJson->GetStringField(WwiseWaapiHelper::ID);
- FGuid ParsedID;
- FGuid::ParseExact(StringId, EGuidFormats::DigitsWithHyphensInBraces, ParsedID);
- for (int32 ChildIndex = 0; ChildIndex < ParentTreeItem->GetChildren().Num(); ++ChildIndex)
- {
- ParentTreeItem->RemoveChild(ParsedID);
- if (ParentTreeItem->ChildCountInWwise <= 0)
- {
- sharedThis->LastExpandedItems.Remove(ParentTreeItem->ItemId);
- }
- }
- });
- }
- TSharedPtr<FWwiseTreeItem> SWaapiPicker::FindOrConstructTreeItemFromJsonObject(const TSharedPtr<FJsonObject>& ObjectJson)
- {
- FString objectPath;
- if (!ObjectJson->TryGetStringField(WwiseWaapiHelper::PATH, objectPath))
- {
- return {};
- }
- FString stringId;
- if (!ObjectJson->TryGetStringField(WwiseWaapiHelper::ID, stringId))
- {
- return {};
- }
- FGuid id;
- FGuid::ParseExact(stringId, EGuidFormats::DigitsWithHyphensInBraces, id);
- TArray<FString> pathParts;
- objectPath.ParseIntoArray(pathParts, *WwiseWaapiHelper::BACK_SLASH);
- if (pathParts.Num() == 0)
- {
- return {};
- }
- TSharedPtr<FWwiseTreeItem> treeItem;
- TArray<TSharedPtr<FWwiseTreeItem>>* children = &RootItems;
- TArray<TSharedPtr<FWwiseTreeItem>> itemsToExpand;
- FString folderPath;
- for (auto& part : pathParts)
- {
- folderPath += FString::Printf(TEXT("%s%s"), *WwiseWaapiHelper::BACK_SLASH, *part);
- bool found = false;
- for (auto& item : *children)
- {
- if (item->ItemId == id)
- {
- treeItem = item;
- break;
- }
- if (item->FolderPath == folderPath)
- {
- if (!TreeViewPtr->IsItemExpanded(item))
- {
- const FString itemIdStringField = item->ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
- TSharedPtr<FJsonObject> Result;
- // Request data from Wwise UI using WAAPI and use them to create a Wwise tree item, getting the informations from a specific "ID".
- if (!CallWaapiGetInfoFrom(WwiseWaapiHelper::ID, itemIdStringField, Result, { { WwiseWaapiHelper::SELECT, { WwiseWaapiHelper::CHILDREN }, {} } }))
- {
- UE_LOG(LogAkAudio, Log, TEXT("Failed to get information from id : %s"), *itemIdStringField);
- return {};
- }
- // The tree view might have been destroyed between scheduling and running this task
- // Recover the information from the Json object Result and use it to construct the tree item.
- TArray<TSharedPtr<FJsonValue>> StructJsonArray = Result->GetArrayField(WwiseWaapiHelper::RETURN);
- /** If the item have just one child and we are expanding it, this means that we need to construct the children list.
- * In case the the number of children gotten form Wwise is not the same of the item, this means that there is some children added/removed,
- * so we also need to construct the new list.
- */
- if ((item->GetChildren().Num() == 1) || (item->GetChildren().Num() != StructJsonArray.Num()))
- {
- item->EmptyChildren();
- for (int i = 0; i < StructJsonArray.Num(); i++)
- {
- TSharedPtr<FWwiseTreeItem> NewRootChild = ConstructWwiseTreeItem(StructJsonArray[i]);
- if (NewRootChild.IsValid())
- {
- item->AddChild(NewRootChild);
- }
- }
- item->SortChildren();
- }
- itemsToExpand.Add(item);
- }
- treeItem = item;
- children = treeItem->GetChildrenMutable();
- found = true;
- }
- }
- if (treeItem && treeItem->ItemId == id)
- {
- break;
- }
- if (!found)
- {
- return {};
- }
- }
- if (treeItem.IsValid() && treeItem->ItemId != id)
- {
- return {};
- }
- for (auto& itemToExpand : itemsToExpand)
- {
- LastExpandedItems.Add(itemToExpand->ItemId);
- TreeViewPtr->SetItemExpansion(itemToExpand, true);
- }
- return treeItem;
- }
- void SWaapiPicker::OnWwiseSelectionChanged(uint64_t Id, TSharedPtr<FJsonObject> Response)
- {
- AsyncTask(ENamedThreads::GameThread, [sharedThis = SharedThis(this), Response]()
- {
- const UAkSettingsPerUser* AkSettingsPerUser = GetDefault<UAkSettingsPerUser>();
- if (AkSettingsPerUser && AkSettingsPerUser->AutoSyncSelection)
- {
- const TArray<TSharedPtr<FJsonValue>>* objectsJsonArray = nullptr;
- if (Response->TryGetArrayField(WwiseWaapiHelper::OBJECTS, objectsJsonArray))
- {
- sharedThis->AllowTreeViewDelegates = false;
- TArray<TSharedPtr<FWwiseTreeItem>> TreeItems;
- for (auto JsonObject : *objectsJsonArray)
- {
- auto TreeItem = sharedThis->FindOrConstructTreeItemFromJsonObject(JsonObject->AsObject());
- if (TreeItem)
- {
- TreeItems.Add(TreeItem);
- }
- }
- sharedThis->TreeViewPtr->RequestTreeRefresh();
- if (TreeItems.Num() > 0)
- {
- sharedThis->TreeViewPtr->ClearSelection();
- sharedThis->TreeViewPtr->SetItemSelection(TreeItems, true);
- sharedThis->TreeViewPtr->RequestScrollIntoView(TreeItems[0]);
- }
- sharedThis->AllowTreeViewDelegates = true;
- }
- }
- });
- }
- #undef LOCTEXT_NAMESPACE
|