Files
UnrealEngine/Engine/Source/Editor/Persona/Private/AnimTimeline/AnimTimeSliderController.h
2025-05-18 13:04:45 +08:00

242 lines
9.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Input/CursorReply.h"
#include "Input/Reply.h"
#include "Widgets/SWidget.h"
#include "TimeSliderArgs.h"
#include "AnimTimeline/SAnimTimeline.h"
class FSlateWindowElementList;
struct FContextMenuSuppressor;
struct FScrubRangeToScreen;
struct FSlateBrush;
class FAnimModel;
struct FPaintSectionAreaViewArgs
{
FPaintSectionAreaViewArgs()
: bDisplayTickLines(false), bDisplayScrubPosition(false)
{}
/** Whether to display tick lines */
bool bDisplayTickLines;
/** Whether to display the scrub position */
bool bDisplayScrubPosition;
/** Optional Paint args for the playback range*/
TOptional<FPaintPlaybackRangeArgs> PlaybackRangeArgs;
};
/**
* A time slider controller for the anim timeline
*/
class FAnimTimeSliderController : public ITimeSliderController
{
public:
FAnimTimeSliderController( const FTimeSliderArgs& InArgs, TWeakPtr<FAnimModel> InWeakModel, TWeakPtr<SAnimTimeline> InWeakTimeline, TSharedPtr<INumericTypeInterface<double>> InSecondaryNumericTypeInterface );
/**
* Determines the optimal spacing between tick marks in the slider for a given pixel density
* Increments until a minimum amount of slate units specified by MinTick is reached
*
* @param InPixelsPerInput The density of pixels between each input
* @param MinTick The minimum slate units per tick allowed
* @param MinTickSpacing The minimum tick spacing in time units allowed
* @return the optimal spacing in time units
*/
float DetermineOptimalSpacing(float InPixelsPerInput, uint32 MinTick, float MinTickSpacing) const;
/** ITimeSliderController Interface */
virtual int32 OnPaintTimeSlider( bool bMirrorLabels, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled ) const override;
virtual int32 OnPaintViewArea( const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, bool bEnabled, const FPaintViewAreaArgs& Args ) const override;
virtual FReply OnMouseButtonDown( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseButtonUp( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseButtonDoubleClick(SWidget& OwnerWidget, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
virtual FReply OnMouseMove( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FReply OnMouseWheel( SWidget& WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& MouseEvent ) override;
virtual FCursorReply OnCursorQuery( TSharedRef<const SWidget> WidgetOwner, const FGeometry& MyGeometry, const FPointerEvent& CursorEvent ) const override;
virtual void SetViewRange( double NewRangeMin, double NewRangeMax, EViewRangeInterpolation Interpolation ) override;
virtual void SetClampRange( double NewRangeMin, double NewRangeMax ) override;
virtual void SetPlayRange( FFrameNumber RangeStart, int32 RangeDuration ) override;
virtual FFrameRate GetDisplayRate() const override { return TimeSliderArgs.DisplayRate.Get(); }
virtual FFrameRate GetTickResolution() const override { return TimeSliderArgs.TickResolution.Get(); }
virtual FAnimatedRange GetViewRange() const override { return TimeSliderArgs.ViewRange.Get(); }
virtual FAnimatedRange GetClampRange() const override { return TimeSliderArgs.ClampRange.Get(); }
virtual TRange<FFrameNumber> GetPlayRange() const override { return TimeSliderArgs.PlaybackRange.Get(TRange<FFrameNumber>()); }
virtual FFrameTime GetScrubPosition() const { return TimeSliderArgs.ScrubPosition.Get(); }
virtual void SetScrubPosition(FFrameTime InTime, bool bEvaluate) { TimeSliderArgs.OnScrubPositionChanged.ExecuteIfBound(InTime, false, bEvaluate); }
/** End ITimeSliderController Interface */
/**
* Clamp the given range to the clamp range
*
* @param NewRangeMin The new lower bound of the range
* @param NewRangeMax The new upper bound of the range
*/
void ClampViewRange(double& NewRangeMin, double& NewRangeMax);
/**
* Zoom the range by a given delta.
*
* @param InDelta The total amount to zoom by (+ve = zoom out, -ve = zoom in)
* @param ZoomBias Bias to apply to lower/upper extents of the range. (0 = lower, 0.5 = equal, 1 = upper)
*/
bool ZoomByDelta( float InDelta, float ZoomBias = 0.5f );
/**
* Pan the range by a given delta
*
* @param InDelta The total amount to pan by (+ve = pan forwards in time, -ve = pan backwards in time)
*/
void PanByDelta( float InDelta );
/** Determine frame time from a mouse position */
FFrameTime GetFrameTimeFromMouse(const FGeometry& Geometry, FVector2D ScreenSpacePosition) const;
private:
// forward declared as class members to prevent name collision with similar types defined in other units
struct FDrawTickArgs;
struct FScrubRangeToScreen;
/**
* Call this method when the user's interaction has changed the scrub position
*
* @param NewValue Value resulting from the user's interaction
* @param bIsScrubbing True if done via scrubbing, false if just releasing scrubbing
*/
void CommitScrubPosition( FFrameTime NewValue, bool bIsScrubbing );
/**
* Draw time tick marks
*
* @param OutDrawElements List to add draw elements to
* @param ViewRange The currently visible time range in seconds
* @param RangeToScreen Time range to screen space converter
* @param InArgs Parameters for drawing the tick lines
*/
void DrawTicks( FSlateWindowElementList& OutDrawElements, const TRange<double>& ViewRange, const FScrubRangeToScreen& RangeToScreen, FDrawTickArgs& InArgs ) const;
/**
* Draw the selection range.
*
* @return The new layer ID.
*/
int32 DrawSelectionRange(const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FScrubRangeToScreen& RangeToScreen, const FPaintPlaybackRangeArgs& Args) const;
/**
* Draw the playback range.
*
* @return the new layer ID
*/
int32 DrawPlaybackRange(const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FScrubRangeToScreen& RangeToScreen, const FPaintPlaybackRangeArgs& Args) const;
private:
/**
* Hit test the lower bound of a range
*/
bool HitTestRangeStart(const FScrubRangeToScreen& RangeToScreen, const TRange<double>& Range, float HitPixel) const;
/**
* Hit test the upper bound of a range
*/
bool HitTestRangeEnd(const FScrubRangeToScreen& RangeToScreen, const TRange<double>& Range, float HitPixel) const;
/**
* Hit test a time
*/
bool HitTestTime(const FScrubRangeToScreen& RangeToScreen, double Time, float HitPixel) const;
/**
* Hit test draggable times
* @return the index of the hit time, or INDEX_NONE if not hit
*/
int32 HitTestTimes(const FScrubRangeToScreen& RangeToScreen, float HitPixel) const;
void SetPlaybackRangeStart(FFrameNumber NewStart);
void SetPlaybackRangeEnd(FFrameNumber NewEnd);
void SetSelectionRangeStart(FFrameNumber NewStart);
void SetSelectionRangeEnd(FFrameNumber NewEnd);
TSharedRef<SWidget> OpenSetPlaybackRangeMenu(FFrameNumber FrameNumber);
FFrameTime ComputeFrameTimeFromMouse(const FGeometry& Geometry, FVector2D ScreenSpacePosition, FScrubRangeToScreen RangeToScreen, bool CheckSnapping = true) const;
private:
struct FScrubPixelRange
{
TRange<float> Range;
TRange<float> HandleRange;
bool bClamped;
};
FScrubPixelRange GetHitTestScrubberPixelRange(FFrameTime ScrubTime, const FScrubRangeToScreen& RangeToScreen) const;
FScrubPixelRange GetScrubberPixelRange(FFrameTime ScrubTime, const FScrubRangeToScreen& RangeToScreen) const;
FScrubPixelRange GetScrubberPixelRange(FFrameTime ScrubTime, FFrameRate Resolution, FFrameRate PlayRate, const FScrubRangeToScreen& RangeToScreen, float DilationPixels = 0.f) const;
void SetEditableTime(int32 TimeIndex, float Time, bool bIsDragging);
int32 DrawEditableTimes(const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FScrubRangeToScreen& RangeToScreen) const;
private:
/** Pointer back to the model object */
TWeakPtr<FAnimModel> WeakModel;
/** Pointer back to the timeline */
TWeakPtr<SAnimTimeline> WeakTimeline;
FTimeSliderArgs TimeSliderArgs;
/** Brush for drawing the fill area on the scrubber */
const FSlateBrush* ScrubFillBrush;
/** Brush for drawing an upwards facing scrub handles */
const FSlateBrush* ScrubHandleUpBrush;
/** Brush for drawing a downwards facing scrub handle */
const FSlateBrush* ScrubHandleDownBrush;
/** Brush for drawing an editable time */
const FSlateBrush* EditableTimeBrush;
/** Total mouse delta during dragging **/
float DistanceDragged;
/** If we are dragging a scrubber or dragging to set the time range */
enum DragType
{
DRAG_SCRUBBING_TIME,
DRAG_SETTING_RANGE,
DRAG_PLAYBACK_START,
DRAG_PLAYBACK_END,
DRAG_SELECTION_START,
DRAG_SELECTION_END,
DRAG_TIME,
DRAG_NONE
};
DragType MouseDragType;
/** If we are currently panning the panel */
bool bPanning;
/** Index of the current dragged time */
int32 DraggedTimeIndex;
/** Mouse down position range */
FVector2D MouseDownPosition[2];
/** Geometry on mouse down */
FGeometry MouseDownGeometry;
/** Range stack */
TArray<TRange<double>> ViewRangeStack;
/** Secondary numeric type interface for displaying 'other' numeric types */
TSharedPtr<INumericTypeInterface<double>> SecondaryNumericTypeInterface;
};