/******************************************************************************* 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 "MovieSceneAkAudioRTPCTrackEditor.h" #include "AkAudioDevice.h" #include "AkRtpc.h" #include "MovieScene.h" #include "MovieSceneCommonHelpers.h" #include "MovieSceneAkAudioRTPCTrack.h" #include "MovieSceneAkAudioRTPCSection.h" #include "SequencerUtilities.h" #include "ISequencerSection.h" #include "ISequencerObjectChangeListener.h" #include "ISectionLayoutBuilder.h" #include "SequencerSectionPainter.h" #include "AkAudioStyle.h" #include "ContentBrowserModule.h" #include "IContentBrowserSingleton.h" #include "ScopedTransaction.h" #include "Widgets/Layout/SBorder.h" #include "Widgets/Layout/SUniformGridPanel.h" #include "Widgets/Layout/SExpandableArea.h" #include "Widgets/Input/SEditableTextBox.h" #include "Widgets/Input/SButton.h" #include "Editor.h" #define LOCTEXT_NAMESPACE "MovieSceneAkAudioRTPCTrackEditor" /** * Class that draws a transform section in the sequencer */ class FMovieSceneAkAudioRTPCSection : public ISequencerSection { public: FMovieSceneAkAudioRTPCSection(UMovieSceneSection& InSection) : Section(Cast(&InSection)) { } public: // ISequencerSection interface virtual UMovieSceneSection* GetSectionObject() override { return Section; } virtual FText GetSectionTitle() const override { return FText::FromString(Section->GetRTPCName()); } virtual int32 OnPaintSection(FSequencerSectionPainter& InPainter) const override { return InPainter.PaintSectionBackground(); } private: /** The section we are visualizing */ UMovieSceneAkAudioRTPCSection* Section; }; FMovieSceneAkAudioRTPCTrackEditor::FMovieSceneAkAudioRTPCTrackEditor(TSharedRef InSequencer) : FKeyframeTrackEditor(InSequencer) { } TSharedRef FMovieSceneAkAudioRTPCTrackEditor::CreateTrackEditor(TSharedRef InSequencer) { return MakeShareable(new FMovieSceneAkAudioRTPCTrackEditor(InSequencer)); } TSharedRef FMovieSceneAkAudioRTPCTrackEditor::MakeSectionInterface(UMovieSceneSection& SectionObject, UMovieSceneTrack& Track, FGuid ObjectBinding) { return MakeShareable(new FMovieSceneAkAudioRTPCSection(SectionObject)); } const FSlateBrush* FMovieSceneAkAudioRTPCTrackEditor::GetIconBrush() const { return FAkAudioStyle::Get().GetBrush("AudiokineticTools.RTPCIcon"); } struct FRTPCSectionCreateDialogOptions { FString RTPCName; UAkRtpc* RTPC = nullptr; bool OkClicked; FRTPCSectionCreateDialogOptions() : OkClicked(false) {} bool Validate() { return OkClicked && (RTPC != nullptr || RTPCName.Len() > 0); } }; class SCreateAkAudioRTPCSectionDialog : public SCompoundWidget { public: SLATE_BEGIN_ARGS(SCreateAkAudioRTPCSectionDialog) { } SLATE_END_ARGS() /** Construct this widget. */ void Construct(const FArguments& InArgs, FRTPCSectionCreateDialogOptions& InOptions, TSharedRef InWindow) { Options = &InOptions; Window = InWindow; FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked(TEXT("ContentBrowser")); FAssetPickerConfig AssetPickerConfig; AssetPickerConfig.InitialAssetViewType = EAssetViewType::List; AssetPickerConfig.bAllowNullSelection = false; #if UE_5_1_OR_LATER AssetPickerConfig.Filter.ClassPaths.Add(UAkRtpc::StaticClass()->GetClassPathName()); #else AssetPickerConfig.Filter.ClassNames.Add(UAkRtpc::StaticClass()->GetFName()); #endif AssetPickerConfig.OnAssetSelected = FOnAssetSelected::CreateLambda([&InOptions](const FAssetData& InRTPCAssetData) { if (InRTPCAssetData.IsValid()) { InOptions.RTPC = CastChecked(InRTPCAssetData.GetAsset()); } }); ChildSlot [ SNew(SBorder) .Visibility(EVisibility::Visible) .BorderImage(FAkAppStyle::Get().GetBrush("Menu.Background")) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Top) .Padding(4) [ SNew(SBorder) .BorderImage(FAkAppStyle::Get().GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) .Content() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(2, 2, 6, 2) [ SNew(STextBlock) .Text(LOCTEXT("AkAudioRTPC", "RTPC")) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2, 0, 2, 0) [ SNew(SBox) .WidthOverride(300.0f) .HeightOverride(300.f) [ ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig) ] ] ] ] + SVerticalBox::Slot() .FillHeight(1) .VAlign(VAlign_Top) .Padding(4) [ SNew(SExpandableArea) .AreaTitle(LOCTEXT("Advanced", "Advanced")) .InitiallyCollapsed(true) .BodyContent() [ SNew(SBorder) .BorderImage(FAkAppStyle::Get().GetBrush("ToolPanel.GroupBorder")) .Padding(4.0f) .Content() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(2, 2, 6, 2) [ SNew(STextBlock) .Text(LOCTEXT("AkAudioRTPCName", "RTPC Name")) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2, 0, 2, 0) [ SNew(SEditableTextBox) .HintText(LOCTEXT("AkAudioRTPCNameHint", "Name of the AkAudioRTPC")) .OnTextCommitted(this, &SCreateAkAudioRTPCSectionDialog::OnEventNameCommitted) .OnTextChanged(this, &SCreateAkAudioRTPCSectionDialog::OnEventNameCommitted, ETextCommit::Default) .MinDesiredWidth(200) .RevertTextOnEscape(true) ] ] ] ] + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Right) .VAlign(VAlign_Bottom) .Padding(8) [ SNew(SUniformGridPanel) .SlotPadding(FAkAppStyle::Get().GetMargin("StandardDialog.SlotPadding")) .MinDesiredSlotWidth(FAkAppStyle::Get().GetFloat("StandardDialog.MinDesiredSlotWidth")) .MinDesiredSlotHeight(FAkAppStyle::Get().GetFloat("StandardDialog.MinDesiredSlotHeight")) + SUniformGridPanel::Slot(0, 0) [ SNew(SButton) .HAlign(HAlign_Center) .ContentPadding(FAkAppStyle::Get().GetMargin("StandardDialog.ContentPadding")) .OnClicked_Lambda([this]() -> FReply { CloseDialog(true); return FReply::Handled(); }) .Text(LOCTEXT("OkButtonLabel", "OK")) ] + SUniformGridPanel::Slot(1, 0) [ SNew(SButton) .HAlign(HAlign_Center) .ContentPadding(FAkAppStyle::Get().GetMargin("StandardDialog.ContentPadding")) .OnClicked_Lambda([this]() -> FReply { CloseDialog(false); return FReply::Handled(); }) .Text(LOCTEXT("CancelButtonLabel", "Cancel")) ] ] ] ]; } protected: void CloseDialog(bool InOkClicked) { Options->OkClicked = InOkClicked; if (Window.IsValid()) { Window.Pin()->RequestDestroyWindow(); } } private: void OnEventNameCommitted(const FText& InText, ETextCommit::Type InCommitType) { Options->RTPCName = InText.ToString(); if (InCommitType == ETextCommit::OnEnter || InCommitType == ETextCommit::OnCleared) { CloseDialog(InCommitType == ETextCommit::OnEnter); } } FRTPCSectionCreateDialogOptions* Options; TWeakPtr Window; }; bool ConfigureRTPCSection(FRTPCSectionCreateDialogOptions& Options) { TSharedRef Window = SNew(SWindow) .Title(LOCTEXT("CreateAkAudioRTPCSectionDialog", "Enter AkAudioRTPC Name")) .ClientSize(FVector2D(372, 418)) .SupportsMinimize(false) .SupportsMaximize(false); Window->SetContent(SNew(SCreateAkAudioRTPCSectionDialog, Options, Window)); GEditor->EditorAddModalWindow(Window); return Options.Validate(); } void FMovieSceneAkAudioRTPCTrackEditor::TryAddAkAudioRTPCTrack(FCreateAkAudioRTPCTrack DoCreateAkAudioRTPCTrack) { FRTPCSectionCreateDialogOptions Options; if (ConfigureRTPCSection(Options)) { auto FocusedMovieScene = GetFocusedMovieScene(); if (FocusedMovieScene == nullptr) { return; } const FScopedTransaction Transaction(LOCTEXT("AddAkAudioRTPCTrack_Transaction", "Add AkAudioRTPC Track")); FocusedMovieScene->Modify(); auto NewTrack = DoCreateAkAudioRTPCTrack.Execute(FocusedMovieScene); ensure(NewTrack); auto NewSection = NewTrack->CreateNewSection(); ensure(NewSection); auto RTPCSection = Cast(NewSection); ensure(RTPCSection); if (Options.RTPC) { RTPCSection->SetRTPC(Options.RTPC); } else { RTPCSection->SetRTPCName(Options.RTPCName); } NewSection->SetRange(TRange::All()); NewTrack->AddSection(*NewSection); GetSequencer()->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::MovieSceneStructureItemAdded); } } void FMovieSceneAkAudioRTPCTrackEditor::BuildAddTrackMenu(FMenuBuilder& MenuBuilder) { auto CreateAkAudioRTPCTrack = [=](UMovieScene* MovieScene) { #if UE_5_2_OR_LATER auto NewTrack = MovieScene->AddTrack(); #else auto NewTrack = MovieScene->AddMasterTrack(); #endif if (NewTrack != nullptr) { NewTrack->SetIsAMasterTrack(true); } return NewTrack; }; MenuBuilder.AddMenuEntry( LOCTEXT("AddAkAudioRTPCTrack", "AkAudioRTPC"), LOCTEXT("AddAkAudioRTPCMasterTrackTooltip", "Adds a master AkAudioRTPC track."), FSlateIcon(FAkAudioStyle::GetStyleSetName(), "AudiokineticTools.RTPCIcon"), FUIAction(FExecuteAction::CreateLambda([this, CreateAkAudioRTPCTrack = MoveTemp(CreateAkAudioRTPCTrack)] { TryAddAkAudioRTPCTrack(FCreateAkAudioRTPCTrack::CreateLambda(CreateAkAudioRTPCTrack)); })) ); } bool FMovieSceneAkAudioRTPCTrackEditor::SupportsSequence(UMovieSceneSequence* InSequence) const { #if UE_5_1_OR_LATER static UClass* LevelSequenceClass = UClass::TryFindTypeSlow(TEXT("/Script/LevelSequence.LevelSequence"), EFindFirstObjectOptions::ExactClass); #else static UClass* LevelSequenceClass = FindObject(ANY_PACKAGE, TEXT("LevelSequence"), true); #endif return InSequence != nullptr && LevelSequenceClass != nullptr && InSequence->GetClass()->IsChildOf(LevelSequenceClass); } void FMovieSceneAkAudioRTPCTrackEditor::BuildObjectBindingTrackMenu(FMenuBuilder& MenuBuilder, const TArray& ObjectBindings, const UClass* ObjectClass) { auto ObjectBinding = ObjectBindings[0]; if (!ObjectClass->IsChildOf(AActor::StaticClass()) && !ObjectClass->IsChildOf(USceneComponent::StaticClass())) { return; } auto CreateAkAudioRTPCTrack = [=](UMovieScene* MovieScene) { return MovieScene->AddTrack(ObjectBinding); }; MenuBuilder.AddMenuEntry( LOCTEXT("AddAkAudioRTPCTrack", "AkAudioRTPC"), LOCTEXT("AddAkAudioRTPCTrackTooltip", "Adds an AkAudioRTPC track."), FSlateIcon(FAkAudioStyle::GetStyleSetName(), "AudiokineticTools.RTPCIcon"), FUIAction(FExecuteAction::CreateLambda([this, CreateAkAudioRTPCTrack = MoveTemp(CreateAkAudioRTPCTrack)] { TryAddAkAudioRTPCTrack(FCreateAkAudioRTPCTrack::CreateLambda(CreateAkAudioRTPCTrack)); })) ); } #undef LOCTEXT_NAMESPACE