123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- /*******************************************************************************
- 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.
- *******************************************************************************/
- #include "AkWaapiUMG/Components/AkCheckBox.h"
- #include "AkAudioDevice.h"
- #include "Widgets/SNullWidget.h"
- #include "Widgets/DeclarativeSyntaxSupport.h"
- #include "Widgets/Input/SCheckBox.h"
- #include "AkWaapiUMG/Components/AkBoolPropertyToControlCustomization.h"
- #include "AkWaapiUMG/Components/WwiseBoolPropertyDragDropOp.h"
- #include "AkWaapiUtils.h"
- #include "AkWaapiBlueprints/AkWaapiCalls.h"
- #include "Async/Async.h"
- #include "AkWaapiUMG/Components/WwiseUmgDragDropOp.h"
- #include "WaapiPicker/SWaapiPicker.h"
- #if WITH_EDITOR
- #include "Modules/ModuleManager.h"
- #include "PropertyEditorModule.h"
- #endif
- #define LOCTEXT_NAMESPACE "AkWaapiUMG"
- ////////////////////////////////////////////////
- // SCheckBoxDropHandler
- ////////////////////////////////////////////////
- /** Drag-drop zone for adding a Wwise item or a bool property to the CheckBox */
- class SCheckBoxDropHandler : public SCompoundWidget
- {
- public:
- SLATE_BEGIN_ARGS(SCheckBoxDropHandler) {}
- SLATE_DEFAULT_SLOT(FArguments, Content)
- SLATE_EVENT(FOnDrop, OnDrop)
- SLATE_END_ARGS()
- void Construct(const FArguments& InArgs)
- {
- OnDropDelegate = InArgs._OnDrop;
- this->ChildSlot
- [
- SNew(SBorder)
- [
- InArgs._Content.Widget
- ]
- ];
- }
- FReply OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent) override
- {
- if (OnDropDelegate.IsBound())
- {
- return OnDropDelegate.Execute(MyGeometry, DragDropEvent);
- }
- return FReply::Handled();
- }
- private:
- FOnDrop OnDropDelegate;
- };
- /////////////////////////////////////////////////////
- // UAkCheckBox
- UAkCheckBox::UAkCheckBox(const FObjectInitializer& ObjectInitializer)
- : Super(ObjectInitializer)
- {
- SCheckBox::FArguments SlateDefaults;
- WidgetStyle = *SlateDefaults._Style;
- CheckedState = ECheckBoxState::Unchecked;
- HorizontalAlignment = SlateDefaults._HAlign;
- IsFocusable = true;
- }
- void UAkCheckBox::BeginDestroy()
- {
- if (SubscriptionIdNameChanged != 0)
- {
- bool isUnsubscribed;
- UAkWaapiCalls::Unsubscribe(FAkWaapiSubscriptionId(SubscriptionIdNameChanged), isUnsubscribed);
- if (isUnsubscribed)
- SubscriptionIdNameChanged = 0;
- }
- if (SubscriptionId != 0)
- {
- bool isUnsubscribed;
- UAkWaapiCalls::Unsubscribe(FAkWaapiSubscriptionId(SubscriptionId), isUnsubscribed);
- if (isUnsubscribed)
- SubscriptionId = 0;
- }
- Super::BeginDestroy();
- }
- void UAkCheckBox::ReleaseSlateResources(bool bReleaseChildren)
- {
- Super::ReleaseSlateResources(bReleaseChildren);
- MyCheckbox.Reset();
- }
- TSharedRef<SWidget> UAkCheckBox::RebuildWidget()
- {
- #if WITH_EDITOR
- FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
- PropertyModule.RegisterCustomPropertyTypeLayout("AkBoolPropertyToControl", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FAkBoolPropertyToControlCustomization::MakeInstance));
- PropertyModule.NotifyCustomizationModuleChanged();
- #endif//WITH_EDITOR
- MyCheckbox = SNew(SCheckBox)
- .OnCheckStateChanged(BIND_UOBJECT_DELEGATE(FOnCheckStateChanged, SlateOnCheckStateChangedCallback))
- .Style(&WidgetStyle)
- .HAlign(HorizontalAlignment)
- .IsFocusable(IsFocusable)
- ;
- if (GetChildrenCount() > 0)
- {
- MyCheckbox->SetContent(GetContentSlot()->Content ? GetContentSlot()->Content->TakeWidget() : SNullWidget::NullWidget);
- }
- return
- SNew(SCheckBoxDropHandler)
- .OnDrop(FOnDrop::CreateUObject(this, &UAkCheckBox::OnDropHandler))
- [
- SNew(SHorizontalBox)
- + SHorizontalBox::Slot()
- .AutoWidth()
- .Padding(FMargin(3.0f, 3.0f))
- .HAlign(HAlign_Center)
- .VAlign(VAlign_Center)
- [
- MyCheckbox.ToSharedRef()
- ]
- + SHorizontalBox::Slot()
- .HAlign(HAlign_Left)
- .VAlign(VAlign_Center)
- [
- SNew(SVerticalBox)
- + SVerticalBox::Slot()
- .AutoHeight()
- .Padding(5.0f, 0.0f, 0.0f, 0.0f)
- .HAlign(HAlign_Left)
- [
- SNew(STextBlock)
- .Text(TAttribute<FText>::Create(TAttribute<FText>::FGetter::CreateUObject(this, &UAkCheckBox::GetAkItemControlled)))
- ]
- + SVerticalBox::Slot()
- .AutoHeight()
- .Padding(5.0f, 0.0f, 0.0f, 0.0f)
- .HAlign(HAlign_Left)
- [
- SNew(STextBlock)
- .Text(TAttribute<FText>::Create(TAttribute<FText>::FGetter::CreateUObject(this, &UAkCheckBox::GetAkBoolProperty)))
- ]
- ]
- ];
- }
- void UAkCheckBox::SynchronizeProperties()
- {
- Super::SynchronizeProperties();
- MyCheckbox->SetStyle(&WidgetStyle);
- MyCheckbox->SetIsChecked(PROPERTY_BINDING(ECheckBoxState, CheckedState) );
- ItemToControl.ItemPath = ItemToControl.ItemPicked.ItemPath;
- FGuid ItemId;
- if (!ItemToControl.ItemPicked.ItemId.IsEmpty())
- {
- if(FGuid::ParseExact(ItemToControl.ItemPicked.ItemId, EGuidFormats::DigitsWithHyphensInBraces, ItemId))
- {
- SetAkItemId(ItemId);
- }
- }
- SetAkBoolProperty(ThePropertyToControl.ItemProperty);
- }
- void UAkCheckBox::SetAkItemControlled(const FString& Item)
- {
- ItemControlled = Item;
- }
- FText UAkCheckBox::GetAkItemControlled()
- {
- return FText::FromString(TEXT("Item : ") + ItemControlled);
- }
- void UAkCheckBox::SetAkItemId(const FGuid& ItemId)
- {
- if (ItemId.IsValid())
- {
- IdItemToControl = ItemId.ToString(EGuidFormats::DigitsWithHyphensInBraces);
-
- TSharedPtr<FJsonObject> getResult;
- if (!SWaapiPicker::CallWaapiGetInfoFrom(WwiseWaapiHelper::ID, IdItemToControl, getResult, {}))
- {
- return;
- }
- TArray<TSharedPtr<FJsonValue>> StructJsonArray = getResult->GetArrayField(WwiseWaapiHelper::RETURN);
- if (StructJsonArray.Num() > 0)
- {
- const TSharedPtr<FJsonObject>& ItemInfoObj = StructJsonArray[0]->AsObject();
- SetAkItemControlled(ItemInfoObj->GetStringField(WwiseWaapiHelper::NAME));
- }
- #if AK_SUPPORT_WAAPI
- /** UnSubscribe to object renamed to be notified from Wwise using WAAPI, so we can maintain the name of the item controlled up to date dynamically. */
- // Connect to Wwise Authoring on localhost.
- if (SubscriptionIdNameChanged != 0)
- {
- bool isUnsubscribed;
- UAkWaapiCalls::Unsubscribe(FAkWaapiSubscriptionId(SubscriptionIdNameChanged), isUnsubscribed);
- if (isUnsubscribed)
- SubscriptionIdNameChanged = 0;
- }
- TSharedPtr<FJsonObject> outJsonResult;
- /** Subscribe to object renamed-created-deleted and removed to be notified from Wwise using WAAPI, so we can maintain the Wise picker up to date dynamically. */
- // Connect to Wwise Authoring on localhost.
- FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
- if (waapiClient)
- {
- auto wampEventCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> in_UEJsonObject)
- {
- AsyncTask(ENamedThreads::GameThread, [this, in_UEJsonObject]
- {
- SetAkItemControlled(in_UEJsonObject->GetStringField(WwiseWaapiHelper::NEW_NAME));
- });
- });
- // Construct the options Json object : Getting parent infos.
- TSharedRef<FJsonObject> in_options = MakeShareable(new FJsonObject());
- // Subscribe to object renamed-created-deleted and removed notifications.
- waapiClient->Subscribe(ak::wwise::core::object::nameChanged, in_options, wampEventCallback, SubscriptionIdNameChanged, outJsonResult);
- }
- SynchronizePropertyWithWwise();
- #endif
- }
- }
- const FGuid UAkCheckBox::GetAkItemId() const
- {
- FGuid ItemId;
- if (!IdItemToControl.IsEmpty())
- {
- FGuid::ParseExact(IdItemToControl, EGuidFormats::DigitsWithHyphensInBraces, ItemId);
- }
- return ItemId;
- }
- void UAkCheckBox::SetAkBoolProperty(const FString& BoolProperty)
- {
- BoolPropertyToControl = BoolProperty;
- SynchronizePropertyWithWwise();
- }
- const FString UAkCheckBox::GetAkProperty() const
- {
- return BoolPropertyToControl;
- }
- FText UAkCheckBox::GetAkBoolProperty() const
- {
- return FText::FromString(TEXT("Property : ") + GetAkProperty());
- }
- void UAkCheckBox::OnSlotAdded(UPanelSlot* InSlot)
- {
- // Add the child to the live slot if it already exists
- if ( MyCheckbox.IsValid() )
- {
- MyCheckbox->SetContent(InSlot->Content ? InSlot->Content->TakeWidget() : SNullWidget::NullWidget);
- }
- }
- void UAkCheckBox::SynchronizePropertyWithWwise()
- {
- if (!IdItemToControl.IsEmpty() && !BoolPropertyToControl.IsEmpty())
- {
- TSharedPtr<FJsonObject> ItemInfoResult;
- if (CallWappiGetPropertySate(IdItemToControl, BoolPropertyToControl, ItemInfoResult))
- {
- bool result = false;
- if (ItemInfoResult.Get()->TryGetBoolField(WwiseWaapiHelper::AT + BoolPropertyToControl, result))
- {
- SetIsChecked(result);
- }
- }
- if (SubscriptionId != 0)
- {
- bool isUnsubscribed;
- UAkWaapiCalls::Unsubscribe(FAkWaapiSubscriptionId(SubscriptionId), isUnsubscribed);
- if (isUnsubscribed)
- SubscriptionId = 0;
- }
- TSharedPtr<FJsonObject> outJsonResult;
- auto wampEventCallback = WampEventCallback::CreateLambda([this](uint64_t id, TSharedPtr<FJsonObject> in_UEJsonObject)
- {
- bool result = false;
- if (in_UEJsonObject->TryGetBoolField(WwiseWaapiHelper::NEW, result))
- {
- SetIsChecked(result);
- }
- });
- SubscribeToPropertyStateChange(IdItemToControl, BoolPropertyToControl, wampEventCallback, SubscriptionId, outJsonResult);
- }
- }
- void UAkCheckBox::OnSlotRemoved(UPanelSlot* InSlot)
- {
- // Remove the widget from the live slot if it exists.
- if ( MyCheckbox.IsValid() )
- {
- MyCheckbox->SetContent(SNullWidget::NullWidget);
- }
- }
- bool UAkCheckBox::IsPressed() const
- {
- if ( MyCheckbox.IsValid() )
- {
- return MyCheckbox->IsPressed();
- }
- return false;
- }
- bool UAkCheckBox::IsChecked() const
- {
- if ( MyCheckbox.IsValid() )
- {
- return MyCheckbox->IsChecked();
- }
- return ( CheckedState == ECheckBoxState::Checked );
- }
- ECheckBoxState UAkCheckBox::GetCheckedState() const
- {
- if ( MyCheckbox.IsValid() )
- {
- return MyCheckbox->GetCheckedState();
- }
- return CheckedState;
- }
- void UAkCheckBox::SetIsChecked(bool InIsChecked)
- {
- CheckedState = InIsChecked ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
- if ( MyCheckbox.IsValid() )
- {
- MyCheckbox->SetIsChecked(PROPERTY_BINDING(ECheckBoxState, CheckedState));
- }
- }
- void UAkCheckBox::SetCheckedState(ECheckBoxState InCheckedState)
- {
- CheckedState = InCheckedState;
- if ( MyCheckbox.IsValid() )
- {
- MyCheckbox->SetIsChecked(PROPERTY_BINDING(ECheckBoxState, CheckedState));
- }
- }
- void UAkCheckBox::SlateOnCheckStateChangedCallback(ECheckBoxState NewState)
- {
- CheckedState = NewState;
- if (ItemControlled.IsEmpty() || BoolPropertyToControl.IsEmpty() || IdItemToControl.IsEmpty())
- {
- UE_LOG(LogAkAudio, Log, TEXT("No item or property to control"));
- return;
- }
- // Construct the arguments Json object : setting configs
- TSharedRef<FJsonObject> args = MakeShareable(new FJsonObject());
- {
- args->SetStringField(WwiseWaapiHelper::OBJECT, IdItemToControl);
- args->SetStringField(WwiseWaapiHelper::PROPERTY, BoolPropertyToControl);
- args->SetBoolField(WwiseWaapiHelper::VALUE, IsChecked()); // this gives us a range of volume from [-96 to 12]
- }
- // Construct the options Json object;
- TSharedRef<FJsonObject> options = MakeShareable(new FJsonObject());
- // Connect to Wwise Authoring on localhost.
- FAkWaapiClient* waapiClient = FAkWaapiClient::Get();
- if (waapiClient)
- {
- #if AK_SUPPORT_WAAPI
- TSharedPtr<FJsonObject> outJsonResult;
- // Request data from Wwise using WAAPI
- if (waapiClient->Call(ak::wwise::core::object::setProperty, args, options, outJsonResult))
- {
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Call Failed"));
- return;
- }
- #endif
- }
- else
- {
- UE_LOG(LogAkAudio, Log, TEXT("Unable to connect to localhost"));
- return;
- }
- // Choosing to treat Undetermined as Checked
- const bool bWantsToBeChecked = NewState != ECheckBoxState::Unchecked;
- AkOnCheckStateChanged.Broadcast(bWantsToBeChecked);
- }
- FReply UAkCheckBox::OnDropHandler(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
- {
- FReply HandledState = FReply::Unhandled();
- TSharedPtr<FDragDropOperation> Operation = DragDropEvent.GetOperation();
- if (Operation.IsValid())
- {
- if (Operation->IsOfType<FWwiseUmgDragDropOp>())
- {
- const auto& AssetDragDropOp = StaticCastSharedPtr<FWwiseUmgDragDropOp>(Operation);
- if (AssetDragDropOp.IsValid())
- {
- const auto& WwiseAssets = AssetDragDropOp->GetWiseItems();
- if (WwiseAssets.Num() && WwiseAssets[0].IsValid())
- {
- if (OnItemDropped.IsBound())
- {
- OnItemDropped.Broadcast(WwiseAssets[0]->ItemId);
- }
- else
- {
- SetAkItemId(WwiseAssets[0]->ItemId);
- }
- HandledState = FReply::Handled();
- }
- }
- }
- else if (Operation->IsOfType<FWwiseBoolPropertyDragDropOp>())
- {
- const auto& AssetDragDropOp = StaticCastSharedPtr<FWwiseBoolPropertyDragDropOp>(Operation);
- if (AssetDragDropOp.IsValid())
- {
- const auto& WwiseAssets = AssetDragDropOp->GetWiseProperties();
- if (WwiseAssets.Num() && WwiseAssets[0].IsValid())
- {
- if (OnPropertyDropped.IsBound())
- {
- OnPropertyDropped.Broadcast(*WwiseAssets[0].Get());
- }
- else
- {
- SetAkBoolProperty(*WwiseAssets[0].Get());
- }
- HandledState = FReply::Handled();
- }
- }
- }
- }
- return HandledState;
- }
- #if WITH_EDITOR
- const FText UAkCheckBox::GetPaletteCategory()
- {
- return LOCTEXT("Wwise", "Wwise");
- }
- #endif
- /////////////////////////////////////////////////////
- #undef LOCTEXT_NAMESPACE
|