SWaapiPickerRow.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. SWaapiPickerRow.cpp
  17. ------------------------------------------------------------------------------------*/
  18. /*------------------------------------------------------------------------------------
  19. includes.
  20. ------------------------------------------------------------------------------------*/
  21. #include "WaapiPicker/SWaapiPickerRow.h"
  22. #include "AkAudioDevice.h"
  23. #include "AkWaapiUtils.h"
  24. #include "WaapiPicker/SWaapiPicker.h"
  25. #include "Widgets/Input/SSearchBox.h"
  26. #include "AkAudioStyle.h"
  27. #include "Widgets/Images/SImage.h"
  28. /*------------------------------------------------------------------------------------
  29. Defines
  30. ------------------------------------------------------------------------------------*/
  31. #define LOCTEXT_NAMESPACE "AkAudio"
  32. bool SWaapiPickerRow::CallWaapiExecuteUri(const char* inUri, const TArray<KeyValueArgs>& values, TSharedPtr<FJsonObject>& outJsonResult)
  33. {
  34. TSharedRef<FJsonObject> args = MakeShareable(new FJsonObject());
  35. for (auto value : values)
  36. {
  37. args->SetStringField(value.keyArg, value.valueArg);
  38. }
  39. // Construct the options Json object;
  40. TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
  41. // Connect to Wwise Authoring on localhost.
  42. FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
  43. if (waapiClient)
  44. {
  45. // Request infos/changes in Waapi Picker using WAAPI
  46. if (waapiClient->Call(inUri, args, options, outJsonResult))
  47. {
  48. return true;
  49. }
  50. else
  51. {
  52. UE_LOG(LogAkAudio, Log, TEXT("Call Failed"));
  53. }
  54. }
  55. else
  56. {
  57. UE_LOG(LogAkAudio, Log, TEXT("Unable to connect to localhost"));
  58. }
  59. return false;
  60. }
  61. /*------------------------------------------------------------------------------------
  62. Implementation
  63. ------------------------------------------------------------------------------------*/
  64. void SWaapiPickerRow::Construct(const FArguments& InArgs)
  65. {
  66. ParentWidget = InArgs._ParentWidget;
  67. WaapiPickerItem = InArgs._WaapiPickerItem;
  68. bool bIsRoot = !WaapiPickerItem.Pin()->Parent.IsValid() &&
  69. ((WaapiPickerItem.Pin()->FolderPath == WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[EWwiseItemType::Event]) ||
  70. (WaapiPickerItem.Pin()->FolderPath == WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[EWwiseItemType::AuxBus]) ||
  71. (WaapiPickerItem.Pin()->FolderPath == WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[EWwiseItemType::ActorMixer]) ||
  72. (WaapiPickerItem.Pin()->FolderPath == WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[EWwiseItemType::AcousticTexture]) ||
  73. (WaapiPickerItem.Pin()->FolderPath == WwiseWaapiHelper::BACK_SLASH + EWwiseItemType::FolderNames[EWwiseItemType::EffectShareSet]));
  74. ChildSlot
  75. [
  76. SNew(SHorizontalBox)
  77. + SHorizontalBox::Slot()
  78. .AutoWidth()
  79. .Padding(0, bIsRoot? 2 : 1, 2, 1)
  80. .VAlign(VAlign_Center)
  81. [
  82. // Item Icon
  83. SNew(SImage)
  84. .Image(FAkAudioStyle::GetBrush(WaapiPickerItem.Pin()->ItemType))
  85. ]
  86. + SHorizontalBox::Slot()
  87. .AutoWidth()
  88. .VAlign(VAlign_Center)
  89. [
  90. SAssignNew(InlineRenameWidget, SInlineEditableTextBlock)
  91. .Text(this, &SWaapiPickerRow::GetNameText)
  92. .ToolTipText(this, &SWaapiPickerRow::GetToolTipText)
  93. .HighlightText(InArgs._HighlightText)
  94. .OnTextCommitted(this, &SWaapiPickerRow::HandleNameCommitted)
  95. .OnVerifyTextChanged(this, &SWaapiPickerRow::HandleVerifyNameChanged)
  96. .IsSelected(InArgs._IsSelected)
  97. .IsReadOnly(this, &SWaapiPickerRow::IsWiseItemNameReadOnly)
  98. ]
  99. ];
  100. if (InlineRenameWidget.IsValid())
  101. {
  102. EnterEditingModeDelegateHandle = OnRenamedRequestEvent.AddSP(InlineRenameWidget.Get(), &SInlineEditableTextBlock::EnterEditingMode);
  103. }
  104. }
  105. void SWaapiPickerRow::EnterEditingMode()
  106. {
  107. InlineRenameWidget->EnterEditingMode();
  108. }
  109. SWaapiPickerRow::~SWaapiPickerRow()
  110. {
  111. if (InlineRenameWidget.IsValid())
  112. {
  113. OnRenamedRequestEvent.Remove(EnterEditingModeDelegateHandle);
  114. }
  115. }
  116. void SWaapiPickerRow::HandleNameCommitted(const FText& NewText, ETextCommit::Type CommitInfo)
  117. {
  118. TSharedPtr<FWwiseTreeItem> WaapiPickerItemPtr = WaapiPickerItem.Pin();
  119. if (WaapiPickerItemPtr.IsValid())
  120. {
  121. FText WarningMessage;
  122. const bool bIsCommitted = (CommitInfo != ETextCommit::OnCleared);
  123. if (!OnItemRenameCommitted(WaapiPickerItemPtr, NewText.ToString(), WarningMessage) && ParentWidget.IsValid() && bIsCommitted)
  124. {
  125. // Failed to rename/create a WaapiPickerItem, display a warning.
  126. UE_LOG(LogAkAudio, Log, TEXT("Rename Failed : %s"), *WarningMessage.ToString());
  127. }
  128. }
  129. }
  130. bool SWaapiPickerRow::OnItemRenameCommitted(const TSharedPtr< FWwiseTreeItem >& WwiseItem, const FString& InNewItemName, FText& OutWarningMessage)
  131. {
  132. if (WwiseItem.IsValid() && !InNewItemName.Equals(WwiseItem->DisplayName, ESearchCase::CaseSensitive))
  133. {
  134. #if AK_SUPPORT_WAAPI
  135. const FGuid& in_ItemId = WwiseItem->ItemId;
  136. const FString itemIdStringField = in_ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
  137. TSharedPtr<FJsonObject> getResult;
  138. if (CallWaapiExecuteUri(ak::wwise::core::object::setName, { {WwiseWaapiHelper::OBJECT, itemIdStringField} , {WwiseWaapiHelper::VALUE, InNewItemName } }, getResult))
  139. {
  140. return true;
  141. }
  142. #endif
  143. }
  144. return false;
  145. }
  146. bool SWaapiPickerRow::HandleVerifyNameChanged(const FText& NewText, FText& OutErrorMessage)
  147. {
  148. TSharedPtr<FWwiseTreeItem> WaapiPickerItemPtr = WaapiPickerItem.Pin();
  149. if (WaapiPickerItemPtr.IsValid())
  150. {
  151. return OnVerifyItemNameChanged(WaapiPickerItemPtr, NewText.ToString(), OutErrorMessage);
  152. }
  153. return false;
  154. }
  155. bool SWaapiPickerRow::OnVerifyItemNameChanged(const TSharedPtr< FWwiseTreeItem >& WwiseItem, const FString& InNewItemName, FText& OutErrorMessage)
  156. {
  157. if (!WwiseItem.IsValid())
  158. {
  159. OutErrorMessage = LOCTEXT("RenameFailed_TreeItemDeleted", "Tree item no longer exists");
  160. return false;
  161. }
  162. if ((WwiseItem->ItemType == EWwiseItemType::PhysicalFolder) || (WwiseItem->ItemType == EWwiseItemType::StandaloneWorkUnit) || (WwiseItem->ItemType == EWwiseItemType::NestedWorkUnit))
  163. {
  164. OutErrorMessage = LOCTEXT("RenameFailed_WorkUnitItem", "You can't change the name of a PhysicalFolder/WorkUnit");
  165. return false;
  166. }
  167. if (WwiseItem->Parent == NULL)
  168. {
  169. OutErrorMessage = LOCTEXT("RenameFailed_RootTreeItem", "A root tree item can not be renamed");
  170. return false;
  171. }
  172. FText TrimmedLabel = FText::TrimPrecedingAndTrailing(FText::FromString(InNewItemName));
  173. if (TrimmedLabel.IsEmpty())
  174. {
  175. OutErrorMessage = LOCTEXT("RenameFailed_LeftBlank", "Names cannot be left blank");
  176. return false;
  177. }
  178. if (TrimmedLabel.ToString().Len() >= NAME_SIZE)
  179. {
  180. FFormatNamedArguments Arguments;
  181. Arguments.Add(TEXT("CharCount"), NAME_SIZE);
  182. OutErrorMessage = FText::Format(LOCTEXT("RenameFailed_TooLong", "Names must be less than {CharCount} characters long."), Arguments);
  183. return false;
  184. }
  185. // If the new name is the same as the old name, consider this to be unchanged, and accept it.
  186. const FString& LabelString = TrimmedLabel.ToString();
  187. if (WwiseItem->DisplayName == LabelString)
  188. {
  189. return true;
  190. }
  191. int32 Dummy = 0;
  192. if (LabelString.FindChar('/', Dummy) || LabelString.FindChar('\\', Dummy))
  193. {
  194. OutErrorMessage = LOCTEXT("RenameFailed_InvalidChar", "Item names cannot contain / or \\.");
  195. return false;
  196. }
  197. // Validate that this folder doesn't exist already
  198. FName NewPath = FName(*(WwiseItem->Parent.Pin()->FolderPath));
  199. NewPath = FName(*(NewPath.ToString() + WwiseWaapiHelper::BACK_SLASH + LabelString));
  200. if (WwiseItem->Parent.Pin()->GetChild(InNewItemName).IsValid())
  201. {
  202. OutErrorMessage = LOCTEXT("RenameFailed_AlreadyExists", "An item with this name already exists at this level");
  203. return false;
  204. }
  205. return true;
  206. }
  207. bool SWaapiPickerRow::IsWiseItemNameReadOnly() const
  208. {
  209. // We can't rename roots or Wise items of type "PhysicalFolder || StandaloneWorkUnit || NestedWorkUnit"
  210. const TSharedPtr<FWwiseTreeItem>& WaapiPickerItemPtr = WaapiPickerItem.Pin();
  211. return ((WaapiPickerItemPtr->Parent == NULL) || (WaapiPickerItemPtr->ItemType == EWwiseItemType::PhysicalFolder) || (WaapiPickerItemPtr->ItemType == EWwiseItemType::StandaloneWorkUnit) || (WaapiPickerItemPtr->ItemType == EWwiseItemType::NestedWorkUnit));
  212. }
  213. FText SWaapiPickerRow::GetNameText() const
  214. {
  215. const TSharedPtr<FWwiseTreeItem>& WaapiPickerItemPtr = WaapiPickerItem.Pin();
  216. if (WaapiPickerItemPtr.IsValid())
  217. {
  218. return FText::FromString(WaapiPickerItemPtr->DisplayName);
  219. }
  220. else
  221. {
  222. return FText();
  223. }
  224. }
  225. FText SWaapiPickerRow::GetToolTipText() const
  226. {
  227. const TSharedPtr<FWwiseTreeItem>& WaapiPickerItemPtr = WaapiPickerItem.Pin();
  228. if (WaapiPickerItemPtr.IsValid())
  229. {
  230. return FText::FromString(WaapiPickerItemPtr->FolderPath);
  231. }
  232. else
  233. {
  234. return FText();
  235. }
  236. }
  237. #undef LOCTEXT_NAMESPACE