JD2022-TU1/main/tools/framework/JD.Sequencers/Times/SequencerDraggingTool.cs

210 lines
6.4 KiB
C#

using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using JD.Collections;
using JD.Kernel.Classes;
using JD.Kernel.Interfaces;
using JD.Kernel.StaticHelpers;
using JD.Sequencers.Controls;
using JD.Sequencers.Tools;
using JD.Sequencers.Windowlesses;
namespace JD.Sequencers.Times
{
public class SequencerDraggingTool : DraggingTool
{
#region Variables
private readonly Timeline _timeline;
private readonly Scope _suspendCloneOnDrag = new Scope();
private Track _trackOnStart = null;
private static bool _moveControlsOnSingleAxis = false;
private Axis _lockedAxis = Axis.None;
private enum Axis
{
Horizontal,
Vertical,
None
}
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
public SequencerDraggingTool(WindowlessContainer owner, Timeline timeline)
: base(owner)
{
Throw.IfNull(timeline, "timeline");
_timeline = timeline;
Selection.CollectionChanged += SelectionOnCollectionChanged;
}
private void SelectionOnCollectionChanged(object sender, CollectionChangedEventArgs<WindowlessControl> e)
{
if (IsStarted && e.Action != CollectionChangeAction.EndUpdated)
{
End();
using (SuspendCloneOnDrag.Begin())
{
var axisLocked = _lockedAxis;
Start();
_lockedAxis = axisLocked;
}
}
}
#endregion
#region Properties
public Timeline Timeline
{
get { return _timeline; }
}
public Scope SuspendCloneOnDrag
{
get { return _suspendCloneOnDrag; }
}
public static bool MoveControlsOnSingleAxis
{
get { return _moveControlsOnSingleAxis; }
set { _moveControlsOnSingleAxis = value; }
}
#endregion
#region Methods
protected internal override void Start()
{
if (IsShiftPressed && !SuspendCloneOnDrag.InScope)
{
CloneOnDrag();
}
_lockedAxis = Axis.None;
_trackOnStart = Container.FindControl<Track>(Container.LastMouseDownEventArgs.Location);
base.Start();
}
private void CloneOnDrag()
{
var clones = Selection.ToArray().Select(CloneControl);
Selection.Select(clones);
}
private WindowlessControl CloneControl(WindowlessControl control)
{
var cloneable = control as ICloneable<WindowlessControl>;
var clone = control;
if (cloneable != null)
{
clone = cloneable.Clone();
}
return clone ?? control;
}
protected override void MoveSelection(ref Point newPosition, Point oldPosition)
{
if (MoveControlsOnSingleAxis)
{
MoveSelectionSingleAxis(ref newPosition, oldPosition);
}
else
{
MoveSelectionBothAxis(ref newPosition, oldPosition);
}
}
private void MoveSelectionBothAxis(ref Point newPosition, Point oldPosition)
{
float newPositionInTimeUnits = Timeline.PixelToTime(newPosition.X, false);
float oldPositionInTimeUnits = Timeline.PixelToTime(oldPosition.X, false);
if (CanMoveControl(CurrentControl))
{
MoveImpl(ref newPositionInTimeUnits, oldPositionInTimeUnits);
}
newPosition = new Point(Timeline.TimeToPixel(newPositionInTimeUnits), newPosition.Y);
}
private void MoveSelectionSingleAxis(ref Point newPosition, Point oldPosition)
{
float newPositionInTimeUnits = Timeline.PixelToTime(newPosition.X, false);
float oldPositionInTimeUnits = Timeline.PixelToTime(oldPosition.X, false);
var track = Container.FindControl<Track>(newPosition);
//We check on which axis the drag occurs
if (_lockedAxis == Axis.None && track != _trackOnStart)
{
_lockedAxis = Axis.Vertical;
}
else if (_lockedAxis == Axis.None && System.Math.Abs(newPosition.X - InitialMovePosition.X) > SystemInformation.DragSize.Width)
{
_lockedAxis = Axis.Horizontal;
}
if (_lockedAxis == Axis.Horizontal)
{
newPosition.Y = InitialMovePosition.Y;
MoveImpl(ref newPositionInTimeUnits, oldPositionInTimeUnits);
}
else if (_lockedAxis == Axis.Vertical)
{
newPositionInTimeUnits = Timeline.PixelToTime(InitialMovePosition.X, false);
foreach (IMovable selectedMovable in Selection.OfType<IMovable>())
{
selectedMovable.Move(newPositionInTimeUnits - oldPositionInTimeUnits);
}
}
else
{
MoveImpl(ref newPositionInTimeUnits, oldPositionInTimeUnits);
}
newPosition = new Point(Timeline.TimeToPixel(newPositionInTimeUnits), newPosition.Y);
}
private void MoveImpl(ref float newPos, float oldPos)
{
float originalDelta = newPos - oldPos;
float snappedDelta = originalDelta;
float diff = Timeline.MinorInterval;
IEnumerable<IMovable> selectedMovables = Selection.OfType<IMovable>();
if (Timeline.ShouldSnap)
{
((IMovable)CurrentControl).Snap_Self(originalDelta, ref snappedDelta, ref diff);
}
foreach (IMovable selectedMovable in selectedMovables)
{
selectedMovable.Snap_Bounds(originalDelta, ref snappedDelta, ref diff);
}
foreach (IMovable selectedMovable in selectedMovables)
{
selectedMovable.Move(snappedDelta);
}
newPos = oldPos + snappedDelta;
}
private static bool CanMoveControl(WindowlessControl control)
{
return control is IMovable movable &&
movable.IsMoveAllowed;
}
#endregion
}
}