210 lines
6.4 KiB
C#
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
|
|
}
|
|
}
|