Files
UnrealEngine/Engine/Source/Editor/Sequencer/Private/SKeyAreaEditorSwitcher.cpp
2025-05-18 13:04:45 +08:00

125 lines
3.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SKeyAreaEditorSwitcher.h"
#include "Widgets/Layout/SWidgetSwitcher.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SBoxPanel.h"
#include "Sequencer.h"
#include "SequencerCommonHelpers.h"
#include "IKeyArea.h"
#include "MVVM/ViewModels/ChannelModel.h"
#include "MVVM/ViewModels/SequencerEditorViewModel.h"
#include "MVVM/Extensions/IObjectBindingExtension.h"
#include "MVVM/Views/SKeyNavigationButtons.h"
namespace UE::Sequencer
{
void SKeyAreaEditorSwitcher::Construct(const FArguments& InArgs, TSharedPtr<FChannelGroupModel> InModel, TWeakPtr<FSequencerEditorViewModel> InWeakEditorModel)
{
WeakModel = InModel;
WeakEditorModel = InWeakEditorModel;
CachedChannelsSerialNumber = 0;
SetVisibility(MakeAttributeSP(this, &SKeyAreaEditorSwitcher::ComputeVisibility));
}
int32 SKeyAreaEditorSwitcher::GetWidgetIndex() const
{
return VisibleIndex;
}
EVisibility SKeyAreaEditorSwitcher::ComputeVisibility() const
{
return VisibleIndex != INDEX_NONE
? EVisibility::Visible
: EVisibility::Collapsed;
}
void SKeyAreaEditorSwitcher::Rebuild()
{
TSharedPtr<FChannelGroupModel> Model = WeakModel.Pin();
TSharedPtr<FSequencerEditorViewModel> Editor = WeakEditorModel.Pin();
if (!Model || !Editor)
{
// Empty our cache so we don't persistently rebuild
CachedKeyAreas.Empty();
// Node is no longer valid so just make this a null widget
ChildSlot
[
SNullWidget::NullWidget
];
return;
}
SetEnabled(MakeAttributeSP(Editor.ToSharedRef(), &FEditorViewModel::IsEditable));
VisibleIndex = INDEX_NONE;
TSharedRef<SWidgetSwitcher> Switcher = SNew(SWidgetSwitcher)
.WidgetIndex(this, &SKeyAreaEditorSwitcher::GetWidgetIndex);
TSharedPtr<IObjectBindingExtension> ParentObjectBinding = Model->FindAncestorOfType<IObjectBindingExtension>();
FGuid ObjectBindingID = ParentObjectBinding.IsValid() ? ParentObjectBinding->GetObjectGuid() : FGuid();
for (TSharedRef<IKeyArea> KeyArea : CachedKeyAreas)
{
Switcher->AddSlot()
.HAlign(HAlign_Left)
[
KeyArea->CreateKeyEditor(Editor->GetSequencer(), ObjectBindingID)
];
}
ChildSlot
[
Switcher
];
}
void SKeyAreaEditorSwitcher::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
{
TSharedPtr<FChannelGroupModel> Model = WeakModel.Pin();
TSharedPtr<FSequencerEditorViewModel> Editor = WeakEditorModel.Pin();
if (!Model || !Editor)
{
if (CachedKeyAreas.Num() != 0)
{
CachedKeyAreas.Empty();
// Node is not valid but we have a valid cache - we need to rebuild the switcher now
Rebuild();
}
return;
}
else
{
const uint32 NewChannelsSerialNumber = Model->GetChannelsSerialNumber();
const bool bRebuild = (NewChannelsSerialNumber != CachedChannelsSerialNumber);
if (bRebuild)
{
CachedChannelsSerialNumber = NewChannelsSerialNumber;
CachedKeyAreas = Model->GetAllKeyAreas();
for (int32 Index = CachedKeyAreas.Num()-1; Index >= 0; --Index)
{
if (!CachedKeyAreas[Index]->CanCreateKeyEditor())
{
CachedKeyAreas.RemoveAtSwap(Index);
}
}
Rebuild();
}
// Figure out which widget is active based on which section the current time is at.
TArray<UMovieSceneSection*> AllSections;
for (const TSharedRef<IKeyArea>& KeyArea : CachedKeyAreas)
{
AllSections.Add(KeyArea->GetOwningSection());
}
VisibleIndex = SequencerHelpers::GetSectionFromTime(AllSections, Editor->GetSequencer()->GetLocalTime().Time.FrameNumber);
}
}
} // namespace UE::Sequencer