211 lines
7.5 KiB
C++
211 lines
7.5 KiB
C++
// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2020.
|
|
|
|
#include "Sequencer/FMODChannelEditors.h"
|
|
#include "ISequencerChannelInterface.h"
|
|
#include "Widgets/DeclarativeSyntaxSupport.h"
|
|
#include "Widgets/SCompoundWidget.h"
|
|
#include "MovieSceneTimeHelpers.h"
|
|
#include "MovieSceneToolHelpers.h"
|
|
#include "ScopedTransaction.h"
|
|
#include "EditorWidgets/Public/SEnumCombobox.h"
|
|
#include "EditorStyleSet.h"
|
|
|
|
class SFMODEventControlKeyEditor : public SCompoundWidget
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS(SFMODEventControlKeyEditor) {}
|
|
SLATE_END_ARGS();
|
|
|
|
void Construct(const FArguments &InArgs, TMovieSceneChannelHandle<FMovieSceneByteChannel> InChannelHandle,
|
|
TWeakObjectPtr<UMovieSceneSection> InWeakSection, TWeakPtr<ISequencer> InWeakSequencer, UEnum *InEnum)
|
|
{
|
|
ChannelHandle = InChannelHandle;
|
|
WeakSection = InWeakSection;
|
|
WeakSequencer = InWeakSequencer;
|
|
|
|
ChildSlot[MovieSceneToolHelpers::MakeEnumComboBox(InEnum,
|
|
TAttribute<int32>::Create(TAttribute<int32>::FGetter::CreateSP(this, &SFMODEventControlKeyEditor::OnGetCurrentValueAsInt)),
|
|
SEnumComboBox::FOnEnumSelectionChanged::CreateSP(this, &SFMODEventControlKeyEditor::OnChangeKey))];
|
|
}
|
|
|
|
private:
|
|
int32 OnGetCurrentValueAsInt() const
|
|
{
|
|
using namespace MovieScene;
|
|
|
|
FMovieSceneByteChannel *Channel = ChannelHandle.Get();
|
|
ISequencer *Sequencer = WeakSequencer.Pin().Get();
|
|
UMovieSceneSection *OwningSection = WeakSection.Get();
|
|
uint8 Result = 0;
|
|
|
|
if (Channel && Sequencer && OwningSection)
|
|
{
|
|
const FFrameTime CurrentTime = MovieScene::ClampToDiscreteRange(Sequencer->GetLocalTime().Time, OwningSection->GetRange());
|
|
EvaluateChannel(Channel, CurrentTime, Result);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
void SetValue(uint8 InValue)
|
|
{
|
|
using namespace MovieScene;
|
|
using namespace Sequencer;
|
|
|
|
UMovieSceneSection *OwningSection = WeakSection.Get();
|
|
if (!OwningSection)
|
|
{
|
|
return;
|
|
}
|
|
|
|
OwningSection->SetFlags(RF_Transactional);
|
|
|
|
FMovieSceneByteChannel *Channel = ChannelHandle.Get();
|
|
ISequencer *Sequencer = WeakSequencer.Pin().Get();
|
|
|
|
if (!OwningSection->TryModify() || !Channel || !Sequencer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const FFrameNumber CurrentTime = Sequencer->GetLocalTime().Time.FloorToFrame();
|
|
const bool bAutoSetTrackDefaults = Sequencer->GetAutoSetTrackDefaults();
|
|
|
|
EMovieSceneKeyInterpolation Interpolation = Sequencer->GetKeyInterpolation();
|
|
|
|
TArray<FKeyHandle> KeysAtCurrentTime;
|
|
Channel->GetKeys(TRange<FFrameNumber>(CurrentTime), nullptr, &KeysAtCurrentTime);
|
|
|
|
if (KeysAtCurrentTime.Num() > 0)
|
|
{
|
|
AssignValue(Channel, KeysAtCurrentTime[0], InValue);
|
|
}
|
|
else
|
|
{
|
|
const bool bHasAnyKeys = Channel->GetNumKeys() != 0;
|
|
|
|
if (bHasAnyKeys || bAutoSetTrackDefaults == false)
|
|
{
|
|
// When auto setting track defaults are disabled, add a key even when it's empty so that the changed
|
|
// value is saved and is propagated to the property.
|
|
AddKeyToChannel(Channel, CurrentTime, InValue, Interpolation);
|
|
}
|
|
|
|
if (bHasAnyKeys)
|
|
{
|
|
TRange<FFrameNumber> KeyRange = TRange<FFrameNumber>(CurrentTime);
|
|
TRange<FFrameNumber> SectionRange = OwningSection->GetRange();
|
|
|
|
if (!SectionRange.Contains(KeyRange))
|
|
{
|
|
OwningSection->SetRange(TRange<FFrameNumber>::Hull(KeyRange, SectionRange));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Always update the default value when auto-set default values is enabled so that the last changes
|
|
// are always saved to the track.
|
|
if (bAutoSetTrackDefaults)
|
|
{
|
|
SetChannelDefault(Channel, InValue);
|
|
}
|
|
}
|
|
|
|
void OnChangeKey(int32 Selection, ESelectInfo::Type SelectionType)
|
|
{
|
|
FScopedTransaction Transaction(FText::FromString("Set FMOD Event Control Key Value"));
|
|
SetValue(Selection);
|
|
if (ISequencer *Sequencer = WeakSequencer.Pin().Get())
|
|
{
|
|
Sequencer->NotifyMovieSceneDataChanged(EMovieSceneDataChangeType::TrackValueChangedRefreshImmediately);
|
|
}
|
|
}
|
|
|
|
TMovieSceneChannelHandle<FMovieSceneByteChannel> ChannelHandle;
|
|
TWeakObjectPtr<UMovieSceneSection> WeakSection;
|
|
TWeakPtr<ISequencer> WeakSequencer;
|
|
};
|
|
|
|
bool CanCreateKeyEditor(const FMovieSceneByteChannel *Channel)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
TSharedRef<SWidget> CreateKeyEditor(const TMovieSceneChannelHandle<FMovieSceneByteChannel> &Channel, UMovieSceneSection *Section,
|
|
const FGuid &InObjectBindingID, TWeakPtr<FTrackInstancePropertyBindings> PropertyBindings, TWeakPtr<ISequencer> InSequencer)
|
|
{
|
|
const FMovieSceneByteChannel *RawChannel = Channel.Get();
|
|
|
|
if (!RawChannel)
|
|
{
|
|
return SNullWidget::NullWidget;
|
|
}
|
|
|
|
UEnum *Enum = RawChannel->GetEnum();
|
|
return SNew(SFMODEventControlKeyEditor, Channel, Section, InSequencer, Enum);
|
|
}
|
|
|
|
TSharedPtr<FStructOnScope> GetKeyStruct(const TMovieSceneChannelHandle<FFMODEventControlChannel> &ChannelHandle, FKeyHandle InHandle)
|
|
{
|
|
FFMODEventControlChannel *Channel = ChannelHandle.Get();
|
|
if (!Channel)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
TMovieSceneChannelData<uint8> ChannelData = Channel->GetData();
|
|
const int32 KeyIndex = ChannelData.GetIndex(InHandle);
|
|
|
|
if (KeyIndex == INDEX_NONE)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
TSharedPtr<FStructOnScope> KeyStruct = MakeShared<FStructOnScope>(FFMODEventControlKeyStruct::StaticStruct());
|
|
FFMODEventControlKeyStruct *Struct = reinterpret_cast<FFMODEventControlKeyStruct *>(KeyStruct->GetStructMemory());
|
|
|
|
Struct->Time = ChannelData.GetTimes()[KeyIndex];
|
|
Struct->Value = (EFMODEventControlKey)ChannelData.GetValues()[KeyIndex];
|
|
|
|
Struct->KeyStructInterop.Add(FMovieSceneChannelValueHelper(ChannelHandle, &Struct->Value, MakeTuple(InHandle, Struct->Time)));
|
|
return KeyStruct;
|
|
}
|
|
|
|
void DrawKeys(FFMODEventControlChannel *Channel, TArrayView<const FKeyHandle> InKeyHandles, TArrayView<FKeyDrawParams> OutKeyDrawParams)
|
|
{
|
|
static const FName KeyLeftBrushName("Sequencer.KeyLeft");
|
|
static const FName KeyRightBrushName("Sequencer.KeyRight");
|
|
static const FName KeyDiamondBrushName("Sequencer.KeyDiamond");
|
|
|
|
const FSlateBrush *LeftKeyBrush = FEditorStyle::GetBrush(KeyLeftBrushName);
|
|
const FSlateBrush *RightKeyBrush = FEditorStyle::GetBrush(KeyRightBrushName);
|
|
const FSlateBrush *DiamondBrush = FEditorStyle::GetBrush(KeyDiamondBrushName);
|
|
|
|
TMovieSceneChannelData<uint8> ChannelData = Channel->GetData();
|
|
|
|
for (int32 Index = 0; Index < InKeyHandles.Num(); ++Index)
|
|
{
|
|
FKeyHandle Handle = InKeyHandles[Index];
|
|
|
|
FKeyDrawParams Params;
|
|
Params.BorderBrush = Params.FillBrush = DiamondBrush;
|
|
|
|
const int32 KeyIndex = ChannelData.GetIndex(Handle);
|
|
if (KeyIndex != INDEX_NONE)
|
|
{
|
|
const EFMODEventControlKey Value = (EFMODEventControlKey)ChannelData.GetValues()[KeyIndex];
|
|
if (Value == EFMODEventControlKey::Play)
|
|
{
|
|
Params.BorderBrush = Params.FillBrush = LeftKeyBrush;
|
|
Params.FillOffset = FVector2D(-1.0f, 1.0f);
|
|
}
|
|
else if (Value == EFMODEventControlKey::Stop)
|
|
{
|
|
Params.BorderBrush = Params.FillBrush = RightKeyBrush;
|
|
Params.FillOffset = FVector2D(1.0f, 1.0f);
|
|
}
|
|
}
|
|
|
|
OutKeyDrawParams[Index] = Params;
|
|
}
|
|
}
|