I’m working with UE5.1.1 and trying to create a system to detect when the values of actor channels bound to a LevelSequencer are changed. For this, I’ve created a class that inherits from EditorUtilityWidget.
I’ve written the following C++ code and, in Unreal Engine, instantiated the CustomEditorUtilityWidget and executed SetEnableSequencerChannelChangedEvent during its construction.
However, even when I change the value of the channels registered with the Sequencer, OnEditorSequencerChannelChanged() does not get executed.
I’m wondering if I might be missing a step or doing something wrong with the binding process. Any insights or suggestions would be greatly appreciated!
CustomEditorUtilityWidget.h
#pragma once
#include "CoreMinimal.h"
#include "LevelSequenceActor.h"
#include "LevelSequence.h"
#include "MovieSceneSection.h"
#include "Channels/MovieSceneChannelProxy.h"
#include "Channels/MovieSceneChannel.h"
#include "Misc/Guid.h"
#include "Editor.h"
#include "Engine/Selection.h" // USelection
#include "EngineUtils.h"
#include "EditorUtilityWidget.h"
#include "CustomEditorUtilityWidget.generated.h"
UCLASS()
class EDITORMODULE_API UCustomEditorUtilityWidget : public UEditorUtilityWidget
{
GENERATED_BODY()
public:
UCustomEditorUtilityWidget(const FObjectInitializer& InObjectInitializer)
: Super(InObjectInitializer)
{}
UFUNCTION(BlueprintCallable, Category = "Sequencer Channel Changed Editor Utility Widget")
void SetEnableSequencerChannelChangedEvent(bool InEnabled);
UFUNCTION(BlueprintImplementableEvent, CallInEditor, Category = "Sequencer Channel Changed Editor Utility Widget")
void OnEditorSequencerChannelChanged();
private:
void OnSequencerChannelChanged(FMovieSceneChannel* Channel, const TArray< FKeyAddOrDeleteEventItem >& Items);
TArray<FDelegateHandle> SequencerChannelChangedEventHandles;
TArray<FHandlePair> HandlePairs;
};
USTRUCT()
struct FHandlePair
{
GENERATED_BODY()
FMovieSceneChannel* Channel;
FDelegateHandle Handle;
};
CustomEditorUtilityWidget.cpp
#include "CustomEditorUtilityWidget.h"
void UCustomEditorUtilityWidget::SetEnableSequencerChannelChangedEvent(bool InEnabled) {
if (InEnabled) {
UWorld* World = GetWorld();
TArray<ALevelSequenceActor*> SequenceActors;
TArray<ULevelSequence*> Sequences;
if (World) {
if (!HandlePairs.IsEmpty()) {
for (FHandlePair pair : HandlePairs) {
if (pair.Handle.IsValid())
{
UE_LOG(LogTemp, Log, TEXT("EventDeactivate"));
pair.Channel->OnKeyAddedEvent().Remove(pair.Handle);
pair.Handle.Reset();
}
}
}
for (TActorIterator<ALevelSequenceActor> ActorItr(World); ActorItr; ++ActorItr)
{
ALevelSequenceActor* SeqActor = *ActorItr;
if (SeqActor) {
SequenceActors.Add(SeqActor);
ULevelSequence* Sequence = SeqActor->GetSequence();
if (Sequence) {
Sequences.Add(Sequence);
UMovieScene* MovieScene = Sequence->GetMovieScene();
const TArray<FMovieSceneBinding>& Bindings = MovieScene->GetBindings();
for (FMovieSceneBinding Bind : Bindings) {
const TArray<UMovieSceneTrack*>& Tracks = Bind.GetTracks();
for (UMovieSceneTrack* Track : Tracks) {
const TArray< UMovieSceneSection* >& Sections = Track->GetAllSections();
for (UMovieSceneSection* Section : Sections) {
FMovieSceneChannelProxy& ChannelProxy = Section->GetChannelProxy();
TArrayView< const FMovieSceneChannelEntry > Entries = ChannelProxy.GetAllEntries();
for (const FMovieSceneChannelEntry& Entry : Entries) {
TArrayView < FMovieSceneChannel* const> Channels = Entry.GetChannels();
for (FMovieSceneChannel* const Channel : Channels) {
UE_LOG(LogTemp, Log, TEXT("EventActivate"));
FDelegateHandle handle = Channel->OnKeyAddedEvent().AddUObject(
this, &UCustomEditorUtilityWidget::OnSequencerChannelChanged);
SequencerChannelChangedEventHandles.Add(handle);
FHandlePair HandlePair;
HandlePair.Channel = Channel;
HandlePair.Handle = handle;
HandlePairs.Add(HandlePair);
}
}
}
}
}
}
}
}
}
}
else {
for (FHandlePair pair : HandlePairs) {
if (pair.Handle.IsValid())
{
UE_LOG(LogTemp, Log, TEXT("EventDeactivate"));
pair.Channel->OnKeyAddedEvent().Remove(pair.Handle);
pair.Handle.Reset();
}
}
HandlePairs.Empty();
}
}
void UCustomEditorUtilityWidget::OnSequencerChannelChanged(FMovieSceneChannel* Channel, const TArray< FKeyAddOrDeleteEventItem >& Items)
{
// Function implementation
UE_LOG(LogTemp, Log, TEXT("OnSequencerChannelChanged"));
OnEditorSequencerChannelChanged();
}