Merge remote-tracking branch 'origin/master' into 1.10
This commit is contained in:
@@ -4,7 +4,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
@@ -29,6 +28,7 @@ namespace FlaxEditor.GUI
|
||||
internal Float2 _mousePos = Float2.Minimum;
|
||||
internal bool _isMovingSelection;
|
||||
internal bool _isMovingTangent;
|
||||
internal bool _movedView;
|
||||
internal bool _movedKeyframes;
|
||||
private TangentPoint _movingTangent;
|
||||
private Float2 _movingSelectionStart;
|
||||
@@ -190,31 +190,28 @@ namespace FlaxEditor.GUI
|
||||
// Moving view
|
||||
if (_rightMouseDown)
|
||||
{
|
||||
var delta = location - _movingViewLastPos;
|
||||
var movingViewPos = Parent.PointToParent(PointToParent(location));
|
||||
var delta = movingViewPos - _movingViewLastPos;
|
||||
if (_editor.CustomViewPanning != null)
|
||||
delta = _editor.CustomViewPanning(delta);
|
||||
delta *= GetUseModeMask(_editor.EnablePanning) * _editor.ViewScale;
|
||||
delta *= GetUseModeMask(_editor.EnablePanning);
|
||||
if (delta.LengthSquared > 0.01f)
|
||||
{
|
||||
_editor._mainPanel.ViewOffset += delta;
|
||||
_movingViewLastPos = location;
|
||||
_movingViewLastPos = movingViewPos;
|
||||
_movedView = true;
|
||||
if (_editor.CustomViewPanning != null)
|
||||
{
|
||||
Cursor = CursorType.SizeAll;
|
||||
if (Cursor == CursorType.Default)
|
||||
Cursor = CursorType.SizeAll;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_editor.EnablePanning)
|
||||
{
|
||||
case UseMode.Vertical:
|
||||
Cursor = CursorType.SizeNS;
|
||||
break;
|
||||
case UseMode.Horizontal:
|
||||
Cursor = CursorType.SizeWE;
|
||||
break;
|
||||
case UseMode.On:
|
||||
Cursor = CursorType.SizeAll;
|
||||
break;
|
||||
case UseMode.Vertical: Cursor = CursorType.SizeNS; break;
|
||||
case UseMode.Horizontal: Cursor = CursorType.SizeWE; break;
|
||||
case UseMode.On: Cursor = CursorType.SizeAll; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,11 +231,10 @@ namespace FlaxEditor.GUI
|
||||
else if (_isMovingTangent)
|
||||
{
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
var direction = _movingTangent.IsIn ? -1.0f : 1.0f;
|
||||
var k = _editor.GetKeyframe(_movingTangent.Index);
|
||||
var kv = _editor.GetKeyframeValue(k);
|
||||
var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component);
|
||||
_movingTangent.TangentValue = direction * (PointToKeyframes(location, ref viewRect).Y - value);
|
||||
_movingTangent.TangentValue = PointToKeyframes(location, ref viewRect).Y - value;
|
||||
_editor.UpdateTangents();
|
||||
Cursor = CursorType.SizeNS;
|
||||
_movedKeyframes = true;
|
||||
@@ -299,7 +295,8 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
_rightMouseDown = true;
|
||||
_rightMouseDownPos = location;
|
||||
_movingViewLastPos = location;
|
||||
_movedView = false;
|
||||
_movingViewLastPos = Parent.PointToParent(PointToParent(location));
|
||||
}
|
||||
|
||||
// Check if any node is under the mouse
|
||||
@@ -444,7 +441,7 @@ namespace FlaxEditor.GUI
|
||||
Cursor = CursorType.Default;
|
||||
|
||||
// Check if no move has been made at all
|
||||
if (Float2.Distance(ref location, ref _rightMouseDownPos) < 2.0f)
|
||||
if (!_movedView)
|
||||
{
|
||||
var selectionCount = _editor.SelectionCount;
|
||||
var point = GetChildAt(location) as KeyframePoint;
|
||||
@@ -512,6 +509,27 @@ namespace FlaxEditor.GUI
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
if (base.OnMouseDoubleClick(location, button))
|
||||
return true;
|
||||
|
||||
// Add keyframe on double click
|
||||
var child = GetChildAt(location);
|
||||
if (child is not KeyframePoint &&
|
||||
child is not TangentPoint &&
|
||||
_editor.KeyframesCount < _editor.MaxKeyframes)
|
||||
{
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
var pos = PointToKeyframes(location, ref viewRect);
|
||||
_editor.AddKeyframe(pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseWheel(Float2 location, float delta)
|
||||
{
|
||||
@@ -519,10 +537,29 @@ namespace FlaxEditor.GUI
|
||||
return true;
|
||||
|
||||
// Zoom in/out
|
||||
if (_editor.EnableZoom != UseMode.Off && IsMouseOver && !_leftMouseDown && RootWindow.GetKey(KeyboardKeys.Control))
|
||||
var zoom = RootWindow.GetKey(KeyboardKeys.Control);
|
||||
var zoomAlt = RootWindow.GetKey(KeyboardKeys.Shift);
|
||||
if (_editor.EnableZoom != UseMode.Off && IsMouseOver && !_leftMouseDown && (zoom || zoomAlt))
|
||||
{
|
||||
// TODO: preserve the view center point for easier zooming
|
||||
_editor.ViewScale += GetUseModeMask(_editor.EnableZoom) * (delta * 0.1f);
|
||||
// Cache mouse location in curve-space
|
||||
var viewRect = _editor._mainPanel.GetClientArea();
|
||||
var locationInKeyframes = PointToKeyframes(location, ref viewRect);
|
||||
var locationInEditorBefore = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect);
|
||||
|
||||
// Scale relative to the curve size
|
||||
var scale = new Float2(delta * 0.1f);
|
||||
_editor._mainPanel.GetDesireClientArea(out var mainPanelArea);
|
||||
var curveScale = mainPanelArea.Size / _editor._contents.Size;
|
||||
scale *= curveScale;
|
||||
if (zoomAlt)
|
||||
scale.X = 0; // Scale Y axis only
|
||||
scale *= GetUseModeMask(_editor.EnableZoom); // Mask scale depending on allowed usage
|
||||
_editor.ViewScale += scale;
|
||||
|
||||
// Zoom towards the mouse position
|
||||
var locationInEditorAfter = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect);
|
||||
var locationInEditorDelta = locationInEditorAfter - locationInEditorBefore;
|
||||
_editor.ViewOffset -= locationInEditorDelta;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -671,8 +671,22 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public override void ShowWholeCurve()
|
||||
{
|
||||
ViewScale = ApplyUseModeMask(EnableZoom, _mainPanel.Size / _contents.Size, ViewScale);
|
||||
ViewOffset = ApplyUseModeMask(EnablePanning, -_mainPanel.ControlsBounds.Location, ViewOffset);
|
||||
_mainPanel.GetDesireClientArea(out var mainPanelArea);
|
||||
ViewScale = ApplyUseModeMask(EnableZoom, mainPanelArea.Size / _contents.Size, ViewScale);
|
||||
Float2 minPos = Float2.Maximum;
|
||||
foreach (var point in _points)
|
||||
{
|
||||
var pos = point.PointToParent(point.Location);
|
||||
Float2.Min(ref minPos, ref pos, out minPos);
|
||||
}
|
||||
var minPosPoint = _contents.PointToParent(ref minPos);
|
||||
var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0);
|
||||
scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll);
|
||||
if (_mainPanel.HScrollBar != null)
|
||||
_mainPanel.HScrollBar.TargetValue = scroll.X;
|
||||
if (_mainPanel.VScrollBar != null)
|
||||
_mainPanel.VScrollBar.TargetValue = scroll.Y;
|
||||
|
||||
UpdateKeyframes();
|
||||
}
|
||||
|
||||
@@ -923,6 +937,11 @@ namespace FlaxEditor.GUI
|
||||
KeyframesEditorUtils.Paste(this);
|
||||
return true;
|
||||
}
|
||||
else if (options.FocusSelection.Process(this))
|
||||
{
|
||||
ShowWholeCurve();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1384,9 +1403,7 @@ namespace FlaxEditor.GUI
|
||||
// Calculate bounds
|
||||
var bounds = _points[0].Bounds;
|
||||
for (var i = 1; i < _points.Count; i++)
|
||||
{
|
||||
bounds = Rectangle.Union(bounds, _points[i].Bounds);
|
||||
}
|
||||
|
||||
// Adjust contents bounds to fill the curve area
|
||||
if (EnablePanning != UseMode.Off || !ShowCollapsed)
|
||||
@@ -1632,6 +1649,7 @@ namespace FlaxEditor.GUI
|
||||
var o = _keyframes[p.Index - 1];
|
||||
var oValue = Accessor.GetCurveValue(ref o.Value, p.Component);
|
||||
var slope = (value - oValue) / (k.Time - o.Time);
|
||||
slope = -slope;
|
||||
Accessor.SetCurveValue(slope, ref k.TangentIn, p.Component);
|
||||
}
|
||||
|
||||
@@ -2116,9 +2134,7 @@ namespace FlaxEditor.GUI
|
||||
// Calculate bounds
|
||||
var bounds = _points[0].Bounds;
|
||||
for (int i = 1; i < _points.Count; i++)
|
||||
{
|
||||
bounds = Rectangle.Union(bounds, _points[i].Bounds);
|
||||
}
|
||||
|
||||
// Adjust contents bounds to fill the curve area
|
||||
if (EnablePanning != UseMode.Off || !ShowCollapsed)
|
||||
@@ -2184,12 +2200,12 @@ namespace FlaxEditor.GUI
|
||||
|
||||
var tangent = t.TangentValue;
|
||||
var direction = t.IsIn ? -1.0f : 1.0f;
|
||||
var offset = 30.0f * direction;
|
||||
var offset = 30.0f;
|
||||
var location = GetKeyframePoint(ref k, selectedComponent);
|
||||
t.Size = KeyframesSize / ViewScale;
|
||||
t.Location = new Float2
|
||||
(
|
||||
location.X * UnitsPerSecond - t.Width * 0.5f + offset,
|
||||
location.X * UnitsPerSecond - t.Width * 0.5f + offset * direction,
|
||||
location.Y * -UnitsPerSecond - t.Height * 0.5f + curveContentAreaBounds.Height - offset * tangent
|
||||
);
|
||||
|
||||
@@ -2265,14 +2281,13 @@ namespace FlaxEditor.GUI
|
||||
var startTangent = Accessor.GetCurveValue(ref startK.TangentOut, component);
|
||||
var endTangent = Accessor.GetCurveValue(ref endK.TangentIn, component);
|
||||
|
||||
var offset = (end.X - start.X) * 0.5f;
|
||||
|
||||
var tangentScale = (endK.Time - startK.Time) / 3.0f;
|
||||
var p1 = PointFromKeyframes(start, ref viewRect);
|
||||
var p2 = PointFromKeyframes(start + new Float2(offset, startTangent * offset), ref viewRect);
|
||||
var p3 = PointFromKeyframes(end - new Float2(offset, endTangent * offset), ref viewRect);
|
||||
var p2 = PointFromKeyframes(start + new Float2(0, startTangent * tangentScale), ref viewRect);
|
||||
var p3 = PointFromKeyframes(end + new Float2(0, endTangent * tangentScale), ref viewRect);
|
||||
var p4 = PointFromKeyframes(end, ref viewRect);
|
||||
|
||||
Render2D.DrawBezier(p1, p2, p3, p4, color);
|
||||
Render2D.DrawSpline(p1, p2, p3, p4, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
86
Source/Editor/GUI/Splitter.cs
Normal file
86
Source/Editor/GUI/Splitter.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
sealed class Splitter : Control
|
||||
{
|
||||
private bool _clicked;
|
||||
|
||||
public Action<Float2> Moved;
|
||||
public const float DefaultHeight = 5.0f;
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
var style = Style.Current;
|
||||
if (IsMouseOver || _clicked)
|
||||
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), _clicked ? style.BackgroundSelected : style.BackgroundHighlighted);
|
||||
}
|
||||
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
|
||||
_clicked = false;
|
||||
}
|
||||
|
||||
public override void Defocus()
|
||||
{
|
||||
base.Defocus();
|
||||
|
||||
_clicked = false;
|
||||
}
|
||||
|
||||
public override void OnMouseEnter(Float2 location)
|
||||
{
|
||||
base.OnMouseEnter(location);
|
||||
|
||||
Cursor = CursorType.SizeNS;
|
||||
}
|
||||
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
Cursor = CursorType.Default;
|
||||
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
_clicked = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
|
||||
if (_clicked)
|
||||
{
|
||||
Moved(location);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _clicked)
|
||||
{
|
||||
_clicked = false;
|
||||
EndMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
||||
continue;
|
||||
|
||||
// Draw all ticks
|
||||
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1);
|
||||
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2);
|
||||
var lStep = _tickSteps[l];
|
||||
var lNextStep = _tickSteps[l + 1];
|
||||
int startTick = Mathf.FloorToInt(min / lStep);
|
||||
|
||||
@@ -1446,6 +1446,17 @@ namespace FlaxEditor.GUI.Timeline
|
||||
{
|
||||
GetTracks(SelectedTracks[i], tracks);
|
||||
}
|
||||
|
||||
// Find the lowest track position for selection
|
||||
int lowestTrackLocation = Tracks.Count - 1;
|
||||
for (int i = 0; i < tracks.Count; i++)
|
||||
{
|
||||
var trackToDelete = tracks[i];
|
||||
if (trackToDelete.TrackIndex < lowestTrackLocation)
|
||||
{
|
||||
lowestTrackLocation = trackToDelete.TrackIndex;
|
||||
}
|
||||
}
|
||||
SelectedTracks.Clear();
|
||||
if (withUndo && Undo != null && Undo.Enabled)
|
||||
{
|
||||
@@ -1468,6 +1479,18 @@ namespace FlaxEditor.GUI.Timeline
|
||||
}
|
||||
OnTracksChanged();
|
||||
MarkAsEdited();
|
||||
|
||||
// Select track above deleted tracks unless track is first track
|
||||
if (Tracks.Count > 0)
|
||||
{
|
||||
if (lowestTrackLocation - 1 >= 0)
|
||||
Select(Tracks[lowestTrackLocation - 1]);
|
||||
else
|
||||
Select(Tracks[0]);
|
||||
|
||||
SelectedTracks[0].Focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1655,6 +1678,14 @@ namespace FlaxEditor.GUI.Timeline
|
||||
}
|
||||
OnTracksChanged();
|
||||
MarkAsEdited();
|
||||
|
||||
// Deselect and select new clones.
|
||||
Deselect();
|
||||
foreach (var clone in clones)
|
||||
{
|
||||
Select(clone, true);
|
||||
}
|
||||
|
||||
SelectedTracks[0].Focus();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,87 +19,6 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
/// <seealso cref="MemberTrack" />
|
||||
public abstract class CurvePropertyTrackBase : MemberTrack, IKeyframesEditorContext
|
||||
{
|
||||
private sealed class Splitter : Control
|
||||
{
|
||||
private bool _clicked;
|
||||
internal CurvePropertyTrackBase _track;
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
var style = Style.Current;
|
||||
if (IsMouseOver || _clicked)
|
||||
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), _clicked ? style.BackgroundSelected : style.BackgroundHighlighted);
|
||||
}
|
||||
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
|
||||
_clicked = false;
|
||||
}
|
||||
|
||||
public override void Defocus()
|
||||
{
|
||||
base.Defocus();
|
||||
|
||||
_clicked = false;
|
||||
}
|
||||
|
||||
public override void OnMouseEnter(Float2 location)
|
||||
{
|
||||
base.OnMouseEnter(location);
|
||||
|
||||
Cursor = CursorType.SizeNS;
|
||||
}
|
||||
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
Cursor = CursorType.Default;
|
||||
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
_clicked = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
|
||||
if (_clicked)
|
||||
{
|
||||
var height = Mathf.Clamp(PointToParent(location).Y, 40.0f, 1000.0f);
|
||||
if (!Mathf.NearEqual(height, _track._expandedHeight))
|
||||
{
|
||||
_track.Height = _track._expandedHeight = height;
|
||||
_track.Timeline.ArrangeTracks();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _clicked)
|
||||
{
|
||||
_clicked = false;
|
||||
EndMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] _curveEditingStartData;
|
||||
private float _expandedHeight = 120.0f;
|
||||
private Splitter _splitter;
|
||||
@@ -251,12 +170,21 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
_splitter = new Splitter
|
||||
{
|
||||
_track = this,
|
||||
Moved = OnSplitterMoved,
|
||||
Parent = Curve,
|
||||
};
|
||||
}
|
||||
var splitterHeight = 5.0f;
|
||||
_splitter.Bounds = new Rectangle(0, Curve.Height - splitterHeight, Curve.Width, splitterHeight);
|
||||
_splitter.Bounds = new Rectangle(0, Curve.Height - Splitter.DefaultHeight, Curve.Width, Splitter.DefaultHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSplitterMoved(Float2 location)
|
||||
{
|
||||
var height = Mathf.Clamp(PointToParent(location).Y, 40.0f, 1000.0f);
|
||||
if (!Mathf.NearEqual(height, _expandedHeight))
|
||||
{
|
||||
Height = _expandedHeight = height;
|
||||
Timeline.ArrangeTracks();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,19 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
MaxMediaCount = 1;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDuplicated(Track clone)
|
||||
{
|
||||
base.OnDuplicated(clone);
|
||||
|
||||
// Clone overriden parameters
|
||||
if (clone is ParticleEmitterTrack cloneTrack)
|
||||
{
|
||||
foreach (var e in ParametersOverrides)
|
||||
cloneTrack.ParametersOverrides.Add(e.Key, e.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
|
||||
@@ -61,6 +61,9 @@ namespace FlaxEditor.GUI.Timeline.Undo
|
||||
_timeline.AddTrack(track, false);
|
||||
track.TrackIndex = _order;
|
||||
_timeline.OnTracksOrderChanged();
|
||||
_timeline.Focus();
|
||||
_timeline.Select(track);
|
||||
track.Focus();
|
||||
}
|
||||
|
||||
private void Remove()
|
||||
@@ -68,10 +71,11 @@ namespace FlaxEditor.GUI.Timeline.Undo
|
||||
var track = _timeline.FindTrack(_name);
|
||||
if (track == null)
|
||||
{
|
||||
Editor.LogWarning($"Cannot remove track {_name}. It doesn't already exists.");
|
||||
Editor.LogWarning($"Cannot remove track {_name}. It doesn't exist.");
|
||||
return;
|
||||
}
|
||||
_timeline.Delete(track, false);
|
||||
_timeline.Focus();
|
||||
}
|
||||
|
||||
public string ActionString => _isAdd ? "Add track" : "Remove track";
|
||||
|
||||
Reference in New Issue
Block a user