Tweaks and improvements for curves editing

#519
This commit is contained in:
Wojtek Figat
2021-08-04 16:35:19 +02:00
parent 41b7897857
commit fc8c8b5c25
7 changed files with 98 additions and 72 deletions

View File

@@ -153,6 +153,21 @@ namespace FlaxEditor.GUI
/// </summary> /// </summary>
public abstract void UpdateTangents(); public abstract void UpdateTangents();
/// <summary>
/// Shows the whole curve.
/// </summary>
public abstract void ShowWholeCurve();
/// <summary>
/// Resets the view.
/// </summary>
public void ResetView()
{
ViewScale = ApplyUseModeMask(EnableZoom, Vector2.One, ViewScale);
ViewOffset = ApplyUseModeMask(EnablePanning, Vector2.Zero, ViewOffset);
UpdateKeyframes();
}
/// <summary> /// <summary>
/// Evaluates the animation curve value at the specified time. /// Evaluates the animation curve value at the specified time.
/// </summary> /// </summary>
@@ -204,6 +219,14 @@ namespace FlaxEditor.GUI
/// <param name="value">The keyframe value.</param> /// <param name="value">The keyframe value.</param>
public abstract void SetKeyframeValue(int index, object value); public abstract void SetKeyframeValue(int index, object value);
/// <summary>
/// Gets the keyframe point (in keyframes space).
/// </summary>
/// <param name="index">The keyframe index.</param>
/// <param name="component">The keyframe value component index.</param>
/// <returns>The point in time/value space.</returns>
public abstract Vector2 GetKeyframePoint(int index, int component);
/// <summary> /// <summary>
/// Converts the <see cref="UseMode"/> into the <see cref="Vector2"/> mask. /// Converts the <see cref="UseMode"/> into the <see cref="Vector2"/> mask.
/// </summary> /// </summary>

View File

@@ -77,13 +77,11 @@ namespace FlaxEditor.GUI
// Moving view // Moving view
if (_rightMouseDown) if (_rightMouseDown)
{ {
// Calculate delta
Vector2 delta = location - _movingViewLastPos; Vector2 delta = location - _movingViewLastPos;
delta *= GetUseModeMask(_editor.EnablePanning); delta *= GetUseModeMask(_editor.EnablePanning) * _editor.ViewScale;
if (delta.LengthSquared > 0.01f) if (delta.LengthSquared > 0.01f)
{ {
// Move view _editor._mainPanel.ViewOffset += delta;
_editor.ViewOffset += delta * _editor.ViewScale;
_movingViewLastPos = location; _movingViewLastPos = location;
Cursor = CursorType.SizeAll; Cursor = CursorType.SizeAll;
} }
@@ -239,7 +237,7 @@ namespace FlaxEditor.GUI
if (Root.GetKey(KeyboardKeys.Control)) if (Root.GetKey(KeyboardKeys.Control))
{ {
// Add to selection // Add to selection
keyframe.Select(); keyframe.IsSelected = true;
_editor.UpdateTangents(); _editor.UpdateTangents();
} }
// Check if node isn't selected // Check if node isn't selected
@@ -247,7 +245,7 @@ namespace FlaxEditor.GUI
{ {
// Select node // Select node
_editor.ClearSelection(); _editor.ClearSelection();
keyframe.Select(); keyframe.IsSelected = true;
_editor.UpdateTangents(); _editor.UpdateTangents();
} }
@@ -260,7 +258,7 @@ namespace FlaxEditor.GUI
if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count) if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count)
_movingSelectionOffsets = new Vector2[_editor._points.Count]; _movingSelectionOffsets = new Vector2[_editor._points.Count];
for (int i = 0; i < _movingSelectionOffsets.Length; i++) for (int i = 0; i < _movingSelectionOffsets.Length; i++)
_movingSelectionOffsets[i] = _editor._points[i].TimeValue - _movingSelectionStart; _movingSelectionOffsets[i] = _editor._points[i].Point - _movingSelectionStart;
_editor.OnEditingStart(); _editor.OnEditingStart();
Focus(); Focus();
Tooltip?.Hide(); Tooltip?.Hide();
@@ -361,7 +359,7 @@ namespace FlaxEditor.GUI
{ {
// Select node // Select node
selectionCount = 1; selectionCount = 1;
point.Select(); point.IsSelected = true;
_editor.UpdateTangents(); _editor.UpdateTangents();
} }

View File

@@ -152,16 +152,7 @@ namespace FlaxEditor.GUI
/// <summary> /// <summary>
/// Gets the point time and value on a curve. /// Gets the point time and value on a curve.
/// </summary> /// </summary>
public Vector2 TimeValue public Vector2 Point => Editor.GetKeyframePoint(Index, Component);
{
get
{
var k = Editor.GetKeyframe(Index);
var time = Editor.GetKeyframeTime(k);
var value = Editor.GetKeyframeValue(k);
return new Vector2(time, Editor.Accessor.GetCurveValue(ref value, Component));
}
}
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
@@ -190,21 +181,8 @@ namespace FlaxEditor.GUI
return false; return false;
} }
/// <summary> /// <inheritdoc />
/// Adds this keyframe to the selection. protected override bool ShowTooltip => base.ShowTooltip && !Editor._contents._isMovingSelection;
/// </summary>
public void Select()
{
IsSelected = true;
}
/// <summary>
/// Removes this keyframe from the selection.
/// </summary>
public void Deselect()
{
IsSelected = false;
}
/// <summary> /// <summary>
/// Updates the tooltip. /// Updates the tooltip.
@@ -350,7 +328,11 @@ namespace FlaxEditor.GUI
public override Vector2 ViewOffset public override Vector2 ViewOffset
{ {
get => _mainPanel.ViewOffset; get => _mainPanel.ViewOffset;
set => _mainPanel.ViewOffset = value; set
{
_mainPanel.ViewOffset = value;
_mainPanel.FastScroll();
}
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -614,7 +596,7 @@ namespace FlaxEditor.GUI
var p = _points[i]; var p = _points[i];
if (p.IsSelected) if (p.IsSelected)
{ {
p.Deselect(); p.IsSelected = false;
indicesToRemove.Add(p.Index); indicesToRemove.Add(p.Index);
} }
} }
@@ -628,26 +610,14 @@ namespace FlaxEditor.GUI
OnEditingEnd(); OnEditingEnd();
} }
/// <summary> /// <inheritdoc />
/// Shows the whole curve. public override void ShowWholeCurve()
/// </summary>
public void ShowWholeCurve()
{ {
ViewScale = ApplyUseModeMask(EnableZoom, _mainPanel.Size / _contents.Size, ViewScale); ViewScale = ApplyUseModeMask(EnableZoom, _mainPanel.Size / _contents.Size, ViewScale);
ViewOffset = ApplyUseModeMask(EnablePanning, -_mainPanel.ControlsBounds.Location, ViewOffset); ViewOffset = ApplyUseModeMask(EnablePanning, -_mainPanel.ControlsBounds.Location, ViewOffset);
UpdateKeyframes(); UpdateKeyframes();
} }
/// <summary>
/// Resets the view.
/// </summary>
public void ResetView()
{
ViewScale = ApplyUseModeMask(EnableZoom, Vector2.One, ViewScale);
ViewOffset = ApplyUseModeMask(EnablePanning, Vector2.Zero, ViewOffset);
UpdateKeyframes();
}
/// <inheritdoc /> /// <inheritdoc />
public override void Evaluate(out object result, float time, bool loop = false) public override void Evaluate(out object result, float time, bool loop = false)
{ {
@@ -671,7 +641,7 @@ namespace FlaxEditor.GUI
{ {
for (int i = 0; i < _points.Count; i++) for (int i = 0; i < _points.Count; i++)
{ {
_points[i].Deselect(); _points[i].IsSelected = false;
} }
} }
@@ -679,7 +649,7 @@ namespace FlaxEditor.GUI
{ {
for (int i = 0; i < _points.Count; i++) for (int i = 0; i < _points.Count; i++)
{ {
_points[i].Select(); _points[i].IsSelected = true;
} }
} }
@@ -1244,6 +1214,13 @@ namespace FlaxEditor.GUI
OnEdited(); OnEdited();
} }
/// <inheritdoc />
public override Vector2 GetKeyframePoint(int index, int component)
{
var k = _keyframes[index];
return new Vector2(k.Time, Accessor.GetCurveValue(ref k.Value, component));
}
/// <inheritdoc /> /// <inheritdoc />
public override int KeyframesCount => _keyframes.Count; public override int KeyframesCount => _keyframes.Count;
@@ -1910,6 +1887,13 @@ namespace FlaxEditor.GUI
OnEdited(); OnEdited();
} }
/// <inheritdoc />
public override Vector2 GetKeyframePoint(int index, int component)
{
var k = _keyframes[index];
return new Vector2(k.Time, Accessor.GetCurveValue(ref k.Value, component));
}
/// <inheritdoc /> /// <inheritdoc />
public override int KeyframesCount => _keyframes.Count; public override int KeyframesCount => _keyframes.Count;
@@ -1928,35 +1912,32 @@ namespace FlaxEditor.GUI
// Place keyframes // Place keyframes
Rectangle curveContentAreaBounds = _mainPanel.GetClientArea(); Rectangle curveContentAreaBounds = _mainPanel.GetClientArea();
var viewScale = ViewScale; var viewScale = ViewScale;
var pointsSize = _showCollapsed ? new Vector2(4.0f / viewScale.X, Height - 2.0f) : KeyframesSize / viewScale;
for (int i = 0; i < _points.Count; i++) for (int i = 0; i < _points.Count; i++)
{ {
var p = _points[i]; var p = _points[i];
var k = _keyframes[p.Index]; var k = _keyframes[p.Index];
var point = GetKeyframePoint(ref k, p.Component);
var location = GetKeyframePoint(ref k, p.Component); var location = new Vector2
var point = new Vector2
( (
location.X * UnitsPerSecond - p.Width * 0.5f, point.X * UnitsPerSecond - pointsSize.X * 0.5f,
location.Y * -UnitsPerSecond - p.Height * 0.5f + curveContentAreaBounds.Height point.Y * -UnitsPerSecond - pointsSize.Y * 0.5f + curveContentAreaBounds.Height
); );
if (_showCollapsed) if (_showCollapsed)
{ {
point.Y = 1.0f; location.Y = 1.0f;
p.Size = new Vector2(4.0f / viewScale.X, Height - 2.0f);
p.Visible = p.Component == 0; p.Visible = p.Component == 0;
} }
else else
{ {
p.Size = KeyframesSize / viewScale;
p.Visible = true; p.Visible = true;
} }
p.Location = point; p.Bounds = new Rectangle(location, pointsSize);
} }
// Calculate bounds // Calculate bounds
var bounds = _points[0].Bounds; var bounds = _points[0].Bounds;
for (var i = 1; i < _points.Count; i++) for (int i = 1; i < _points.Count; i++)
{ {
bounds = Rectangle.Union(bounds, _points[i].Bounds); bounds = Rectangle.Union(bounds, _points[i].Bounds);
} }

View File

@@ -1276,24 +1276,24 @@ namespace FlaxEditor.GUI.Timeline
case KeyboardKeys.ArrowUp: case KeyboardKeys.ArrowUp:
{ {
int index = IndexInParent; int index = IndexInParent;
if (index > 0) while (index != 0)
{ {
do toSelect = Parent.GetChild(--index) as Track;
{ if (toSelect != null && toSelect.HasParentsExpanded)
toSelect = Parent.GetChild(--index) as Track; break;
} while (index != -1 && toSelect != null && !toSelect.HasParentsExpanded); toSelect = null;
} }
break; break;
} }
case KeyboardKeys.ArrowDown: case KeyboardKeys.ArrowDown:
{ {
int index = IndexInParent; int index = IndexInParent;
if (index < Parent.ChildrenCount - 1) while (index < Parent.ChildrenCount - 1)
{ {
do toSelect = Parent.GetChild(++index) as Track;
{ if (toSelect != null && toSelect.HasParentsExpanded)
toSelect = Parent.GetChild(++index) as Track; break;
} while (index != Parent.ChildrenCount && toSelect != null && !toSelect.HasParentsExpanded); toSelect = null;
} }
break; break;
} }

View File

@@ -259,6 +259,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
{ {
Height = IsExpanded ? ExpandedHeight : CollapsedHeight; Height = IsExpanded ? ExpandedHeight : CollapsedHeight;
UpdateCurve(); UpdateCurve();
if (IsExpanded)
Curve.ShowWholeCurve();
base.OnExpandedChanged(); base.OnExpandedChanged();
} }

View File

@@ -172,6 +172,15 @@ namespace FlaxEngine.GUI
base.SetViewOffset(ref value); base.SetViewOffset(ref value);
} }
/// <summary>
/// Cuts the scroll bars value smoothing and imminently goes to the target scroll value.
/// </summary>
public void FastScroll()
{
HScrollBar?.FastScroll();
VScrollBar?.FastScroll();
}
/// <summary> /// <summary>
/// Scrolls the view to the given control area. /// Scrolls the view to the given control area.
/// </summary> /// </summary>

View File

@@ -182,6 +182,19 @@ namespace FlaxEngine.GUI
_orientation = orientation; _orientation = orientation;
} }
/// <summary>
/// Cuts the scroll bar value smoothing and imminently goes to the target scroll value.
/// </summary>
public void FastScroll()
{
if (!Mathf.NearEqual(_value, _targetValue))
{
_value = _targetValue;
SetUpdate(ref _update, null);
OnValueChanged();
}
}
/// <summary> /// <summary>
/// Scrolls the view to the desire range (favors minimum value if cannot cover whole range in a bounds). /// Scrolls the view to the desire range (favors minimum value if cannot cover whole range in a bounds).
/// </summary> /// </summary>