Files
FlaxEngine/Source/Editor/GUI/Timeline/GUI/TimelineEdge.cs

197 lines
6.4 KiB
C#

// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Globalization;
using FlaxEditor.GUI.Timeline.Undo;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.GUI.Timeline.GUI
{
/// <summary>
/// Timeline ending edge control that can be used to modify timeline duration with a mouse.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
class TimelineEdge : Control
{
private Timeline _timeline;
private bool _isMoving;
private Float2 _startMoveLocation;
private int _startMoveDuration;
private bool _isStart;
private bool _canEdit;
/// <summary>
/// Initializes a new instance of the <see cref="TimelineEdge"/> class.
/// </summary>
/// <param name="timeline">The parent timeline.</param>
/// <param name="isStart">True if edge edits the timeline start, otherwise it's for the ending cap.</param>
/// <param name="canEdit">True if can edit the edge.</param>
public TimelineEdge(Timeline timeline, bool isStart, bool canEdit)
{
AutoFocus = false;
_timeline = timeline;
_isStart = isStart;
_canEdit = canEdit;
}
/// <inheritdoc />
public override void Draw()
{
var style = Style.Current;
var timeAxisOverlap = Timeline.HeaderTopAreaHeight * 0.5f;
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y - timeAxisOverlap;
var moveColor = style.SelectionBorder;
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);
if (_canEdit && _isMoving)
{
// TODO: handle start
string labelText;
switch (_timeline.TimeShowMode)
{
case Timeline.TimeShowModes.Frames:
labelText = _timeline.DurationFrames.ToString("###0", CultureInfo.InvariantCulture);
break;
case Timeline.TimeShowModes.Seconds:
labelText = _timeline.Duration.ToString("###0.##'s'", CultureInfo.InvariantCulture);
break;
case Timeline.TimeShowModes.Time:
labelText = TimeSpan.FromSeconds(_timeline.DurationFrames / _timeline.FramesPerSecond).ToString("g");
break;
default: throw new ArgumentOutOfRangeException();
}
Render2D.DrawText(style.FontSmall, labelText, style.Foreground, new Float2((Width - thickness) * 0.5f + 4, timeAxisHeaderOffset));
}
}
/// <inheritdoc />
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;
}
/// <inheritdoc />
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();
}
Cursor = CursorType.SizeWE;
}
else if (IsMouseOver && _canEdit)
{
Cursor = CursorType.SizeWE;
}
else
{
Cursor = CursorType.Default;
base.OnMouseMove(location);
}
}
/// <inheritdoc />
public override void OnMouseLeave()
{
Cursor = CursorType.Default;
base.OnMouseLeave();
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _isMoving)
{
EndMoving();
return true;
}
return base.OnMouseUp(location, button);
}
/// <inheritdoc />
public override void OnEndMouseCapture()
{
if (_isMoving)
{
EndMoving();
}
base.OnEndMouseCapture();
}
/// <inheritdoc />
public override void OnLostFocus()
{
if (_isMoving)
{
EndMoving();
}
Cursor = CursorType.Default;
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();
}
/// <inheritdoc />
public override void OnDestroy()
{
if (_isMoving)
{
EndMoving();
}
_timeline = null;
base.OnDestroy();
}
}
}