// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/ArrayView.h" #include "Containers/Map.h" #include "Containers/Set.h" #include "CurveDataAbstraction.h" #include "CurveDrawInfo.h" #include "CurveEditor.h" #include "CurveEditorTypes.h" #include "WidgetFocusUtils.h" #include "Curves/RealCurve.h" #include "Curves/RichCurve.h" #include "Filters/PromotedFilterCommandBinder.h" #include "HAL/Platform.h" #include "Input/Reply.h" #include "Internationalization/Text.h" #include "Layout/Geometry.h" #include "Layout/Visibility.h" #include "Math/Axis.h" #include "Math/Color.h" #include "Misc/Attribute.h" #include "Misc/Optional.h" #include "Templates/SharedPointer.h" #include "Templates/SubclassOf.h" #include "Templates/UniquePtr.h" #include "Textures/SlateIcon.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/SCompoundWidget.h" class FCurveEditor; class FExtender; class FTabManager; class FToolBarBuilder; class FMenuBuilder; class FUICommandList; class IDetailsView; class IGraphEditorView; class ITimeSliderController; class SCurveEditorToolProperties; class SCurveEditorView; class SCurveEditorViewContainer; class SCurveEditorFilterPanel; class SCurveKeyDetailPanel; class SScrollBox; class SWidget; class UCurveEditorFilterBase; struct FCurveEditorDelayedDrag; struct FCurveEditorEditObjectContainer; struct FCurveEditorToolID; struct FKeyEvent; namespace UE::CurveEditor { class FPromotedFilterContainer; } /** * Curve editor widget that reflects the state of an FCurveEditor */ class CURVEEDITOR_API SCurveEditorPanel : public SCompoundWidget { SLATE_BEGIN_ARGS(SCurveEditorPanel) : _GridLineTint(FLinearColor(0.1f, 0.1f, 0.1f, 1.f)) , _MinimumViewPanelHeight(300.0f) {} /** Color to draw grid lines */ SLATE_ATTRIBUTE(FLinearColor, GridLineTint) /** Tab Manager which owns this panel. */ SLATE_ARGUMENT(TSharedPtr, TabManager) /** Optional Time Slider Controller which allows us to synchronize with an externally controlled Time Slider */ SLATE_ARGUMENT(TSharedPtr, ExternalTimeSliderController) /** If specified, causes the time snap adjustment UI controls to be disabled and specifies the tooltip to be used. Can be used to disable time snap controls when externally controlled. */ SLATE_ATTRIBUTE(FText, DisabledTimeSnapTooltip) /** Widget slot for the tree content */ SLATE_NAMED_SLOT(FArguments, TreeContent) /** The minimum height for the panel which contains the curve editor views. */ SLATE_ARGUMENT(float, MinimumViewPanelHeight) SLATE_END_ARGS() SCurveEditorPanel(); ~SCurveEditorPanel(); /** * Construct a new curve editor panel widget */ void Construct(const FArguments& InArgs, TSharedRef InCurveEditor); /** * Access the combined command list for this curve editor and panel widget */ TSharedPtr GetCommands() const { return CommandList; } /** * Access the details view used for editing selected keys */ TSharedPtr GetKeyDetailsView() const { return KeyDetailsView; } /** * Access the filter panel */ TSharedPtr GetFilterPanel() const { return FilterPanel; } /** * Access the tool properties panel */ TSharedPtr GetToolPropertiesPanel() const { return ToolPropertiesPanel; } void AddView(TSharedRef ViewToAdd); void RemoveView(TSharedRef ViewToRemove); /** This returns an extender which is pre-configured with the standard set of Toolbar Icons. Implementers of SCurveEditorPanel should use this * to generate the icons and then add any additional context-specific icons (such as save buttons in the Asset Editor) to ensure that the Curve * Editor has a consistent set (and order) of icons across all usages. */ TSharedPtr GetToolbarExtender(); /** Access the cached geometry of the outer scroll panel that contains this panel's views */ const FGeometry& GetScrollPanelGeometry() const; /** Access the cached geometry of container housing all this panel's views */ const FGeometry& GetViewContainerGeometry() const; /** Get all the views stored in this panel. */ TArrayView> GetViews() const; /** Get the grid line tint to be used for views on panel */ FLinearColor GetGridLineTint() const { return GridLineTintAttribute.Get(); } /** Scroll this panel's view scroll box vertically by the specified amount */ void ScrollBy(float Amount); /** * Find all the views that the specified curve is being displayed on * @note: Returns an in-place iterator to this curve's view mapping. Adding or removing curves from views *will* invalidate this iterator. * * @param InCurveID The identifier of the curve to find views for * @return An iterator to all the views that this cuvrve is displayed within. */ TMultiMap>::TConstKeyIterator FindViews(TRetainedRef InCurveID) { return CurveViews.CreateConstKeyIterator(InCurveID.Get()); } /** * Remove the specified curve from all views it is currently displayed on. */ void RemoveCurveFromViews(FCurveModelID InCurveID); /** Get the last set View Mode for this UI. Utility function for the UI. */ ECurveEditorViewID GetViewMode() const { return DefaultViewID; } /** Undo occurred, invalidate or update internal structures */ void PostUndo(); /** Reset Stored Min/Max's*/ void ResetMinMaxes(); /** Update the axis snapping based on the settings. */ void UpdateAxisSnapping(); /** Delegate for when the chosen filter class has changed */ FSimpleDelegate OnFilterClassChanged; void FilterClassChanged(); /** Enable/disable pending focus */ void EnablePendingFocusOnHovering(const bool InEnabled); /** Broadcasts after the curve views have been rebuilt (by RebuildCurveViews). */ FSimpleMulticastDelegate& OnPostRebuildCurveViews() { return OnPostRebuildCurveViewsDelegate; } private: // SWidget Interface virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; // ~SWidget Interface /*~ Keyboard interaction */ virtual bool SupportsKeyboardFocus() const override { return true; } virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override; virtual void OnMouseEnter(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; virtual void OnMouseLeave(const FPointerEvent& MouseEvent) override; /** @return Extender combining all ICurveEditorModule::GetAllToolBarMenuExtenders and the owning FCurveEditor's ICurveEditorExtensions. */ TSharedPtr CombineEditorExtensions() const; /** Adds all base curve editor UI elements to ToolbarBuilder. */ void BuildToolbar(FToolBarBuilder& InToolBarBuilder, TSharedPtr InBaseExtender); TSharedRef MakeTimeSnapMenu(); FText GetTimeSnapMenuTooltip() const; TSharedRef MakeGridSpacingMenu(); TSharedRef MakeAxisSnapMenu(); /* Curve Flip make menu function and settings */ TSharedRef MakeFlipCurveMenu(FCurveEditor::ECurveFlipDirection Direction); bool IsInlineEditPanelEditable() const; EVisibility ShouldInstructionOverlayBeVisible() const; private: TSharedRef MakeToolsComboMenu(TSharedPtr InExtender); FText GetCurrentToolLabel() const; FText GetCurrentToolDescription() const; FSlateIcon GetCurrentToolIcon() const; private: // Tangent mode toolbar combo button TSharedRef MakeTangentModeMenu(); FText GetTangentModeLabel() const; FText GetTangentModeTooltip() const; FSlateIcon GetTangentModeIcon() const; bool IsTangentModeComboEnabled() const; enum class ETangentModeComboState : uint8 { NoSelection, // All keys in selection share the following mode: Constant, Linear, CubicAuto, CubicSmartAuto, CubicUser, CubicBreak, // The keys are mixed Mixed }; ETangentModeComboState DetermineTangentMode() const; private: /** * Get the visibility for the value splitter control */ EVisibility GetSplitterVisibility() const; /*~ Event bindings */ void UpdateTime(); void UpdateEditBox(); void UpdateCommonCurveInfo(); /** Creates the drop-down list you see when changing Curve View options. */ TSharedRef MakeCurveEditorCurveViewOptionsMenu(TSharedPtr InExtender); /** Creates the drop-down for changing curves on a whole. */ TSharedRef MakeCurvesMenu(TSharedPtr InExtender); void AddPreInfinityToMenu(FMenuBuilder& InMenuBuilder); void AddPostInfinityToMenu(FMenuBuilder& InMenuBuilder); FSlateIcon GetCurveExtrapolationPreIcon() const; FSlateIcon GetCurveExtrapolationPostIcon() const; /** Creates the Curve Editor Filter UI and pre-populates it with the specified class. */ void ShowCurveFilterUI(TSubclassOf FilterClass); private: /** * Bind command mappings for this widget */ void BindCommands(); /** * Assign new attributes to the currently selected keys */ void SetKeyAttributes(FKeyAttributes KeyAttributes, FText Description); /** * Assign new curve attributes to all visible curves */ void SetCurveAttributes(FCurveAttributes CurveAttributes, FText Description); /** Compare all the currently selected keys' interp modes against the specified interp mode */ bool CompareCommonInterpolationMode(ERichCurveInterpMode InterpMode) const { return CachedCommonKeyAttributes.HasInterpMode() && CachedCommonKeyAttributes.GetInterpMode() == InterpMode; } /** Compare all the currently selected keys' tangent modes against the specified tangent mode */ bool CompareCommonTangentMode(ERichCurveInterpMode InterpMode, ERichCurveTangentMode TangentMode) const { return CompareCommonInterpolationMode(InterpMode) && CachedCommonKeyAttributes.HasTangentMode() && CachedCommonKeyAttributes.GetTangentMode() == TangentMode; } /** Compare all the currently selected keys' tangent modes against the specified tangent mode */ bool CompareCommonTangentWeightMode(ERichCurveInterpMode InterpMode, ERichCurveTangentWeightMode TangentWeightMode) const { return CompareCommonInterpolationMode(InterpMode) && CachedCommonKeyAttributes.HasTangentWeightMode() && CachedCommonKeyAttributes.GetTangentWeightMode() == TangentWeightMode; } /** Compare all the visible curves' pre-extrapolation modes against the specified extrapolation mode */ bool CompareCommonPreExtrapolationMode(ERichCurveExtrapolation PreExtrapolationMode) const { return CachedCommonCurveAttributes.HasPreExtrapolation() && CachedCommonCurveAttributes.GetPreExtrapolation() == PreExtrapolationMode; } /** Compare all the visible curves' post-extrapolation modes against the specified extrapolation mode */ bool CompareCommonPostExtrapolationMode(ERichCurveExtrapolation PostExtrapolationMode) const { return CachedCommonCurveAttributes.HasPostExtrapolation() && CachedCommonCurveAttributes.GetPostExtrapolation() == PostExtrapolationMode; } /** * Toggle weighted tangents on the current selection */ void ToggleWeightedTangents(); /** * Check whether we can toggle weighted tangents on the current selection */ bool CanToggleWeightedTangents() const; /** * Check whether or not we can set a key interpolation on the current selection. If no keys are selected, you can't set an interpolation! */ bool CanSetKeyInterpolation() const; /** Sets the axis snapping to the specified value. Only supports X, Y and None. */ void SetAxisSnapping(ECurveEditorSnapAxis); /** Get a reference to the curve editor this panel represents. */ TSharedPtr GetCurveEditor() const { return CurveEditor; } float GetColumnFillCoefficient(int32 ColumnIndex) const { ensure(ColumnIndex == 0 || ColumnIndex == 1); return ColumnFillCoefficients[ColumnIndex]; } /** Called when a column fill percentage is changed by a splitter slot. */ void OnColumnFillCoefficientChanged(float FillCoefficient, int32 ColumnIndex); void OnSplitterFinishedResizing(); private: /** * Create a new view for a model of the specified type, and add the curve to the view * * @param CurveModelID The ID of the curve we're creating a view for * @param ViewTypeID The ID of the view we'd like to create * @param bPinned Whether the view should be pinned or not * @return A new view or nullptr if one could not be created */ TSharedPtr CreateViewOfType(FCurveModelID CurveModelID, ECurveEditorViewID ViewTypeID, bool bPinned); private: /** The curve editor pointer */ TSharedPtr CurveEditor; /** Map from curve model ID to the views that it is on */ TMultiMap> CurveViews; /** Set of externally added views */ TSet> ExternalViews; /** (Optional) the current drag operation */ TOptional DragOperation; /** Cached curve attributes that are common to all visible curves */ FCurveAttributes CachedCommonCurveAttributes; /** Cached key attributes that are common to all selected keys */ FKeyAttributes CachedCommonKeyAttributes; /** True if the current selection supports weighted tangents, false otherwise */ bool bSelectionSupportsWeightedTangents; /** Attribute used for retrieving the desired grid line color */ TAttribute GridLineTintAttribute; /** Attribute used for retrieving the tooltip for when the Time Snap control is disabled. Specifying this causes the Time Snap Adjustment to be disabled. */ TAttribute DisabledTimeSnapTooltipAttribute; /** Edit panel */ TSharedPtr KeyDetailsView; /* Filter panel */ TSharedPtr FilterPanel; /** Tool options panel */ TSharedPtr ToolPropertiesPanel; /** Map of edit UI widgets for each curve in the current selection set */ TMap> CurveToEditUI; /** Command list for widget specific command bindings */ TSharedPtr CommandList; /** Binds commands from FPromotedFilterContainer so the filters surfaced from SCurveEditorFilterPanel show up in the toolbar. */ TUniquePtr ToolbarPromotedFilterBinder; /** Cached serial number from the curve editor selection. Used to update edit UIs when the selection changes. */ uint32 CachedSelectionSerialNumber; private: /** Sets the View Mode for the UI to the specified mode. This will destroy and re-create all views, but leave additional pinned views unmodified. */ void SetViewMode(const ECurveEditorViewID NewViewMode); /** Compare if our current view mode matches the specified one. Utility function for the UI. */ bool CompareViewMode(const ECurveEditorViewID InViewMode) const; /** Rebuild the Curve Views layout to match the currently specified View Mode. */ void RebuildCurveViews(); /** Reconstructs the properties widget on tool switch */ void OnCurveEditorToolChanged(FCurveEditorToolID InToolId); /** Last Output Min and Max values for the views*/ double LastOutputMin = DBL_MAX; double LastOutputMax = DBL_MIN; /** The last set View Mode for this UI. */ ECurveEditorViewID DefaultViewID; /** Broadcasts after the curve views have been rebuilt (by RebuildCurveViews). */ FSimpleMulticastDelegate OnPostRebuildCurveViewsDelegate; TMultiMap> FreeViewsByType; /** The scrool box that all curve views live inside */ TSharedPtr ScrollBox; /** The container for all our vertically laid out curve views. */ TSharedPtr CurveViewsContainer; private: /** Pending focus handler */ FPendingWidgetFocus PendingFocus; /** Whether to explicitly refresh the views for this panel */ bool bNeedsRefresh; /** Serial number cached from FCurveEditor::GetActiveCurvesSerialNumber() on tick */ uint32 CachedActiveCurvesSerialNumber; /** A copy of the View Geometry used to represent the View portion of the Curve Editor. */ FGeometry CachedViewGeometry; /** The fill coefficients of each column in the grid. */ float ColumnFillCoefficients[2]; TSharedPtr TreeViewSplitter; /** Container of objects that are being used to edit keys on the curve editor */ TUniquePtr EditObjects; TWeakPtr WeakTabManager; };