diff --git a/Source/Editor/GUI/CurveEditor.Contents.cs b/Source/Editor/GUI/CurveEditor.Contents.cs index c2831046b..75f37d457 100644 --- a/Source/Editor/GUI/CurveEditor.Contents.cs +++ b/Source/Editor/GUI/CurveEditor.Contents.cs @@ -522,6 +522,16 @@ namespace FlaxEditor.GUI cm.AddButton("Show whole curve", _editor.ShowWholeCurve); cm.AddButton("Reset view", _editor.ResetView); } + cm.AddSeparator(); + var presetCm = cm.AddChildMenu("Apply preset"); + foreach (var value in Enum.GetValues(typeof(CurvePreset))) + { + CurvePreset preset = (CurvePreset)value; + string name = Utilities.Utils.GetPropertyNameUI(preset.ToString()); + var b = presetCm.ContextMenu.AddButton(name, () => _editor.ApplyPreset(preset)); + b.Enabled = !(_editor is LinearCurveEditor && (preset != CurvePreset.Constant && preset != CurvePreset.Linear)); + } + _editor.OnShowContextMenu(cm, selectionCount); cm.Show(this, location); } @@ -619,6 +629,33 @@ namespace FlaxEditor.GUI } } + /// + /// A list of avaliable curve presets for the . + /// + public enum CurvePreset + { + /// + /// A curve where every point has the same value. + /// + Constant, + /// + /// A curve linear curve. + /// + Linear, + /// + /// A curve that starts a slowly and then accelerates until the end. + /// + EaseIn, + /// + /// A curve that starts a steep and then flattens until the end. + /// + EaseOut, + /// + /// A combination of the and preset. + /// + Smoothstep + } + /// public override void OnKeyframesDeselect(IKeyframesEditor editor) { diff --git a/Source/Editor/GUI/CurveEditor.cs b/Source/Editor/GUI/CurveEditor.cs index 706d07b32..4fb727ea1 100644 --- a/Source/Editor/GUI/CurveEditor.cs +++ b/Source/Editor/GUI/CurveEditor.cs @@ -19,6 +19,48 @@ namespace FlaxEditor.GUI /// public abstract partial class CurveEditor : CurveEditorBase where T : new() { + /// + /// Represents a single point in a . + /// + protected struct CurvePresetPoint + { + /// + /// The time. + /// + public float Time; + + /// + /// The value. + /// + public float Value; + + /// + /// The in tangent. Will be ignored in + /// + public float TangentIn; + + /// + /// The out tangent. Will be ignored in + /// + public float TangentOut; + } + + /// + /// A curve preset. + /// + protected struct CurveEditorPreset() + { + /// + /// If the tangents will be linear or smooth. + /// + public bool LinearTangents; + + /// + /// The points of the preset. + /// + public List Points; + } + private class Popup : ContextMenuBase { private CustomEditorPresenter _presenter; @@ -26,11 +68,12 @@ namespace FlaxEditor.GUI private List _keyframeIndices; private bool _isDirty; - public Popup(CurveEditor editor, object[] selection, List keyframeIndices = null, float height = 140.0f) - : this(editor, height) + public Popup(CurveEditor editor, object[] selection, List keyframeIndices = null, float maxHeight = 140.0f) + : this(editor, maxHeight) { _presenter.Select(selection); _presenter.OpenAllGroups(); + Size = new Float2(Size.X, Mathf.Min(_presenter.ContainerControl.Size.Y, maxHeight)); _keyframeIndices = keyframeIndices; if (keyframeIndices != null && selection.Length != keyframeIndices.Count) throw new Exception(); @@ -169,7 +212,7 @@ namespace FlaxEditor.GUI if (IsSelected) color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f); if (IsMouseOver) - color *= 1.1f; + color *= 1.5f; Render2D.FillRectangle(rect, color); } @@ -285,7 +328,7 @@ namespace FlaxEditor.GUI /// /// The keyframes size. /// - protected static readonly Float2 KeyframesSize = new Float2(7.0f); + protected static readonly Float2 KeyframesSize = new Float2(8.0f); /// /// The colors for the keyframe points. @@ -326,6 +369,63 @@ namespace FlaxEditor.GUI private Color _labelsColor; private Font _labelsFont; + /// + /// Preset values for to be applied to a . + /// + protected Dictionary Presets = new Dictionary + { + { CurvePreset.Constant, new CurveEditorPreset + { + LinearTangents = true, + Points = new List + { + new CurvePresetPoint { Time = 0f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f }, + new CurvePresetPoint { Time = 1f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f }, + } + } + }, + { CurvePreset.EaseIn, new CurveEditorPreset + { + LinearTangents = false, + Points = new List + { + new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f }, + new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = -1.4f, TangentOut = 0f }, + } + } + }, + { CurvePreset.EaseOut, new CurveEditorPreset + { + LinearTangents = false, + Points = new List + { + new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f }, + new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 1.4f }, + } + } + }, + { CurvePreset.Linear, new CurveEditorPreset + { + LinearTangents = true, + Points = new List + { + new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f }, + new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f }, + } + } + }, + { CurvePreset.Smoothstep, new CurveEditorPreset + { + LinearTangents = false, + Points = new List + { + new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f }, + new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f }, + } + } + }, + }; + /// /// The keyframe UI points. /// @@ -568,6 +668,28 @@ namespace FlaxEditor.GUI /// The list of indices of the keyframes to remove. protected abstract void RemoveKeyframesInternal(HashSet indicesToRemove); + /// + /// Tries to convert a float to the type of the type wildcard of the curve editor. + /// + /// The float. + /// The converted value. + public static object ConvertCurvePresetValueToCurveEditorType(float value) + { + if (typeof(T) == typeof(Float2)) + return new Float2(value); + if (typeof(T) == typeof(Float3)) + return new Float3(value); + if (typeof(T) == typeof(Float4)) + return new Float4(value); + if (typeof(T) == typeof(Vector2)) + return new Vector2(value); + if (typeof(T) == typeof(Vector3)) + return new Vector3(value); + if (typeof(T) == typeof(Vector4)) + return new Vector4(value); + return value; + } + /// /// Called when showing a context menu. Can be used to add custom buttons with actions. /// @@ -752,6 +874,17 @@ namespace FlaxEditor.GUI ShowCurve(false); } + /// + /// Applies a to the curve editor. + /// + /// The preset. + public virtual void ApplyPreset(CurvePreset preset) + { + // Remove existing keyframes + SelectAll(); + RemoveKeyframes(); + } + /// public override void Evaluate(out object result, float time, bool loop = false) { @@ -1028,6 +1161,31 @@ namespace FlaxEditor.GUI return true; } + bool left = key == KeyboardKeys.ArrowLeft; + bool right = key == KeyboardKeys.ArrowRight; + bool up = key == KeyboardKeys.ArrowUp; + bool down = key == KeyboardKeys.ArrowDown; + + if (left || right || up || down) + { + bool shift = Root.GetKey(KeyboardKeys.Shift); + bool alt = Root.GetKey(KeyboardKeys.Alt); + float deltaValue = 10f; + if (shift || alt) + deltaValue = shift ? 2.5f : 5f; + + Float2 moveDelta = Float2.Zero; + if (left || right) + moveDelta.X = left ? -deltaValue : deltaValue; + if (up || down) + moveDelta.Y = up ? -deltaValue : deltaValue; + + _contents.OnMoveStart(Float2.Zero); + _contents.OnMove(moveDelta); + _contents.OnMoveEnd(Float2.Zero); + return true; + } + return false; } @@ -1526,6 +1684,22 @@ namespace FlaxEditor.GUI _tangents[i].Visible = false; } + /// + public override void ApplyPreset(CurvePreset preset) + { + base.ApplyPreset(preset); + + CurveEditorPreset data = Presets[preset]; + foreach (var point in data.Points) + { + float time = point.Time; + object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value); + AddKeyframe(time, value); + } + + ShowWholeCurve(); + } + /// protected override void DrawCurve(ref Rectangle viewRect) { @@ -2312,6 +2486,30 @@ namespace FlaxEditor.GUI } } + /// + public override void ApplyPreset(CurvePreset preset) + { + base.ApplyPreset(preset); + + CurveEditorPreset data = Presets[preset]; + + foreach (var point in data.Points) + { + float time = point.Time; + object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value); + object tangentIn = ConvertCurvePresetValueToCurveEditorType((float)point.TangentIn); + object tangentOut = ConvertCurvePresetValueToCurveEditorType((float)point.TangentOut); + + AddKeyframe(time, value, tangentIn, tangentOut); + } + + SelectAll(); + if (data.LinearTangents) + SetTangentsLinear(); + + ShowWholeCurve(); + } + /// protected override void SetScaleInternal(ref Float2 scale) {