// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using FlaxEditor.GUI.Timeline.Undo; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.GUI.Timeline.GUI { /// /// Timeline ending edge control that can be used to modify timeline duration with a mouse. /// /// class TimelineEdge : Control { private Timeline _timeline; private bool _isMoving; private Float2 _startMoveLocation; private int _startMoveDuration; private bool _isStart; private bool _canEdit; /// /// Initializes a new instance of the class. /// /// The parent timeline. /// True if edge edits the timeline start, otherwise it's for the ending cap. /// True if can edit the edge. public TimelineEdge(Timeline timeline, bool isStart, bool canEdit) { AutoFocus = false; _timeline = timeline; _isStart = isStart; _canEdit = canEdit; } /// public override void Draw() { var style = Style.Current; var timeAxisOverlap = Timeline.HeaderTopAreaHeight * 0.5f; var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y - timeAxisOverlap; var moveColor = style.ProgressNormal; var thickness = 2.0f; var borderColor = _isMoving ? moveColor : (IsMouseOver && _canEdit ? Color.Yellow : style.BorderNormal); Render2D.FillRectangle(new Rectangle((Width - thickness) * 0.5f, timeAxisHeaderOffset, thickness, Height - timeAxisHeaderOffset), borderColor); } /// public override bool OnMouseDown(Float2 location, MouseButton button) { if (base.OnMouseDown(location, button)) return true; if (button == MouseButton.Left && _canEdit) { _isMoving = true; _startMoveLocation = Root.MousePosition; _startMoveDuration = _timeline.DurationFrames; StartMouseCapture(true); return true; } return false; } /// public override void OnMouseMove(Float2 location) { if (_isMoving && !_timeline.RootWindow.Window.IsMouseFlippingHorizontally) { var moveLocation = Root.MousePosition; var moveLocationDelta = moveLocation - _startMoveLocation + _timeline.Root.TrackingMouseOffset.X; var moveDelta = (int)(moveLocationDelta.X / (Timeline.UnitsPerSecond * _timeline.Zoom) * _timeline.FramesPerSecond); var durationFrames = _timeline.DurationFrames; if (_isStart) { // TODO: editing timeline start frame? } else { _timeline.DurationFrames = _startMoveDuration + moveDelta; _timeline.MediaBackground.HScrollBar.Value = _timeline.MediaBackground.HScrollBar.Maximum; } if (_timeline.DurationFrames != durationFrames) { _timeline.MarkAsEdited(); } } else { base.OnMouseMove(location); } } /// public override bool OnMouseUp(Float2 location, MouseButton button) { if (button == MouseButton.Left && _isMoving) { EndMoving(); return true; } return base.OnMouseUp(location, button); } /// public override void OnEndMouseCapture() { if (_isMoving) { EndMoving(); } base.OnEndMouseCapture(); } /// public override void OnLostFocus() { if (_isMoving) { EndMoving(); } base.OnLostFocus(); } private void EndMoving() { var duration = _timeline.DurationFrames; if (duration != _startMoveDuration) { _timeline.DurationFrames = _startMoveDuration; using (new TimelineUndoBlock(_timeline)) _timeline.DurationFrames = duration; } _isMoving = false; _timeline.MediaBackground.HScrollBar.Value = _timeline.MediaBackground.HScrollBar.Maximum; EndMouseCapture(); } /// public override void OnDestroy() { if (_isMoving) { EndMoving(); } _timeline = null; base.OnDestroy(); } } }