diff --git a/Source/Editor/GUI/CurveEditor.Base.cs b/Source/Editor/GUI/CurveEditor.Base.cs index 1cdd72761..d767d8ba9 100644 --- a/Source/Editor/GUI/CurveEditor.Base.cs +++ b/Source/Editor/GUI/CurveEditor.Base.cs @@ -276,5 +276,8 @@ namespace FlaxEditor.GUI /// public abstract void OnKeyframesDelete(IKeyframesEditor editor); + + /// + public abstract void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end); } } diff --git a/Source/Editor/GUI/CurveEditor.Contents.cs b/Source/Editor/GUI/CurveEditor.Contents.cs index c914e6c25..b77ea1a10 100644 --- a/Source/Editor/GUI/CurveEditor.Contents.cs +++ b/Source/Editor/GUI/CurveEditor.Contents.cs @@ -59,6 +59,97 @@ namespace FlaxEditor.GUI _editor.UpdateTangents(); } + internal void OnMoveStart(Vector2 location) + { + // Start moving selected keyframes + _isMovingSelection = true; + _movedKeyframes = false; + var viewRect = _editor._mainPanel.GetClientArea(); + _movingSelectionStart = PointToKeyframes(location, ref viewRect); + if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count) + _movingSelectionOffsets = new Vector2[_editor._points.Count]; + for (int i = 0; i < _movingSelectionOffsets.Length; i++) + _movingSelectionOffsets[i] = _editor._points[i].Point - _movingSelectionStart; + _editor.OnEditingStart(); + } + + internal void OnMove(Vector2 location) + { + var viewRect = _editor._mainPanel.GetClientArea(); + var locationKeyframes = PointToKeyframes(location, ref viewRect); + var accessor = _editor.Accessor; + var components = accessor.GetCurveComponents(); + for (var i = 0; i < _editor._points.Count; i++) + { + var p = _editor._points[i]; + if (p.IsSelected) + { + var k = _editor.GetKeyframe(p.Index); + float time = _editor.GetKeyframeTime(k); + float value = _editor.GetKeyframeValue(k, p.Component); + + float minTime = p.Index != 0 ? _editor.GetKeyframeTime(_editor.GetKeyframe(p.Index - 1)) + Mathf.Epsilon : float.MinValue; + float maxTime = p.Index != _editor.KeyframesCount - 1 ? _editor.GetKeyframeTime(_editor.GetKeyframe(p.Index + 1)) - Mathf.Epsilon : float.MaxValue; + + var offset = _movingSelectionOffsets[i]; + + if (!_editor.ShowCollapsed) + { + // Move on value axis + value = locationKeyframes.Y + offset.Y; + } + + // Let the first selected point of this keyframe to edit time + bool isFirstSelected = false; + for (var j = 0; j < components; j++) + { + var idx = p.Index * components + j; + if (idx == i) + { + isFirstSelected = true; + break; + } + if (_editor._points[idx].IsSelected) + break; + } + if (isFirstSelected) + { + time = locationKeyframes.X + offset.X; + + if (_editor.FPS.HasValue) + { + float fps = _editor.FPS.Value; + time = Mathf.Floor(time * fps) / fps; + } + time = Mathf.Clamp(time, minTime, maxTime); + } + + // TODO: snapping keyframes to grid when moving + + _editor.SetKeyframeInternal(p.Index, time, value, p.Component); + } + _editor.UpdateKeyframes(); + _editor.UpdateTooltips(); + if (_editor.EnablePanning == UseMode.On) + { + //_editor._mainPanel.ScrollViewTo(PointToParent(_editor._mainPanel, location)); + } + Cursor = CursorType.SizeAll; + _movedKeyframes = true; + } + } + + internal void OnMoveEnd(Vector2 location) + { + if (_movedKeyframes) + { + _editor.OnEdited(); + _editor.OnEditingEnd(); + _movedKeyframes = false; + } + _isMovingSelection = false; + } + /// public override bool IntersectsContent(ref Vector2 locationParent, out Vector2 location) { @@ -83,16 +174,10 @@ namespace FlaxEditor.GUI // Start moving selection if movement started from the keyframe if (_leftMouseDown && !_isMovingSelection && GetChildAt(_leftMouseDownPos) is KeyframePoint) { - // Start moving selected nodes - _isMovingSelection = true; - _movedKeyframes = false; - var viewRect = _editor._mainPanel.GetClientArea(); - _movingSelectionStart = PointToKeyframes(location, ref viewRect); - if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count) - _movingSelectionOffsets = new Vector2[_editor._points.Count]; - for (int i = 0; i < _movingSelectionOffsets.Length; i++) - _movingSelectionOffsets[i] = _editor._points[i].Point - _movingSelectionStart; - _editor.OnEditingStart(); + if (_editor.KeyframesEditorContext != null) + _editor.KeyframesEditorContext.OnKeyframesMove(_editor, this, location, true, false); + else + OnMoveStart(location); } // Moving view @@ -132,68 +217,10 @@ namespace FlaxEditor.GUI // Moving selection else if (_isMovingSelection) { - var viewRect = _editor._mainPanel.GetClientArea(); - var locationKeyframes = PointToKeyframes(location, ref viewRect); - var accessor = _editor.Accessor; - var components = accessor.GetCurveComponents(); - for (var i = 0; i < _editor._points.Count; i++) - { - var p = _editor._points[i]; - if (p.IsSelected) - { - var k = _editor.GetKeyframe(p.Index); - float time = _editor.GetKeyframeTime(k); - float value = _editor.GetKeyframeValue(k, p.Component); - - float minTime = p.Index != 0 ? _editor.GetKeyframeTime(_editor.GetKeyframe(p.Index - 1)) + Mathf.Epsilon : float.MinValue; - float maxTime = p.Index != _editor.KeyframesCount - 1 ? _editor.GetKeyframeTime(_editor.GetKeyframe(p.Index + 1)) - Mathf.Epsilon : float.MaxValue; - - var offset = _movingSelectionOffsets[i]; - - if (!_editor.ShowCollapsed) - { - // Move on value axis - value = locationKeyframes.Y + offset.Y; - } - - // Let the first selected point of this keyframe to edit time - bool isFirstSelected = false; - for (var j = 0; j < components; j++) - { - var idx = p.Index * components + j; - if (idx == i) - { - isFirstSelected = true; - break; - } - if (_editor._points[idx].IsSelected) - break; - } - if (isFirstSelected) - { - time = locationKeyframes.X + offset.X; - - if (_editor.FPS.HasValue) - { - float fps = _editor.FPS.Value; - time = Mathf.Floor(time * fps) / fps; - } - time = Mathf.Clamp(time, minTime, maxTime); - } - - // TODO: snapping keyframes to grid when moving - - _editor.SetKeyframeInternal(p.Index, time, value, p.Component); - } - _editor.UpdateKeyframes(); - _editor.UpdateTooltips(); - if (_editor.EnablePanning == UseMode.On) - { - //_editor._mainPanel.ScrollViewTo(PointToParent(_editor._mainPanel, location)); - } - Cursor = CursorType.SizeAll; - _movedKeyframes = true; - } + if (_editor.KeyframesEditorContext != null) + _editor.KeyframesEditorContext.OnKeyframesMove(_editor, this, location, false, false); + else + OnMove(location); return; } // Moving tangent @@ -374,11 +401,10 @@ namespace FlaxEditor.GUI // Moving keyframes else if (_isMovingSelection) { - if (_movedKeyframes) - { - _editor.OnEdited(); - _editor.OnEditingEnd(); - } + if (_editor.KeyframesEditorContext != null) + _editor.KeyframesEditorContext.OnKeyframesMove(_editor, this, location, false, true); + else + OnMoveEnd(location); } _isMovingSelection = false; @@ -509,5 +535,19 @@ namespace FlaxEditor.GUI { RemoveKeyframesInner(); } + + /// + public override void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + if (_points.Count == 0) + return; + location = _contents.PointFromParent(control, location); + if (start) + _contents.OnMoveStart(location); + else if (end) + _contents.OnMoveEnd(location); + else + _contents.OnMove(location); + } } } diff --git a/Source/Editor/GUI/IKeyframesEditor.cs b/Source/Editor/GUI/IKeyframesEditor.cs index f23be8dd1..b7e37e9f4 100644 --- a/Source/Editor/GUI/IKeyframesEditor.cs +++ b/Source/Editor/GUI/IKeyframesEditor.cs @@ -40,5 +40,15 @@ namespace FlaxEditor.GUI /// /// The source editor. void OnKeyframesDelete(IKeyframesEditor editor); + + /// + /// Called when keyframes selection should be moved. + /// + /// The source editor. + /// The source movement control. + /// The source movement location (in source control local space). + /// The movement start flag. + /// The movement end flag. + void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end); } } diff --git a/Source/Editor/GUI/IKeyframesEditorContext.cs b/Source/Editor/GUI/IKeyframesEditorContext.cs index ed4ee3676..d66a03b19 100644 --- a/Source/Editor/GUI/IKeyframesEditorContext.cs +++ b/Source/Editor/GUI/IKeyframesEditorContext.cs @@ -35,5 +35,15 @@ namespace FlaxEditor.GUI /// /// The source editor. void OnKeyframesDelete(IKeyframesEditor editor); + + /// + /// Called when keyframes selection should be moved. + /// + /// The source editor. + /// The source movement control. + /// The source movement location (in source control local space). + /// The movement start flag. + /// The movement end flag. + void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end); } } diff --git a/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs b/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs index df0358645..e7e906aab 100644 --- a/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs +++ b/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs @@ -109,6 +109,69 @@ namespace FlaxEditor.GUI } } + internal void OnMoveStart(Vector2 location) + { + // Start moving selected nodes + _isMovingSelection = true; + _movedKeyframes = false; + var viewRect = _editor._mainPanel.GetClientArea(); + _movingSelectionStart = PointToKeyframes(location, ref viewRect).X; + if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._keyframes.Count) + _movingSelectionOffsets = new float[_editor._keyframes.Count]; + for (int i = 0; i < _movingSelectionOffsets.Length; i++) + _movingSelectionOffsets[i] = _editor._keyframes[i].Time - _movingSelectionStart; + _editor.OnEditingStart(); + } + + internal void OnMove(Vector2 location) + { + var viewRect = _editor._mainPanel.GetClientArea(); + var locationKeyframes = PointToKeyframes(location, ref viewRect); + for (var i = 0; i < _editor._points.Count; i++) + { + var p = _editor._points[i]; + if (p.IsSelected) + { + var k = _editor._keyframes[p.Index]; + + float minTime = p.Index != 0 ? _editor._keyframes[p.Index - 1].Time : float.MinValue; + float maxTime = p.Index != _editor._keyframes.Count - 1 ? _editor._keyframes[p.Index + 1].Time : float.MaxValue; + + var offset = _movingSelectionOffsets[p.Index]; + k.Time = locationKeyframes.X + offset; + if (_editor.FPS.HasValue) + { + float fps = _editor.FPS.Value; + k.Time = Mathf.Floor(k.Time * fps) / fps; + } + k.Time = Mathf.Clamp(k.Time, minTime, maxTime); + + // TODO: snapping keyframes to grid when moving + + _editor._keyframes[p.Index] = k; + } + _editor.UpdateKeyframes(); + if (_editor.EnablePanning) + { + //_editor._mainPanel.ScrollViewTo(PointToParent(_editor._mainPanel, location)); + } + Cursor = CursorType.SizeAll; + _movedKeyframes = true; + } + } + + internal void OnMoveEnd(Vector2 location) + { + if (_movedKeyframes) + { + _editor.OnEdited(); + _editor.OnEditingEnd(); + _editor.UpdateKeyframes(); + _movedKeyframes = false; + } + _isMovingSelection = false; + } + /// public override bool IntersectsContent(ref Vector2 locationParent, out Vector2 location) { @@ -133,16 +196,10 @@ namespace FlaxEditor.GUI // Start moving selection if movement started from the keyframe if (_leftMouseDown && !_isMovingSelection && GetChildAt(_leftMouseDownPos) is KeyframePoint) { - // Start moving selected nodes - _isMovingSelection = true; - _movedKeyframes = false; - var viewRect = _editor._mainPanel.GetClientArea(); - _movingSelectionStart = PointToKeyframes(location, ref viewRect).X; - if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._keyframes.Count) - _movingSelectionOffsets = new float[_editor._keyframes.Count]; - for (int i = 0; i < _movingSelectionOffsets.Length; i++) - _movingSelectionOffsets[i] = _editor._keyframes[i].Time - _movingSelectionStart; - _editor.OnEditingStart(); + if (_editor.KeyframesEditorContext != null) + _editor.KeyframesEditorContext.OnKeyframesMove(_editor, this, location, true, false); + else + OnMoveStart(location); } // Moving view @@ -170,40 +227,10 @@ namespace FlaxEditor.GUI // Moving selection else if (_isMovingSelection) { - var viewRect = _editor._mainPanel.GetClientArea(); - var locationKeyframes = PointToKeyframes(location, ref viewRect); - for (var i = 0; i < _editor._points.Count; i++) - { - var p = _editor._points[i]; - if (p.IsSelected) - { - var k = _editor._keyframes[p.Index]; - - float minTime = p.Index != 0 ? _editor._keyframes[p.Index - 1].Time : float.MinValue; - float maxTime = p.Index != _editor._keyframes.Count - 1 ? _editor._keyframes[p.Index + 1].Time : float.MaxValue; - - var offset = _movingSelectionOffsets[p.Index]; - k.Time = locationKeyframes.X + offset; - if (_editor.FPS.HasValue) - { - float fps = _editor.FPS.Value; - k.Time = Mathf.Floor(k.Time * fps) / fps; - } - k.Time = Mathf.Clamp(k.Time, minTime, maxTime); - - // TODO: snapping keyframes to grid when moving - - _editor._keyframes[p.Index] = k; - } - _editor.UpdateKeyframes(); - if (_editor.EnablePanning) - { - //_editor._mainPanel.ScrollViewTo(PointToParent(_editor._mainPanel, location)); - } - Cursor = CursorType.SizeAll; - _movedKeyframes = true; - } - + if (_editor.KeyframesEditorContext != null) + _editor.KeyframesEditorContext.OnKeyframesMove(_editor, this, location, false, false); + else + OnMove(location); return; } // Selecting @@ -329,12 +356,10 @@ namespace FlaxEditor.GUI // Moving keyframes if (_isMovingSelection) { - if (_movedKeyframes) - { - _editor.OnEdited(); - _editor.OnEditingEnd(); - _editor.UpdateKeyframes(); - } + if (_editor.KeyframesEditorContext != null) + _editor.KeyframesEditorContext.OnKeyframesMove(_editor, this, location, false, true); + else + OnMoveEnd(location); } _isMovingSelection = false; @@ -1227,5 +1252,17 @@ namespace FlaxEditor.GUI { RemoveKeyframesInner(); } + + /// + public void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + location = _contents.PointFromParent(control, location); + if (start) + _contents.OnMoveStart(location); + else if (end) + _contents.OnMoveEnd(location); + else + _contents.OnMove(location); + } } } diff --git a/Source/Editor/GUI/Timeline/Timeline.cs b/Source/Editor/GUI/Timeline/Timeline.cs index 20386de5d..931d2ce7a 100644 --- a/Source/Editor/GUI/Timeline/Timeline.cs +++ b/Source/Editor/GUI/Timeline/Timeline.cs @@ -2458,5 +2458,16 @@ namespace FlaxEditor.GUI.Timeline trackContext.OnKeyframesDelete(editor); } } + + /// + public void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + location = control.PointToParent(_backgroundArea, location); + for (int i = 0; i < _tracks.Count; i++) + { + if (_tracks[i] is IKeyframesEditorContext trackContext) + trackContext.OnKeyframesMove(editor, _backgroundArea, location, start, end); + } + } } } diff --git a/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs b/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs index 72f4cd7f3..2aed48ee0 100644 --- a/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs @@ -670,5 +670,12 @@ namespace FlaxEditor.GUI.Timeline.Tracks if (Curve != null && Curve.Visible) Curve.OnKeyframesDelete(editor); } + + /// + public void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + if (Curve != null && Curve.Visible) + Curve.OnKeyframesMove(editor, control, location, start, end); + } } } diff --git a/Source/Editor/GUI/Timeline/Tracks/CurvePropertyTrack.cs b/Source/Editor/GUI/Timeline/Tracks/CurvePropertyTrack.cs index e6fc59355..7c7c9d9af 100644 --- a/Source/Editor/GUI/Timeline/Tracks/CurvePropertyTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/CurvePropertyTrack.cs @@ -457,6 +457,13 @@ namespace FlaxEditor.GUI.Timeline.Tracks if (Curve != null && Curve.Visible) Curve.OnKeyframesDelete(editor); } + + /// + public void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + if (Curve != null && Curve.Visible) + Curve.OnKeyframesMove(editor, control, location, start, end); + } } /// diff --git a/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs b/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs index fe2b52c9e..3e9e0fefb 100644 --- a/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/EventTrack.cs @@ -438,5 +438,12 @@ namespace FlaxEditor.GUI.Timeline.Tracks if (Events != null && Events.Visible) Events.OnKeyframesDelete(editor); } + + /// + public void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + if (Events != null && Events.Visible) + Events.OnKeyframesMove(editor, control, location, start, end); + } } } diff --git a/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs b/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs index 930e310a7..c78f96fea 100644 --- a/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/KeyframesPropertyTrack.cs @@ -418,5 +418,12 @@ namespace FlaxEditor.GUI.Timeline.Tracks if (Keyframes != null && Keyframes.Visible) Keyframes.OnKeyframesDelete(editor); } + + /// + public void OnKeyframesMove(IKeyframesEditor editor, ContainerControl control, Vector2 location, bool start, bool end) + { + if (Keyframes != null && Keyframes.Visible) + Keyframes.OnKeyframesMove(editor, control, location, start, end); + } } }