You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2945755 on 2016/04/15 by Frank.Fella
Sequencer - Fix issues with level visibility.
+ Don't mark sub-levels as dirty when the track evaluates.
+ Fix an issue where sequencer gets into a refresh loop because drawing thumbnails causes levels to be added which was rebuilding the tree, which was redrawing thumbnails.
+ Null check for when an objects world is null but the track is still evaluating.
+ Remove UnrealEd references.
Change 2947197 on 2016/04/18 by Max.Chen
Sequencer: Expose settings sequencer settings in the Editor Preferences page. Note, UMG and Niagara have separate sequencer settings pages.
#jira UE-29516
Change 2948468 on 2016/04/19 by Max.Chen
Sequencer: Fix particles not firing on loop.
#jira UE-27881
Change 2948590 on 2016/04/19 by Max.Chen
Sequencer: Fix spawnables not getting default tracks.
#jira UE-29644
Change 2955993 on 2016/04/26 by Max.Chen
Sequencer: Refresh instances when done recording. This fixes a bug where spawned recorded actors aren't visible when done recording.
#jira UE-29841
Change 2958567 on 2016/04/27 by Max.Preussner
RHI: Made SetReferencedTexture public, so that the referenced texture can be set
Change 2958718 on 2016/04/28 by Max.Chen
Sequencer: Folder colors. Right click on a folder and choose "Set Color"
#jira UE-28669
Change 2960172 on 2016/04/28 by Max.Preussner
Slate: Slate Remote Server (for the iOS touch input app) is now disabled by default, so we don't open up the socket unless desired by the user
Change 2960411 on 2016/04/28 by Max.Chen
Sequencer: Don't remove label if it's not being used.
#jira UE-24283
Change 2960414 on 2016/04/28 by Max.Chen
Matinee: Don't automatically turn frustums on/off when entering and exiting Matinee.
#jira UE-1020
Change 2962784 on 2016/05/02 by Max.Chen
Sequencer: Add master sequence
#jira UE-29799
Change 2964399 on 2016/05/03 by Andrew.Rodham
Sequencer: Added ability to apply cook-time optimization to tracks and objects
- For now, if a spawnable has a spawn track that is disabled, or will never spawn, the entire spawnable object will be removed from a cooked package.
- Possessables also afford the same optimization, although none is currently implemented
- We could, in future, also remove any tracks that are completely disabled
- Deprecated UMovieSceneBoolSection::DefaultValue in favor of the default stored on FIntegralCurve
Change 2967549 on 2016/05/05 by Max.Chen
Sequencer: Fix crash converting possessable to spawnable when the possessable doesn't exist.
#jira UE-30360
Change 2967670 on 2016/05/05 by Max.Chen
Sequencer: Set ui min/max for sequencer settings
#jira UE-30344
Change 2978969 on 2016/05/16 by Max.Chen
Sequencer: Restore state when focusing on a shot level sequence. This fixes issues where tracks in the movie scene that are active before switching to the new movie scene need to return to
their initial state. For example, setting a fade track in the master sequence and switching into a shot should disable the effects of the fade track in the master sequence.
#jira UE-30798
Change 2983237 on 2016/05/19 by Andrew.Rodham
Protocol settings for movie captures are now set up correctly when a capture type is specified on the command line
Thanks to original github author, yuhe00
#pr
#2257
Change 2991115 on 2016/05/26 by Andrew.Rodham
Sequencer: Added {shot} and {shot_frame} format args for movie captures
- Additionally, rendering out movie scenes as videos will now generate a new video for each unique filename it encounters. This allows us to render out a video per shot by using {shot} as
the output format.
- Frame numbers are now zero-padded as per the sequencer setting.
Change 2991920 on 2016/05/26 by Max.Chen
Sequencer: Fix movie scene getting dirtied unnecessarily when the fixed frame interval changes.
#jira UE-31343
Change 2992387 on 2016/05/26 by Max.Chen
Sequencer: Fix crash when getting the color key properties of a collapsed key that doesn't have all channels keyed.
#jira UE-31392
Change 2993553 on 2016/05/27 by Andrew.Rodham
Sequencer: Added the ability to add burn-ins to level sequences
- A default burn-in is provided which hosts a great level of flexibility
- 6 regions (L/C/R + T/B) on a 30% black border allow positioning of a range of frame statistics such as shot name ({ShotName}), frame numbers ({MasterFrame}, {ShotFrame}), and other
information.
- Watermark is provided by default (currently no tiling is exposed)
- Users can use the default built in UMG widget as a guideline for their own custom implementations.
Change 2993554 on 2016/05/27 by Andrew.Rodham
Sequencer: Default level sequence burn ins
- Also made a font asset out of our fixed width font shipped with the engine
Change 2993856 on 2016/05/30 by Max.Chen
Sequencer: Import/Export EDL
- Added a new option in the render movie dialog to export an Edit Decision List (EDL) in cmx and rv formats if there is a shot track. The default is true.
- Added "Import EDL" to shot track right click menu which imports a cmx EDL and conforms the shot order and cut information to it.
- Added "Export EDL" to shot track right click menu which exports EDLs in cmx and rv formats.
- Added "Render Shot" to shot right click menu which loads up the render movie dialog with the start and end frames of the selected shot.
#jira UETOOL-829, UETOOL-830
Change 2994761 on 2016/05/31 by Max.Chen
Sequence Recorder: Add a setting to allow recording of actors that are spawned by sequencer itself.
Change 2995648 on 2016/06/01 by HaarmPieter.Duiker
Sequencer EXR output gamut controls
Change 2996241 on 2016/06/01 by Frank.Fella
Sequencer - Add a small epsilon when "force fixed frame interval" is enabled, to make sure we're in the start of the next frame.
Change 2996244 on 2016/06/01 by Frank.Fella
Sequencer - Set the tick prerequisite for all components, not just the root.
Change 2997865 on 2016/06/02 by Max.Preussner
Sequencer: Fixed Crash in Sequencer play rate track when setting negative play rate (UE-31431)
#jira UE-31431
Change 2999631 on 2016/06/03 by Frank.Fella
Sequencer - At runtime, make sure to stop playing skeletal animations to prevent them from being double updated each frame, once by sequencer, and then again by tick.
Change 3000820 on 2016/06/03 by Max.Chen
Sequencer: Add hotkey (ctrl-T) to toggle between showing frame numbers and time.
#jira UE-31497
Change 3001056 on 2016/06/05 by Max.Chen
Sequencer: Fix fade color section crash by using an inline color picker in the details panel instead of a popup color picker.
#jira UE-31647
Change 3001057 on 2016/06/05 by Max.Chen
Movie Capture: Fix audio getting disabled after recording a movie.
Change 3001690 on 2016/06/06 by Andrew.Rodham
Sequencer: Fixed recording video sequences when not overwriting existing videos
Change 3001823 on 2016/06/06 by Max.Chen
Sequencer: Fix filtered nodes in folders so that other unfiltered children aren't visible.
#jira UE-31499
#lockdown Nick.Penwarden
[CL 3003974 by Max Chen in Main branch]
615 lines
20 KiB
C++
615 lines
20 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SequencerPrivatePCH.h"
|
|
#include "SequencerObjectBindingNode.h"
|
|
#include "Sequencer.h"
|
|
#include "MovieScene.h"
|
|
#include "MovieSceneSequence.h"
|
|
#include "MovieSceneTrack.h"
|
|
#include "ObjectEditorUtils.h"
|
|
#include "AssetEditorManager.h"
|
|
#include "SequencerUtilities.h"
|
|
#include "SlateIconFinder.h"
|
|
#include "SequencerCommands.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "FObjectBindingNode"
|
|
|
|
|
|
namespace SequencerNodeConstants
|
|
{
|
|
extern const float CommonPadding;
|
|
}
|
|
|
|
|
|
void GetKeyablePropertyPaths(UClass* Class, UStruct* PropertySource, TArray<UProperty*>& PropertyPath, FSequencer& Sequencer, TArray<TArray<UProperty*>>& KeyablePropertyPaths)
|
|
{
|
|
//@todo need to resolve this between UMG and the level editor sequencer
|
|
const bool bRecurseAllProperties = Sequencer.IsLevelEditorSequencer();
|
|
|
|
for (TFieldIterator<UProperty> PropertyIterator(PropertySource); PropertyIterator; ++PropertyIterator)
|
|
{
|
|
UProperty* Property = *PropertyIterator;
|
|
|
|
if (Property && !Property->HasAnyPropertyFlags(CPF_Deprecated))
|
|
{
|
|
PropertyPath.Add(Property);
|
|
|
|
bool bIsPropertyKeyable = Sequencer.CanKeyProperty(FCanKeyPropertyParams(Class, PropertyPath));
|
|
if (bIsPropertyKeyable)
|
|
{
|
|
KeyablePropertyPaths.Add(PropertyPath);
|
|
}
|
|
|
|
if (!bIsPropertyKeyable || bRecurseAllProperties)
|
|
{
|
|
UStructProperty* StructProperty = Cast<UStructProperty>(Property);
|
|
if (StructProperty != nullptr)
|
|
{
|
|
GetKeyablePropertyPaths(Class, StructProperty->Struct, PropertyPath, Sequencer, KeyablePropertyPaths);
|
|
}
|
|
}
|
|
|
|
PropertyPath.RemoveAt(PropertyPath.Num() - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct PropertyMenuData
|
|
{
|
|
FString MenuName;
|
|
TArray<UProperty*> PropertyPath;
|
|
};
|
|
|
|
|
|
|
|
FSequencerObjectBindingNode::FSequencerObjectBindingNode(FName NodeName, const FText& InDisplayName, const FGuid& InObjectBinding, TSharedPtr<FSequencerDisplayNode> InParentNode, FSequencerNodeTree& InParentTree)
|
|
: FSequencerDisplayNode(NodeName, InParentNode, InParentTree)
|
|
, ObjectBinding(InObjectBinding)
|
|
, DefaultDisplayName(InDisplayName)
|
|
{
|
|
UMovieScene* MovieScene = GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();
|
|
|
|
if (MovieScene->FindPossessable(ObjectBinding))
|
|
{
|
|
BindingType = EObjectBindingType::Possessable;
|
|
}
|
|
else if (MovieScene->FindSpawnable(ObjectBinding))
|
|
{
|
|
BindingType = EObjectBindingType::Spawnable;
|
|
}
|
|
else
|
|
{
|
|
BindingType = EObjectBindingType::Unknown;
|
|
}
|
|
}
|
|
|
|
/* FSequencerDisplayNode interface
|
|
*****************************************************************************/
|
|
|
|
void FSequencerObjectBindingNode::BuildContextMenu(FMenuBuilder& MenuBuilder)
|
|
{
|
|
if (GetSequencer().IsLevelEditorSequencer())
|
|
{
|
|
UMovieScene* MovieScene = GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();
|
|
FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(ObjectBinding);
|
|
|
|
if (Spawnable)
|
|
{
|
|
MenuBuilder.AddSubMenu(
|
|
LOCTEXT("OwnerLabel", "Spawned Object Owner"),
|
|
LOCTEXT("OwnerTooltip", "Specifies how the spawned object is to be owned"),
|
|
FNewMenuDelegate::CreateSP(this, &FSequencerObjectBindingNode::AddSpawnOwnershipMenu)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
const UClass* ObjectClass = GetClassForObjectBinding();
|
|
|
|
if (ObjectClass->IsChildOf(AActor::StaticClass()))
|
|
{
|
|
FFormatNamedArguments Args;
|
|
|
|
MenuBuilder.AddSubMenu(
|
|
FText::Format( LOCTEXT("Assign Actor ", "Assign Actor"), Args),
|
|
FText::Format( LOCTEXT("AssignActorTooltip", "Assign an actor to this track"), Args ),
|
|
FNewMenuDelegate::CreateRaw(&GetSequencer(), &FSequencer::AssignActor, ObjectBinding));
|
|
}
|
|
|
|
MenuBuilder.AddMenuEntry( FSequencerCommands::Get().ConvertToSpawnable );
|
|
}
|
|
|
|
/*
|
|
MenuBuilder.AddMenuEntry(
|
|
LOCTEXT("Import FBX", "Import FBX..."),
|
|
LOCTEXT("ImportFBXTooltip", "Import FBX animation to this object"),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateLambda([=]{ GetSequencer().ImportFBX(ObjectBinding); })
|
|
));
|
|
*/
|
|
|
|
MenuBuilder.BeginSection("Organize", LOCTEXT("OrganizeContextMenuSectionName", "Organize"));
|
|
{
|
|
MenuBuilder.AddSubMenu(
|
|
LOCTEXT("LabelsSubMenuText", "Labels"),
|
|
LOCTEXT("LabelsSubMenuTip", "Add or remove labels on this track"),
|
|
FNewMenuDelegate::CreateSP(this, &FSequencerObjectBindingNode::HandleLabelsSubMenuCreate)
|
|
);
|
|
}
|
|
MenuBuilder.EndSection();
|
|
}
|
|
|
|
FSequencerDisplayNode::BuildContextMenu(MenuBuilder);
|
|
}
|
|
|
|
void FSequencerObjectBindingNode::AddSpawnOwnershipMenu(FMenuBuilder& MenuBuilder)
|
|
{
|
|
FMovieSceneSpawnable* Spawnable = GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene()->FindSpawnable(ObjectBinding);
|
|
if (!Spawnable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MenuBuilder.AddMenuEntry(
|
|
LOCTEXT("ThisSequence_Label", "This Sequence"),
|
|
LOCTEXT("ThisSequence_Tooltip", "Indicates that this sequence will own the spawned object. The object will be destroyed at the end of the sequence."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateLambda([=]{ Spawnable->SetSpawnOwnership(ESpawnOwnership::InnerSequence); }),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateLambda([=]{ return Spawnable->GetSpawnOwnership() == ESpawnOwnership::InnerSequence; })
|
|
),
|
|
NAME_None,
|
|
EUserInterfaceActionType::ToggleButton
|
|
);
|
|
|
|
MenuBuilder.AddMenuEntry(
|
|
LOCTEXT("MasterSequence_Label", "Master Sequence"),
|
|
LOCTEXT("MasterSequence_Tooltip", "Indicates that the outermost sequence will own the spawned object. The object will be destroyed when the outermost sequence stops playing."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateLambda([=]{ Spawnable->SetSpawnOwnership(ESpawnOwnership::MasterSequence); }),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateLambda([=]{ return Spawnable->GetSpawnOwnership() == ESpawnOwnership::MasterSequence; })
|
|
),
|
|
NAME_None,
|
|
EUserInterfaceActionType::ToggleButton
|
|
);
|
|
|
|
MenuBuilder.AddMenuEntry(
|
|
LOCTEXT("External_Label", "External"),
|
|
LOCTEXT("External_Tooltip", "Indicates this object's lifetime is managed externally once spawned. It will not be destroyed by sequencer."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateLambda([=]{ Spawnable->SetSpawnOwnership(ESpawnOwnership::External); }),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateLambda([=]{ return Spawnable->GetSpawnOwnership() == ESpawnOwnership::External; })
|
|
),
|
|
NAME_None,
|
|
EUserInterfaceActionType::ToggleButton
|
|
);
|
|
|
|
MenuBuilder.AddMenuSeparator();
|
|
MenuBuilder.AddMenuEntry(
|
|
LOCTEXT("IgnoreOwnership_Label", "Keep Alive Outside Playback Range (In Sequencer)"),
|
|
LOCTEXT("IgnoreOwnership_Tooltip", "Keeps the spawned object alive when viewing this specific sequence outside of its playback range. Does not apply to runtime evaluation."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateLambda([=]{
|
|
Spawnable->SetIgnoreOwnershipInEditor(!Spawnable->ShouldIgnoreOwnershipInEditor());
|
|
GetSequencer().SetGlobalTimeDirectly(GetSequencer().GetGlobalTime());
|
|
}),
|
|
FCanExecuteAction(),
|
|
FIsActionChecked::CreateLambda([=]{ return Spawnable->ShouldIgnoreOwnershipInEditor(); })
|
|
),
|
|
NAME_None,
|
|
EUserInterfaceActionType::ToggleButton
|
|
);
|
|
}
|
|
|
|
bool FSequencerObjectBindingNode::CanRenameNode() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
TSharedRef<SWidget> FSequencerObjectBindingNode::GetCustomOutlinerContent()
|
|
{
|
|
// Create a container edit box
|
|
TSharedRef<SHorizontalBox> BoxPanel = SNew(SHorizontalBox)
|
|
+ SHorizontalBox::Slot()
|
|
[
|
|
SNew(SSpacer)
|
|
];
|
|
|
|
|
|
TAttribute<bool> HoverState = TAttribute<bool>::Create(TAttribute<bool>::FGetter::CreateSP(this, &FSequencerDisplayNode::IsHovered));
|
|
|
|
BoxPanel->AddSlot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
FSequencerUtilities::MakeAddButton(LOCTEXT("TrackText", "Track"), FOnGetContent::CreateSP(this, &FSequencerObjectBindingNode::HandleAddTrackComboButtonGetMenuContent), HoverState)
|
|
];
|
|
|
|
const UClass* ObjectClass = GetClassForObjectBinding();
|
|
GetSequencer().BuildObjectBindingEditButtons(BoxPanel, ObjectBinding, ObjectClass);
|
|
|
|
return BoxPanel;
|
|
}
|
|
|
|
|
|
FText FSequencerObjectBindingNode::GetDisplayName() const
|
|
{
|
|
UMovieScene* MovieScene = GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();
|
|
|
|
if (MovieScene != nullptr)
|
|
{
|
|
return MovieScene->GetObjectDisplayName(ObjectBinding);
|
|
}
|
|
|
|
return DefaultDisplayName;
|
|
}
|
|
|
|
FLinearColor FSequencerObjectBindingNode::GetDisplayNameColor() const
|
|
{
|
|
FSequencer& Sequencer = ParentTree.GetSequencer();
|
|
TArray<TWeakObjectPtr<UObject>> RuntimeObjects;
|
|
Sequencer.GetRuntimeObjects( Sequencer.GetFocusedMovieSceneSequenceInstance(), ObjectBinding, RuntimeObjects );
|
|
if ( RuntimeObjects.Num() == 0 )
|
|
{
|
|
return FLinearColor::Red;
|
|
}
|
|
else
|
|
{
|
|
return FSequencerDisplayNode::GetDisplayNameColor();
|
|
}
|
|
}
|
|
|
|
FText FSequencerObjectBindingNode::GetDisplayNameToolTipText() const
|
|
{
|
|
FSequencer& Sequencer = ParentTree.GetSequencer();
|
|
TArray<TWeakObjectPtr<UObject>> RuntimeObjects;
|
|
Sequencer.GetRuntimeObjects( Sequencer.GetFocusedMovieSceneSequenceInstance(), ObjectBinding, RuntimeObjects );
|
|
if ( RuntimeObjects.Num() == 0 )
|
|
{
|
|
return LOCTEXT("InvalidBoundObjectToolTip", "The object bound to this track is missing.");
|
|
}
|
|
else
|
|
{
|
|
return FText();
|
|
}
|
|
}
|
|
|
|
const FSlateBrush* FSequencerObjectBindingNode::GetIconBrush() const
|
|
{
|
|
return FSlateIconFinder::FindIconBrushForClass(GetClassForObjectBinding());
|
|
}
|
|
|
|
const FSlateBrush* FSequencerObjectBindingNode::GetIconOverlayBrush() const
|
|
{
|
|
if (BindingType == EObjectBindingType::Spawnable)
|
|
{
|
|
return FEditorStyle::GetBrush("Sequencer.SpawnableIconOverlay");
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
FText FSequencerObjectBindingNode::GetIconToolTipText() const
|
|
{
|
|
if (BindingType == EObjectBindingType::Spawnable)
|
|
{
|
|
return LOCTEXT("SpawnableToolTip", "This item is spawned by sequencer according to this object's spawn track.");
|
|
}
|
|
else if (BindingType == EObjectBindingType::Possessable)
|
|
{
|
|
return LOCTEXT("PossessableToolTip", "This item is a possessable reference to an existing object.");
|
|
}
|
|
|
|
return FText();
|
|
}
|
|
|
|
float FSequencerObjectBindingNode::GetNodeHeight() const
|
|
{
|
|
return SequencerLayoutConstants::ObjectNodeHeight + SequencerNodeConstants::CommonPadding*2;
|
|
}
|
|
|
|
|
|
FNodePadding FSequencerObjectBindingNode::GetNodePadding() const
|
|
{
|
|
return FNodePadding(0.f);//SequencerNodeConstants::CommonPadding);
|
|
}
|
|
|
|
|
|
ESequencerNode::Type FSequencerObjectBindingNode::GetType() const
|
|
{
|
|
return ESequencerNode::Object;
|
|
}
|
|
|
|
|
|
void FSequencerObjectBindingNode::SetDisplayName(const FText& NewDisplayName)
|
|
{
|
|
UMovieScene* MovieScene = GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();
|
|
|
|
if (MovieScene != nullptr)
|
|
{
|
|
MovieScene->SetObjectDisplayName(ObjectBinding, NewDisplayName);
|
|
}
|
|
}
|
|
|
|
|
|
bool FSequencerObjectBindingNode::CanDrag() const
|
|
{
|
|
TSharedPtr<FSequencerDisplayNode> ParentSeqNode = GetParent();
|
|
return ParentSeqNode.IsValid() == false || ParentSeqNode->GetType() != ESequencerNode::Object;
|
|
}
|
|
|
|
|
|
/* FSequencerObjectBindingNode implementation
|
|
*****************************************************************************/
|
|
|
|
void FSequencerObjectBindingNode::AddPropertyMenuItems(FMenuBuilder& AddTrackMenuBuilder, TArray<TArray<UProperty*> > KeyableProperties, int32 PropertyNameIndexStart, int32 PropertyNameIndexEnd)
|
|
{
|
|
TArray<PropertyMenuData> KeyablePropertyMenuData;
|
|
|
|
for (auto KeyableProperty : KeyableProperties)
|
|
{
|
|
TArray<FString> PropertyNames;
|
|
if (PropertyNameIndexEnd == -1)
|
|
{
|
|
PropertyNameIndexEnd = KeyableProperty.Num();
|
|
}
|
|
|
|
//@todo
|
|
if (PropertyNameIndexStart >= KeyableProperty.Num())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (int32 PropertyNameIndex = PropertyNameIndexStart; PropertyNameIndex < PropertyNameIndexEnd; ++PropertyNameIndex)
|
|
{
|
|
PropertyNames.Add(KeyableProperty[PropertyNameIndex]->GetDisplayNameText().ToString());
|
|
}
|
|
|
|
PropertyMenuData KeyableMenuData;
|
|
{
|
|
KeyableMenuData.PropertyPath = KeyableProperty;
|
|
KeyableMenuData.MenuName = FString::Join( PropertyNames, TEXT( "." ) );
|
|
}
|
|
|
|
KeyablePropertyMenuData.Add(KeyableMenuData);
|
|
}
|
|
|
|
// Sort on the menu name
|
|
KeyablePropertyMenuData.Sort([](const PropertyMenuData& A, const PropertyMenuData& B)
|
|
{
|
|
int32 CompareResult = A.MenuName.Compare(B.MenuName);
|
|
return CompareResult < 0;
|
|
});
|
|
|
|
// Add menu items
|
|
for (int32 MenuDataIndex = 0; MenuDataIndex < KeyablePropertyMenuData.Num(); ++MenuDataIndex)
|
|
{
|
|
FUIAction AddTrackMenuAction(FExecuteAction::CreateSP(this, &FSequencerObjectBindingNode::HandlePropertyMenuItemExecute, KeyablePropertyMenuData[MenuDataIndex].PropertyPath));
|
|
AddTrackMenuBuilder.AddMenuEntry(FText::FromString(KeyablePropertyMenuData[MenuDataIndex].MenuName), FText(), FSlateIcon(), AddTrackMenuAction);
|
|
}
|
|
}
|
|
|
|
|
|
const UClass* FSequencerObjectBindingNode::GetClassForObjectBinding() const
|
|
{
|
|
UMovieScene* MovieScene = GetSequencer().GetFocusedMovieSceneSequence()->GetMovieScene();
|
|
FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(ObjectBinding);
|
|
FMovieScenePossessable* Possessable = MovieScene->FindPossessable(ObjectBinding);
|
|
|
|
// should exist, but also shouldn't be both a spawnable and a possessable
|
|
check((Spawnable != nullptr) ^ (Possessable != nullptr));
|
|
check((nullptr == Spawnable) || (nullptr != Spawnable->GetObjectTemplate()) );
|
|
const UClass* ObjectClass = Spawnable ? Spawnable->GetObjectTemplate()->GetClass() : Possessable->GetPossessedObjectClass();
|
|
|
|
return ObjectClass;
|
|
}
|
|
|
|
/* FSequencerObjectBindingNode callbacks
|
|
*****************************************************************************/
|
|
|
|
TSharedRef<SWidget> FSequencerObjectBindingNode::HandleAddTrackComboButtonGetMenuContent()
|
|
{
|
|
FSequencer& Sequencer = GetSequencer();
|
|
|
|
//@todo need to resolve this between UMG and the level editor sequencer
|
|
const bool bUseSubMenus = Sequencer.IsLevelEditorSequencer();
|
|
|
|
UObject* BoundObject = GetSequencer().FindSpawnedObjectOrTemplate(ObjectBinding);
|
|
|
|
ISequencerModule& SequencerModule = FModuleManager::GetModuleChecked<ISequencerModule>( "Sequencer" );
|
|
TSharedRef<FUICommandList> CommandList(new FUICommandList);
|
|
FMenuBuilder AddTrackMenuBuilder(true, nullptr, SequencerModule.GetMenuExtensibilityManager()->GetAllExtenders(CommandList, TArrayBuilder<UObject*>().Add(BoundObject)));
|
|
|
|
const UClass* ObjectClass = GetClassForObjectBinding();
|
|
AddTrackMenuBuilder.BeginSection(NAME_None, LOCTEXT("TracksMenuHeader" , "Tracks"));
|
|
GetSequencer().BuildObjectBindingTrackMenu(AddTrackMenuBuilder, ObjectBinding, ObjectClass);
|
|
AddTrackMenuBuilder.EndSection();
|
|
|
|
TArray<TArray<UProperty*>> KeyablePropertyPaths;
|
|
|
|
if (BoundObject != nullptr)
|
|
{
|
|
TArray<UProperty*> PropertyPath;
|
|
GetKeyablePropertyPaths(BoundObject->GetClass(), BoundObject->GetClass(), PropertyPath, Sequencer, KeyablePropertyPaths);
|
|
}
|
|
|
|
// [Aspect Ratio]
|
|
// [PostProcess Settings] [Bloom1Tint] [X]
|
|
// [PostProcess Settings] [Bloom1Tint] [Y]
|
|
// [PostProcess Settings] [ColorGrading]
|
|
// [Ortho View]
|
|
|
|
// Create property menu data based on keyable property paths
|
|
TArray<PropertyMenuData> KeyablePropertyMenuData;
|
|
for (auto KeyablePropertyPath : KeyablePropertyPaths)
|
|
{
|
|
PropertyMenuData KeyableMenuData;
|
|
KeyableMenuData.PropertyPath = KeyablePropertyPath;
|
|
KeyableMenuData.MenuName = KeyablePropertyPath[0]->GetDisplayNameText().ToString();
|
|
KeyablePropertyMenuData.Add(KeyableMenuData);
|
|
}
|
|
|
|
// Sort on the menu name
|
|
KeyablePropertyMenuData.Sort([](const PropertyMenuData& A, const PropertyMenuData& B)
|
|
{
|
|
int32 CompareResult = A.MenuName.Compare(B.MenuName);
|
|
return CompareResult < 0;
|
|
});
|
|
|
|
|
|
// Add menu items
|
|
AddTrackMenuBuilder.BeginSection( SequencerMenuExtensionPoints::AddTrackMenu_PropertiesSection, LOCTEXT("PropertiesMenuHeader" , "Properties"));
|
|
for (int32 MenuDataIndex = 0; MenuDataIndex < KeyablePropertyMenuData.Num(); )
|
|
{
|
|
TArray<TArray<UProperty*> > KeyableSubMenuPropertyPaths;
|
|
|
|
KeyableSubMenuPropertyPaths.Add(KeyablePropertyMenuData[MenuDataIndex].PropertyPath);
|
|
|
|
// If this menu data only has one property name, add the menu item
|
|
if (KeyablePropertyMenuData[MenuDataIndex].PropertyPath.Num() == 1 || !bUseSubMenus)
|
|
{
|
|
AddPropertyMenuItems(AddTrackMenuBuilder, KeyableSubMenuPropertyPaths);
|
|
++MenuDataIndex;
|
|
}
|
|
// Otherwise, look to the next menu data to gather up new data
|
|
else
|
|
{
|
|
for (; MenuDataIndex < KeyablePropertyMenuData.Num()-1; )
|
|
{
|
|
if (KeyablePropertyMenuData[MenuDataIndex].MenuName == KeyablePropertyMenuData[MenuDataIndex+1].MenuName)
|
|
{
|
|
++MenuDataIndex;
|
|
KeyableSubMenuPropertyPaths.Add(KeyablePropertyMenuData[MenuDataIndex].PropertyPath);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
AddTrackMenuBuilder.AddSubMenu(
|
|
FText::FromString(KeyablePropertyMenuData[MenuDataIndex].MenuName),
|
|
FText::GetEmpty(),
|
|
FNewMenuDelegate::CreateSP(this, &FSequencerObjectBindingNode::HandleAddTrackSubMenuNew, KeyableSubMenuPropertyPaths));
|
|
|
|
++MenuDataIndex;
|
|
}
|
|
}
|
|
AddTrackMenuBuilder.EndSection();
|
|
|
|
return AddTrackMenuBuilder.MakeWidget();
|
|
}
|
|
|
|
|
|
void FSequencerObjectBindingNode::HandleAddTrackSubMenuNew(FMenuBuilder& AddTrackMenuBuilder, TArray<TArray<UProperty*> > KeyablePropertyPaths)
|
|
{
|
|
// [PostProcessSettings] [Bloom1Tint] [X]
|
|
// [PostProcessSettings] [Bloom1Tint] [Y]
|
|
// [PostProcessSettings] [ColorGrading]
|
|
|
|
// Create property menu data based on keyable property paths
|
|
TSet<UProperty*> PropertiesTraversed;
|
|
TArray<PropertyMenuData> KeyablePropertyMenuData;
|
|
for (auto KeyablePropertyPath : KeyablePropertyPaths)
|
|
{
|
|
PropertyMenuData KeyableMenuData;
|
|
KeyableMenuData.PropertyPath = KeyablePropertyPath;
|
|
|
|
// If the path is greater than 1, keep track of the actual properties (not channels) and only add these properties once since we can't do single channel keying of a property yet.
|
|
if (KeyablePropertyPath.Num() > 1) //@todo
|
|
{
|
|
if (PropertiesTraversed.Find(KeyablePropertyPath[1]) != nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
KeyableMenuData.MenuName = FObjectEditorUtils::GetCategoryFName(KeyablePropertyPath[1]).ToString();
|
|
PropertiesTraversed.Add(KeyablePropertyPath[1]);
|
|
}
|
|
else
|
|
{
|
|
// No sub menus items, so skip
|
|
continue;
|
|
}
|
|
KeyablePropertyMenuData.Add(KeyableMenuData);
|
|
}
|
|
|
|
// Sort on the menu name
|
|
KeyablePropertyMenuData.Sort([](const PropertyMenuData& A, const PropertyMenuData& B)
|
|
{
|
|
int32 CompareResult = A.MenuName.Compare(B.MenuName);
|
|
return CompareResult < 0;
|
|
});
|
|
|
|
// Add menu items
|
|
for (int32 MenuDataIndex = 0; MenuDataIndex < KeyablePropertyMenuData.Num(); )
|
|
{
|
|
TArray<TArray<UProperty*> > KeyableSubMenuPropertyPaths;
|
|
KeyableSubMenuPropertyPaths.Add(KeyablePropertyMenuData[MenuDataIndex].PropertyPath);
|
|
|
|
for (; MenuDataIndex < KeyablePropertyMenuData.Num()-1; )
|
|
{
|
|
if (KeyablePropertyMenuData[MenuDataIndex].MenuName == KeyablePropertyMenuData[MenuDataIndex+1].MenuName)
|
|
{
|
|
++MenuDataIndex;
|
|
KeyableSubMenuPropertyPaths.Add(KeyablePropertyMenuData[MenuDataIndex].PropertyPath);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
const int32 PropertyNameIndexStart = 1; // Strip off the struct property name
|
|
const int32 PropertyNameIndexEnd = 2; // Stop at the property name, don't descend into the channels
|
|
|
|
AddTrackMenuBuilder.AddSubMenu(
|
|
FText::FromString(KeyablePropertyMenuData[MenuDataIndex].MenuName),
|
|
FText::GetEmpty(),
|
|
FNewMenuDelegate::CreateSP(this, &FSequencerObjectBindingNode::AddPropertyMenuItems, KeyableSubMenuPropertyPaths, PropertyNameIndexStart, PropertyNameIndexEnd));
|
|
|
|
++MenuDataIndex;
|
|
}
|
|
}
|
|
|
|
|
|
void FSequencerObjectBindingNode::HandleLabelsSubMenuCreate(FMenuBuilder& MenuBuilder)
|
|
{
|
|
MenuBuilder.AddWidget(SNew(SSequencerLabelEditor, GetSequencer(), ObjectBinding), FText::GetEmpty(), true);
|
|
}
|
|
|
|
|
|
void FSequencerObjectBindingNode::HandlePropertyMenuItemExecute(TArray<UProperty*> PropertyPath)
|
|
{
|
|
FSequencer& Sequencer = GetSequencer();
|
|
UObject* BoundObject = GetSequencer().FindSpawnedObjectOrTemplate(ObjectBinding);
|
|
|
|
TArray<UObject*> KeyableBoundObjects;
|
|
if (BoundObject != nullptr)
|
|
{
|
|
if (Sequencer.CanKeyProperty(FCanKeyPropertyParams(BoundObject->GetClass(), PropertyPath)))
|
|
{
|
|
KeyableBoundObjects.Add(BoundObject);
|
|
}
|
|
}
|
|
|
|
FKeyPropertyParams KeyPropertyParams(KeyableBoundObjects, PropertyPath);
|
|
{
|
|
KeyPropertyParams.KeyParams.bCreateTrackIfMissing = true;
|
|
KeyPropertyParams.KeyParams.bCreateHandleIfMissing = true;
|
|
KeyPropertyParams.KeyParams.bCreateKeyIfUnchanged = true;
|
|
KeyPropertyParams.KeyParams.bCreateKeyIfEmpty = true;
|
|
}
|
|
|
|
Sequencer.KeyProperty(KeyPropertyParams);
|
|
}
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|