2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "DetailCustomizationsPrivatePCH.h"
# include "ComponentTransformDetails.h"
# include "SVectorInputBox.h"
# include "SRotatorInputBox.h"
# include "PropertyCustomizationHelpers.h"
# include "ActorEditorUtils.h"
# include "Editor/UnrealEd/Public/Kismet2/ComponentEditorUtils.h"
# include "ScopedTransaction.h"
2014-05-03 00:37:05 -04:00
# include "IPropertyUtilities.h"
2014-03-14 14:13:41 -04:00
2015-01-06 07:30:01 -05:00
# include "UnitConversion.h"
# include "NumericUnitTypeInterface.inl"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "FComponentTransformDetails"
class FScopedSwitchWorldForObject
{
public :
FScopedSwitchWorldForObject ( UObject * Object )
: PrevWorld ( NULL )
{
bool bRequiresPlayWorld = false ;
if ( GUnrealEd - > PlayWorld & & ! GIsPlayInEditorWorld )
{
UPackage * ObjectPackage = Object - > GetOutermost ( ) ;
bRequiresPlayWorld = ! ! ( ObjectPackage - > PackageFlags & PKG_PlayInEditor ) ;
}
if ( bRequiresPlayWorld )
{
PrevWorld = SetPlayInEditorWorld ( GUnrealEd - > PlayWorld ) ;
}
}
~ FScopedSwitchWorldForObject ( )
{
if ( PrevWorld )
{
RestoreEditorWorld ( PrevWorld ) ;
}
}
private :
UWorld * PrevWorld ;
} ;
2015-02-16 06:51:44 -05:00
static USceneComponent * GetSceneComponentFromDetailsObject ( UObject * InObject )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
AActor * Actor = Cast < AActor > ( InObject ) ;
if ( Actor )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
return Actor - > GetRootComponent ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-16 06:51:44 -05:00
return Cast < USceneComponent > ( InObject ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-02 15:00:21 -04:00
FComponentTransformDetails : : FComponentTransformDetails ( const TArray < TWeakObjectPtr < UObject > > & InSelectedObjects , const FSelectedActorInfo & InSelectedActorInfo , IDetailLayoutBuilder & DetailBuilder )
2015-01-06 07:30:01 -05:00
: TNumericUnitTypeInterface ( EUnit : : Centimeters )
, SelectedActorInfo ( InSelectedActorInfo )
2014-03-14 14:13:41 -04:00
, SelectedObjects ( InSelectedObjects )
2014-05-02 15:00:21 -04:00
, NotifyHook ( DetailBuilder . GetPropertyUtilities ( ) - > GetNotifyHook ( ) )
2014-07-30 14:51:27 -04:00
, bPreserveScaleRatio ( false )
2014-03-14 14:13:41 -04:00
, bEditingRotationInUI ( false )
2014-07-24 20:56:55 -04:00
, HiddenFieldMask ( 0 )
2014-03-14 14:13:41 -04:00
{
2015-04-20 10:12:55 -04:00
GConfig - > GetBool ( TEXT ( " SelectionDetails " ) , TEXT ( " PreserveScaleRatio " ) , bPreserveScaleRatio , GEditorPerProjectIni ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-02 15:00:21 -04:00
TSharedRef < SWidget > FComponentTransformDetails : : BuildTransformFieldLabel ( ETransformField : : Type TransformField )
{
FText Label ;
switch ( TransformField )
{
case ETransformField : : Rotation :
Label = LOCTEXT ( " RotationLabel " , " Rotation " ) ;
break ;
case ETransformField : : Scale :
Label = LOCTEXT ( " ScaleLabel " , " Scale " ) ;
break ;
case ETransformField : : Location :
default :
Label = LOCTEXT ( " LocationLabel " , " Location " ) ;
break ;
}
FMenuBuilder MenuBuilder ( true , NULL , NULL ) ;
FUIAction SetRelativeLocationAction
(
FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnSetRelativeTransform , TransformField ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FComponentTransformDetails : : IsRelativeTransformChecked , TransformField )
) ;
FUIAction SetWorldLocationAction
(
FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnSetWorldTransform , TransformField ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FComponentTransformDetails : : IsWorldTransformChecked , TransformField )
) ;
MenuBuilder . BeginSection ( TEXT ( " TransformType " ) , FText : : Format ( LOCTEXT ( " TransformType " , " {0} Type " ) , Label ) ) ;
MenuBuilder . AddMenuEntry
(
FText : : Format ( LOCTEXT ( " RelativeLabel " , " Relative " ) , Label ) ,
FText : : Format ( LOCTEXT ( " RelativeLabel_ToolTip " , " {0} is relative to its parent " ) , Label ) ,
FSlateIcon ( ) ,
SetRelativeLocationAction ,
NAME_None ,
EUserInterfaceActionType : : RadioButton
) ;
MenuBuilder . AddMenuEntry
(
FText : : Format ( LOCTEXT ( " WorldLabel " , " World " ) , Label ) ,
FText : : Format ( LOCTEXT ( " WorldLabel_ToolTip " , " {0} is relative to the world " ) , Label ) ,
FSlateIcon ( ) ,
SetWorldLocationAction ,
NAME_None ,
EUserInterfaceActionType : : RadioButton
) ;
MenuBuilder . EndSection ( ) ;
return
SNew ( SComboButton )
. ContentPadding ( 0 )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. ForegroundColor ( FSlateColor : : UseForeground ( ) )
. MenuContent ( )
[
MenuBuilder . MakeWidget ( )
]
. ButtonContent ( )
[
SNew ( SBox )
. Padding ( FMargin ( 0.0f , 0.0f , 2.0f , 0.0f ) )
[
SNew ( STextBlock )
. Text ( this , & FComponentTransformDetails : : GetTransformFieldText , TransformField )
. Font ( IDetailLayoutBuilder : : GetDetailFont ( ) )
]
] ;
}
FText FComponentTransformDetails : : GetTransformFieldText ( ETransformField : : Type TransformField ) const
{
switch ( TransformField )
{
case ETransformField : : Location :
return GetLocationText ( ) ;
break ;
case ETransformField : : Rotation :
return GetRotationText ( ) ;
break ;
case ETransformField : : Scale :
return GetScaleText ( ) ;
break ;
default :
return FText : : GetEmpty ( ) ;
break ;
}
}
void FComponentTransformDetails : : OnSetRelativeTransform ( ETransformField : : Type TransformField )
{
const bool bEnable = false ;
switch ( TransformField )
{
case ETransformField : : Location :
OnToggleAbsoluteLocation ( bEnable ) ;
break ;
case ETransformField : : Rotation :
OnToggleAbsoluteRotation ( bEnable ) ;
break ;
case ETransformField : : Scale :
OnToggleAbsoluteScale ( bEnable ) ;
break ;
default :
break ;
}
}
bool FComponentTransformDetails : : IsRelativeTransformChecked ( ETransformField : : Type TransformField ) const
{
switch ( TransformField )
{
case ETransformField : : Location :
return ! bAbsoluteLocation ;
break ;
case ETransformField : : Rotation :
return ! bAbsoluteRotation ;
break ;
case ETransformField : : Scale :
return ! bAbsoluteScale ;
break ;
default :
return false ;
break ;
}
}
void FComponentTransformDetails : : OnSetWorldTransform ( ETransformField : : Type TransformField )
{
const bool bEnable = true ;
switch ( TransformField )
{
case ETransformField : : Location :
OnToggleAbsoluteLocation ( bEnable ) ;
break ;
case ETransformField : : Rotation :
OnToggleAbsoluteRotation ( bEnable ) ;
break ;
case ETransformField : : Scale :
OnToggleAbsoluteScale ( bEnable ) ;
break ;
default :
break ;
}
}
bool FComponentTransformDetails : : IsWorldTransformChecked ( ETransformField : : Type TransformField ) const
{
return ! IsRelativeTransformChecked ( TransformField ) ;
}
bool FComponentTransformDetails : : OnCanCopy ( ETransformField : : Type TransformField ) const
{
// We can only copy values if the whole field is set. If multiple values are defined we do not copy since we are unable to determine the value
switch ( TransformField )
{
case ETransformField : : Location :
return CachedLocation . IsSet ( ) ;
break ;
case ETransformField : : Rotation :
return CachedRotation . IsSet ( ) ;
break ;
case ETransformField : : Scale :
return CachedScale . IsSet ( ) ;
break ;
default :
return false ;
break ;
}
}
void FComponentTransformDetails : : OnCopy ( ETransformField : : Type TransformField )
{
CacheTransform ( ) ;
FString CopyStr ;
switch ( TransformField )
{
case ETransformField : : Location :
2014-07-07 07:00:30 -04:00
CopyStr = FString : : Printf ( TEXT ( " (X=%f,Y=%f,Z=%f) " ) , CachedLocation . X . GetValue ( ) , CachedLocation . Y . GetValue ( ) , CachedLocation . Z . GetValue ( ) ) ;
2014-05-02 15:00:21 -04:00
break ;
case ETransformField : : Rotation :
2014-07-07 07:00:30 -04:00
CopyStr = FString : : Printf ( TEXT ( " (Pitch=%f,Yaw=%f,Roll=%f) " ) , CachedRotation . Y . GetValue ( ) , CachedRotation . Z . GetValue ( ) , CachedRotation . X . GetValue ( ) ) ;
2014-05-02 15:00:21 -04:00
break ;
case ETransformField : : Scale :
2014-07-07 07:00:30 -04:00
CopyStr = FString : : Printf ( TEXT ( " (X=%f,Y=%f,Z=%f) " ) , CachedScale . X . GetValue ( ) , CachedScale . Y . GetValue ( ) , CachedScale . Z . GetValue ( ) ) ;
2014-05-02 15:00:21 -04:00
break ;
default :
break ;
}
if ( ! CopyStr . IsEmpty ( ) )
{
FPlatformMisc : : ClipboardCopy ( * CopyStr ) ;
}
}
void FComponentTransformDetails : : OnPaste ( ETransformField : : Type TransformField )
{
FString PastedText ;
FPlatformMisc : : ClipboardPaste ( PastedText ) ;
switch ( TransformField )
{
case ETransformField : : Location :
{
FVector Location ;
if ( Location . InitFromString ( PastedText ) )
{
FScopedTransaction Transaction ( LOCTEXT ( " PasteLocation " , " Paste Location " ) ) ;
OnSetLocation ( Location . X , ETextCommit : : Default , 0 ) ;
OnSetLocation ( Location . Y , ETextCommit : : Default , 1 ) ;
OnSetLocation ( Location . Z , ETextCommit : : Default , 2 ) ;
}
}
break ;
case ETransformField : : Rotation :
{
FRotator Rotation ;
2014-07-07 07:00:30 -04:00
PastedText . ReplaceInline ( TEXT ( " Pitch= " ) , TEXT ( " P= " ) ) ;
PastedText . ReplaceInline ( TEXT ( " Yaw= " ) , TEXT ( " Y= " ) ) ;
PastedText . ReplaceInline ( TEXT ( " Roll= " ) , TEXT ( " R= " ) ) ;
2014-05-02 15:00:21 -04:00
if ( Rotation . InitFromString ( PastedText ) )
{
FScopedTransaction Transaction ( LOCTEXT ( " PasteRotation " , " Paste Rotation " ) ) ;
OnSetRotation ( Rotation . Roll , ETextCommit : : Default , 0 ) ;
OnSetRotation ( Rotation . Pitch , ETextCommit : : Default , 1 ) ;
OnSetRotation ( Rotation . Yaw , ETextCommit : : Default , 2 ) ;
}
}
break ;
case ETransformField : : Scale :
{
FVector Scale ;
if ( Scale . InitFromString ( PastedText ) )
{
FScopedTransaction Transaction ( LOCTEXT ( " PasteScale " , " Paste Scale " ) ) ;
OnSetScale ( Scale . X , ETextCommit : : Default , 0 ) ;
OnSetScale ( Scale . Y , ETextCommit : : Default , 1 ) ;
OnSetScale ( Scale . Z , ETextCommit : : Default , 2 ) ;
}
}
break ;
default :
break ;
}
}
FUIAction FComponentTransformDetails : : CreateCopyAction ( ETransformField : : Type TransformField ) const
{
return
FUIAction
(
FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnCopy , TransformField ) ,
FCanExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnCanCopy , TransformField )
) ;
}
FUIAction FComponentTransformDetails : : CreatePasteAction ( ETransformField : : Type TransformField ) const
{
return
FUIAction ( FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnPaste , TransformField ) ) ;
}
2014-03-14 14:13:41 -04:00
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FComponentTransformDetails : : GenerateChildContent ( IDetailChildrenBuilder & ChildrenBuilder )
{
UClass * SceneComponentClass = USceneComponent : : StaticClass ( ) ;
FSlateFontInfo FontInfo = IDetailLayoutBuilder : : GetDetailFont ( ) ;
2014-05-02 15:00:21 -04:00
2014-07-24 20:56:55 -04:00
const bool bHideLocationField = ( HiddenFieldMask & ( 1 < < ETransformField : : Location ) ) ! = 0 ;
const bool bHideRotationField = ( HiddenFieldMask & ( 1 < < ETransformField : : Rotation ) ) ! = 0 ;
const bool bHideScaleField = ( HiddenFieldMask & ( 1 < < ETransformField : : Scale ) ) ! = 0 ;
2014-03-14 14:13:41 -04:00
// Location
2014-07-24 20:56:55 -04:00
if ( ! bHideLocationField )
{
2015-01-06 07:30:01 -05:00
TSharedPtr < INumericTypeInterface < float > > TypeInterface ;
2015-04-02 05:30:34 -04:00
if ( FUnitConversion : : Settings ( ) . ShouldDisplayUnits ( ) )
2015-01-06 07:30:01 -05:00
{
TypeInterface = SharedThis ( this ) ;
}
2014-12-01 11:19:41 -05:00
ChildrenBuilder . AddChildContent ( LOCTEXT ( " LocationFilter " , " Location " ) )
2014-05-02 15:00:21 -04:00
. CopyAction ( CreateCopyAction ( ETransformField : : Location ) )
. PasteAction ( CreatePasteAction ( ETransformField : : Location ) )
2014-03-14 14:13:41 -04:00
. NameContent ( )
2014-05-02 15:00:21 -04:00
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
2014-03-14 14:13:41 -04:00
[
2014-05-02 15:00:21 -04:00
BuildTransformFieldLabel ( ETransformField : : Location )
2014-03-14 14:13:41 -04:00
]
. ValueContent ( )
. MinDesiredWidth ( 125.0f * 3.0f )
. MaxDesiredWidth ( 125.0f * 3.0f )
[
SNew ( SHorizontalBox )
2014-07-24 20:56:55 -04:00
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. FillWidth ( 1 )
. VAlign ( VAlign_Center )
[
SNew ( SVectorInputBox )
. X ( this , & FComponentTransformDetails : : GetLocationX )
. Y ( this , & FComponentTransformDetails : : GetLocationY )
. Z ( this , & FComponentTransformDetails : : GetLocationZ )
. bColorAxisLabels ( true )
2015-07-14 17:48:50 -04:00
. AllowResponsiveLayout ( true )
2014-03-14 14:13:41 -04:00
. IsEnabled ( this , & FComponentTransformDetails : : GetIsEnabled )
. OnXCommitted ( this , & FComponentTransformDetails : : OnSetLocation , 0 )
. OnYCommitted ( this , & FComponentTransformDetails : : OnSetLocation , 1 )
. OnZCommitted ( this , & FComponentTransformDetails : : OnSetLocation , 2 )
. Font ( FontInfo )
2015-01-06 07:30:01 -05:00
. TypeInterface ( TypeInterface )
2014-03-14 14:13:41 -04:00
]
2014-07-24 20:56:55 -04:00
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. AutoWidth ( )
[
// Just take up space for alignment
SNew ( SBox )
. WidthOverride ( 18.0f )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SButton )
. OnClicked ( this , & FComponentTransformDetails : : OnLocationResetClicked )
. Visibility ( this , & FComponentTransformDetails : : GetLocationResetVisibility )
. ContentPadding ( FMargin ( 5.f , 0.f ) )
. ToolTipText ( LOCTEXT ( " ResetToDefaultToolTip " , " Reset to Default " ) )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. Content ( )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " PropertyWindow.DiffersFromDefault " ) )
]
]
] ;
2014-07-24 20:56:55 -04:00
}
2014-03-14 14:13:41 -04:00
// Rotation
2014-07-24 20:56:55 -04:00
if ( ! bHideRotationField )
{
2015-01-06 07:30:01 -05:00
TSharedPtr < INumericTypeInterface < float > > TypeInterface ;
2015-04-02 05:30:34 -04:00
if ( FUnitConversion : : Settings ( ) . ShouldDisplayUnits ( ) )
2015-01-06 07:30:01 -05:00
{
TypeInterface = MakeShareable ( new TNumericUnitTypeInterface < float > ( EUnit : : Degrees ) ) ;
}
2014-12-01 11:19:41 -05:00
ChildrenBuilder . AddChildContent ( LOCTEXT ( " RotationFilter " , " Rotation " ) )
2014-05-02 15:00:21 -04:00
. CopyAction ( CreateCopyAction ( ETransformField : : Rotation ) )
. PasteAction ( CreatePasteAction ( ETransformField : : Rotation ) )
2014-03-14 14:13:41 -04:00
. NameContent ( )
2014-05-02 15:00:21 -04:00
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
2014-03-14 14:13:41 -04:00
[
2014-05-02 15:00:21 -04:00
BuildTransformFieldLabel ( ETransformField : : Rotation )
2014-03-14 14:13:41 -04:00
]
. ValueContent ( )
. MinDesiredWidth ( 125.0f * 3.0f )
. MaxDesiredWidth ( 125.0f * 3.0f )
[
SNew ( SHorizontalBox )
2014-07-24 20:56:55 -04:00
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. FillWidth ( 1 )
. VAlign ( VAlign_Center )
[
SNew ( SRotatorInputBox )
. AllowSpin ( SelectedObjects . Num ( ) = = 1 )
. Roll ( this , & FComponentTransformDetails : : GetRotationX )
. Pitch ( this , & FComponentTransformDetails : : GetRotationY )
. Yaw ( this , & FComponentTransformDetails : : GetRotationZ )
2015-07-14 17:48:50 -04:00
. AllowResponsiveLayout ( true )
2014-03-14 14:13:41 -04:00
. bColorAxisLabels ( true )
. IsEnabled ( this , & FComponentTransformDetails : : GetIsEnabled )
. OnBeginSliderMovement ( this , & FComponentTransformDetails : : OnBeginRotatonSlider )
. OnEndSliderMovement ( this , & FComponentTransformDetails : : OnEndRotationSlider )
. OnRollChanged ( this , & FComponentTransformDetails : : OnSetRotation , false , 0 )
. OnPitchChanged ( this , & FComponentTransformDetails : : OnSetRotation , false , 1 )
. OnYawChanged ( this , & FComponentTransformDetails : : OnSetRotation , false , 2 )
. OnRollCommitted ( this , & FComponentTransformDetails : : OnRotationCommitted , 0 )
. OnPitchCommitted ( this , & FComponentTransformDetails : : OnRotationCommitted , 1 )
. OnYawCommitted ( this , & FComponentTransformDetails : : OnRotationCommitted , 2 )
2015-01-06 07:30:01 -05:00
. TypeInterface ( TypeInterface )
2014-03-14 14:13:41 -04:00
. Font ( FontInfo )
]
2014-07-24 20:56:55 -04:00
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. AutoWidth ( )
[
// Just take up space for alignment
SNew ( SBox )
. WidthOverride ( 18.0f )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SButton )
. OnClicked ( this , & FComponentTransformDetails : : OnRotationResetClicked )
. Visibility ( this , & FComponentTransformDetails : : GetRotationResetVisibility )
. ContentPadding ( FMargin ( 5.f , 0.f ) )
. ToolTipText ( LOCTEXT ( " ResetToDefaultToolTip " , " Reset to Default " ) )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. Content ( )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " PropertyWindow.DiffersFromDefault " ) )
]
]
] ;
2014-07-24 20:56:55 -04:00
}
// Scale
if ( ! bHideScaleField )
{
2014-12-01 11:19:41 -05:00
ChildrenBuilder . AddChildContent ( LOCTEXT ( " ScaleFilter " , " Scale " ) )
2014-05-02 15:00:21 -04:00
. CopyAction ( CreateCopyAction ( ETransformField : : Scale ) )
. PasteAction ( CreatePasteAction ( ETransformField : : Scale ) )
2014-03-14 14:13:41 -04:00
. NameContent ( )
2014-05-02 15:00:21 -04:00
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Center )
2014-03-14 14:13:41 -04:00
[
2014-05-02 15:00:21 -04:00
BuildTransformFieldLabel ( ETransformField : : Scale )
2014-03-14 14:13:41 -04:00
]
. ValueContent ( )
. MinDesiredWidth ( 125.0f * 3.0f )
. MaxDesiredWidth ( 125.0f * 3.0f )
[
SNew ( SHorizontalBox )
2014-07-24 20:56:55 -04:00
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. VAlign ( VAlign_Center )
. FillWidth ( 1.0f )
[
SNew ( SVectorInputBox )
. X ( this , & FComponentTransformDetails : : GetScaleX )
. Y ( this , & FComponentTransformDetails : : GetScaleY )
. Z ( this , & FComponentTransformDetails : : GetScaleZ )
. bColorAxisLabels ( true )
2015-07-14 17:48:50 -04:00
. AllowResponsiveLayout ( true )
2014-03-14 14:13:41 -04:00
. IsEnabled ( this , & FComponentTransformDetails : : GetIsEnabled )
. OnXCommitted ( this , & FComponentTransformDetails : : OnSetScale , 0 )
. OnYCommitted ( this , & FComponentTransformDetails : : OnSetScale , 1 )
. OnZCommitted ( this , & FComponentTransformDetails : : OnSetScale , 2 )
. ContextMenuExtenderX ( this , & FComponentTransformDetails : : ExtendXScaleContextMenu )
. ContextMenuExtenderY ( this , & FComponentTransformDetails : : ExtendYScaleContextMenu )
. ContextMenuExtenderZ ( this , & FComponentTransformDetails : : ExtendZScaleContextMenu )
. Font ( FontInfo )
]
2014-07-24 20:56:55 -04:00
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. AutoWidth ( )
. MaxWidth ( 18.0f )
[
// Add a checkbox to toggle between preserving the ratio of x,y,z components of scale when a value is entered
SNew ( SCheckBox )
. IsChecked ( this , & FComponentTransformDetails : : IsPreserveScaleRatioChecked )
. IsEnabled ( this , & FComponentTransformDetails : : GetIsEnabled )
. OnCheckStateChanged ( this , & FComponentTransformDetails : : OnPreserveScaleRatioToggled )
. Style ( FEditorStyle : : Get ( ) , " TransparentCheckBox " )
. ToolTipText ( LOCTEXT ( " PreserveScaleToolTip " , " When locked, scales uniformly based on the current xyz scale values so the object maintains its shape in each direction when scaled " ) )
[
SNew ( SImage )
. Image ( this , & FComponentTransformDetails : : GetPreserveScaleRatioImage )
. ColorAndOpacity ( FSlateColor : : UseForeground ( ) )
]
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SButton )
. OnClicked ( this , & FComponentTransformDetails : : OnScaleResetClicked )
. Visibility ( this , & FComponentTransformDetails : : GetScaleResetVisibility )
. ContentPadding ( FMargin ( 5.f , 0.f ) )
. ToolTipText ( LOCTEXT ( " ResetToDefaultToolTip " , " Reset to Default " ) )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. Content ( )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " PropertyWindow.DiffersFromDefault " ) )
]
]
] ;
2014-07-24 20:56:55 -04:00
}
2014-03-14 14:13:41 -04:00
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FComponentTransformDetails : : Tick ( float DeltaTime )
{
CacheTransform ( ) ;
2015-04-21 08:27:25 -04:00
if ( ! FixedDisplayUnits . IsSet ( ) )
{
CacheCommonLocationUnits ( ) ;
}
2015-01-06 07:30:01 -05:00
}
void FComponentTransformDetails : : CacheCommonLocationUnits ( )
{
2015-04-21 08:27:25 -04:00
float LargestValue = 0.f ;
if ( CachedLocation . X . IsSet ( ) & & CachedLocation . X . GetValue ( ) > LargestValue )
2015-01-06 07:30:01 -05:00
{
2015-04-21 08:27:25 -04:00
LargestValue = CachedLocation . X . GetValue ( ) ;
2015-01-06 07:30:01 -05:00
}
2015-04-21 17:39:55 -04:00
if ( CachedLocation . Y . IsSet ( ) & & CachedLocation . Y . GetValue ( ) > LargestValue )
2015-01-06 07:30:01 -05:00
{
2015-04-21 08:27:25 -04:00
LargestValue = CachedLocation . Y . GetValue ( ) ;
2015-01-06 07:30:01 -05:00
}
2015-04-21 17:39:55 -04:00
if ( CachedLocation . Z . IsSet ( ) & & CachedLocation . Z . GetValue ( ) > LargestValue )
2015-01-06 07:30:01 -05:00
{
2015-04-21 08:27:25 -04:00
LargestValue = CachedLocation . Z . GetValue ( ) ;
2015-01-06 07:30:01 -05:00
}
2015-04-21 08:27:25 -04:00
SetupFixedDisplay ( LargestValue ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-24 20:56:55 -04:00
bool FComponentTransformDetails : : GetIsEnabled ( ) const
2014-03-14 14:13:41 -04:00
{
return ! GEditor - > HasLockedActors ( ) | | SelectedActorInfo . NumSelected = = 0 ;
}
const FSlateBrush * FComponentTransformDetails : : GetPreserveScaleRatioImage ( ) const
{
return bPreserveScaleRatio ? FEditorStyle : : GetBrush ( TEXT ( " GenericLock " ) ) : FEditorStyle : : GetBrush ( TEXT ( " GenericUnlock " ) ) ;
}
2014-12-10 14:24:09 -05:00
ECheckBoxState FComponentTransformDetails : : IsPreserveScaleRatioChecked ( ) const
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
return bPreserveScaleRatio ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 14:24:09 -05:00
void FComponentTransformDetails : : OnPreserveScaleRatioToggled ( ECheckBoxState NewState )
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
bPreserveScaleRatio = ( NewState = = ECheckBoxState : : Checked ) ? true : false ;
2015-04-20 10:12:55 -04:00
GConfig - > SetBool ( TEXT ( " SelectionDetails " ) , TEXT ( " PreserveScaleRatio " ) , bPreserveScaleRatio , GEditorPerProjectIni ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-02 15:00:21 -04:00
FText FComponentTransformDetails : : GetLocationText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-05-02 15:00:21 -04:00
return bAbsoluteLocation ? LOCTEXT ( " AbsoluteLocation " , " Absolute Location " ) : LOCTEXT ( " Location " , " Location " ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-02 15:00:21 -04:00
FText FComponentTransformDetails : : GetRotationText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-05-02 15:00:21 -04:00
return bAbsoluteRotation ? LOCTEXT ( " AbsoluteRotation " , " Absolute Rotation " ) : LOCTEXT ( " Rotation " , " Rotation " ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-02 15:00:21 -04:00
FText FComponentTransformDetails : : GetScaleText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-05-02 15:00:21 -04:00
return bAbsoluteScale ? LOCTEXT ( " AbsoluteScale " , " Absolute Scale " ) : LOCTEXT ( " Scale " , " Scale " ) ;
2014-03-14 14:13:41 -04:00
}
2014-05-02 15:00:21 -04:00
void FComponentTransformDetails : : OnToggleAbsoluteLocation ( bool bEnable )
2014-03-14 14:13:41 -04:00
{
UProperty * AbsoluteLocationProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " bAbsoluteLocation " ) ;
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent & & SceneComponent - > bAbsoluteLocation ! = bEnable )
2014-03-14 14:13:41 -04:00
{
if ( ! bBeganTransaction )
{
// NOTE: One transaction per change, not per actor
GEditor - > BeginTransaction ( LOCTEXT ( " ToggleAbsoluteLocation " , " Toggle Absolute Location " ) ) ;
bBeganTransaction = true ;
}
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
Object - > PreEditChange ( AbsoluteLocationProperty ) ;
2014-04-02 18:09:23 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPreChange ( AbsoluteLocationProperty ) ;
}
2015-02-16 06:51:44 -05:00
SceneComponent - > bAbsoluteLocation = ! SceneComponent - > bAbsoluteLocation ;
2014-03-14 14:13:41 -04:00
FPropertyChangedEvent PropertyChangedEvent ( AbsoluteLocationProperty ) ;
2015-02-06 11:25:56 -05:00
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
2014-03-14 14:13:41 -04:00
2015-02-16 06:51:44 -05:00
// If it's a template, propagate the change out to any current instances of the object
if ( SceneComponent - > IsTemplate ( ) )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
uint32 NewValue = SceneComponent - > bAbsoluteLocation ;
2014-03-14 14:13:41 -04:00
uint32 OldValue = ! NewValue ;
2015-02-16 06:51:44 -05:00
TSet < USceneComponent * > UpdatedInstances ;
FComponentEditorUtils : : PropagateDefaultValueChange ( SceneComponent , AbsoluteLocationProperty , OldValue , NewValue , UpdatedInstances ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-02 18:09:23 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPostChange ( PropertyChangedEvent , AbsoluteLocationProperty ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
if ( bBeganTransaction )
{
GEditor - > EndTransaction ( ) ;
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
}
2014-05-02 15:00:21 -04:00
void FComponentTransformDetails : : OnToggleAbsoluteRotation ( bool bEnable )
2014-03-14 14:13:41 -04:00
{
UProperty * AbsoluteRotationProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " bAbsoluteRotation " ) ;
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent & & SceneComponent - > bAbsoluteRotation ! = bEnable )
2014-03-14 14:13:41 -04:00
{
if ( ! bBeganTransaction )
{
// NOTE: One transaction per change, not per actor
GEditor - > BeginTransaction ( LOCTEXT ( " ToggleAbsoluteRotation " , " Toggle Absolute Rotation " ) ) ;
bBeganTransaction = true ;
}
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
Object - > PreEditChange ( AbsoluteRotationProperty ) ;
2014-04-02 18:09:23 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPreChange ( AbsoluteRotationProperty ) ;
}
2015-02-16 06:51:44 -05:00
SceneComponent - > bAbsoluteRotation = ! SceneComponent - > bAbsoluteRotation ;
2014-03-14 14:13:41 -04:00
FPropertyChangedEvent PropertyChangedEvent ( AbsoluteRotationProperty ) ;
2015-02-06 11:25:56 -05:00
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
2014-03-14 14:13:41 -04:00
2015-02-16 06:51:44 -05:00
// If it's a template, propagate the change out to any current instances of the object
if ( SceneComponent - > IsTemplate ( ) )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
uint32 NewValue = SceneComponent - > bAbsoluteRotation ;
2014-03-14 14:13:41 -04:00
uint32 OldValue = ! NewValue ;
2015-02-16 06:51:44 -05:00
TSet < USceneComponent * > UpdatedInstances ;
FComponentEditorUtils : : PropagateDefaultValueChange ( SceneComponent , AbsoluteRotationProperty , OldValue , NewValue , UpdatedInstances ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-02 18:09:23 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPostChange ( PropertyChangedEvent , AbsoluteRotationProperty ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
if ( bBeganTransaction )
{
GEditor - > EndTransaction ( ) ;
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
}
2014-05-02 15:00:21 -04:00
void FComponentTransformDetails : : OnToggleAbsoluteScale ( bool bEnable )
2014-03-14 14:13:41 -04:00
{
UProperty * AbsoluteScaleProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " bAbsoluteScale " ) ;
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent & & SceneComponent - > bAbsoluteScale ! = bEnable )
2014-03-14 14:13:41 -04:00
{
if ( ! bBeganTransaction )
{
// NOTE: One transaction per change, not per actor
GEditor - > BeginTransaction ( LOCTEXT ( " ToggleAbsoluteScale " , " Toggle Absolute Scale " ) ) ;
bBeganTransaction = true ;
}
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
Object - > PreEditChange ( AbsoluteScaleProperty ) ;
2014-04-02 18:09:23 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPreChange ( AbsoluteScaleProperty ) ;
}
2015-02-16 06:51:44 -05:00
SceneComponent - > bAbsoluteScale = ! SceneComponent - > bAbsoluteScale ;
2014-03-14 14:13:41 -04:00
FPropertyChangedEvent PropertyChangedEvent ( AbsoluteScaleProperty ) ;
2015-02-06 11:25:56 -05:00
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
2014-03-14 14:13:41 -04:00
2015-02-16 06:51:44 -05:00
// If it's a template, propagate the change out to any current instances of the object
if ( SceneComponent - > IsTemplate ( ) )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
uint32 NewValue = SceneComponent - > bAbsoluteScale ;
2014-03-14 14:13:41 -04:00
uint32 OldValue = ! NewValue ;
2015-02-16 06:51:44 -05:00
TSet < USceneComponent * > UpdatedInstances ;
FComponentEditorUtils : : PropagateDefaultValueChange ( SceneComponent , AbsoluteScaleProperty , OldValue , NewValue , UpdatedInstances ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-02 18:09:23 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPostChange ( PropertyChangedEvent , AbsoluteScaleProperty ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
if ( bBeganTransaction )
{
GEditor - > EndTransaction ( ) ;
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
}
2015-02-06 11:42:25 -05:00
struct FGetRootComponentArchetype
{
static USceneComponent * Get ( UObject * Object )
{
2015-02-16 06:51:44 -05:00
auto RootComponent = Object ? GetSceneComponentFromDetailsObject ( Object ) : nullptr ;
2015-02-06 11:42:25 -05:00
return RootComponent ? Cast < USceneComponent > ( RootComponent - > GetArchetype ( ) ) : nullptr ;
}
} ;
2014-03-14 14:13:41 -04:00
FReply FComponentTransformDetails : : OnLocationResetClicked ( )
{
const FText TransactionName = LOCTEXT ( " ResetLocation " , " Reset Location " ) ;
FScopedTransaction Transaction ( TransactionName ) ;
2015-02-06 11:42:25 -05:00
const USceneComponent * Archetype = FGetRootComponentArchetype : : Get ( SelectedObjects [ 0 ] . Get ( ) ) ;
const FVector Data = Archetype ? Archetype - > RelativeLocation : FVector ( ) ;
OnSetLocation ( Data [ 0 ] , ETextCommit : : Default , 0 ) ;
OnSetLocation ( Data [ 1 ] , ETextCommit : : Default , 1 ) ;
OnSetLocation ( Data [ 2 ] , ETextCommit : : Default , 2 ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
FReply FComponentTransformDetails : : OnRotationResetClicked ( )
{
const FText TransactionName = LOCTEXT ( " ResetRotation " , " Reset Rotation " ) ;
FScopedTransaction Transaction ( TransactionName ) ;
2015-02-06 11:42:25 -05:00
const USceneComponent * Archetype = FGetRootComponentArchetype : : Get ( SelectedObjects [ 0 ] . Get ( ) ) ;
const FRotator Data = Archetype ? Archetype - > RelativeRotation : FRotator ( ) ;
OnSetRotation ( Data . Roll , true , 0 ) ;
OnSetRotation ( Data . Pitch , true , 1 ) ;
OnSetRotation ( Data . Yaw , true , 2 ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
FReply FComponentTransformDetails : : OnScaleResetClicked ( )
{
const FText TransactionName = LOCTEXT ( " ResetScale " , " Reset Scale " ) ;
FScopedTransaction Transaction ( TransactionName ) ;
2015-02-06 11:42:25 -05:00
const USceneComponent * Archetype = FGetRootComponentArchetype : : Get ( SelectedObjects [ 0 ] . Get ( ) ) ;
const FVector Data = Archetype ? Archetype - > RelativeScale3D : FVector ( ) ;
ScaleObject ( Data [ 0 ] , 0 , false , TransactionName ) ;
ScaleObject ( Data [ 1 ] , 1 , false , TransactionName ) ;
ScaleObject ( Data [ 2 ] , 2 , false , TransactionName ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
void FComponentTransformDetails : : ExtendXScaleContextMenu ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . BeginSection ( " ScaleOperations " , LOCTEXT ( " ScaleOperations " , " Scale Operations " ) ) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " MirrorValueX " , " Mirror X " ) ,
LOCTEXT ( " MirrorValueX_Tooltip " , " Mirror scale value on the X axis " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnXScaleMirrored ) , FCanExecuteAction ( ) )
) ;
MenuBuilder . EndSection ( ) ;
}
void FComponentTransformDetails : : ExtendYScaleContextMenu ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . BeginSection ( " ScaleOperations " , LOCTEXT ( " ScaleOperations " , " Scale Operations " ) ) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " MirrorValueY " , " Mirror Y " ) ,
LOCTEXT ( " MirrorValueY_Tooltip " , " Mirror scale value on the Y axis " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnYScaleMirrored ) , FCanExecuteAction ( ) )
) ;
MenuBuilder . EndSection ( ) ;
}
void FComponentTransformDetails : : ExtendZScaleContextMenu ( FMenuBuilder & MenuBuilder )
{
MenuBuilder . BeginSection ( " ScaleOperations " , LOCTEXT ( " ScaleOperations " , " Scale Operations " ) ) ;
MenuBuilder . AddMenuEntry (
LOCTEXT ( " MirrorValueZ " , " Mirror Z " ) ,
LOCTEXT ( " MirrorValueZ_Tooltip " , " Mirror scale value on the Z axis " ) ,
FSlateIcon ( ) ,
FUIAction ( FExecuteAction : : CreateSP ( this , & FComponentTransformDetails : : OnZScaleMirrored ) , FCanExecuteAction ( ) )
) ;
MenuBuilder . EndSection ( ) ;
}
void FComponentTransformDetails : : OnXScaleMirrored ( )
{
2014-10-30 12:29:36 -04:00
FSlateApplication : : Get ( ) . ClearKeyboardFocus ( EFocusCause : : Mouse ) ;
2014-03-14 14:13:41 -04:00
ScaleObject ( 1.0f , 0 , true , LOCTEXT ( " MirrorActorScaleX " , " Mirror actor scale X " ) ) ;
}
void FComponentTransformDetails : : OnYScaleMirrored ( )
{
2014-10-30 12:29:36 -04:00
FSlateApplication : : Get ( ) . ClearKeyboardFocus ( EFocusCause : : Mouse ) ;
2014-09-30 11:36:36 -04:00
ScaleObject ( 1.0f , 1 , true , LOCTEXT ( " MirrorActorScaleY " , " Mirror actor scale Y " ) ) ;
2014-03-14 14:13:41 -04:00
}
void FComponentTransformDetails : : OnZScaleMirrored ( )
{
2014-10-30 12:29:36 -04:00
FSlateApplication : : Get ( ) . ClearKeyboardFocus ( EFocusCause : : Mouse ) ;
2014-09-30 11:36:36 -04:00
ScaleObject ( 1.0f , 2 , true , LOCTEXT ( " MirrorActorScaleZ " , " Mirror actor scale Z " ) ) ;
2014-03-14 14:13:41 -04:00
}
/**
* Cache the entire transform at it is seen by the input boxes so we dont have to iterate over the selected actors multiple times
*/
void FComponentTransformDetails : : CacheTransform ( )
{
FVector CurLoc ;
FRotator CurRot ;
FVector CurScale ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
2014-03-14 14:13:41 -04:00
FVector Loc ;
FRotator Rot ;
FVector Scale ;
2015-02-16 06:51:44 -05:00
if ( SceneComponent )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
Loc = SceneComponent - > RelativeLocation ;
Rot = ( bEditingRotationInUI & & ! Object - > IsTemplate ( ) ) ? ObjectToRelativeRotationMap . FindOrAdd ( Object ) : SceneComponent - > RelativeRotation ;
Scale = SceneComponent - > RelativeScale3D ;
2014-03-14 14:13:41 -04:00
if ( ObjectIndex = = 0 )
{
// Cache the current values from the first actor to see if any values differ among other actors
CurLoc = Loc ;
CurRot = Rot ;
CurScale = Scale ;
CachedLocation . Set ( Loc ) ;
CachedRotation . Set ( Rot ) ;
CachedScale . Set ( Scale ) ;
2015-02-16 06:51:44 -05:00
bAbsoluteLocation = SceneComponent - > bAbsoluteLocation ;
bAbsoluteScale = SceneComponent - > bAbsoluteScale ;
bAbsoluteRotation = SceneComponent - > bAbsoluteRotation ;
2014-03-14 14:13:41 -04:00
}
else if ( CurLoc ! = Loc | | CurRot ! = Rot | | CurScale ! = Scale )
{
// Check which values differ and unset the different values
CachedLocation . X = Loc . X = = CurLoc . X & & CachedLocation . X . IsSet ( ) ? Loc . X : TOptional < float > ( ) ;
CachedLocation . Y = Loc . Y = = CurLoc . Y & & CachedLocation . Y . IsSet ( ) ? Loc . Y : TOptional < float > ( ) ;
CachedLocation . Z = Loc . Z = = CurLoc . Z & & CachedLocation . Z . IsSet ( ) ? Loc . Z : TOptional < float > ( ) ;
CachedRotation . X = Rot . Roll = = CurRot . Roll & & CachedRotation . X . IsSet ( ) ? Rot . Roll : TOptional < float > ( ) ;
CachedRotation . Y = Rot . Pitch = = CurRot . Pitch & & CachedRotation . Y . IsSet ( ) ? Rot . Pitch : TOptional < float > ( ) ;
CachedRotation . Z = Rot . Yaw = = CurRot . Yaw & & CachedRotation . Z . IsSet ( ) ? Rot . Yaw : TOptional < float > ( ) ;
CachedScale . X = Scale . X = = CurScale . X & & CachedScale . X . IsSet ( ) ? Scale . X : TOptional < float > ( ) ;
CachedScale . Y = Scale . Y = = CurScale . Y & & CachedScale . Y . IsSet ( ) ? Scale . Y : TOptional < float > ( ) ;
CachedScale . Z = Scale . Z = = CurScale . Z & & CachedScale . Z . IsSet ( ) ? Scale . Z : TOptional < float > ( ) ;
// If all values are unset all values are different and we can stop looking
const bool bAllValuesDiffer = ! CachedLocation . IsSet ( ) & & ! CachedRotation . IsSet ( ) & & ! CachedScale . IsSet ( ) ;
if ( bAllValuesDiffer )
{
break ;
}
}
}
}
}
}
void FComponentTransformDetails : : OnSetLocation ( float NewValue , ETextCommit : : Type CommitInfo , int32 Axis )
{
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
FVector OldRelativeLocation = SceneComponent - > RelativeLocation ;
2014-03-14 14:13:41 -04:00
FVector RelativeLocation = OldRelativeLocation ;
float OldValue = RelativeLocation [ Axis ] ;
if ( OldValue ! = NewValue )
{
if ( ! bBeganTransaction )
{
// Begin a transaction the first time an actors location is about to change.
// NOTE: One transaction per change, not per actor
if ( Object - > IsA < AActor > ( ) )
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetLocation " , " Set actor location " ) ) ;
}
else
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetLocation_ComponentDirect " , " Modify Component(s) " ) ) ;
}
bBeganTransaction = true ;
}
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
// Begin a new movement event which will broadcast delegates before and after the actor moves
FScopedObjectMovement ActorMoveEvent ( Object ) ;
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
UProperty * RelativeLocationProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " RelativeLocation " ) ;
Object - > PreEditChange ( RelativeLocationProperty ) ;
if ( NotifyHook )
{
NotifyHook - > NotifyPreChange ( RelativeLocationProperty ) ;
}
RelativeLocation [ Axis ] = NewValue ;
if ( SelectedActorInfo . NumSelected = = 0 )
{
// HACK: Set directly if no actors are selected since this causes Rot->Quat->Rot conversion
// (recalculates relative rotation even though this is location)
2015-02-16 06:51:44 -05:00
SceneComponent - > RelativeLocation = RelativeLocation ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-02-16 06:51:44 -05:00
SceneComponent - > SetRelativeLocation ( RelativeLocation ) ;
2014-03-14 14:13:41 -04:00
}
FPropertyChangedEvent PropertyChangedEvent ( RelativeLocationProperty ) ;
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
2015-02-16 06:51:44 -05:00
// If it's a template, propagate the change out to any current instances of the object
if ( SceneComponent - > IsTemplate ( ) )
{
TSet < USceneComponent * > UpdatedInstances ;
FComponentEditorUtils : : PropagateDefaultValueChange ( SceneComponent , RelativeLocationProperty , OldRelativeLocation , RelativeLocation , UpdatedInstances ) ;
}
2014-03-14 14:13:41 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPostChange ( PropertyChangedEvent , RelativeLocationProperty ) ;
}
}
}
}
}
if ( bBeganTransaction )
{
GEditor - > EndTransaction ( ) ;
}
CacheTransform ( ) ;
2015-07-27 12:47:07 -04:00
GUnrealEd - > UpdatePivotLocationForSelection ( ) ;
GUnrealEd - > SetPivotMovedIndependently ( false ) ;
2014-03-14 14:13:41 -04:00
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
void FComponentTransformDetails : : OnSetRotation ( float NewValue , bool bCommitted , int32 Axis )
{
// OnSetRotation is sent from the slider or when the value changes and we dont have slider and the value is being typed.
// We should only change the value on commit when it is being typed
const bool bAllowSpin = SelectedObjects . Num ( ) = = 1 ;
if ( bAllowSpin | | bCommitted )
{
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
const bool bIsEditingTemplateObject = Object - > IsTemplate ( ) ;
2014-09-23 17:21:34 -04:00
2015-06-23 15:16:28 -04:00
FRotator CurrentComponentRotation = SceneComponent - > RelativeRotation ; // Intentionally make a copy, we don't want the FRotator& below to directly edit the component's values!
FRotator & RelativeRotation = ( bEditingRotationInUI & & ! bIsEditingTemplateObject ) ? ObjectToRelativeRotationMap . FindOrAdd ( Object ) : CurrentComponentRotation ;
2014-03-14 14:13:41 -04:00
FRotator OldRelativeRotation = RelativeRotation ;
float & ValueToChange = Axis = = 0 ? RelativeRotation . Roll : Axis = = 1 ? RelativeRotation . Pitch : RelativeRotation . Yaw ;
2014-09-23 17:21:34 -04:00
if ( ValueToChange ! = NewValue )
2014-03-14 14:13:41 -04:00
{
if ( ! bBeganTransaction & & bCommitted )
{
// Begin a transaction the first time an actors rotation is about to change.
// NOTE: One transaction per change, not per actor
if ( Object - > IsA < AActor > ( ) )
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetRotation " , " Set actor rotation " ) ) ;
}
else
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetRotation_ComponentDirect " , " Modify Component(s) " ) ) ;
}
2015-02-16 06:51:44 -05:00
if ( ! bIsEditingTemplateObject )
2014-03-14 14:13:41 -04:00
{
// Broadcast the first time an actor is about to move
GEditor - > BroadcastBeginObjectMovement ( * Object ) ;
}
bBeganTransaction = true ;
}
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
UProperty * RelativeRotationProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " RelativeRotation " ) ;
if ( bCommitted & & ! bEditingRotationInUI )
{
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
Object - > PreEditChange ( RelativeRotationProperty ) ;
}
if ( NotifyHook )
{
NotifyHook - > NotifyPreChange ( RelativeRotationProperty ) ;
}
ValueToChange = NewValue ;
2015-06-23 15:16:28 -04:00
if ( ! bIsEditingTemplateObject & & SelectedActorInfo . NumSelected ! = 0 )
2014-03-14 14:13:41 -04:00
{
2015-06-23 15:16:28 -04:00
SceneComponent - > SetRelativeRotation ( RelativeRotation ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-23 15:16:28 -04:00
// HACK: Set directly since to avoid Rot->Quat->Rot conversion issues
// (functions recalculate relative rotation from quat which can give an equivalent but different value than the user typed)
SceneComponent - > RelativeRotation = RelativeRotation ;
2015-02-16 09:29:00 -05:00
AActor * EditedActor = Cast < AActor > ( Object ) ;
if ( ! EditedActor & & SceneComponent )
2014-03-14 14:13:41 -04:00
{
2015-02-16 09:29:00 -05:00
EditedActor = SceneComponent - > GetOwner ( ) ;
}
if ( EditedActor & & ! bIsEditingTemplateObject )
{
EditedActor - > ReregisterAllComponents ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-16 06:51:44 -05:00
// If it's a template, propagate the change out to any current instances of the object
if ( SceneComponent - > IsTemplate ( ) )
{
TSet < USceneComponent * > UpdatedInstances ;
FComponentEditorUtils : : PropagateDefaultValueChange ( SceneComponent , RelativeRotationProperty , OldRelativeRotation , RelativeRotation , UpdatedInstances ) ;
}
2014-03-14 14:13:41 -04:00
2014-09-19 19:00:52 -04:00
FPropertyChangedEvent PropertyChangedEvent ( RelativeRotationProperty , ! bCommitted & & bEditingRotationInUI ? EPropertyChangeType : : Interactive : EPropertyChangeType : : ValueSet ) ;
2014-03-14 14:13:41 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPostChange ( PropertyChangedEvent , RelativeRotationProperty ) ;
}
if ( bCommitted )
{
if ( ! bEditingRotationInUI )
{
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
}
2014-09-23 17:21:34 -04:00
if ( ! bIsEditingTemplateObject )
2014-03-14 14:13:41 -04:00
{
// The actor is done moving
GEditor - > BroadcastEndObjectMovement ( * Object ) ;
}
}
}
}
}
}
if ( bCommitted & & bBeganTransaction )
{
GEditor - > EndTransaction ( ) ;
}
2015-07-27 12:47:07 -04:00
GUnrealEd - > UpdatePivotLocationForSelection ( ) ;
GUnrealEd - > SetPivotMovedIndependently ( false ) ;
2014-03-14 14:13:41 -04:00
// Redraw
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
}
void FComponentTransformDetails : : OnRotationCommitted ( float NewValue , ETextCommit : : Type CommitInfo , int32 Axis )
{
OnSetRotation ( NewValue , true , Axis ) ;
CacheTransform ( ) ;
}
void FComponentTransformDetails : : OnBeginRotatonSlider ( )
{
bEditingRotationInUI = true ;
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
// Start a new transation when a rotator slider begins to change
// We'll end it when the slider is release
// NOTE: One transaction per change, not per actor
if ( ! bBeganTransaction )
{
if ( Object - > IsA < AActor > ( ) )
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetRotation " , " Set actor rotation " ) ) ;
}
else
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetRotation_ComponentDirect " , " Modify Component(s) " ) ) ;
}
bBeganTransaction = true ;
}
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent )
2014-03-14 14:13:41 -04:00
{
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
UProperty * RelativeRotationProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " RelativeRotation " ) ;
Object - > PreEditChange ( RelativeRotationProperty ) ;
2014-09-23 17:21:34 -04:00
// Add/update cached rotation value prior to slider interaction
2015-02-16 06:51:44 -05:00
ObjectToRelativeRotationMap . FindOrAdd ( Object ) = SceneComponent - > RelativeRotation ;
2014-03-14 14:13:41 -04:00
}
}
}
// Just in case we couldn't start a new transaction for some reason
if ( ! bBeganTransaction )
{
GEditor - > BeginTransaction ( LOCTEXT ( " OnSetRotation " , " Set actor rotation " ) ) ;
}
}
void FComponentTransformDetails : : OnEndRotationSlider ( float NewValue )
{
bEditingRotationInUI = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent )
2014-03-14 14:13:41 -04:00
{
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
UProperty * RelativeRotationProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " RelativeRotation " ) ;
FPropertyChangedEvent PropertyChangedEvent ( RelativeRotationProperty ) ;
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
}
}
}
GEditor - > EndTransaction ( ) ;
// Redraw
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
void FComponentTransformDetails : : OnSetScale ( const float NewValue , ETextCommit : : Type CommitInfo , int32 Axis )
{
ScaleObject ( NewValue , Axis , false , LOCTEXT ( " OnSetScale " , " Set actor scale " ) ) ;
}
void FComponentTransformDetails : : ScaleObject ( float NewValue , int32 Axis , bool bMirror , const FText & TransactionSessionName )
{
UProperty * RelativeScale3DProperty = FindField < UProperty > ( USceneComponent : : StaticClass ( ) , " RelativeScale3D " ) ;
bool bBeganTransaction = false ;
for ( int32 ObjectIndex = 0 ; ObjectIndex < SelectedObjects . Num ( ) ; + + ObjectIndex )
{
TWeakObjectPtr < UObject > ObjectPtr = SelectedObjects [ ObjectIndex ] ;
if ( ObjectPtr . IsValid ( ) )
{
UObject * Object = ObjectPtr . Get ( ) ;
2015-02-16 06:51:44 -05:00
USceneComponent * SceneComponent = GetSceneComponentFromDetailsObject ( Object ) ;
if ( SceneComponent )
2014-03-14 14:13:41 -04:00
{
2015-02-16 06:51:44 -05:00
FVector OldRelativeScale = SceneComponent - > RelativeScale3D ;
2014-03-14 14:13:41 -04:00
FVector RelativeScale = OldRelativeScale ;
if ( bMirror )
{
NewValue = - RelativeScale [ Axis ] ;
}
float OldValue = RelativeScale [ Axis ] ;
if ( OldValue ! = NewValue )
{
if ( ! bBeganTransaction )
{
// Begin a transaction the first time an actors scale is about to change.
// NOTE: One transaction per change, not per actor
GEditor - > BeginTransaction ( TransactionSessionName ) ;
bBeganTransaction = true ;
}
FScopedSwitchWorldForObject WorldSwitcher ( Object ) ;
if ( Object - > HasAnyFlags ( RF_DefaultSubObject ) )
{
// Default subobjects must be included in any undo/redo operations
Object - > SetFlags ( RF_Transactional ) ;
}
// Begin a new movement event which will broadcast delegates before and after the actor moves
FScopedObjectMovement ActorMoveEvent ( Object ) ;
Object - > PreEditChange ( RelativeScale3DProperty ) ;
if ( NotifyHook )
{
NotifyHook - > NotifyPreChange ( RelativeScale3DProperty ) ;
}
// Set the new value for the corresponding axis
RelativeScale [ Axis ] = NewValue ;
if ( bPreserveScaleRatio )
{
// Account for the previous scale being zero. Just set to the new value in that case?
float Ratio = OldValue = = 0.0f ? NewValue : NewValue / OldValue ;
// Change values on axes besides the one being directly changed
switch ( Axis )
{
case 0 :
RelativeScale . Y * = Ratio ;
RelativeScale . Z * = Ratio ;
break ;
case 1 :
RelativeScale . X * = Ratio ;
RelativeScale . Z * = Ratio ;
break ;
case 2 :
RelativeScale . X * = Ratio ;
RelativeScale . Y * = Ratio ;
}
}
2015-02-16 06:51:44 -05:00
SceneComponent - > SetRelativeScale3D ( RelativeScale ) ;
2014-03-14 14:13:41 -04:00
// Build property chain so the actor knows whether we changed the X, Y or Z
FEditPropertyChain PropertyChain ;
if ( ! bPreserveScaleRatio )
{
2015-01-22 20:04:37 -05:00
UStruct * VectorStruct = FindObjectChecked < UScriptStruct > ( UObject : : StaticClass ( ) - > GetOutermost ( ) , TEXT ( " Vector " ) , false ) ;
2014-03-14 14:13:41 -04:00
UProperty * VectorValueProperty = NULL ;
switch ( Axis )
{
case 0 :
VectorValueProperty = FindField < UFloatProperty > ( VectorStruct , TEXT ( " X " ) ) ;
break ;
case 1 :
VectorValueProperty = FindField < UFloatProperty > ( VectorStruct , TEXT ( " Y " ) ) ;
break ;
case 2 :
VectorValueProperty = FindField < UFloatProperty > ( VectorStruct , TEXT ( " Z " ) ) ;
}
PropertyChain . AddHead ( VectorValueProperty ) ;
}
PropertyChain . AddHead ( RelativeScale3DProperty ) ;
2014-09-19 19:00:52 -04:00
FPropertyChangedEvent PropertyChangedEvent ( RelativeScale3DProperty , EPropertyChangeType : : ValueSet ) ;
2014-03-14 14:13:41 -04:00
FPropertyChangedChainEvent PropertyChangedChainEvent ( PropertyChain , PropertyChangedEvent ) ;
Object - > PostEditChangeChainProperty ( PropertyChangedChainEvent ) ;
// For backwards compatibility, as for some reason PostEditChangeChainProperty calls PostEditChangeProperty with the property set to "X" not "RelativeScale3D"
// (it does that for all vector properties, and I don't want to be the one to change that)
if ( ! bPreserveScaleRatio )
{
Object - > PostEditChangeProperty ( PropertyChangedEvent ) ;
}
else
{
// If the other scale values have been updated, make sure we update the transform now (as the tick will be too late)
// so they appear correct when their EditedText is fetched from the delegate.
CacheTransform ( ) ;
}
2015-02-16 06:51:44 -05:00
// If it's a template, propagate the change out to any current instances of the object
if ( SceneComponent - > IsTemplate ( ) )
{
TSet < USceneComponent * > UpdatedInstances ;
FComponentEditorUtils : : PropagateDefaultValueChange ( SceneComponent , RelativeScale3DProperty , OldRelativeScale , RelativeScale , UpdatedInstances ) ;
}
2014-03-14 14:13:41 -04:00
if ( NotifyHook )
{
NotifyHook - > NotifyPostChange ( PropertyChangedEvent , RelativeScale3DProperty ) ;
}
}
}
}
}
if ( bBeganTransaction )
{
GEditor - > EndTransaction ( ) ;
}
CacheTransform ( ) ;
// Redraw
GUnrealEd - > RedrawLevelEditingViewports ( ) ;
}
# undef LOCTEXT_NAMESPACE