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 "UnrealEd.h"
2014-08-14 23:35:07 -04:00
# include "RichCurveEditorCommands.h"
2014-03-14 14:13:41 -04:00
# include "SCurveEditor.h"
# include "ScopedTransaction.h"
# include "SColorGradientEditor.h"
2014-10-14 22:50:06 -04:00
# include "GenericCommands.h"
# include "SNumericEntryBox.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "SCurveEditor"
2014-08-19 16:22:40 -04:00
const static FVector2D CONST_KeySize = FVector2D ( 11 , 11 ) ;
2014-08-25 12:21:17 -04:00
const static FVector2D CONST_TangentSize = FVector2D ( 7 , 7 ) ;
2014-03-14 14:13:41 -04:00
const static FVector2D CONST_CurveSize = FVector2D ( 12 , 12 ) ;
const static float CONST_FitMargin = 0.05f ;
const static float CONST_MinViewRange = 0.01f ;
const static float CONST_DefaultZoomRange = 1.0f ;
2014-08-25 12:21:17 -04:00
const static float CONST_KeyTangentOffset = 60.0f ;
2014-03-14 14:13:41 -04:00
//////////////////////////////////////////////////////////////////////////
// SCurveEditor
void SCurveEditor : : Construct ( const FArguments & InArgs )
{
CurveFactory = NULL ;
Commands = TSharedPtr < FUICommandList > ( new FUICommandList ) ;
CurveOwner = NULL ;
// view input
ViewMinInput = InArgs . _ViewMinInput ;
ViewMaxInput = InArgs . _ViewMaxInput ;
// data input - only used when it's set
DataMinInput = InArgs . _DataMinInput ;
DataMaxInput = InArgs . _DataMaxInput ;
ViewMinOutput = InArgs . _ViewMinOutput ;
ViewMaxOutput = InArgs . _ViewMaxOutput ;
2014-08-22 17:36:08 -04:00
InputSnap = InArgs . _InputSnap ;
OutputSnap = InArgs . _OutputSnap ;
bSnappingEnabled = InArgs . _SnappingEnabled ;
2014-07-30 15:42:17 -04:00
bZoomToFitVertical = InArgs . _ZoomToFitVertical ;
bZoomToFitHorizontal = InArgs . _ZoomToFitHorizontal ;
2014-03-14 14:13:41 -04:00
DesiredSize = InArgs . _DesiredSize ;
2015-02-16 11:59:08 -05:00
GridColor = InArgs . _GridColor ;
2014-04-23 17:30:58 -04:00
bIsUsingSlider = false ;
2014-03-14 14:13:41 -04:00
// if editor size is set, use it, otherwise, use default value
if ( DesiredSize . Get ( ) . IsZero ( ) )
{
DesiredSize . Set ( FVector2D ( 128 , 64 ) ) ;
}
TimelineLength = InArgs . _TimelineLength ;
SetInputViewRangeHandler = InArgs . _OnSetInputViewRange ;
2014-09-22 09:47:37 -04:00
SetOutputViewRangeHandler = InArgs . _OnSetOutputViewRange ;
2014-03-14 14:13:41 -04:00
bDrawCurve = InArgs . _DrawCurve ;
bHideUI = InArgs . _HideUI ;
bAllowZoomOutput = InArgs . _AllowZoomOutput ;
bAlwaysDisplayColorCurves = InArgs . _AlwaysDisplayColorCurves ;
2014-08-14 11:09:42 -04:00
bShowZoomButtons = InArgs . _ShowZoomButtons ;
2015-02-16 11:59:08 -05:00
bShowCurveSelector = InArgs . _ShowCurveSelector ;
bDrawInputGridNumbers = InArgs . _ShowInputGridNumbers ;
bDrawOutputGridNumbers = InArgs . _ShowOutputGridNumbers ;
bShowCurveToolTips = InArgs . _ShowCurveToolTips ;
2014-03-14 14:13:41 -04:00
OnCreateAsset = InArgs . _OnCreateAsset ;
2014-08-19 16:22:40 -04:00
DragState = EDragState : : None ;
DragThreshold = 4 ;
2014-03-14 14:13:41 -04:00
//Simple r/g/b for now
2014-04-23 17:42:50 -04:00
CurveColors . Add ( FLinearColor ( 1.0f , 0.0f , 0.0f ) ) ;
CurveColors . Add ( FLinearColor ( 0.0f , 1.0f , 0.0f ) ) ;
2014-09-03 11:17:17 -04:00
CurveColors . Add ( FLinearColor ( 0.05f , 0.05f , 1.0f ) ) ;
2014-03-14 14:13:41 -04:00
TransactionIndex = - 1 ;
2014-08-14 11:09:42 -04:00
Commands - > MapAction ( FGenericCommands : : Get ( ) . Undo ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : UndoAction ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-14 11:09:42 -04:00
Commands - > MapAction ( FGenericCommands : : Get ( ) . Redo ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : RedoAction ) ) ;
2014-03-14 14:13:41 -04:00
2014-08-14 11:09:42 -04:00
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . ZoomToFitHorizontal ,
2015-06-24 08:02:15 -04:00
FExecuteAction : : CreateSP ( this , & SCurveEditor : : ZoomToFitHorizontal ) ) ;
2014-08-14 11:09:42 -04:00
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . ZoomToFitVertical ,
2015-06-24 08:02:15 -04:00
FExecuteAction : : CreateSP ( this , & SCurveEditor : : ZoomToFitVertical ) ) ;
2014-08-26 10:26:37 -04:00
2015-06-24 08:02:15 -04:00
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . ZoomToFit ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : ZoomToFit ) ) ;
2014-08-14 11:09:42 -04:00
2014-08-22 17:36:08 -04:00
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . ToggleSnapping ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : ToggleSnapping ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsSnappingEnabled ) ) ;
2014-08-26 10:26:37 -04:00
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . InterpolationConstant ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnSelectInterpolationMode , RCIM_Constant , RCTM_Auto ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsInterpolationModeSelected , RCIM_Constant , RCTM_Auto ) ) ;
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . InterpolationLinear ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnSelectInterpolationMode , RCIM_Linear , RCTM_Auto ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsInterpolationModeSelected , RCIM_Linear , RCTM_Auto ) ) ;
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . InterpolationCubicAuto ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnSelectInterpolationMode , RCIM_Cubic , RCTM_Auto ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsInterpolationModeSelected , RCIM_Cubic , RCTM_Auto ) ) ;
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . InterpolationCubicUser ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnSelectInterpolationMode , RCIM_Cubic , RCTM_User ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsInterpolationModeSelected , RCIM_Cubic , RCTM_User ) ) ;
Commands - > MapAction ( FRichCurveEditorCommands : : Get ( ) . InterpolationCubicBreak ,
FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnSelectInterpolationMode , RCIM_Cubic , RCTM_Break ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsInterpolationModeSelected , RCIM_Cubic , RCTM_Break ) ) ;
2014-08-14 11:09:42 -04:00
SAssignNew ( WarningMessageText , SErrorText ) ;
2014-03-14 14:13:41 -04:00
2014-08-14 15:48:56 -04:00
TSharedRef < SBox > CurveSelector = SNew ( SBox )
2014-09-03 11:17:17 -04:00
. VAlign ( VAlign_Top )
2015-02-16 11:59:08 -05:00
. Visibility ( this , & SCurveEditor : : GetCurveSelectorVisibility )
2014-03-14 14:13:41 -04:00
[
CreateCurveSelectionWidget ( )
] ;
CurveSelectionWidget = CurveSelector ;
2015-02-16 11:59:08 -05:00
InputAxisName = InArgs . _XAxisName . IsSet ( ) ? FText : : FromString ( InArgs . _XAxisName . GetValue ( ) ) : LOCTEXT ( " Time " , " Time " ) ;
2015-04-24 16:41:41 -04:00
OutputAxisName = InArgs . _YAxisName . IsSet ( ) ? FText : : FromString ( InArgs . _YAxisName . GetValue ( ) ) : LOCTEXT ( " Value " , " Value " ) ;
2015-02-16 11:59:08 -05:00
2014-03-14 14:13:41 -04:00
this - > ChildSlot
[
2014-09-03 11:17:17 -04:00
SNew ( SHorizontalBox )
2014-04-23 17:42:18 -04:00
2014-09-03 11:17:17 -04:00
+ SHorizontalBox : : Slot ( )
. FillWidth ( 1.0f )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SVerticalBox )
2014-04-23 17:42:18 -04:00
2014-09-22 09:47:37 -04:00
+ SVerticalBox : : Slot ( )
. FillHeight ( 1.0f )
[
SNew ( SHorizontalBox )
. Visibility ( this , & SCurveEditor : : GetCurveAreaVisibility )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( FMargin ( 30 , 12 , 0 , 0 ) )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
CurveSelector
]
2014-04-23 17:30:58 -04:00
2014-09-22 09:47:37 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SBorder )
. VAlign ( VAlign_Top )
. HAlign ( HAlign_Left )
. BorderImage ( FEditorStyle : : GetBrush ( " NoBorder " ) )
. DesiredSizeScale ( FVector2D ( 256.0f , 32.0f ) )
. Padding ( FMargin ( 2 , 12 , 0 , 0 ) )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SHorizontalBox )
2014-08-14 11:09:42 -04:00
2014-09-22 09:47:37 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SButton )
. ToolTipText ( LOCTEXT ( " ZoomToFitHorizontal " , " Zoom To Fit Horizontal " ) )
. Visibility ( this , & SCurveEditor : : GetZoomButtonVisibility )
. OnClicked ( this , & SCurveEditor : : ZoomToFitHorizontalClicked )
. ContentPadding ( 1 )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " CurveEd.FitHorizontal " ) )
. ColorAndOpacity ( FSlateColor : : UseForeground ( ) )
2014-03-14 14:13:41 -04:00
]
2014-09-22 09:47:37 -04:00
]
2014-04-23 17:30:58 -04:00
2014-09-22 09:47:37 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SButton )
. ToolTipText ( LOCTEXT ( " ZoomToFitVertical " , " Zoom To Fit Vertical " ) )
. Visibility ( this , & SCurveEditor : : GetZoomButtonVisibility )
. OnClicked ( this , & SCurveEditor : : ZoomToFitVerticalClicked )
. ContentPadding ( 1 )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " CurveEd.FitVertical " ) )
. ColorAndOpacity ( FSlateColor : : UseForeground ( ) )
2014-09-03 11:17:17 -04:00
]
2014-09-22 09:47:37 -04:00
]
2014-09-03 11:17:17 -04:00
2014-09-22 09:47:37 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " NoBorder " ) )
. Visibility ( this , & SCurveEditor : : GetEditVisibility )
. VAlign ( VAlign_Center )
2014-09-03 11:17:17 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SNumericEntryBox < float > )
. IsEnabled ( this , & SCurveEditor : : GetInputEditEnabled )
. Font ( FEditorStyle : : GetFontStyle ( " CurveEd.InfoFont " ) )
. Value ( this , & SCurveEditor : : OnGetTime )
2014-12-02 06:47:27 -05:00
. UndeterminedString ( LOCTEXT ( " MultipleValues " , " Multiple Values " ) )
2014-09-22 09:47:37 -04:00
. OnValueCommitted ( this , & SCurveEditor : : OnTimeComitted )
. OnValueChanged ( this , & SCurveEditor : : OnTimeChanged )
. OnBeginSliderMovement ( this , & SCurveEditor : : OnBeginSliderMovement , LOCTEXT ( " SetValue " , " Set New Time " ) )
. OnEndSliderMovement ( this , & SCurveEditor : : OnEndSliderMovement )
. LabelVAlign ( VAlign_Center )
. AllowSpin ( true )
. MinValue ( TOptional < float > ( ) )
. MaxValue ( TOptional < float > ( ) )
. MaxSliderValue ( TOptional < float > ( ) )
. MinSliderValue ( TOptional < float > ( ) )
. Delta ( 0.001f )
. MinDesiredValueWidth ( 60.0f )
. Label ( )
2014-09-03 11:17:17 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( STextBlock )
2015-02-16 11:59:08 -05:00
. Text ( InputAxisName )
2014-09-03 11:17:17 -04:00
]
]
2014-09-22 09:47:37 -04:00
]
2014-09-03 11:17:17 -04:00
2014-09-22 09:47:37 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " NoBorder " ) )
. Visibility ( this , & SCurveEditor : : GetEditVisibility )
. VAlign ( VAlign_Center )
2014-09-03 11:17:17 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( SNumericEntryBox < float > )
. Font ( FEditorStyle : : GetFontStyle ( " CurveEd.InfoFont " ) )
. Value ( this , & SCurveEditor : : OnGetValue )
2014-12-02 06:47:27 -05:00
. UndeterminedString ( LOCTEXT ( " MultipleValues " , " Multiple Values " ) )
2014-09-22 09:47:37 -04:00
. OnValueCommitted ( this , & SCurveEditor : : OnValueComitted )
. OnValueChanged ( this , & SCurveEditor : : OnValueChanged )
. OnBeginSliderMovement ( this , & SCurveEditor : : OnBeginSliderMovement , LOCTEXT ( " SetValue " , " Set New Value " ) )
. OnEndSliderMovement ( this , & SCurveEditor : : OnEndSliderMovement )
. LabelVAlign ( VAlign_Center )
. AllowSpin ( true )
. MinValue ( TOptional < float > ( ) )
. MaxValue ( TOptional < float > ( ) )
. MaxSliderValue ( TOptional < float > ( ) )
. MinSliderValue ( TOptional < float > ( ) )
. Delta ( .001f )
. MinDesiredValueWidth ( 60.0f )
. Label ( )
2014-09-03 11:17:17 -04:00
[
2014-09-22 09:47:37 -04:00
SNew ( STextBlock )
2015-04-24 16:41:41 -04:00
. Text ( OutputAxisName )
2014-04-23 17:30:58 -04:00
]
2014-03-14 14:13:41 -04:00
]
]
]
]
2014-09-22 09:47:37 -04:00
]
2014-04-23 17:30:58 -04:00
2014-09-22 09:47:37 -04:00
+ SVerticalBox : : Slot ( )
. VAlign ( VAlign_Bottom )
. FillHeight ( .75f )
[
SNew ( SBorder )
. Visibility ( this , & SCurveEditor : : GetColorGradientVisibility )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
. BorderBackgroundColor ( FLinearColor ( .8f , .8f , .8f , .60f ) )
. Padding ( 1.0f )
2014-03-14 14:13:41 -04:00
[
2014-09-22 09:47:37 -04:00
SAssignNew ( GradientViewer , SColorGradientEditor )
. ViewMinInput ( ViewMinInput )
. ViewMaxInput ( ViewMaxInput )
. IsEditingEnabled ( this , & SCurveEditor : : IsEditingEnabled )
2014-03-14 14:13:41 -04:00
]
]
2014-09-22 09:47:37 -04:00
]
2014-03-14 14:13:41 -04:00
] ;
if ( GEditor ! = NULL )
{
GEditor - > RegisterForUndo ( this ) ;
}
}
2014-09-03 11:17:17 -04:00
FText SCurveEditor : : GetIsCurveVisibleToolTip ( TSharedPtr < FCurveViewModel > CurveViewModel ) const
{
return CurveViewModel - > bIsVisible ?
FText : : Format ( LOCTEXT ( " HideFormat " , " Hide {0} curve " ) , FText : : FromName ( CurveViewModel - > CurveInfo . CurveName ) ) :
FText : : Format ( LOCTEXT ( " ShowFormat " , " Show {0} curve " ) , FText : : FromName ( CurveViewModel - > CurveInfo . CurveName ) ) ;
}
2014-12-10 14:24:09 -05:00
ECheckBoxState SCurveEditor : : IsCurveVisible ( TSharedPtr < FCurveViewModel > CurveViewModel ) const
2014-09-03 11:17:17 -04:00
{
2014-12-10 14:24:09 -05:00
return CurveViewModel - > bIsVisible ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-09-03 11:17:17 -04:00
}
2014-12-10 14:24:09 -05:00
void SCurveEditor : : OnCurveIsVisibleChanged ( ECheckBoxState NewCheckboxState , TSharedPtr < FCurveViewModel > CurveViewModel )
2014-09-03 11:17:17 -04:00
{
2014-12-10 14:24:09 -05:00
if ( NewCheckboxState = = ECheckBoxState : : Checked )
2014-09-03 11:17:17 -04:00
{
CurveViewModel - > bIsVisible = true ;
}
else
{
CurveViewModel - > bIsVisible = false ;
RemoveCurveKeysFromSelection ( CurveViewModel ) ;
}
}
FText SCurveEditor : : GetIsCurveLockedToolTip ( TSharedPtr < FCurveViewModel > CurveViewModel ) const
{
return CurveViewModel - > bIsLocked ?
FText : : Format ( LOCTEXT ( " UnlockFormat " , " Unlock {0} curve for editing " ) , FText : : FromName ( CurveViewModel - > CurveInfo . CurveName ) ) :
FText : : Format ( LOCTEXT ( " LockFormat " , " Lock {0} curve for editing " ) , FText : : FromName ( CurveViewModel - > CurveInfo . CurveName ) ) ;
}
2014-12-10 14:24:09 -05:00
ECheckBoxState SCurveEditor : : IsCurveLocked ( TSharedPtr < FCurveViewModel > CurveViewModel ) const
2014-09-03 11:17:17 -04:00
{
2014-12-10 14:24:09 -05:00
return CurveViewModel - > bIsLocked ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-09-03 11:17:17 -04:00
}
2014-12-10 14:24:09 -05:00
void SCurveEditor : : OnCurveIsLockedChanged ( ECheckBoxState NewCheckboxState , TSharedPtr < FCurveViewModel > CurveViewModel )
2014-09-03 11:17:17 -04:00
{
2014-12-10 14:24:09 -05:00
if ( NewCheckboxState = = ECheckBoxState : : Checked )
2014-09-03 11:17:17 -04:00
{
CurveViewModel - > bIsLocked = true ;
RemoveCurveKeysFromSelection ( CurveViewModel ) ;
}
else
{
CurveViewModel - > bIsLocked = false ;
}
}
void SCurveEditor : : RemoveCurveKeysFromSelection ( TSharedPtr < FCurveViewModel > CurveViewModel )
{
TArray < FSelectedCurveKey > SelectedKeysForLockedCurve ;
for ( auto SelectedKey : SelectedKeys )
{
if ( SelectedKey . Curve = = CurveViewModel - > CurveInfo . CurveToEdit )
{
SelectedKeysForLockedCurve . Add ( SelectedKey ) ;
}
}
for ( auto KeyToDeselect : SelectedKeysForLockedCurve )
{
RemoveFromSelection ( KeyToDeselect ) ;
}
}
2015-02-16 11:59:08 -05:00
FText SCurveEditor : : GetCurveToolTipNameText ( ) const
{
return CurveToolTipNameText ;
}
FText SCurveEditor : : GetCurveToolTipInputText ( ) const
{
return CurveToolTipInputText ;
}
FText SCurveEditor : : GetCurveToolTipOutputText ( ) const
{
return CurveToolTipOutputText ;
}
2014-03-14 14:13:41 -04:00
SCurveEditor : : ~ SCurveEditor ( )
{
if ( GEditor ! = NULL )
{
GEditor - > UnregisterForUndo ( this ) ;
}
}
TSharedRef < SWidget > SCurveEditor : : CreateCurveSelectionWidget ( ) const
{
2014-09-03 11:17:17 -04:00
TSharedRef < SVerticalBox > CurveBox = SNew ( SVerticalBox ) ;
if ( CurveViewModels . Num ( ) > 1 )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
// Only create curve controls if there are more than one.
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
CurveBox - > AddSlot ( )
2014-03-14 14:13:41 -04:00
. AutoHeight ( )
[
SNew ( SHorizontalBox )
2014-09-03 11:17:17 -04:00
+ SHorizontalBox : : Slot ( )
. Padding ( 0 , 0 , 5 , 0 )
. FillWidth ( 1.0f )
[
SNew ( STextBlock )
. Font ( FEditorStyle : : GetFontStyle ( " CurveEd.LabelFont " ) )
. ColorAndOpacity ( CurveViewModel - > Color )
2015-01-07 09:52:40 -05:00
. Text ( FText : : FromName ( CurveViewModel - > CurveInfo . CurveName ) )
2014-09-03 11:17:17 -04:00
]
+ SHorizontalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
. AutoWidth ( )
2014-09-03 11:17:17 -04:00
. VAlign ( VAlign_Center )
2014-03-14 14:13:41 -04:00
[
SNew ( SCheckBox )
2014-09-03 11:17:17 -04:00
. IsChecked ( this , & SCurveEditor : : IsCurveVisible , CurveViewModel )
. OnCheckStateChanged ( this , & SCurveEditor : : OnCurveIsVisibleChanged , CurveViewModel )
. ToolTipText ( this , & SCurveEditor : : GetIsCurveVisibleToolTip , CurveViewModel )
. CheckedImage ( FEditorStyle : : GetBrush ( " CurveEd.Visible " ) )
. CheckedHoveredImage ( FEditorStyle : : GetBrush ( " CurveEd.VisibleHighlight " ) )
. CheckedPressedImage ( FEditorStyle : : GetBrush ( " CurveEd.Visible " ) )
. UncheckedImage ( FEditorStyle : : GetBrush ( " CurveEd.Invisible " ) )
. UncheckedHoveredImage ( FEditorStyle : : GetBrush ( " CurveEd.InvisibleHighlight " ) )
. UncheckedPressedImage ( FEditorStyle : : GetBrush ( " CurveEd.Invisible " ) )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( 2 , 0 , 0 , 0 )
[
SNew ( SCheckBox )
. IsChecked ( this , & SCurveEditor : : IsCurveLocked , CurveViewModel )
. OnCheckStateChanged ( this , & SCurveEditor : : OnCurveIsLockedChanged , CurveViewModel )
. ToolTipText ( this , & SCurveEditor : : GetIsCurveLockedToolTip , CurveViewModel )
. CheckedImage ( FEditorStyle : : GetBrush ( " CurveEd.Locked " ) )
. CheckedHoveredImage ( FEditorStyle : : GetBrush ( " CurveEd.LockedHighlight " ) )
. CheckedPressedImage ( FEditorStyle : : GetBrush ( " CurveEd.Locked " ) )
. UncheckedImage ( FEditorStyle : : GetBrush ( " CurveEd.Unlocked " ) )
. UncheckedHoveredImage ( FEditorStyle : : GetBrush ( " CurveEd.UnlockedHighlight " ) )
. UncheckedPressedImage ( FEditorStyle : : GetBrush ( " CurveEd.Unlocked " ) )
. Visibility ( bCanEditTrack ? EVisibility : : Visible : EVisibility : : Collapsed )
2014-04-23 17:42:50 -04:00
]
2014-03-14 14:13:41 -04:00
] ;
}
}
2014-09-03 11:17:17 -04:00
TSharedRef < SBorder > Border = SNew ( SBorder )
. Padding ( FMargin ( 3 , 2 , 2 , 2 ) )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
. BorderBackgroundColor ( FLinearColor ( 0.0f , 0.0f , 0.0f , 0.3f ) )
[
CurveBox
] ;
return Border ;
2014-03-14 14:13:41 -04:00
}
void SCurveEditor : : PushWarningMenu ( FVector2D Position , const FText & Message )
{
WarningMessageText - > SetError ( Message ) ;
FSlateApplication : : Get ( ) . PushMenu (
SharedThis ( this ) ,
2015-06-05 20:19:33 -04:00
FWidgetPath ( ) ,
2014-03-14 14:13:41 -04:00
WarningMessageText - > AsWidget ( ) ,
Position ,
FPopupTransitionEffect ( FPopupTransitionEffect : : ContextMenu ) ) ;
}
2015-06-05 20:19:33 -04:00
void SCurveEditor : : PushKeyMenu ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
2014-03-14 14:13:41 -04:00
{
2014-08-26 10:26:37 -04:00
FMenuBuilder MenuBuilder ( true , Commands . ToSharedRef ( ) ) ;
2014-09-03 11:17:17 -04:00
MenuBuilder . BeginSection ( " CurveEditorInterpolation " , LOCTEXT ( " KeyInterpolationMode " , " Key Interpolation " ) ) ;
2014-03-14 14:13:41 -04:00
{
2014-08-26 10:26:37 -04:00
MenuBuilder . AddMenuEntry ( FRichCurveEditorCommands : : Get ( ) . InterpolationCubicAuto ) ;
MenuBuilder . AddMenuEntry ( FRichCurveEditorCommands : : Get ( ) . InterpolationCubicUser ) ;
MenuBuilder . AddMenuEntry ( FRichCurveEditorCommands : : Get ( ) . InterpolationCubicBreak ) ;
MenuBuilder . AddMenuEntry ( FRichCurveEditorCommands : : Get ( ) . InterpolationLinear ) ;
MenuBuilder . AddMenuEntry ( FRichCurveEditorCommands : : Get ( ) . InterpolationConstant ) ;
2014-03-14 14:13:41 -04:00
}
MenuBuilder . EndSection ( ) ; //CurveEditorInterpolation
2015-06-05 20:19:33 -04:00
FWidgetPath WidgetPath = InMouseEvent . GetEventPath ( ) ! = nullptr ? * InMouseEvent . GetEventPath ( ) : FWidgetPath ( ) ;
2015-06-18 14:10:19 -04:00
FVector2D Position = InMouseEvent . GetScreenSpacePosition ( ) ;
2014-03-14 14:13:41 -04:00
FSlateApplication : : Get ( ) . PushMenu (
SharedThis ( this ) ,
2015-06-05 20:19:33 -04:00
WidgetPath ,
2014-03-14 14:13:41 -04:00
MenuBuilder . MakeWidget ( ) ,
Position ,
FPopupTransitionEffect ( FPopupTransitionEffect : : ContextMenu ) ) ;
}
2015-01-14 19:04:45 -05:00
FVector2D SCurveEditor : : ComputeDesiredSize ( float ) const
2014-03-14 14:13:41 -04:00
{
return DesiredSize . Get ( ) ;
}
EVisibility SCurveEditor : : GetCurveAreaVisibility ( ) const
{
return AreCurvesVisible ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2015-02-16 11:59:08 -05:00
EVisibility SCurveEditor : : GetCurveSelectorVisibility ( ) const
2014-03-14 14:13:41 -04:00
{
2015-02-16 11:59:08 -05:00
return ( IsHovered ( ) | | ( false = = bHideUI ) ) & & bShowCurveSelector ? EVisibility : : Visible : EVisibility : : Collapsed ;
2014-03-14 14:13:41 -04:00
}
EVisibility SCurveEditor : : GetEditVisibility ( ) const
{
2015-02-16 11:59:08 -05:00
return ( SelectedKeys . Num ( ) > 0 ) & & ( IsHovered ( ) | | ( false = = bHideUI ) ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
2014-03-14 14:13:41 -04:00
}
EVisibility SCurveEditor : : GetColorGradientVisibility ( ) const
{
return bIsGradientEditorVisible & & IsLinearColorCurve ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2014-08-14 11:09:42 -04:00
EVisibility SCurveEditor : : GetZoomButtonVisibility ( ) const
{
2015-02-16 11:59:08 -05:00
return ( IsHovered ( ) | | ( false = = bHideUI ) ) & & bShowZoomButtons ? EVisibility : : Visible : EVisibility : : Collapsed ;
2014-08-14 11:09:42 -04:00
}
2014-03-14 14:13:41 -04:00
bool SCurveEditor : : GetInputEditEnabled ( ) const
{
return ( SelectedKeys . Num ( ) = = 1 ) ;
}
2014-07-23 08:23:21 -04:00
int32 SCurveEditor : : OnPaint ( const FPaintArgs & Args , const FGeometry & AllottedGeometry , const FSlateRect & MyClippingRect , FSlateWindowElementList & OutDrawElements , int32 LayerId , const FWidgetStyle & InWidgetStyle , bool bParentEnabled ) const
2014-03-14 14:13:41 -04:00
{
// Rendering info
bool bEnabled = ShouldBeEnabled ( bParentEnabled ) ;
ESlateDrawEffect : : Type DrawEffects = bEnabled ? ESlateDrawEffect : : None : ESlateDrawEffect : : DisabledEffect ;
const FSlateBrush * TimelineAreaBrush = FEditorStyle : : GetBrush ( " CurveEd.TimelineArea " ) ;
const FSlateBrush * WhiteBrush = FEditorStyle : : GetBrush ( " WhiteTexture " ) ;
FGeometry CurveAreaGeometry = AllottedGeometry ;
// Positioning info
2014-09-22 09:47:37 -04:00
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , CurveAreaGeometry . Size ) ;
2014-03-14 14:13:41 -04:00
// Draw background to indicate valid timeline area
float ZeroInputX = ScaleInfo . InputToLocalX ( 0.f ) ;
float ZeroOutputY = ScaleInfo . OutputToLocalY ( 0.f ) ;
2014-09-03 11:17:17 -04:00
// timeline background
int32 BackgroundLayerId = LayerId ;
float TimelineMaxX = ScaleInfo . InputToLocalX ( TimelineLength . Get ( ) ) ;
FSlateDrawElement : : MakeBox
(
OutDrawElements ,
BackgroundLayerId ,
CurveAreaGeometry . ToPaintGeometry ( FVector2D ( ZeroInputX , 0 ) , FVector2D ( TimelineMaxX - ZeroInputX , CurveAreaGeometry . Size . Y ) ) ,
TimelineAreaBrush ,
MyClippingRect ,
DrawEffects ,
TimelineAreaBrush - > GetTint ( InWidgetStyle ) * InWidgetStyle . GetColorAndOpacityTint ( )
) ;
// grid lines.
int32 GridLineLayerId = BackgroundLayerId + 1 ;
PaintGridLines ( CurveAreaGeometry , ScaleInfo , OutDrawElements , GridLineLayerId , MyClippingRect , DrawEffects ) ;
2014-03-14 14:13:41 -04:00
// time=0 line
2014-09-03 11:17:17 -04:00
int32 ZeroLineLayerId = GridLineLayerId + 1 ;
2015-02-16 11:59:08 -05:00
TArray < FVector2D > ZeroLinePoints ;
ZeroLinePoints . Add ( FVector2D ( ZeroInputX , 0 ) ) ;
ZeroLinePoints . Add ( FVector2D ( ZeroInputX , CurveAreaGeometry . Size . Y ) ) ;
FSlateDrawElement : : MakeLines (
OutDrawElements ,
2014-09-03 11:17:17 -04:00
ZeroLineLayerId ,
2015-02-16 11:59:08 -05:00
AllottedGeometry . ToPaintGeometry ( ) ,
ZeroLinePoints ,
MyClippingRect ,
DrawEffects ,
FLinearColor : : White ,
false ) ;
2014-03-14 14:13:41 -04:00
2014-09-03 11:17:17 -04:00
// value=0 line
2014-03-14 14:13:41 -04:00
if ( AreCurvesVisible ( ) )
{
FSlateDrawElement : : MakeBox
(
OutDrawElements ,
2014-09-03 11:17:17 -04:00
ZeroLineLayerId ,
2014-03-14 14:13:41 -04:00
CurveAreaGeometry . ToPaintGeometry ( FVector2D ( 0 , ZeroOutputY ) , FVector2D ( CurveAreaGeometry . Size . X , 1 ) ) ,
WhiteBrush ,
MyClippingRect ,
DrawEffects ,
WhiteBrush - > GetTint ( InWidgetStyle ) * InWidgetStyle . GetColorAndOpacityTint ( )
) ;
}
2014-09-03 11:17:17 -04:00
int32 LockedCurveLayerID = ZeroLineLayerId + 1 ;
int32 CurveLayerId = LockedCurveLayerID + 1 ;
2014-03-14 14:13:41 -04:00
2014-09-03 11:17:17 -04:00
int32 KeyLayerId = CurveLayerId + 1 ;
int32 SelectedKeyLayerId = KeyLayerId + 1 ;
2014-09-22 09:47:37 -04:00
2014-03-14 14:13:41 -04:00
if ( AreCurvesVisible ( ) )
{
2014-09-03 11:17:17 -04:00
//Paint the curves, unlocked curves will be on top
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
if ( CurveViewModel - > bIsVisible )
2014-09-22 09:47:37 -04:00
{
2014-09-03 11:17:17 -04:00
PaintCurve ( CurveViewModel , CurveAreaGeometry , ScaleInfo , OutDrawElements , CurveViewModel - > bIsLocked ? LockedCurveLayerID : CurveLayerId , MyClippingRect , DrawEffects , InWidgetStyle ) ;
2014-09-22 09:47:37 -04:00
}
2014-03-14 14:13:41 -04:00
}
//Paint the keys on top of the curve
2014-09-03 11:17:17 -04:00
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
if ( CurveViewModel - > bIsVisible )
2014-09-22 09:47:37 -04:00
{
2014-09-03 11:17:17 -04:00
PaintKeys ( CurveViewModel , ScaleInfo , OutDrawElements , KeyLayerId , SelectedKeyLayerId , CurveAreaGeometry , MyClippingRect , DrawEffects , InWidgetStyle ) ;
}
2014-03-14 14:13:41 -04:00
}
}
2014-09-03 11:17:17 -04:00
// Paint children
int32 ChildrenLayerId = SelectedKeyLayerId + 1 ;
int32 MarqueeLayerId = SCompoundWidget : : OnPaint ( Args , CurveAreaGeometry , MyClippingRect , OutDrawElements , ChildrenLayerId , InWidgetStyle , bParentEnabled ) ;
// Paint marquee
2014-08-19 16:22:40 -04:00
if ( DragState = = EDragState : : MarqueeSelect )
{
2014-09-03 11:17:17 -04:00
PaintMarquee ( AllottedGeometry , MyClippingRect , OutDrawElements , MarqueeLayerId ) ;
2014-08-19 16:22:40 -04:00
}
2014-09-03 11:17:17 -04:00
return MarqueeLayerId + 1 ;
2014-03-14 14:13:41 -04:00
}
2014-09-03 11:17:17 -04:00
void SCurveEditor : : PaintCurve ( TSharedPtr < FCurveViewModel > CurveViewModel , const FGeometry & AllottedGeometry , FTrackScaleInfo & ScaleInfo , FSlateWindowElementList & OutDrawElements ,
2014-03-14 14:13:41 -04:00
int32 LayerId , const FSlateRect & MyClippingRect , ESlateDrawEffect : : Type DrawEffects , const FWidgetStyle & InWidgetStyle ) const
{
2014-09-03 11:17:17 -04:00
if ( CurveViewModel . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-23 17:42:50 -04:00
if ( bDrawCurve )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
FLinearColor Color = InWidgetStyle . GetColorAndOpacityTint ( ) * CurveViewModel - > Color ;
2014-03-14 14:13:41 -04:00
2014-09-03 11:17:17 -04:00
// Fade out curves which are locked.
if ( CurveViewModel - > bIsLocked )
2014-03-14 14:13:41 -04:00
{
Color * = FLinearColor ( 1.0f , 1.0f , 1.0f , 0.35f ) ;
}
TArray < FVector2D > LinePoints ;
int32 CurveDrawInterval = 1 ;
2014-09-03 11:17:17 -04:00
FRichCurve * Curve = CurveViewModel - > CurveInfo . CurveToEdit ;
2014-04-23 17:42:50 -04:00
if ( Curve - > GetNumKeys ( ) < 2 )
2014-03-14 14:13:41 -04:00
{
//Not enough point, just draw flat line
float Value = Curve - > Eval ( 0.0f ) ;
float Y = ScaleInfo . OutputToLocalY ( Value ) ;
LinePoints . Add ( FVector2D ( 0.0f , Y ) ) ;
LinePoints . Add ( FVector2D ( AllottedGeometry . Size . X , Y ) ) ;
2014-04-23 17:42:50 -04:00
FSlateDrawElement : : MakeLines ( OutDrawElements , LayerId , AllottedGeometry . ToPaintGeometry ( ) , LinePoints , MyClippingRect , DrawEffects , Color ) ;
2014-03-14 14:13:41 -04:00
LinePoints . Empty ( ) ;
}
else
{
//Add arrive and exit lines
{
const FRichCurveKey & FirstKey = Curve - > GetFirstKey ( ) ;
const FRichCurveKey & LastKey = Curve - > GetLastKey ( ) ;
float ArriveX = ScaleInfo . InputToLocalX ( FirstKey . Time ) ;
float ArriveY = ScaleInfo . OutputToLocalY ( FirstKey . Value ) ;
float LeaveY = ScaleInfo . OutputToLocalY ( LastKey . Value ) ;
float LeaveX = ScaleInfo . InputToLocalX ( LastKey . Time ) ;
//Arrival line
LinePoints . Add ( FVector2D ( 0.0f , ArriveY ) ) ;
LinePoints . Add ( FVector2D ( ArriveX , ArriveY ) ) ;
2014-04-23 17:42:50 -04:00
FSlateDrawElement : : MakeLines ( OutDrawElements , LayerId , AllottedGeometry . ToPaintGeometry ( ) , LinePoints , MyClippingRect , DrawEffects , Color ) ;
2014-03-14 14:13:41 -04:00
LinePoints . Empty ( ) ;
//Leave line
LinePoints . Add ( FVector2D ( AllottedGeometry . Size . X , LeaveY ) ) ;
LinePoints . Add ( FVector2D ( LeaveX , LeaveY ) ) ;
2014-04-23 17:42:50 -04:00
FSlateDrawElement : : MakeLines ( OutDrawElements , LayerId , AllottedGeometry . ToPaintGeometry ( ) , LinePoints , MyClippingRect , DrawEffects , Color ) ;
2014-03-14 14:13:41 -04:00
LinePoints . Empty ( ) ;
}
//Add enclosed segments
TArray < FRichCurveKey > Keys = Curve - > GetCopyOfKeys ( ) ;
for ( int32 i = 0 ; i < Keys . Num ( ) - 1 ; + + i )
{
CreateLinesForSegment ( Curve , Keys [ i ] , Keys [ i + 1 ] , LinePoints , ScaleInfo ) ;
2014-04-23 17:42:50 -04:00
FSlateDrawElement : : MakeLines ( OutDrawElements , LayerId , AllottedGeometry . ToPaintGeometry ( ) , LinePoints , MyClippingRect , DrawEffects , Color ) ;
2014-03-14 14:13:41 -04:00
LinePoints . Empty ( ) ;
}
}
}
}
}
void SCurveEditor : : CreateLinesForSegment ( FRichCurve * Curve , const FRichCurveKey & Key1 , const FRichCurveKey & Key2 , TArray < FVector2D > & Points , FTrackScaleInfo & ScaleInfo ) const
{
switch ( Key1 . InterpMode )
{
case RCIM_Constant :
{
//@todo: should really only need 3 points here but something about the line rendering isn't quite behaving as I'd expect, so need extras
Points . Add ( FVector2D ( Key1 . Time , Key1 . Value ) ) ;
Points . Add ( FVector2D ( Key2 . Time , Key1 . Value ) ) ;
Points . Add ( FVector2D ( Key2 . Time , Key1 . Value ) ) ;
Points . Add ( FVector2D ( Key2 . Time , Key2 . Value ) ) ;
Points . Add ( FVector2D ( Key2 . Time , Key1 . Value ) ) ;
} break ;
case RCIM_Linear :
{
Points . Add ( FVector2D ( Key1 . Time , Key1 . Value ) ) ;
Points . Add ( FVector2D ( Key2 . Time , Key2 . Value ) ) ;
} break ;
case RCIM_Cubic :
{
const float StepSize = 1.0f ;
//clamp to screen to avoid massive slowdown when zoomed in
float StartX = FMath : : Max ( ScaleInfo . InputToLocalX ( Key1 . Time ) , 0.0f ) ;
float EndX = FMath : : Min ( ScaleInfo . InputToLocalX ( Key2 . Time ) , ScaleInfo . WidgetSize . X ) ;
for ( ; StartX < EndX ; StartX + = StepSize )
{
float CurveIn = ScaleInfo . LocalXToInput ( FMath : : Min ( StartX , EndX ) ) ;
float CurveOut = Curve - > Eval ( CurveIn ) ;
Points . Add ( FVector2D ( CurveIn , CurveOut ) ) ;
}
Points . Add ( FVector2D ( Key2 . Time , Key2 . Value ) ) ;
} break ;
}
//Transform to screen
for ( auto It = Points . CreateIterator ( ) ; It ; + + It )
{
FVector2D Vec2D = * It ;
Vec2D . X = ScaleInfo . InputToLocalX ( Vec2D . X ) ;
Vec2D . Y = ScaleInfo . OutputToLocalY ( Vec2D . Y ) ;
* It = Vec2D ;
}
}
2014-09-03 11:17:17 -04:00
void SCurveEditor : : PaintKeys ( TSharedPtr < FCurveViewModel > CurveViewModel , FTrackScaleInfo & ScaleInfo , FSlateWindowElementList & OutDrawElements , int32 LayerId , int32 SelectedLayerId , const FGeometry & AllottedGeometry , const FSlateRect & MyClippingRect , ESlateDrawEffect : : Type DrawEffects , const FWidgetStyle & InWidgetStyle ) const
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
FLinearColor KeyColor = CurveViewModel - > bIsLocked ? FLinearColor ( 0.1f , 0.1f , 0.1f , 1.f ) : InWidgetStyle . GetColorAndOpacityTint ( ) ;
2014-03-14 14:13:41 -04:00
// Iterate over each key
ERichCurveInterpMode LastInterpMode = RCIM_Linear ;
2014-09-03 11:17:17 -04:00
FRichCurve * Curve = CurveViewModel - > CurveInfo . CurveToEdit ;
2014-03-14 14:13:41 -04:00
for ( auto It ( Curve - > GetKeyHandleIterator ( ) ) ; It ; + + It )
{
FKeyHandle KeyHandle = It . Key ( ) ;
// Work out where it is
2014-08-25 12:21:17 -04:00
FVector2D KeyLocation (
ScaleInfo . InputToLocalX ( Curve - > GetKeyTime ( KeyHandle ) ) ,
ScaleInfo . OutputToLocalY ( Curve - > GetKeyValue ( KeyHandle ) ) ) ;
FVector2D KeyIconLocation = KeyLocation - ( CONST_KeySize / 2 ) ;
2014-03-14 14:13:41 -04:00
// Get brush
bool IsSelected = IsKeySelected ( FSelectedCurveKey ( Curve , KeyHandle ) ) ;
const FSlateBrush * KeyBrush = IsSelected ? FEditorStyle : : GetBrush ( " CurveEd.CurveKeySelected " ) : FEditorStyle : : GetBrush ( " CurveEd.CurveKey " ) ;
2014-09-03 11:17:17 -04:00
int32 LayerToUse = IsSelected ? SelectedLayerId : LayerId ;
2014-03-14 14:13:41 -04:00
FSlateDrawElement : : MakeBox (
OutDrawElements ,
LayerToUse ,
2014-08-25 12:21:17 -04:00
AllottedGeometry . ToPaintGeometry ( KeyIconLocation , CONST_KeySize ) ,
2014-03-14 14:13:41 -04:00
KeyBrush ,
MyClippingRect ,
DrawEffects ,
KeyBrush - > GetTint ( InWidgetStyle ) * InWidgetStyle . GetColorAndOpacityTint ( ) * KeyColor
) ;
//Handle drawing the tangent controls for curve
if ( IsSelected & & ( Curve - > GetKeyInterpMode ( KeyHandle ) = = RCIM_Cubic | | LastInterpMode = = RCIM_Cubic ) )
{
2014-08-25 12:21:17 -04:00
PaintTangent ( ScaleInfo , Curve , KeyHandle , KeyLocation , OutDrawElements , LayerId , AllottedGeometry , MyClippingRect , DrawEffects , LayerToUse , InWidgetStyle ) ;
2014-03-14 14:13:41 -04:00
}
LastInterpMode = Curve - > GetKeyInterpMode ( KeyHandle ) ;
}
}
2014-08-25 12:21:17 -04:00
void SCurveEditor : : PaintTangent ( FTrackScaleInfo & ScaleInfo , FRichCurve * Curve , FKeyHandle KeyHandle , FVector2D KeyLocation , FSlateWindowElementList & OutDrawElements , int32 LayerId , const FGeometry & AllottedGeometry , const FSlateRect & MyClippingRect , ESlateDrawEffect : : Type DrawEffects , int32 LayerToUse , const FWidgetStyle & InWidgetStyle ) const
2014-03-14 14:13:41 -04:00
{
2014-08-25 12:21:17 -04:00
FVector2D ArriveTangentLocation , LeaveTangentLocation ;
GetTangentPoints ( ScaleInfo , FSelectedCurveKey ( Curve , KeyHandle ) , ArriveTangentLocation , LeaveTangentLocation ) ;
2014-03-14 14:13:41 -04:00
2014-08-25 12:21:17 -04:00
FVector2D ArriveTangentIconLocation = ArriveTangentLocation - ( CONST_TangentSize / 2 ) ;
FVector2D LeaveTangentIconLocation = LeaveTangentLocation - ( CONST_TangentSize / 2 ) ;
2014-03-14 14:13:41 -04:00
const FSlateBrush * TangentBrush = FEditorStyle : : GetBrush ( " CurveEd.Tangent " ) ;
2014-08-19 16:22:40 -04:00
const FLinearColor TangentColor = FEditorStyle : : GetColor ( " CurveEd.TangentColor " ) ;
2014-03-14 14:13:41 -04:00
//Add lines from tangent control point to 'key'
TArray < FVector2D > LinePoints ;
2014-08-25 12:21:17 -04:00
LinePoints . Add ( KeyLocation ) ;
LinePoints . Add ( ArriveTangentLocation ) ;
2014-03-14 14:13:41 -04:00
FSlateDrawElement : : MakeLines (
OutDrawElements ,
LayerId ,
AllottedGeometry . ToPaintGeometry ( ) ,
LinePoints ,
MyClippingRect ,
DrawEffects ,
2014-08-19 16:22:40 -04:00
TangentColor
2014-03-14 14:13:41 -04:00
) ;
LinePoints . Empty ( ) ;
2014-08-25 12:21:17 -04:00
LinePoints . Add ( KeyLocation ) ;
LinePoints . Add ( LeaveTangentLocation ) ;
2014-03-14 14:13:41 -04:00
FSlateDrawElement : : MakeLines (
OutDrawElements ,
LayerId ,
AllottedGeometry . ToPaintGeometry ( ) ,
LinePoints ,
MyClippingRect ,
DrawEffects ,
2014-08-19 16:22:40 -04:00
TangentColor
2014-03-14 14:13:41 -04:00
) ;
//Arrive tangent control
FSlateDrawElement : : MakeBox (
OutDrawElements ,
LayerToUse ,
2014-08-25 12:21:17 -04:00
AllottedGeometry . ToPaintGeometry ( ArriveTangentIconLocation , CONST_TangentSize ) ,
2014-03-14 14:13:41 -04:00
TangentBrush ,
MyClippingRect ,
DrawEffects ,
TangentBrush - > GetTint ( InWidgetStyle ) * InWidgetStyle . GetColorAndOpacityTint ( )
) ;
//Leave tangent control
FSlateDrawElement : : MakeBox (
OutDrawElements ,
LayerToUse ,
2014-08-25 12:21:17 -04:00
AllottedGeometry . ToPaintGeometry ( LeaveTangentIconLocation , CONST_TangentSize ) ,
2014-03-14 14:13:41 -04:00
TangentBrush ,
MyClippingRect ,
DrawEffects ,
TangentBrush - > GetTint ( InWidgetStyle ) * InWidgetStyle . GetColorAndOpacityTint ( )
) ;
}
float SCurveEditor : : CalcGridLineStepDistancePow2 ( double RawValue )
{
return float ( double ( FMath : : RoundUpToPowerOfTwo ( uint32 ( RawValue * 1024.0 ) ) > > 1 ) / 1024.0 ) ;
}
float SCurveEditor : : GetTimeStep ( FTrackScaleInfo & ScaleInfo ) const
{
const float MaxGridPixelSpacing = 150.0f ;
const float GridPixelSpacing = FMath : : Min ( ScaleInfo . WidgetSize . GetMin ( ) / 1.5f , MaxGridPixelSpacing ) ;
double MaxTimeStep = ScaleInfo . LocalXToInput ( ViewMinInput . Get ( ) + GridPixelSpacing ) - ScaleInfo . LocalXToInput ( ViewMinInput . Get ( ) ) ;
return CalcGridLineStepDistancePow2 ( MaxTimeStep ) ;
}
void SCurveEditor : : PaintGridLines ( const FGeometry & AllottedGeometry , FTrackScaleInfo & ScaleInfo , FSlateWindowElementList & OutDrawElements ,
int32 LayerId , const FSlateRect & MyClippingRect , ESlateDrawEffect : : Type DrawEffects ) const
{
const float MaxGridPixelSpacing = 150.0f ;
const float GridPixelSpacing = FMath : : Min ( ScaleInfo . WidgetSize . GetMin ( ) / 1.5f , MaxGridPixelSpacing ) ;
const FLinearColor GridTextColor = FLinearColor ( 1.0f , 1.0f , 1.0f , 0.75f ) ;
//Vertical grid(time)
{
float TimeStep = GetTimeStep ( ScaleInfo ) ;
float ScreenStepTime = ScaleInfo . InputToLocalX ( TimeStep ) - ScaleInfo . InputToLocalX ( 0.0f ) ;
if ( ScreenStepTime > = 1.0f )
{
float StartTime = ScaleInfo . LocalXToInput ( 0.0f ) ;
TArray < FVector2D > LinePoints ;
float ScaleX = ( TimeStep ) / ( AllottedGeometry . Size . X ) ;
//draw vertical grid lines
float StartOffset = - FMath : : Fractional ( StartTime / TimeStep ) * ScreenStepTime ;
float Time = ScaleInfo . LocalXToInput ( StartOffset ) ;
for ( float X = StartOffset ; X < AllottedGeometry . Size . X ; X + = ScreenStepTime , Time + = TimeStep )
{
if ( SMALL_NUMBER < FMath : : Abs ( X ) ) //don't show at 0 to avoid overlapping with center axis
{
LinePoints . Add ( FVector2D ( X , 0.0 ) ) ;
LinePoints . Add ( FVector2D ( X , AllottedGeometry . Size . Y ) ) ;
2015-02-16 11:59:08 -05:00
FSlateDrawElement : : MakeLines (
OutDrawElements ,
LayerId ,
AllottedGeometry . ToPaintGeometry ( ) ,
LinePoints ,
MyClippingRect ,
DrawEffects ,
GridColor ,
false ) ;
2014-03-14 14:13:41 -04:00
//Show grid time
2015-02-16 11:59:08 -05:00
if ( bDrawInputGridNumbers )
2014-03-14 14:13:41 -04:00
{
FString TimeStr = FString : : Printf ( TEXT ( " %.2f " ) , Time ) ;
FSlateDrawElement : : MakeText ( OutDrawElements , LayerId , AllottedGeometry . MakeChild ( FVector2D ( X , 0.0 ) , FVector2D ( 1.0f , ScaleX ) ) . ToPaintGeometry ( ) , TimeStr ,
FEditorStyle : : GetFontStyle ( " CurveEd.InfoFont " ) , MyClippingRect , DrawEffects , GridTextColor ) ;
}
LinePoints . Empty ( ) ;
}
}
}
}
//Horizontal grid(values)
// This is only useful if the curves are visible
if ( AreCurvesVisible ( ) )
{
double MaxValueStep = ScaleInfo . LocalYToOutput ( 0 ) - ScaleInfo . LocalYToOutput ( GridPixelSpacing ) ;
float ValueStep = CalcGridLineStepDistancePow2 ( MaxValueStep ) ;
float ScreenStepValue = ScaleInfo . OutputToLocalY ( 0.0f ) - ScaleInfo . OutputToLocalY ( ValueStep ) ;
if ( ScreenStepValue > = 1.0f )
{
float StartValue = ScaleInfo . LocalYToOutput ( 0.0f ) ;
TArray < FVector2D > LinePoints ;
float StartOffset = FMath : : Fractional ( StartValue / ValueStep ) * ScreenStepValue ;
float Value = ScaleInfo . LocalYToOutput ( StartOffset ) ;
float ScaleY = ( ValueStep ) / ( AllottedGeometry . Size . Y ) ;
for ( float Y = StartOffset ; Y < AllottedGeometry . Size . Y ; Y + = ScreenStepValue , Value - = ValueStep )
{
if ( SMALL_NUMBER < FMath : : Abs ( Y ) ) //don't show at 0 to avoid overlapping with center axis
{
LinePoints . Add ( FVector2D ( 0.0f , Y ) ) ;
LinePoints . Add ( FVector2D ( AllottedGeometry . Size . X , Y ) ) ;
2015-02-16 11:59:08 -05:00
FSlateDrawElement : : MakeLines (
OutDrawElements ,
LayerId ,
AllottedGeometry . ToPaintGeometry ( ) ,
LinePoints ,
MyClippingRect ,
DrawEffects ,
GridColor ,
false ) ;
2014-03-14 14:13:41 -04:00
//Show grid value
2015-02-16 11:59:08 -05:00
if ( bDrawOutputGridNumbers )
2014-03-14 14:13:41 -04:00
{
FString ValueStr = FString : : Printf ( TEXT ( " %.2f " ) , Value ) ;
FSlateFontInfo Font = FEditorStyle : : GetFontStyle ( " CurveEd.InfoFont " ) ;
const TSharedRef < FSlateFontMeasure > FontMeasureService = FSlateApplication : : Get ( ) . GetRenderer ( ) - > GetFontMeasureService ( ) ;
FVector2D DrawSize = FontMeasureService - > Measure ( ValueStr , Font ) ;
// draw at the start
FSlateDrawElement : : MakeText ( OutDrawElements , LayerId , AllottedGeometry . MakeChild ( FVector2D ( 0.0f , Y ) , FVector2D ( ScaleY , 1.0f ) ) . ToPaintGeometry ( ) , ValueStr ,
Font , MyClippingRect , DrawEffects , GridTextColor ) ;
// draw at the last since sometimes start can be hidden
FSlateDrawElement : : MakeText ( OutDrawElements , LayerId , AllottedGeometry . MakeChild ( FVector2D ( AllottedGeometry . Size . X - DrawSize . X , Y ) , FVector2D ( ScaleY , 1.0f ) ) . ToPaintGeometry ( ) , ValueStr ,
Font , MyClippingRect , DrawEffects , GridTextColor ) ;
}
LinePoints . Empty ( ) ;
}
}
}
}
}
2014-08-19 16:22:40 -04:00
void SCurveEditor : : PaintMarquee ( const FGeometry & AllottedGeometry , const FSlateRect & MyClippingRect , FSlateWindowElementList & OutDrawElements , int32 LayerId ) const
{
FVector2D MarqueTopLeft (
FMath : : Min ( MouseDownLocation . X , MouseMoveLocation . X ) ,
FMath : : Min ( MouseDownLocation . Y , MouseMoveLocation . Y )
) ;
FVector2D MarqueBottomRight (
FMath : : Max ( MouseDownLocation . X , MouseMoveLocation . X ) ,
FMath : : Max ( MouseDownLocation . Y , MouseMoveLocation . Y )
) ;
FSlateDrawElement : : MakeBox (
OutDrawElements ,
LayerId ,
AllottedGeometry . ToPaintGeometry ( MarqueTopLeft , MarqueBottomRight - MarqueTopLeft ) ,
FEditorStyle : : GetBrush ( TEXT ( " MarqueeSelection " ) ) ,
MyClippingRect
) ;
}
2014-03-14 14:13:41 -04:00
void SCurveEditor : : SetCurveOwner ( FCurveOwnerInterface * InCurveOwner , bool bCanEdit )
{
if ( InCurveOwner ! = CurveOwner )
{
EmptySelection ( ) ;
}
GradientViewer - > SetCurveOwner ( InCurveOwner ) ;
CurveOwner = InCurveOwner ;
bCanEditTrack = bCanEdit ;
bAreCurvesVisible = ! IsLinearColorCurve ( ) ;
bIsGradientEditorVisible = IsLinearColorCurve ( ) ;
2014-09-03 11:17:17 -04:00
CurveViewModels . Empty ( ) ;
2014-03-14 14:13:41 -04:00
if ( CurveOwner ! = NULL )
{
2014-09-03 11:17:17 -04:00
int curveIndex = 0 ;
for ( auto CurveInfo : CurveOwner - > GetCurves ( ) )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
CurveViewModels . Add ( TSharedPtr < FCurveViewModel > ( new FCurveViewModel ( CurveInfo , CurveColors [ curveIndex % CurveColors . Num ( ) ] , ! bCanEdit ) ) ) ;
curveIndex + + ;
2014-03-14 14:13:41 -04:00
}
CurveOwner - > MakeTransactional ( ) ;
}
SelectedKeys . Empty ( ) ;
2014-07-30 15:42:17 -04:00
if ( bZoomToFitVertical )
2014-03-14 14:13:41 -04:00
{
2015-06-24 08:02:15 -04:00
ZoomToFitVertical ( ) ;
2014-07-30 15:42:17 -04:00
}
if ( bZoomToFitHorizontal )
{
2015-06-24 08:02:15 -04:00
ZoomToFitHorizontal ( ) ;
2014-03-14 14:13:41 -04:00
}
CurveSelectionWidget . Pin ( ) - > SetContent ( CreateCurveSelectionWidget ( ) ) ;
}
2014-07-30 15:42:17 -04:00
void SCurveEditor : : SetZoomToFit ( bool bNewZoomToFitVertical , bool bNewZoomToFitHorizontal )
2014-03-14 14:13:41 -04:00
{
2014-07-30 15:42:17 -04:00
bZoomToFitVertical = bNewZoomToFitVertical ;
bZoomToFitHorizontal = bNewZoomToFitHorizontal ;
2014-03-14 14:13:41 -04:00
}
FCurveOwnerInterface * SCurveEditor : : GetCurveOwner ( ) const
{
return CurveOwner ;
}
FRichCurve * SCurveEditor : : GetCurve ( int32 CurveIndex ) const
{
2014-09-03 11:17:17 -04:00
if ( CurveIndex < CurveViewModels . Num ( ) )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
return CurveViewModels [ CurveIndex ] - > CurveInfo . CurveToEdit ;
2014-03-14 14:13:41 -04:00
}
return NULL ;
}
void SCurveEditor : : DeleteSelectedKeys ( )
{
2015-02-16 11:59:08 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_RemoveKeys " , " Delete Key(s) " )) ;
CurveOwner - > ModifyOwner ( ) ;
TSet < FRichCurve * > ChangedCurves ;
2014-03-14 14:13:41 -04:00
// While there are still keys
while ( SelectedKeys . Num ( ) > 0 )
{
// Pull one out of the selected set
FSelectedCurveKey Key = SelectedKeys . Pop ( ) ;
if ( IsValidCurve ( Key . Curve ) )
{
// Remove from the curve
Key . Curve - > DeleteKey ( Key . KeyHandle ) ;
2015-02-16 11:59:08 -05:00
ChangedCurves . Add ( Key . Curve ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-08-19 15:57:46 -04:00
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
for ( auto CurveViewModel : CurveViewModels )
{
if ( ChangedCurves . Contains ( CurveViewModel - > CurveInfo . CurveToEdit ) )
{
ChangedCurveEditInfos . Add ( CurveViewModel - > CurveInfo ) ;
}
}
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-19 16:22:40 -04:00
FReply SCurveEditor : : OnMouseButtonDown ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
2014-03-14 14:13:41 -04:00
{
const bool bLeftMouseButton = InMouseEvent . GetEffectingButton ( ) = = EKeys : : LeftMouseButton ;
const bool bRightMouseButton = InMouseEvent . GetEffectingButton ( ) = = EKeys : : RightMouseButton ;
2014-08-19 16:22:40 -04:00
DragState = EDragState : : PreDrag ;
if ( bLeftMouseButton | | bRightMouseButton )
2014-03-14 14:13:41 -04:00
{
2014-08-19 16:22:40 -04:00
MouseDownLocation = InMyGeometry . AbsoluteToLocal ( InMouseEvent . GetScreenSpacePosition ( ) ) ;
2014-03-14 14:13:41 -04:00
// Set keyboard focus to this so that selected text box doesn't try to apply to newly selected keys
if ( ! HasKeyboardFocus ( ) )
{
2014-10-30 12:29:36 -04:00
FSlateApplication : : Get ( ) . SetKeyboardFocus ( SharedThis ( this ) , EFocusCause : : SetDirectly ) ;
2014-03-14 14:13:41 -04:00
}
// Always capture mouse if we left or right click on the widget
return FReply : : Handled ( ) . CaptureMouse ( SharedThis ( this ) ) ;
}
return FReply : : Unhandled ( ) ;
}
2015-06-18 14:10:19 -04:00
void SCurveEditor : : AddNewKey ( FGeometry InMyGeometry , FVector2D ScreenPosition , TSharedPtr < TArray < TSharedPtr < FCurveViewModel > > > CurvesToAddKeysTo , bool bAddKeysInline )
2014-04-23 17:30:58 -04:00
{
2015-02-16 11:59:08 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_AddKey " , " Add Key(s) " )) ;
CurveOwner - > ModifyOwner ( ) ;
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
2015-06-18 14:10:19 -04:00
for ( TSharedPtr < FCurveViewModel > CurveViewModel : * CurvesToAddKeysTo )
2014-09-22 09:47:37 -04:00
{
2015-02-16 11:59:08 -05:00
if ( ! CurveViewModel - > bIsLocked )
2014-09-22 09:47:37 -04:00
{
2015-02-16 11:59:08 -05:00
FRichCurve * SelectedCurve = CurveViewModel - > CurveInfo . CurveToEdit ;
if ( IsValidCurve ( SelectedCurve ) )
{
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
2014-09-03 11:17:17 -04:00
2015-02-16 11:59:08 -05:00
FVector2D LocalClickPos = InMyGeometry . AbsoluteToLocal ( ScreenPosition ) ;
2014-09-03 11:17:17 -04:00
2015-06-18 14:10:19 -04:00
float Input = ScaleInfo . LocalXToInput ( LocalClickPos . X ) ;
float Output ;
if ( bAddKeysInline )
{
Output = SelectedCurve - > Eval ( Input ) ;
}
else
{
Output = ScaleInfo . LocalYToOutput ( LocalClickPos . Y ) ;
}
FVector2D NewKeyLocation = SnapLocation ( FVector2D ( Input , Output ) ) ;
2014-09-03 11:17:17 -04:00
FKeyHandle NewKeyHandle = SelectedCurve - > AddKey ( NewKeyLocation . X , NewKeyLocation . Y ) ;
2015-02-16 11:59:08 -05:00
EmptySelection ( ) ;
AddToSelection ( FSelectedCurveKey ( SelectedCurve , NewKeyHandle ) ) ;
ChangedCurveEditInfos . Add ( CurveViewModel - > CurveInfo ) ;
2014-09-03 11:17:17 -04:00
}
2014-04-23 17:30:58 -04:00
}
}
2015-02-16 11:59:08 -05:00
if ( ChangedCurveEditInfos . Num ( ) > 0 )
2014-04-23 17:30:58 -04:00
{
2015-02-16 11:59:08 -05:00
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
}
2014-04-23 17:30:58 -04:00
}
2014-03-14 14:13:41 -04:00
void SCurveEditor : : OnMouseCaptureLost ( )
{
// if we began a drag transaction we need to finish it to make sure undo doesn't get out of sync
2014-09-03 11:17:17 -04:00
if ( DragState = = EDragState : : DragKey | | DragState = = EDragState : : DragTangent )
2014-03-14 14:13:41 -04:00
{
EndDragTransaction ( ) ;
}
2014-08-19 16:22:40 -04:00
DragState = EDragState : : None ;
2014-03-14 14:13:41 -04:00
}
FReply SCurveEditor : : OnMouseButtonUp ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
2014-08-19 16:22:40 -04:00
if ( this - > HasMouseCapture ( ) )
2014-03-14 14:13:41 -04:00
{
2014-08-19 16:22:40 -04:00
if ( DragState = = EDragState : : PreDrag )
2014-03-14 14:13:41 -04:00
{
2014-08-19 16:22:40 -04:00
// If the user didn't start dragging, handle the mouse operation as a click.
ProcessClick ( InMyGeometry , InMouseEvent ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-19 16:22:40 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-08-19 16:22:40 -04:00
EndDrag ( InMyGeometry , InMouseEvent ) ;
2014-03-14 14:13:41 -04:00
}
return FReply : : Handled ( ) . ReleaseMouseCapture ( ) ;
}
return FReply : : Unhandled ( ) ;
}
2014-10-01 14:45:23 -04:00
void ClampViewRangeToDataIfBound ( float & NewViewMin , float & NewViewMax , const TAttribute < TOptional < float > > & DataMin , const TAttribute < TOptional < float > > & DataMax , const float ViewRange )
2014-03-14 14:13:41 -04:00
{
// if we have data bound
const TOptional < float > & Min = DataMin . Get ( ) ;
const TOptional < float > & Max = DataMax . Get ( ) ;
if ( Min . IsSet ( ) & & NewViewMin < Min . GetValue ( ) )
{
// if we have min data set
NewViewMin = Min . GetValue ( ) ;
NewViewMax = ViewRange ;
}
else if ( Max . IsSet ( ) & & NewViewMax > Max . GetValue ( ) )
{
// if we have min data set
NewViewMin = Max . GetValue ( ) - ViewRange ;
NewViewMax = Max . GetValue ( ) ;
}
}
FReply SCurveEditor : : OnMouseMove ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
2015-02-16 11:59:08 -05:00
UpdateCurveToolTip ( InMyGeometry , InMouseEvent ) ;
2014-03-14 14:13:41 -04:00
FRichCurve * Curve = GetCurve ( 0 ) ;
2014-08-19 16:22:40 -04:00
if ( Curve ! = NULL & & this - > HasMouseCapture ( ) )
2014-03-14 14:13:41 -04:00
{
2014-08-19 16:22:40 -04:00
if ( DragState = = EDragState : : PreDrag )
2014-03-14 14:13:41 -04:00
{
2014-08-19 16:22:40 -04:00
TryStartDrag ( InMyGeometry , InMouseEvent ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-22 17:36:08 -04:00
if ( DragState ! = EDragState : : None )
2014-08-19 16:22:40 -04:00
{
ProcessDrag ( InMyGeometry , InMouseEvent ) ;
}
MouseMoveLocation = InMyGeometry . AbsoluteToLocal ( InMouseEvent . GetScreenSpacePosition ( ) ) ;
return FReply : : Handled ( ) ;
2014-03-14 14:13:41 -04:00
}
return FReply : : Unhandled ( ) ;
}
2015-02-16 11:59:08 -05:00
void SCurveEditor : : UpdateCurveToolTip ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
if ( bShowCurveToolTips . Get ( ) )
{
TSharedPtr < FCurveViewModel > HoveredCurve = HitTestCurves ( InMyGeometry , InMouseEvent ) ;
if ( HoveredCurve . IsValid ( ) )
{
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
const FVector2D HitPosition = InMyGeometry . AbsoluteToLocal ( InMouseEvent . GetScreenSpacePosition ( ) ) ;
float Time = ScaleInfo . LocalXToInput ( HitPosition . X ) ;
float Value = HoveredCurve - > CurveInfo . CurveToEdit - > Eval ( Time ) ;
FNumberFormattingOptions FormattingOptions ;
FormattingOptions . MaximumFractionalDigits = 2 ;
CurveToolTipNameText = FText : : FromName ( HoveredCurve - > CurveInfo . CurveName ) ;
CurveToolTipInputText = FText : : Format ( LOCTEXT ( " CurveToolTipTimeFormat " , " {0}: {1} " ) , InputAxisName , FText : : AsNumber ( Time , & FormattingOptions ) ) ;
CurveToolTipOutputText = FText : : Format ( LOCTEXT ( " CurveToolTipValueFormat " , " {0}: {1} " ) , OutputAxisName , FText : : AsNumber ( Value , & FormattingOptions ) ) ;
if ( CurveToolTip . IsValid ( ) = = false )
{
SetToolTip (
SAssignNew ( CurveToolTip , SToolTip )
. BorderImage ( FCoreStyle : : Get ( ) . GetBrush ( " ToolTip.BrightBackground " ) )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
[
SNew ( STextBlock )
. Text ( this , & SCurveEditor : : GetCurveToolTipNameText )
. Font ( FCoreStyle : : Get ( ) . GetFontStyle ( " ToolTip.LargerFont " ) )
. ColorAndOpacity ( FLinearColor : : Black )
]
+ SVerticalBox : : Slot ( )
[
SNew ( STextBlock )
. Text ( this , & SCurveEditor : : GetCurveToolTipInputText )
. Font ( FCoreStyle : : Get ( ) . GetFontStyle ( " ToolTip.LargerFont " ) )
. ColorAndOpacity ( FLinearColor : : Black )
]
+ SVerticalBox : : Slot ( )
[
SNew ( STextBlock )
. Text ( this , & SCurveEditor : : GetCurveToolTipOutputText )
. Font ( FCoreStyle : : Get ( ) . GetFontStyle ( " ToolTip.LargerFont " ) )
. ColorAndOpacity ( FLinearColor : : Black )
]
] ) ;
}
}
else
{
CurveToolTip . Reset ( ) ;
SetToolTip ( CurveToolTip ) ;
}
}
}
FReply SCurveEditor : : OnMouseWheel ( const FGeometry & MyGeometry , const FPointerEvent & MouseEvent )
2014-03-14 14:13:41 -04:00
{
const float ZoomDelta = - 0.1f * MouseEvent . GetWheelDelta ( ) ;
if ( bAllowZoomOutput )
{
2014-09-22 09:47:37 -04:00
const float OutputViewSize = ViewMaxOutput . Get ( ) - ViewMinOutput . Get ( ) ;
2014-03-14 14:13:41 -04:00
const float OutputChange = OutputViewSize * ZoomDelta ;
2014-09-22 09:47:37 -04:00
const float NewMinOutput = ( ViewMinOutput . Get ( ) - ( OutputChange * 0.5f ) ) ;
const float NewMaxOutput = ( ViewMaxOutput . Get ( ) + ( OutputChange * 0.5f ) ) ;
SetOutputMinMax ( NewMinOutput , NewMaxOutput ) ;
2014-03-14 14:13:41 -04:00
}
{
const float InputViewSize = ViewMaxInput . Get ( ) - ViewMinInput . Get ( ) ;
const float InputChange = InputViewSize * ZoomDelta ;
const float NewMinInput = ViewMinInput . Get ( ) - ( InputChange * 0.5f ) ;
const float NewMaxInput = ViewMaxInput . Get ( ) + ( InputChange * 0.5f ) ;
2014-05-05 14:06:27 -04:00
SetInputMinMax ( NewMinInput , NewMaxInput ) ;
2014-03-14 14:13:41 -04:00
}
return FReply : : Handled ( ) ;
}
2014-10-30 12:29:36 -04:00
FReply SCurveEditor : : OnKeyDown ( const FGeometry & MyGeometry , const FKeyEvent & InKeyEvent )
2014-03-14 14:13:41 -04:00
{
2014-10-30 12:29:36 -04:00
if ( InKeyEvent . GetKey ( ) = = EKeys : : Platform_Delete & & SelectedKeys . Num ( ) ! = 0 )
2014-03-14 14:13:41 -04:00
{
DeleteSelectedKeys ( ) ;
return FReply : : Handled ( ) ;
}
else
{
2014-10-30 12:29:36 -04:00
if ( Commands - > ProcessCommandBindings ( InKeyEvent ) )
2014-03-14 14:13:41 -04:00
{
return FReply : : Handled ( ) ;
}
return FReply : : Unhandled ( ) ;
}
}
2014-08-19 16:22:40 -04:00
void SCurveEditor : : TryStartDrag ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
const bool bLeftMouseButton = InMouseEvent . IsMouseButtonDown ( EKeys : : LeftMouseButton ) ;
const bool bRightMouseButton = InMouseEvent . IsMouseButtonDown ( EKeys : : RightMouseButton ) ;
const bool bControlDown = InMouseEvent . IsControlDown ( ) ;
FVector2D DragVector = InMyGeometry . AbsoluteToLocal ( InMouseEvent . GetScreenSpacePosition ( ) ) - MouseDownLocation ;
if ( DragVector . Size ( ) > = DragThreshold )
{
2014-09-03 11:17:17 -04:00
if ( bLeftMouseButton )
2014-08-19 16:22:40 -04:00
{
// Check if we should start dragging keys.
FSelectedCurveKey HitKey = HitTestKeys ( InMyGeometry , InMyGeometry . LocalToAbsolute ( MouseDownLocation ) ) ;
if ( HitKey . IsValid ( ) )
{
if ( IsKeySelected ( HitKey ) = = false )
{
if ( ! bControlDown )
{
EmptySelection ( ) ;
}
AddToSelection ( HitKey ) ;
}
BeginDragTransaction ( ) ;
DragState = EDragState : : DragKey ;
2014-08-22 17:36:08 -04:00
DraggedKeyHandle = HitKey . KeyHandle ;
PreDragKeyLocations . Empty ( ) ;
for ( auto selectedKey : SelectedKeys )
{
PreDragKeyLocations . Add ( selectedKey . KeyHandle , FVector2D
(
selectedKey . Curve - > GetKeyTime ( selectedKey . KeyHandle ) ,
selectedKey . Curve - > GetKeyValue ( selectedKey . KeyHandle )
) ) ;
}
2014-08-19 16:22:40 -04:00
}
else
{
// Check if we should start dragging a tangent.
FSelectedTangent Tangent = HitTestCubicTangents ( InMyGeometry , InMyGeometry . LocalToAbsolute ( MouseDownLocation ) ) ;
if ( Tangent . IsValid ( ) )
{
BeginDragTransaction ( ) ;
SelectedTangent = Tangent ;
DragState = EDragState : : DragTangent ;
}
else
{
// Otherwise if the user left clicked on nothing and start a marquee select.
DragState = EDragState : : MarqueeSelect ;
}
}
}
else if ( bRightMouseButton )
{
DragState = EDragState : : Pan ;
}
else
{
DragState = EDragState : : None ;
}
}
}
void SCurveEditor : : ProcessDrag ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
2014-09-22 09:47:37 -04:00
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
2014-08-19 16:22:40 -04:00
FVector2D ScreenDelta = InMouseEvent . GetCursorDelta ( ) ;
FVector2D InputDelta ;
InputDelta . X = ScreenDelta . X / ScaleInfo . PixelsPerInput ;
InputDelta . Y = - ScreenDelta . Y / ScaleInfo . PixelsPerOutput ;
if ( DragState = = EDragState : : DragKey )
{
2014-08-22 17:36:08 -04:00
FVector2D MousePosition = InMyGeometry . AbsoluteToLocal ( InMouseEvent . GetScreenSpacePosition ( ) ) ;
MoveSelectedKeys ( FVector2D ( ScaleInfo . LocalXToInput ( MousePosition . X ) , ScaleInfo . LocalYToOutput ( MousePosition . Y ) ) ) ;
2014-08-19 16:22:40 -04:00
}
else if ( DragState = = EDragState : : DragTangent )
{
FVector2D MousePositionScreen = InMouseEvent . GetScreenSpacePosition ( ) ;
MousePositionScreen - = InMyGeometry . AbsolutePosition ;
FVector2D MousePositionCurve ( ScaleInfo . LocalXToInput ( MousePositionScreen . X ) , ScaleInfo . LocalYToOutput ( MousePositionScreen . Y ) ) ;
OnMoveTangent ( MousePositionCurve ) ;
}
else if ( DragState = = EDragState : : Pan )
{
// Output is not clamped.
2014-09-22 09:47:37 -04:00
const float NewMinOutput = ( ViewMinOutput . Get ( ) - InputDelta . Y ) ;
const float NewMaxOutput = ( ViewMaxOutput . Get ( ) - InputDelta . Y ) ;
SetOutputMinMax ( NewMinOutput , NewMaxOutput ) ;
2014-08-19 16:22:40 -04:00
// Input maybe clamped if DataMinInput or DataMaxOutput was set.
float NewMinInput = ViewMinInput . Get ( ) - InputDelta . X ;
float NewMaxInput = ViewMaxInput . Get ( ) - InputDelta . X ;
ClampViewRangeToDataIfBound ( NewMinInput , NewMaxInput , DataMinInput , DataMaxInput , ScaleInfo . ViewInputRange ) ;
SetInputMinMax ( NewMinInput , NewMaxInput ) ;
}
}
void SCurveEditor : : EndDrag ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
const bool bControlDown = InMouseEvent . IsControlDown ( ) ;
if ( DragState = = EDragState : : DragKey | | DragState = = EDragState : : DragTangent )
{
2014-09-22 09:47:37 -04:00
EndDragTransaction ( ) ;
}
2014-08-19 16:22:40 -04:00
else if ( DragState = = EDragState : : MarqueeSelect )
{
2014-09-03 11:17:17 -04:00
FVector2D MarqueTopLeft
(
2014-08-19 16:22:40 -04:00
FMath : : Min ( MouseDownLocation . X , MouseMoveLocation . X ) ,
FMath : : Min ( MouseDownLocation . Y , MouseMoveLocation . Y )
2014-09-22 09:47:37 -04:00
) ;
2014-08-19 16:22:40 -04:00
2014-09-03 11:17:17 -04:00
FVector2D MarqueBottomRight
(
2014-08-19 16:22:40 -04:00
FMath : : Max ( MouseDownLocation . X , MouseMoveLocation . X ) ,
FMath : : Max ( MouseDownLocation . Y , MouseMoveLocation . Y )
2014-09-22 09:47:37 -04:00
) ;
2014-08-19 16:22:40 -04:00
2014-09-03 11:17:17 -04:00
TArray < FSelectedCurveKey > SelectedCurveKeys = GetEditableKeysWithinMarquee ( InMyGeometry , MarqueTopLeft , MarqueBottomRight ) ;
2014-08-19 16:22:40 -04:00
if ( ! bControlDown )
{
EmptySelection ( ) ;
}
for ( auto SelectedCurveKey : SelectedCurveKeys )
{
2014-09-03 11:17:17 -04:00
2014-08-19 16:22:40 -04:00
if ( IsKeySelected ( SelectedCurveKey ) )
{
RemoveFromSelection ( SelectedCurveKey ) ;
}
else
{
AddToSelection ( SelectedCurveKey ) ;
}
}
}
DragState = EDragState : : None ;
}
void SCurveEditor : : ProcessClick ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
{
const bool bLeftMouseButton = InMouseEvent . GetEffectingButton ( ) = = EKeys : : LeftMouseButton ;
const bool bRightMouseButton = InMouseEvent . GetEffectingButton ( ) = = EKeys : : RightMouseButton ;
const bool bControlDown = InMouseEvent . IsControlDown ( ) ;
const bool bShiftDown = InMouseEvent . IsShiftDown ( ) ;
FSelectedCurveKey HitKey = HitTestKeys ( InMyGeometry , InMouseEvent . GetScreenSpacePosition ( ) ) ;
2015-06-05 20:19:33 -04:00
if ( bLeftMouseButton )
{
// If the user left clicked a key, update selection based on modifier key state.
if ( HitKey . IsValid ( ) )
2014-08-19 16:22:40 -04:00
{
2015-06-05 20:19:33 -04:00
if ( ! IsKeySelected ( HitKey ) )
2014-08-19 16:22:40 -04:00
{
2015-06-05 20:19:33 -04:00
if ( ! bControlDown )
2014-08-19 16:22:40 -04:00
{
2014-09-22 09:47:37 -04:00
EmptySelection ( ) ;
}
2015-06-05 20:19:33 -04:00
AddToSelection ( HitKey ) ;
}
else if ( bControlDown )
{
RemoveFromSelection ( HitKey ) ;
2014-09-03 11:17:17 -04:00
}
}
2015-06-05 20:19:33 -04:00
else
2014-09-03 11:17:17 -04:00
{
2015-06-05 20:19:33 -04:00
// If the user didn't click a key, add a new one if shift is held down, or try to select a curve.
if ( bShiftDown )
2014-09-03 11:17:17 -04:00
{
2015-06-18 14:10:19 -04:00
TSharedPtr < TArray < TSharedPtr < FCurveViewModel > > > CurvesToAddKeysTo = MakeShareable ( new TArray < TSharedPtr < FCurveViewModel > > ( ) ) ;
TSharedPtr < FCurveViewModel > HoveredCurve = HitTestCurves ( InMyGeometry , InMouseEvent ) ;
bool bAddKeysInline ;
if ( HoveredCurve . IsValid ( ) )
{
CurvesToAddKeysTo - > Add ( HoveredCurve ) ;
bAddKeysInline = false ;
}
else
{
if ( CurveViewModels . Num ( ) = = 1 )
{
CurvesToAddKeysTo - > Add ( CurveViewModels [ 0 ] ) ;
bAddKeysInline = true ;
}
else
{
CurvesToAddKeysTo - > Append ( CurveViewModels ) ;
bAddKeysInline = false ;
}
}
AddNewKey ( InMyGeometry , InMouseEvent . GetScreenSpacePosition ( ) , CurvesToAddKeysTo , bAddKeysInline ) ;
2014-09-03 11:17:17 -04:00
}
else
2014-09-22 09:47:37 -04:00
{
2015-06-05 20:19:33 -04:00
// clicking on background clears key selection
EmptySelection ( ) ;
}
}
}
else if ( bRightMouseButton )
{
// If the user right clicked, handle opening context menus.
if ( HitKey . IsValid ( ) )
{
// Make sure key is selected in readiness for context menu
if ( ! IsKeySelected ( HitKey ) )
{
EmptySelection ( ) ;
AddToSelection ( HitKey ) ;
}
PushKeyMenu ( InMyGeometry , InMouseEvent ) ;
}
else
{
if ( ! HitTestCubicTangents ( InMyGeometry , InMouseEvent . GetScreenSpacePosition ( ) ) . IsValid ( ) )
{
CreateContextMenu ( InMyGeometry , InMouseEvent ) ;
}
2014-09-22 09:47:37 -04:00
else
2014-09-03 11:17:17 -04:00
{
EmptySelection ( ) ;
2014-08-19 16:22:40 -04:00
}
}
}
}
2014-04-23 17:30:58 -04:00
TOptional < float > SCurveEditor : : OnGetTime ( ) const
{
if ( SelectedKeys . Num ( ) = = 1 )
{
return GetKeyTime ( SelectedKeys [ 0 ] ) ;
}
// Value couldn't be accessed. Return an unset value
return TOptional < float > ( ) ;
}
void SCurveEditor : : OnTimeComitted ( float NewTime , ETextCommit : : Type CommitType )
{
// Don't digest the number if we just clicked away from the pop-up
if ( ! bIsUsingSlider & & ( ( CommitType = = ETextCommit : : OnEnter ) | | ( CommitType = = ETextCommit : : OnUserMovedFocus ) ) )
{
if ( SelectedKeys . Num ( ) > = 1 )
{
auto Key = SelectedKeys [ 0 ] ;
if ( IsValidCurve ( Key . Curve ) )
{
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_NewTime " , " New Time Entered " ) ) ;
CurveOwner - > ModifyOwner ( ) ;
Key . Curve - > SetKeyTime ( Key . KeyHandle , NewTime ) ;
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
ChangedCurveEditInfos . Add ( GetViewModelForCurve ( Key . Curve ) - > CurveInfo ) ;
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-04-23 17:30:58 -04:00
}
}
FSlateApplication : : Get ( ) . DismissAllMenus ( ) ;
}
}
void SCurveEditor : : OnTimeChanged ( float NewTime )
{
if ( bIsUsingSlider )
{
if ( SelectedKeys . Num ( ) > = 1 )
{
auto Key = SelectedKeys [ 0 ] ;
if ( IsValidCurve ( Key . Curve ) )
{
2015-02-16 11:59:08 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_NewTime " , " New Time Entered " ) ) ;
2014-04-23 17:30:58 -04:00
CurveOwner - > ModifyOwner ( ) ;
Key . Curve - > SetKeyTime ( Key . KeyHandle , NewTime ) ;
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
ChangedCurveEditInfos . Add ( GetViewModelForCurve ( Key . Curve ) - > CurveInfo ) ;
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-04-23 17:30:58 -04:00
}
}
}
}
TOptional < float > SCurveEditor : : OnGetValue ( ) const
{
TOptional < float > Value ;
// Return the value string if all selected keys have the same output string, otherwise empty
if ( SelectedKeys . Num ( ) > 0 )
{
Value = GetKeyValue ( SelectedKeys [ 0 ] ) ;
for ( int32 i = 1 ; i < SelectedKeys . Num ( ) ; i + + )
{
TOptional < float > NewValue = GetKeyValue ( SelectedKeys [ i ] ) ;
bool bAreEqual = ( ( ! Value . IsSet ( ) & & ! NewValue . IsSet ( ) ) | | ( Value . IsSet ( ) & & NewValue . IsSet ( ) & & Value . GetValue ( ) = = NewValue . GetValue ( ) ) ) ;
if ( ! bAreEqual )
{
return TOptional < float > ( ) ;
}
}
}
return Value ;
}
void SCurveEditor : : OnValueComitted ( float NewValue , ETextCommit : : Type CommitType )
2014-03-14 14:13:41 -04:00
{
// Don't digest the number if we just clicked away from the popup
2014-04-23 17:30:58 -04:00
if ( ! bIsUsingSlider & & ( ( CommitType = = ETextCommit : : OnEnter ) | | ( CommitType = = ETextCommit : : OnUserMovedFocus ) ) )
2014-03-14 14:13:41 -04:00
{
2015-02-16 11:59:08 -05:00
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_NewValue " , " New Value Entered " ) ) ;
CurveOwner - > ModifyOwner ( ) ;
TSet < FRichCurve * > ChangedCurves ;
2014-03-14 14:13:41 -04:00
// Iterate over selected set
2014-04-23 17:30:58 -04:00
for ( int32 i = 0 ; i < SelectedKeys . Num ( ) ; i + + )
2014-03-14 14:13:41 -04:00
{
auto Key = SelectedKeys [ i ] ;
2014-04-23 17:30:58 -04:00
if ( IsValidCurve ( Key . Curve ) )
2014-03-14 14:13:41 -04:00
{
// Fill in each element of this key
Key . Curve - > SetKeyValue ( Key . KeyHandle , NewValue ) ;
2015-02-16 11:59:08 -05:00
ChangedCurves . Add ( Key . Curve ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
for ( auto CurveViewModel : CurveViewModels )
{
if ( ChangedCurves . Contains ( CurveViewModel - > CurveInfo . CurveToEdit ) )
{
ChangedCurveEditInfos . Add ( CurveViewModel - > CurveInfo ) ;
}
}
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-08-19 15:57:46 -04:00
2014-03-14 14:13:41 -04:00
FSlateApplication : : Get ( ) . DismissAllMenus ( ) ;
}
}
2014-04-23 17:30:58 -04:00
void SCurveEditor : : OnValueChanged ( float NewValue )
2014-03-14 14:13:41 -04:00
{
2014-04-23 17:30:58 -04:00
if ( bIsUsingSlider )
2014-03-14 14:13:41 -04:00
{
2014-04-23 17:30:58 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_NewValue " , " New Value Entered " ) ) ;
2015-02-16 11:59:08 -05:00
TSet < FRichCurve * > ChangedCurves ;
2014-03-14 14:13:41 -04:00
2014-04-23 17:30:58 -04:00
// Iterate over selected set
for ( int32 i = 0 ; i < SelectedKeys . Num ( ) ; i + + )
2014-03-14 14:13:41 -04:00
{
2014-04-23 17:30:58 -04:00
auto Key = SelectedKeys [ i ] ;
if ( IsValidCurve ( Key . Curve ) )
2014-03-14 14:13:41 -04:00
{
CurveOwner - > ModifyOwner ( ) ;
2014-04-23 17:30:58 -04:00
// Fill in each element of this key
Key . Curve - > SetKeyValue ( Key . KeyHandle , NewValue ) ;
2015-02-16 11:59:08 -05:00
ChangedCurves . Add ( Key . Curve ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-08-19 15:57:46 -04:00
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
for ( auto CurveViewModel : CurveViewModels )
{
if ( ChangedCurves . Contains ( CurveViewModel - > CurveInfo . CurveToEdit ) )
{
ChangedCurveEditInfos . Add ( CurveViewModel - > CurveInfo ) ;
}
}
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 17:30:58 -04:00
void SCurveEditor : : OnBeginSliderMovement ( FText TransactionName )
{
bIsUsingSlider = true ;
GEditor - > BeginTransaction ( TransactionName ) ;
}
void SCurveEditor : : OnEndSliderMovement ( float NewValue )
{
bIsUsingSlider = false ;
GEditor - > EndTransaction ( ) ;
}
2014-03-14 14:13:41 -04:00
SCurveEditor : : FSelectedCurveKey SCurveEditor : : HitTestKeys ( const FGeometry & InMyGeometry , const FVector2D & HitScreenPosition )
{
FSelectedCurveKey SelectedKey ( NULL , FKeyHandle ( ) ) ;
if ( AreCurvesVisible ( ) )
{
2014-09-22 09:47:37 -04:00
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
2014-03-14 14:13:41 -04:00
const FVector2D HitPosition = InMyGeometry . AbsoluteToLocal ( HitScreenPosition ) ;
2014-09-03 11:17:17 -04:00
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
if ( ! CurveViewModel - > bIsLocked & & CurveViewModel - > bIsVisible )
2014-09-22 09:47:37 -04:00
{
2014-09-03 11:17:17 -04:00
FRichCurve * Curve = CurveViewModel - > CurveInfo . CurveToEdit ;
2014-09-22 09:47:37 -04:00
if ( Curve ! = NULL )
{
for ( auto It ( Curve - > GetKeyHandleIterator ( ) ) ; It ; + + It )
2014-03-14 14:13:41 -04:00
{
2014-09-22 09:47:37 -04:00
float KeyScreenX = ScaleInfo . InputToLocalX ( Curve - > GetKeyTime ( It . Key ( ) ) ) ;
float KeyScreenY = ScaleInfo . OutputToLocalY ( Curve - > GetKeyValue ( It . Key ( ) ) ) ;
2014-03-14 14:13:41 -04:00
2014-09-22 09:47:37 -04:00
if ( HitPosition . X > ( KeyScreenX - ( 0.5f * CONST_KeySize . X ) ) & &
HitPosition . X < ( KeyScreenX + ( 0.5f * CONST_KeySize . X ) ) & &
HitPosition . Y > ( KeyScreenY - ( 0.5f * CONST_KeySize . Y ) ) & &
HitPosition . Y < ( KeyScreenY + ( 0.5f * CONST_KeySize . Y ) ) )
{
2014-09-03 11:17:17 -04:00
return FSelectedCurveKey ( Curve , It . Key ( ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
}
}
return SelectedKey ;
}
2015-03-02 13:41:53 -05:00
void SCurveEditor : : MoveSelectedKeys ( FVector2D InNewLocation )
2014-03-14 14:13:41 -04:00
{
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_MoveKeys " , " Move Keys " ) ) ;
CurveOwner - > ModifyOwner ( ) ;
// track all unique curves encountered so their tangents can be updated later
TSet < FRichCurve * > UniqueCurves ;
2015-03-02 13:41:53 -05:00
FVector2D SnappedNewLocation = SnapLocation ( InNewLocation ) ;
2014-08-22 17:36:08 -04:00
// The total move distance for all keys is the difference between the current snapped location
// and the start location of the key which was actually dragged.
FVector2D TotalMoveDistance = SnappedNewLocation - PreDragKeyLocations [ DraggedKeyHandle ] ;
for ( int32 i = 0 ; i < SelectedKeys . Num ( ) ; i + + )
2014-03-14 14:13:41 -04:00
{
FSelectedCurveKey OldKey = SelectedKeys [ i ] ;
2014-08-22 17:36:08 -04:00
if ( ! IsValidCurve ( OldKey . Curve ) )
2014-03-14 14:13:41 -04:00
{
continue ;
}
2014-08-22 17:36:08 -04:00
FKeyHandle OldKeyHandle = OldKey . KeyHandle ;
FRichCurve * Curve = OldKey . Curve ;
2014-03-14 14:13:41 -04:00
2014-08-22 17:36:08 -04:00
FVector2D PreDragLocation = PreDragKeyLocations [ OldKeyHandle ] ;
FVector2D NewLocation = PreDragLocation + TotalMoveDistance ;
2014-03-14 14:13:41 -04:00
2014-08-22 17:36:08 -04:00
// Update the key's value without updating the tangents.
Curve - > SetKeyValue ( OldKeyHandle , NewLocation . Y , false ) ;
2014-03-14 14:13:41 -04:00
2014-08-22 17:36:08 -04:00
// Changing the time of a key returns a new handle, so make sure to update existing references.
FKeyHandle KeyHandle = Curve - > SetKeyTime ( OldKeyHandle , NewLocation . X ) ;
2014-03-14 14:13:41 -04:00
SelectedKeys [ i ] = FSelectedCurveKey ( Curve , KeyHandle ) ;
2014-08-22 17:36:08 -04:00
PreDragKeyLocations . Remove ( OldKeyHandle ) ;
PreDragKeyLocations . Add ( KeyHandle , PreDragLocation ) ;
2014-03-14 14:13:41 -04:00
UniqueCurves . Add ( Curve ) ;
}
// update auto tangents for all curves encountered, once each only
for ( TSet < FRichCurve * > : : TIterator SetIt ( UniqueCurves ) ; SetIt ; + + SetIt )
{
( * SetIt ) - > AutoSetTangents ( ) ;
}
}
2014-04-23 17:30:58 -04:00
TOptional < float > SCurveEditor : : GetKeyValue ( FSelectedCurveKey Key ) const
2014-03-14 14:13:41 -04:00
{
if ( IsValidCurve ( Key . Curve ) )
{
2014-04-23 17:30:58 -04:00
return Key . Curve - > GetKeyValue ( Key . KeyHandle ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 17:30:58 -04:00
return TOptional < float > ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 17:30:58 -04:00
TOptional < float > SCurveEditor : : GetKeyTime ( FSelectedCurveKey Key ) const
2014-03-14 14:13:41 -04:00
{
if ( IsValidCurve ( Key . Curve ) )
{
2014-04-23 17:30:58 -04:00
return Key . Curve - > GetKeyTime ( Key . KeyHandle ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 17:30:58 -04:00
return TOptional < float > ( ) ;
2014-03-14 14:13:41 -04:00
}
void SCurveEditor : : EmptySelection ( )
{
SelectedKeys . Empty ( ) ;
}
void SCurveEditor : : AddToSelection ( FSelectedCurveKey Key )
{
SelectedKeys . AddUnique ( Key ) ;
}
void SCurveEditor : : RemoveFromSelection ( FSelectedCurveKey Key )
{
SelectedKeys . Remove ( Key ) ;
}
bool SCurveEditor : : IsKeySelected ( FSelectedCurveKey Key ) const
{
return SelectedKeys . Contains ( Key ) ;
}
bool SCurveEditor : : AreKeysSelected ( ) const
{
return SelectedKeys . Num ( ) > 0 ;
}
TArray < FRichCurve * > SCurveEditor : : GetCurvesToFit ( ) const
{
TArray < FRichCurve * > FitCurves ;
2014-09-03 11:17:17 -04:00
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
if ( CurveViewModel - > bIsVisible )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
FitCurves . Add ( CurveViewModel - > CurveInfo . CurveToEdit ) ;
2014-03-14 14:13:41 -04:00
}
}
return FitCurves ;
}
2015-06-24 08:02:15 -04:00
void SCurveEditor : : ZoomToFitHorizontal ( )
2014-03-14 14:13:41 -04:00
{
TArray < FRichCurve * > CurvesToFit = GetCurvesToFit ( ) ;
2014-09-03 11:17:17 -04:00
if ( CurveViewModels . Num ( ) > 0 )
2014-03-14 14:13:41 -04:00
{
2014-08-26 10:26:37 -04:00
float InMin = FLT_MAX ;
float InMax = - FLT_MAX ;
2014-03-14 14:13:41 -04:00
int32 TotalKeys = 0 ;
2014-08-26 10:26:37 -04:00
2015-06-24 08:02:15 -04:00
if ( SelectedKeys . Num ( ) )
2014-03-14 14:13:41 -04:00
{
2014-08-26 10:26:37 -04:00
for ( auto SelectedKey : SelectedKeys )
{
TotalKeys + + ;
float KeyTime = SelectedKey . Curve - > GetKeyTime ( SelectedKey . KeyHandle ) ;
InMin = FMath : : Min ( KeyTime , InMin ) ;
InMax = FMath : : Max ( KeyTime , InMax ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-08-26 10:26:37 -04:00
else
{
2015-06-24 08:02:15 -04:00
for ( FRichCurve * Curve : CurvesToFit )
2014-08-26 10:26:37 -04:00
{
float MinTime , MaxTime ;
Curve - > GetTimeRange ( MinTime , MaxTime ) ;
InMin = FMath : : Min ( MinTime , InMin ) ;
InMax = FMath : : Max ( MaxTime , InMax ) ;
TotalKeys + = Curve - > GetNumKeys ( ) ;
}
}
if ( TotalKeys > 0 )
2014-03-14 14:13:41 -04:00
{
// Clamp the minimum size
float Size = InMax - InMin ;
2014-08-26 10:26:37 -04:00
if ( Size < CONST_MinViewRange )
2014-03-14 14:13:41 -04:00
{
InMin - = ( 0.5f * CONST_MinViewRange ) ;
InMax + = ( 0.5f * CONST_MinViewRange ) ;
Size = InMax - InMin ;
}
// add margin
InMin - = CONST_FitMargin * Size ;
InMax + = CONST_FitMargin * Size ;
}
else
{
InMin = - CONST_FitMargin * 2.0f ;
InMax = ( CONST_DefaultZoomRange + CONST_FitMargin ) * 2.0 ;
}
2014-05-05 14:06:27 -04:00
SetInputMinMax ( InMin , InMax ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-14 11:09:42 -04:00
}
FReply SCurveEditor : : ZoomToFitHorizontalClicked ( )
{
2015-06-24 08:02:15 -04:00
ZoomToFitHorizontal ( ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
/** Set Default output values when range is too small **/
void SCurveEditor : : SetDefaultOutput ( const float MinZoomRange )
{
2014-09-22 09:47:37 -04:00
const float NewMinOutput = ( ViewMinOutput . Get ( ) - ( 0.5f * MinZoomRange ) ) ;
const float NewMaxOutput = ( ViewMaxOutput . Get ( ) + ( 0.5f * MinZoomRange ) ) ;
SetOutputMinMax ( NewMinOutput , NewMaxOutput ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-24 08:02:15 -04:00
void SCurveEditor : : ZoomToFitVertical ( )
2014-03-14 14:13:41 -04:00
{
TArray < FRichCurve * > CurvesToFit = GetCurvesToFit ( ) ;
if ( CurvesToFit . Num ( ) > 0 )
{
2014-08-26 10:26:37 -04:00
float InMin = FLT_MAX ;
float InMax = - FLT_MAX ;
2014-03-14 14:13:41 -04:00
int32 TotalKeys = 0 ;
2014-08-26 10:26:37 -04:00
2015-06-24 08:02:15 -04:00
if ( SelectedKeys . Num ( ) ! = 0 )
2014-03-14 14:13:41 -04:00
{
2014-08-26 10:26:37 -04:00
for ( auto SelectedKey : SelectedKeys )
{
TotalKeys + + ;
float KeyValue = SelectedKey . Curve - > GetKeyValue ( SelectedKey . KeyHandle ) ;
InMin = FMath : : Min ( KeyValue , InMin ) ;
InMax = FMath : : Max ( KeyValue , InMax ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-08-26 10:26:37 -04:00
else
{
2015-06-24 08:02:15 -04:00
for ( FRichCurve * Curve : CurvesToFit )
2014-08-26 10:26:37 -04:00
{
float MinVal , MaxVal ;
Curve - > GetValueRange ( MinVal , MaxVal ) ;
InMin = FMath : : Min ( MinVal , InMin ) ;
InMax = FMath : : Max ( MaxVal , InMax ) ;
TotalKeys + = Curve - > GetNumKeys ( ) ;
}
}
2014-03-14 14:13:41 -04:00
const float MinZoomRange = ( TotalKeys > 0 ) ? CONST_MinViewRange : CONST_DefaultZoomRange ;
// Clamp the minimum size
2014-09-22 09:47:37 -04:00
float Size = InMax - InMin ;
2014-03-14 14:13:41 -04:00
if ( Size < MinZoomRange )
{
SetDefaultOutput ( MinZoomRange ) ;
2014-09-22 09:47:37 -04:00
InMin = ViewMinOutput . Get ( ) ;
InMax = ViewMaxOutput . Get ( ) ;
Size = InMax - InMin ;
2014-03-14 14:13:41 -04:00
}
// add margin
2014-09-22 09:47:37 -04:00
const float NewMinOutput = ( InMin - CONST_FitMargin * Size ) ;
const float NewMaxOutput = ( InMax + CONST_FitMargin * Size ) ;
SetOutputMinMax ( NewMinOutput , NewMaxOutput ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-14 11:09:42 -04:00
}
FReply SCurveEditor : : ZoomToFitVerticalClicked ( )
{
2015-06-24 08:02:15 -04:00
ZoomToFitVertical ( ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
2015-06-24 08:02:15 -04:00
void SCurveEditor : : ZoomToFit ( )
2014-08-26 10:26:37 -04:00
{
2015-06-24 08:02:15 -04:00
ZoomToFitHorizontal ( ) ;
ZoomToFitVertical ( ) ;
2014-08-26 10:26:37 -04:00
}
2014-08-22 17:36:08 -04:00
void SCurveEditor : : ToggleSnapping ( )
{
2015-02-16 11:59:08 -05:00
if ( bSnappingEnabled . IsBound ( ) = = false )
{
bSnappingEnabled = ! bSnappingEnabled . Get ( ) ;
}
2014-08-22 17:36:08 -04:00
}
bool SCurveEditor : : IsSnappingEnabled ( )
{
2015-02-16 11:59:08 -05:00
return bSnappingEnabled . Get ( ) ;
2014-08-22 17:36:08 -04:00
}
2015-06-05 20:19:33 -04:00
void SCurveEditor : : CreateContextMenu ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
2014-03-14 14:13:41 -04:00
{
2015-06-05 20:19:33 -04:00
const FVector2D & ScreenPosition = InMouseEvent . GetScreenSpacePosition ( ) ;
2014-04-23 17:30:58 -04:00
const bool CloseAfterSelection = true ;
2014-03-14 14:13:41 -04:00
FMenuBuilder MenuBuilder ( CloseAfterSelection , NULL ) ;
2014-04-23 17:30:58 -04:00
MenuBuilder . BeginSection ( " EditCurveEditorActions " , LOCTEXT ( " Actions " , " Actions " ) ) ;
{
2015-06-18 14:10:19 -04:00
FText MenuItemLabel ;
FText MenuItemToolTip ;
TSharedPtr < TArray < TSharedPtr < FCurveViewModel > > > CurvesToAddKeysTo = MakeShareable ( new TArray < TSharedPtr < FCurveViewModel > > ( ) ) ;
bool bAddKeysInline ;
FText AddKeyToCurveLabelFormat = LOCTEXT ( " AddKeyToCurveLabelFormat " , " Add key to {0} " ) ;
FText AddKeyToCurveToolTipFormat = LOCTEXT ( " AddKeyToCurveToolTipFormat " , " Add a new key at the hovered time to the {0} curve. Keys can also be added with Shift + Click. " ) ;
TSharedPtr < FCurveViewModel > HoveredCurve = HitTestCurves ( InMyGeometry , InMouseEvent ) ;
if ( HoveredCurve . IsValid ( ) )
{
MenuItemLabel = FText : : Format ( AddKeyToCurveLabelFormat , FText : : FromName ( HoveredCurve - > CurveInfo . CurveName ) ) ;
MenuItemToolTip = FText : : Format ( AddKeyToCurveToolTipFormat , FText : : FromName ( HoveredCurve - > CurveInfo . CurveName ) ) ;
CurvesToAddKeysTo - > Add ( HoveredCurve ) ;
bAddKeysInline = false ;
}
else
{
if ( CurveViewModels . Num ( ) = = 1 )
{
MenuItemLabel = FText : : Format ( AddKeyToCurveLabelFormat , FText : : FromName ( CurveViewModels [ 0 ] - > CurveInfo . CurveName ) ) ;
MenuItemToolTip = FText : : Format ( AddKeyToCurveToolTipFormat , FText : : FromName ( CurveViewModels [ 0 ] - > CurveInfo . CurveName ) ) ;
CurvesToAddKeysTo - > Add ( CurveViewModels [ 0 ] ) ;
bAddKeysInline = true ;
}
else
{
MenuItemLabel = LOCTEXT ( " AddKeyToAllCurves " , " Add key to all curves " ) ;
MenuItemToolTip = LOCTEXT ( " AddKeyToAllCurveToolTip " , " Adds a key at the hovered time to all curves. Keys can also be added with Shift + Click. " ) ;
CurvesToAddKeysTo - > Append ( CurveViewModels ) ;
bAddKeysInline = false ;
}
}
FVector2D Position = InMouseEvent . GetScreenSpacePosition ( ) ;
FUIAction Action = FUIAction ( FExecuteAction : : CreateSP ( this , & SCurveEditor : : AddNewKey , InMyGeometry , Position , CurvesToAddKeysTo , bAddKeysInline ) ) ;
MenuBuilder . AddMenuEntry (
MenuItemLabel ,
MenuItemToolTip ,
2014-04-23 17:30:58 -04:00
FSlateIcon ( ) ,
2015-06-18 14:10:19 -04:00
Action ) ;
2014-04-23 17:30:58 -04:00
}
MenuBuilder . EndSection ( ) ;
2014-03-14 14:13:41 -04:00
MenuBuilder . BeginSection ( " CurveEditorActions " , LOCTEXT ( " CurveAction " , " Curve Actions " ) ) ;
{
if ( OnCreateAsset . IsBound ( ) & & IsEditingEnabled ( ) )
{
FUIAction Action = FUIAction ( FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnCreateExternalCurveClicked ) ) ;
MenuBuilder . AddMenuEntry
(
LOCTEXT ( " CreateExternalCurve " , " Create External Curve " ) ,
LOCTEXT ( " CreateExternalCurve_ToolTip " , " Create an external asset using this internal curve " ) ,
FSlateIcon ( ) ,
Action
) ;
}
if ( IsLinearColorCurve ( ) & & ! bAlwaysDisplayColorCurves )
{
FUIAction ShowCurveAction ( FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnShowCurveToggled ) , FCanExecuteAction ( ) , FIsActionChecked : : CreateSP ( this , & SCurveEditor : : AreCurvesVisible ) ) ;
MenuBuilder . AddMenuEntry
(
LOCTEXT ( " ShowCurves " , " Show Curves " ) ,
LOCTEXT ( " ShowCurves_ToolTip " , " Toggles displaying the curves for linear colors " ) ,
FSlateIcon ( ) ,
ShowCurveAction ,
NAME_None ,
EUserInterfaceActionType : : ToggleButton
) ;
}
if ( IsLinearColorCurve ( ) )
{
FUIAction ShowGradientAction ( FExecuteAction : : CreateSP ( this , & SCurveEditor : : OnShowGradientToggled ) , FCanExecuteAction ( ) , FIsActionChecked : : CreateSP ( this , & SCurveEditor : : IsGradientEditorVisible ) ) ;
MenuBuilder . AddMenuEntry
(
LOCTEXT ( " ShowGradient " , " Show Gradient " ) ,
LOCTEXT ( " ShowGradient_ToolTip " , " Toggles displaying the gradient for linear colors " ) ,
FSlateIcon ( ) ,
ShowGradientAction ,
NAME_None ,
EUserInterfaceActionType : : ToggleButton
) ;
}
}
MenuBuilder . EndSection ( ) ;
2015-06-05 20:19:33 -04:00
FWidgetPath WidgetPath = InMouseEvent . GetEventPath ( ) ! = nullptr ? * InMouseEvent . GetEventPath ( ) : FWidgetPath ( ) ;
FSlateApplication : : Get ( ) . PushMenu ( SharedThis ( this ) , WidgetPath , MenuBuilder . MakeWidget ( ) , FSlateApplication : : Get ( ) . GetCursorPos ( ) , FPopupTransitionEffect ( FPopupTransitionEffect : : ContextMenu ) ) ;
2014-03-14 14:13:41 -04:00
}
void SCurveEditor : : OnCreateExternalCurveClicked ( )
{
OnCreateAsset . ExecuteIfBound ( ) ;
}
UObject * SCurveEditor : : CreateCurveObject ( TSubclassOf < UCurveBase > CurveType , UObject * PackagePtr , FName & AssetName )
{
UObject * NewObj = NULL ;
2015-02-03 05:40:57 -05:00
CurveFactory = Cast < UCurveFactory > ( NewObject < UFactory > ( GetTransientPackage ( ) , UCurveFactory : : StaticClass ( ) ) ) ;
2014-03-14 14:13:41 -04:00
if ( CurveFactory )
{
CurveFactory - > CurveClass = CurveType ;
NewObj = CurveFactory - > FactoryCreateNew ( CurveFactory - > GetSupportedClass ( ) , PackagePtr , AssetName , RF_Public | RF_Standalone , NULL , GWarn ) ;
}
CurveFactory = NULL ;
return NewObj ;
}
bool SCurveEditor : : IsEditingEnabled ( ) const
{
return bCanEditTrack ;
}
void SCurveEditor : : AddReferencedObjects ( FReferenceCollector & Collector )
{
Collector . AddReferencedObject ( CurveFactory ) ;
}
2014-08-14 11:09:42 -04:00
TSharedPtr < FUICommandList > SCurveEditor : : GetCommands ( )
{
return Commands ;
}
2014-03-14 14:13:41 -04:00
bool SCurveEditor : : IsValidCurve ( FRichCurve * Curve ) const
{
bool bIsValid = false ;
2015-01-30 17:41:04 -05:00
if ( Curve & & CurveOwner )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2015-01-30 17:41:04 -05:00
if ( CurveViewModel - > CurveInfo . CurveToEdit = = Curve & & CurveOwner - > IsValidCurve ( CurveViewModel - > CurveInfo ) )
2014-03-14 14:13:41 -04:00
{
bIsValid = true ;
break ;
}
}
}
return bIsValid ;
}
2014-05-05 14:06:27 -04:00
void SCurveEditor : : SetInputMinMax ( float NewMin , float NewMax )
{
if ( SetInputViewRangeHandler . IsBound ( ) )
{
SetInputViewRangeHandler . Execute ( NewMin , NewMax ) ;
}
else
{
//if no delegate and view min input isn't using a delegate just set value directly
if ( ViewMinInput . IsBound ( ) = = false )
{
ViewMinInput . Set ( NewMin ) ;
}
if ( ViewMaxInput . IsBound ( ) = = false )
{
ViewMaxInput . Set ( NewMax ) ;
}
}
}
2014-09-22 09:47:37 -04:00
void SCurveEditor : : SetOutputMinMax ( float NewMin , float NewMax )
{
if ( SetOutputViewRangeHandler . IsBound ( ) )
{
SetOutputViewRangeHandler . Execute ( NewMin , NewMax ) ;
}
else
{
//if no delegate and view min output isn't using a delegate just set value directly
if ( ViewMinOutput . IsBound ( ) = = false )
{
ViewMinOutput . Set ( NewMin ) ;
}
if ( ViewMaxOutput . IsBound ( ) = = false )
{
ViewMaxOutput . Set ( NewMax ) ;
}
}
}
2014-09-03 11:17:17 -04:00
TSharedPtr < FCurveViewModel > SCurveEditor : : HitTestCurves ( const FGeometry & InMyGeometry , const FPointerEvent & InMouseEvent )
2014-03-14 14:13:41 -04:00
{
if ( AreCurvesVisible ( ) )
{
2014-09-22 09:47:37 -04:00
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
2014-03-14 14:13:41 -04:00
const FVector2D HitPosition = InMyGeometry . AbsoluteToLocal ( InMouseEvent . GetScreenSpacePosition ( ) ) ;
2014-04-23 17:42:50 -04:00
TArray < FRichCurve * > CurvesHit ;
2014-03-14 14:13:41 -04:00
2014-09-03 11:17:17 -04:00
for ( auto CurveViewModel : CurveViewModels )
2014-03-14 14:13:41 -04:00
{
2014-09-03 11:17:17 -04:00
FRichCurve * Curve = CurveViewModel - > CurveInfo . CurveToEdit ;
2014-03-14 14:13:41 -04:00
if ( Curve ! = NULL )
{
float Time = ScaleInfo . LocalXToInput ( HitPosition . X ) ;
float KeyScreenY = ScaleInfo . OutputToLocalY ( Curve - > Eval ( Time ) ) ;
if ( HitPosition . Y > ( KeyScreenY - ( 0.5f * CONST_CurveSize . Y ) ) & &
HitPosition . Y < ( KeyScreenY + ( 0.5f * CONST_CurveSize . Y ) ) )
{
2014-09-03 11:17:17 -04:00
return CurveViewModel ;
2014-04-23 17:42:50 -04:00
}
}
}
2014-03-14 14:13:41 -04:00
}
2014-09-03 11:17:17 -04:00
return TSharedPtr < FCurveViewModel > ( ) ;
2014-03-14 14:13:41 -04:00
}
SCurveEditor : : FSelectedTangent SCurveEditor : : HitTestCubicTangents ( const FGeometry & InMyGeometry , const FVector2D & HitScreenPosition )
{
FSelectedTangent Tangent ;
if ( AreCurvesVisible ( ) )
{
2014-09-22 09:47:37 -04:00
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
2014-03-14 14:13:41 -04:00
const FVector2D HitPosition = InMyGeometry . AbsoluteToLocal ( HitScreenPosition ) ;
for ( auto It = SelectedKeys . CreateConstIterator ( ) ; It ; + + It )
{
FSelectedCurveKey Key = * It ;
if ( Key . IsValid ( ) )
{
float Time = ScaleInfo . LocalXToInput ( HitPosition . X ) ;
float KeyScreenY = ScaleInfo . OutputToLocalY ( Key . Curve - > Eval ( Time ) ) ;
FVector2D Arrive , Leave ;
GetTangentPoints ( ScaleInfo , Key , Arrive , Leave ) ;
if ( HitPosition . Y > ( Arrive . Y - ( 0.5f * CONST_CurveSize . Y ) ) & &
HitPosition . Y < ( Arrive . Y + ( 0.5f * CONST_CurveSize . Y ) ) & &
2014-08-25 12:21:17 -04:00
HitPosition . X > ( Arrive . X - ( 0.5f * CONST_TangentSize . X ) ) & &
HitPosition . X < ( Arrive . X + ( 0.5f * CONST_TangentSize . X ) ) )
2014-03-14 14:13:41 -04:00
{
Tangent . Key = Key ;
Tangent . bIsArrival = true ;
break ;
}
if ( HitPosition . Y > ( Leave . Y - ( 0.5f * CONST_CurveSize . Y ) ) & &
HitPosition . Y < ( Leave . Y + ( 0.5f * CONST_CurveSize . Y ) ) & &
2014-08-25 12:21:17 -04:00
HitPosition . X > ( Leave . X - ( 0.5f * CONST_TangentSize . X ) ) & &
HitPosition . X < ( Leave . X + ( 0.5f * CONST_TangentSize . X ) ) )
2014-03-14 14:13:41 -04:00
{
Tangent . Key = Key ;
Tangent . bIsArrival = false ;
break ;
}
}
}
}
return Tangent ;
}
void SCurveEditor : : OnSelectInterpolationMode ( ERichCurveInterpMode InterpMode , ERichCurveTangentMode TangentMode )
{
if ( SelectedKeys . Num ( ) > 0 )
{
2014-09-03 11:17:17 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " CurveEditor_SetInterpolationMode " , " Select Interpolation Mode " ) ) ;
CurveOwner - > ModifyOwner ( ) ;
2015-02-16 11:59:08 -05:00
TSet < FRichCurve * > ChangedCurves ;
2014-03-14 14:13:41 -04:00
for ( auto It = SelectedKeys . CreateIterator ( ) ; It ; + + It )
{
FSelectedCurveKey & Key = * It ;
check ( IsValidCurve ( Key . Curve ) ) ;
Key . Curve - > SetKeyInterpMode ( Key . KeyHandle , InterpMode ) ;
Key . Curve - > SetKeyTangentMode ( Key . KeyHandle , TangentMode ) ;
}
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
for ( auto CurveViewModel : CurveViewModels )
{
if ( ChangedCurves . Contains ( CurveViewModel - > CurveInfo . CurveToEdit ) )
{
ChangedCurveEditInfos . Add ( CurveViewModel - > CurveInfo ) ;
}
}
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-08-26 10:26:37 -04:00
bool SCurveEditor : : IsInterpolationModeSelected ( ERichCurveInterpMode InterpMode , ERichCurveTangentMode TangentMode )
{
if ( SelectedKeys . Num ( ) > 0 )
{
for ( auto SelectedKey : SelectedKeys )
{
if ( SelectedKey . Curve - > GetKeyInterpMode ( SelectedKey . KeyHandle ) ! = InterpMode | | SelectedKey . Curve - > GetKeyTangentMode ( SelectedKey . KeyHandle ) ! = TangentMode )
{
return false ;
}
}
2014-09-03 11:17:17 -04:00
return true ;
2014-08-26 10:26:37 -04:00
}
else
{
2014-09-22 09:47:37 -04:00
return false ;
}
}
2014-08-26 10:26:37 -04:00
2014-03-14 14:13:41 -04:00
/* Given a tangent value for a key, calculates the 2D delta vector from that key in curve space */
static inline FVector2D CalcTangentDir ( float Tangent )
{
const float Angle = FMath : : Atan ( Tangent ) ;
return FVector2D ( FMath : : Cos ( Angle ) , - FMath : : Sin ( Angle ) ) ;
}
/*Given a 2d delta vector in curve space, calculates a tangent value */
static inline float CalcTangent ( const FVector2D & HandleDelta )
{
// Ensure X is positive and non-zero.
// Tangent is gradient of handle.
return HandleDelta . Y / FMath : : Max < double > ( HandleDelta . X , KINDA_SMALL_NUMBER ) ;
}
void SCurveEditor : : OnMoveTangent ( FVector2D MouseCurvePosition )
{
auto & RichKey = SelectedTangent . Key . Curve - > GetKey ( SelectedTangent . Key . KeyHandle ) ;
const FSelectedCurveKey & Key = SelectedTangent . Key ;
FVector2D KeyPosition ( Key . Curve - > GetKeyTime ( Key . KeyHandle ) , Key . Curve - > GetKeyValue ( Key . KeyHandle ) ) ;
FVector2D Movement = MouseCurvePosition - KeyPosition ;
if ( SelectedTangent . bIsArrival )
{
Movement * = - 1.0f ;
}
float Tangent = CalcTangent ( Movement ) ;
if ( RichKey . TangentMode ! = RCTM_Break )
{
RichKey . ArriveTangent = Tangent ;
RichKey . LeaveTangent = Tangent ;
RichKey . TangentMode = RCTM_User ;
}
else
{
if ( SelectedTangent . bIsArrival )
{
RichKey . ArriveTangent = Tangent ;
}
else
{
RichKey . LeaveTangent = Tangent ;
}
}
}
void SCurveEditor : : GetTangentPoints ( FTrackScaleInfo & ScaleInfo , const FSelectedCurveKey & Key , FVector2D & Arrive , FVector2D & Leave ) const
{
FVector2D ArriveTangentDir = CalcTangentDir ( Key . Curve - > GetKey ( Key . KeyHandle ) . ArriveTangent ) ;
FVector2D LeaveTangentDir = CalcTangentDir ( Key . Curve - > GetKey ( Key . KeyHandle ) . LeaveTangent ) ;
FVector2D KeyPosition ( Key . Curve - > GetKeyTime ( Key . KeyHandle ) , Key . Curve - > GetKeyValue ( Key . KeyHandle ) ) ;
ArriveTangentDir . Y * = - 1.0f ;
LeaveTangentDir . Y * = - 1.0f ;
FVector2D ArrivePosition = - ArriveTangentDir + KeyPosition ;
FVector2D LeavePosition = LeaveTangentDir + KeyPosition ;
Arrive = FVector2D ( ScaleInfo . InputToLocalX ( ArrivePosition . X ) , ScaleInfo . OutputToLocalY ( ArrivePosition . Y ) ) ;
Leave = FVector2D ( ScaleInfo . InputToLocalX ( LeavePosition . X ) , ScaleInfo . OutputToLocalY ( LeavePosition . Y ) ) ;
FVector2D KeyScreenPosition = FVector2D ( ScaleInfo . InputToLocalX ( KeyPosition . X ) , ScaleInfo . OutputToLocalY ( KeyPosition . Y ) ) ;
FVector2D ToArrive = Arrive - KeyScreenPosition ;
ToArrive . Normalize ( ) ;
Arrive = KeyScreenPosition + ToArrive * CONST_KeyTangentOffset ;
FVector2D ToLeave = Leave - KeyScreenPosition ;
ToLeave . Normalize ( ) ;
Leave = KeyScreenPosition + ToLeave * CONST_KeyTangentOffset ;
}
2014-09-03 11:17:17 -04:00
TArray < SCurveEditor : : FSelectedCurveKey > SCurveEditor : : GetEditableKeysWithinMarquee ( const FGeometry & InMyGeometry , FVector2D MarqueeTopLeft , FVector2D MarqueeBottomRight ) const
2014-08-19 16:22:40 -04:00
{
TArray < FSelectedCurveKey > KeysWithinMarquee ;
if ( AreCurvesVisible ( ) )
{
2014-09-22 09:47:37 -04:00
FTrackScaleInfo ScaleInfo ( ViewMinInput . Get ( ) , ViewMaxInput . Get ( ) , ViewMinOutput . Get ( ) , ViewMaxOutput . Get ( ) , InMyGeometry . Size ) ;
2014-09-03 11:17:17 -04:00
for ( auto CurveViewModel : CurveViewModels )
2014-08-19 16:22:40 -04:00
{
2014-09-03 11:17:17 -04:00
if ( ! CurveViewModel - > bIsLocked & & CurveViewModel - > bIsVisible )
2014-08-19 16:22:40 -04:00
{
2014-09-03 11:17:17 -04:00
FRichCurve * Curve = CurveViewModel - > CurveInfo . CurveToEdit ;
if ( Curve ! = NULL )
2014-08-19 16:22:40 -04:00
{
2014-09-03 11:17:17 -04:00
for ( auto It ( Curve - > GetKeyHandleIterator ( ) ) ; It ; + + It )
2014-08-19 16:22:40 -04:00
{
2014-09-03 11:17:17 -04:00
float KeyScreenX = ScaleInfo . InputToLocalX ( Curve - > GetKeyTime ( It . Key ( ) ) ) ;
float KeyScreenY = ScaleInfo . OutputToLocalY ( Curve - > GetKeyValue ( It . Key ( ) ) ) ;
if ( KeyScreenX > = ( MarqueeTopLeft . X - ( 0.5f * CONST_KeySize . X ) ) & &
KeyScreenX < = ( MarqueeBottomRight . X + ( 0.5f * CONST_KeySize . X ) ) & &
KeyScreenY > = ( MarqueeTopLeft . Y - ( 0.5f * CONST_KeySize . Y ) ) & &
KeyScreenY < = ( MarqueeBottomRight . Y + ( 0.5f * CONST_KeySize . Y ) ) )
{
KeysWithinMarquee . Add ( FSelectedCurveKey ( Curve , It . Key ( ) ) ) ;
}
2014-08-19 16:22:40 -04:00
}
}
}
}
}
return KeysWithinMarquee ;
}
2014-03-14 14:13:41 -04:00
void SCurveEditor : : BeginDragTransaction ( )
{
TransactionIndex = GEditor - > BeginTransaction ( LOCTEXT ( " CurveEditor_Drag " , " Mouse Drag " ) ) ;
CurveOwner - > ModifyOwner ( ) ;
}
void SCurveEditor : : EndDragTransaction ( )
{
if ( TransactionIndex > = 0 )
{
2015-02-16 11:59:08 -05:00
TArray < FRichCurveEditInfo > ChangedCurveEditInfos ;
for ( auto CurveViewModel : CurveViewModels )
{
ChangedCurveEditInfos . Add ( CurveViewModel - > CurveInfo ) ;
}
CurveOwner - > OnCurveChanged ( ChangedCurveEditInfos ) ;
2014-08-19 15:57:46 -04:00
GEditor - > EndTransaction ( ) ;
2014-03-14 14:13:41 -04:00
TransactionIndex = - 1 ;
}
}
bool SCurveEditor : : FSelectedTangent : : IsValid ( ) const
{
return Key . IsValid ( ) ;
}
void SCurveEditor : : UndoAction ( )
{
GEditor - > UndoTransaction ( ) ;
}
void SCurveEditor : : RedoAction ( )
{
GEditor - > RedoTransaction ( ) ;
}
void SCurveEditor : : PostUndo ( bool bSuccess )
{
//remove any invalid keys
for ( int32 i = 0 ; i < SelectedKeys . Num ( ) ; + + i )
{
auto Key = SelectedKeys [ i ] ;
if ( ! IsValidCurve ( Key . Curve ) | | ! Key . IsValid ( ) )
{
SelectedKeys . RemoveAt ( i ) ;
i - - ;
}
}
}
bool SCurveEditor : : IsLinearColorCurve ( ) const
{
2014-10-24 08:09:10 -04:00
return CurveOwner & & CurveOwner - > IsLinearColorCurve ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-08-22 17:36:08 -04:00
FVector2D SCurveEditor : : SnapLocation ( FVector2D InLocation )
{
2015-02-16 11:59:08 -05:00
if ( bSnappingEnabled . Get ( ) )
2014-08-22 17:36:08 -04:00
{
2015-06-30 14:04:31 -04:00
const float InputSnapNow = InputSnap . Get ( ) ;
const float OutputSnapNow = OutputSnap . Get ( ) ;
InLocation . X = InputSnapNow ! = 0 ? FMath : : RoundToInt ( InLocation . X / InputSnapNow ) * InputSnapNow : InLocation . X ;
InLocation . Y = OutputSnapNow ! = 0 ? FMath : : RoundToInt ( InLocation . Y / OutputSnapNow ) * OutputSnapNow : InLocation . Y ;
2014-08-22 17:36:08 -04:00
}
return InLocation ;
}
2015-02-16 11:59:08 -05:00
TSharedPtr < FCurveViewModel > SCurveEditor : : GetViewModelForCurve ( FRichCurve * InCurve )
{
for ( auto CurveViewModel : CurveViewModels )
{
if ( InCurve = = CurveViewModel - > CurveInfo . CurveToEdit )
{
return CurveViewModel ;
}
}
return TSharedPtr < FCurveViewModel > ( ) ;
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE