Add focus selection to curve editor and apply margin around shown curve section
#2455
This commit is contained in:
@@ -674,30 +674,84 @@ namespace FlaxEditor.GUI
|
|||||||
OnEditingEnd();
|
OnEditingEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
private void ShowCurve(bool selectedOnly)
|
||||||
public override void ShowWholeCurve()
|
|
||||||
{
|
{
|
||||||
if (_points.Count == 0)
|
if (_points.Count == 0)
|
||||||
return;
|
return;
|
||||||
_mainPanel.GetDesireClientArea(out var mainPanelArea);
|
int pass = 1;
|
||||||
ViewScale = ApplyUseModeMask(EnableZoom, mainPanelArea.Size / _contents.Size, ViewScale);
|
REDO:
|
||||||
Float2 minPos = Float2.Maximum;
|
|
||||||
|
// Get curve bounds in Keyframes (time and value)
|
||||||
|
Float2 posMin = Float2.Maximum, posMax = Float2.Minimum;
|
||||||
|
// TODO: include bezier curve bounds calculation to handle curve outside the bounds made out of points
|
||||||
foreach (var point in _points)
|
foreach (var point in _points)
|
||||||
{
|
{
|
||||||
var pos = point.PointToParent(point.Location);
|
if (selectedOnly && !point.IsSelected)
|
||||||
Float2.Min(ref minPos, ref pos, out minPos);
|
continue;
|
||||||
|
var pos = point.Point;
|
||||||
|
Float2.Min(ref posMin, ref pos, out posMin);
|
||||||
|
Float2.Max(ref posMax, ref pos, out posMax);
|
||||||
}
|
}
|
||||||
var minPosPoint = _contents.PointToParent(ref minPos);
|
|
||||||
var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0);
|
// Apply margin around the area
|
||||||
scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll);
|
var posMargin = (posMax - posMin) * 0.05f;
|
||||||
if (_mainPanel.HScrollBar != null)
|
posMin -= posMargin;
|
||||||
_mainPanel.HScrollBar.TargetValue = scroll.X;
|
posMax += posMargin;
|
||||||
if (_mainPanel.VScrollBar != null)
|
|
||||||
_mainPanel.VScrollBar.TargetValue = scroll.Y;
|
// Convert from Keyframes to Contents
|
||||||
|
_mainPanel.GetDesireClientArea(out var viewRect);
|
||||||
|
PointFromKeyframesToContents(ref posMin, ref viewRect);
|
||||||
|
PointFromKeyframesToContents(ref posMax, ref viewRect);
|
||||||
|
var tmp = posMin;
|
||||||
|
Float2.Min(ref posMin, ref posMax, out posMin);
|
||||||
|
Float2.Max(ref posMax, ref tmp, out posMax);
|
||||||
|
var contentsSize = posMax - posMin;
|
||||||
|
|
||||||
|
// Convert from Contents to Main Panel
|
||||||
|
posMin = _contents.PointToParent(posMin);
|
||||||
|
posMax = _contents.PointToParent(posMax);
|
||||||
|
tmp = posMin;
|
||||||
|
Float2.Min(ref posMin, ref posMax, out posMin);
|
||||||
|
Float2.Max(ref posMax, ref tmp, out posMax);
|
||||||
|
|
||||||
|
// Update zoom (leave unchanged when focusing a single point)
|
||||||
|
var zoomMask = EnableZoom;
|
||||||
|
if (Mathf.IsZero(posMargin.X))
|
||||||
|
zoomMask &= ~UseMode.Horizontal;
|
||||||
|
if (Mathf.IsZero(posMargin.Y))
|
||||||
|
zoomMask &= ~UseMode.Vertical;
|
||||||
|
ViewScale = ApplyUseModeMask(zoomMask, viewRect.Size / contentsSize, ViewScale);
|
||||||
|
|
||||||
|
// Update scroll (attempt to center the area when it's smaller than the view)
|
||||||
|
Float2 viewOffset = -posMin;
|
||||||
|
Float2 viewSize = _mainPanel.Size;
|
||||||
|
Float2 viewSizeLeft = viewSize - Float2.Clamp(posMax - posMin, Float2.Zero, viewSize);
|
||||||
|
viewOffset += viewSizeLeft * 0.5f;
|
||||||
|
viewOffset = ApplyUseModeMask(EnablePanning, viewOffset, _mainPanel.ViewOffset);
|
||||||
|
_mainPanel.ViewOffset = viewOffset;
|
||||||
|
|
||||||
|
// Do it multiple times so the view offset can be properly calculate once the view scale gets changes
|
||||||
|
if (pass++ <= 2)
|
||||||
|
goto REDO;
|
||||||
|
|
||||||
UpdateKeyframes();
|
UpdateKeyframes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Focuses the view on the selected keyframes.
|
||||||
|
/// </summary>
|
||||||
|
public void FocusSelection()
|
||||||
|
{
|
||||||
|
// Fallback to showing whole curve if nothing is selected
|
||||||
|
ShowCurve(SelectionCount != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ShowWholeCurve()
|
||||||
|
{
|
||||||
|
ShowCurve(false);
|
||||||
|
}
|
||||||
|
|
||||||
/// <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)
|
||||||
{
|
{
|
||||||
@@ -774,10 +828,7 @@ namespace FlaxEditor.GUI
|
|||||||
point = _contents.PointFromParent(point);
|
point = _contents.PointFromParent(point);
|
||||||
|
|
||||||
// Contents -> Keyframes
|
// Contents -> Keyframes
|
||||||
return new Float2(
|
return PointFromContentsToKeyframes(ref point, ref curveContentAreaBounds);
|
||||||
(point.X + _contents.Location.X) / UnitsPerSecond,
|
|
||||||
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -789,10 +840,7 @@ namespace FlaxEditor.GUI
|
|||||||
protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds)
|
protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds)
|
||||||
{
|
{
|
||||||
// Keyframes -> Contents
|
// Keyframes -> Contents
|
||||||
point = new Float2(
|
PointFromKeyframesToContents(ref point, ref curveContentAreaBounds);
|
||||||
point.X * UnitsPerSecond - _contents.Location.X,
|
|
||||||
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
|
|
||||||
);
|
|
||||||
|
|
||||||
// Contents -> Main Panel
|
// Contents -> Main Panel
|
||||||
point = _contents.PointToParent(point);
|
point = _contents.PointToParent(point);
|
||||||
@@ -801,6 +849,22 @@ namespace FlaxEditor.GUI
|
|||||||
return _mainPanel.PointToParent(point);
|
return _mainPanel.PointToParent(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Float2 PointFromContentsToKeyframes(ref Float2 point, ref Rectangle curveContentAreaBounds)
|
||||||
|
{
|
||||||
|
return new Float2(
|
||||||
|
(point.X + _contents.Location.X) / UnitsPerSecond,
|
||||||
|
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PointFromKeyframesToContents(ref Float2 point, ref Rectangle curveContentAreaBounds)
|
||||||
|
{
|
||||||
|
point = new Float2(
|
||||||
|
point.X * UnitsPerSecond - _contents.Location.X,
|
||||||
|
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
|
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
|
||||||
{
|
{
|
||||||
Utilities.Utils.DrawCurveTicks((decimal tick, float strength) =>
|
Utilities.Utils.DrawCurveTicks((decimal tick, float strength) =>
|
||||||
@@ -947,7 +1011,7 @@ namespace FlaxEditor.GUI
|
|||||||
}
|
}
|
||||||
else if (options.FocusSelection.Process(this))
|
else if (options.FocusSelection.Process(this))
|
||||||
{
|
{
|
||||||
ShowWholeCurve();
|
FocusSelection();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user