154 lines
No EOL
4.9 KiB
C#
154 lines
No EOL
4.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using JD.Application.View.Misc;
|
|
using JD.Audio.SoundPlayer;
|
|
using JD.Collections;
|
|
using JD.Kernel.Structs;
|
|
using JD.Sequencers.Times;
|
|
using JD.Sequencers.Windowlesses;
|
|
using TeaBox;
|
|
using TeaBox.Core.Source.Gui;
|
|
|
|
namespace JD.Application.View
|
|
{
|
|
using RangeF = Range<float>;
|
|
|
|
/// <summary>
|
|
/// When the user drags a track item, this auto loops around the dragged item.
|
|
/// </summary>
|
|
public class AutoLoopBehavior : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Looping on less than one beat is not useful, its too fast and the user cannot see anything,
|
|
/// this makes sure that we use at least one complete beat to loop on.
|
|
/// </summary>
|
|
private const float MinimalLoopDuration = 1f;
|
|
private const float DefaultLoopDuration = 2f;
|
|
|
|
private readonly TrackView _trackView;
|
|
private PlayerLoop _loop;
|
|
private IEnumerable<LocalizedTrackItem> _itemsToLoopOn = Enumerable.Empty<LocalizedTrackItem>();
|
|
|
|
public AutoLoopBehavior(TrackView trackView)
|
|
{
|
|
_trackView = trackView;
|
|
|
|
trackView.Selection.CollectionChanged += Selection_CollectionChanged;
|
|
EditionOptions.LoopOnSelectionChanged +=EditionOptions_LoopOnSelectionChanged;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_trackView.Selection.CollectionChanged -= Selection_CollectionChanged;
|
|
EditionOptions.LoopOnSelectionChanged -= EditionOptions_LoopOnSelectionChanged;
|
|
}
|
|
|
|
public PlayerLoop Loop
|
|
{
|
|
get { return _loop; }
|
|
set { _loop = value; }
|
|
}
|
|
|
|
private IEnumerable<LocalizedTrackItem> ItemsToLoopOn
|
|
{
|
|
get { return _itemsToLoopOn; }
|
|
set
|
|
{
|
|
value = (value ?? Enumerable.Empty<LocalizedTrackItem>()).ToArray();
|
|
bool hadLoop = _itemsToLoopOn.Any();
|
|
|
|
foreach (var toLoop in _itemsToLoopOn)
|
|
{
|
|
toLoop.BoundsChanged -= toLoop_BoundsChanged;
|
|
toLoop.IsDraggingChanged -= toLoop_IsDraggingChanged;
|
|
}
|
|
|
|
_itemsToLoopOn = value;
|
|
|
|
foreach (var toLoop in _itemsToLoopOn)
|
|
{
|
|
toLoop.BoundsChanged += toLoop_BoundsChanged;
|
|
toLoop.IsDraggingChanged += toLoop_IsDraggingChanged;
|
|
}
|
|
|
|
UpdateLoopRange(hadLoop);
|
|
}
|
|
}
|
|
|
|
private void UpdateLoop()
|
|
{
|
|
ItemsToLoopOn = EditionOptions.LoopOnSelection ? _trackView.Selection.OfType<LocalizedTrackItem>().Where(item => item.SupportAutoLoop) : null;
|
|
}
|
|
|
|
private void UpdateLoopRange(bool hadLoop)
|
|
{
|
|
if (_loop == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RangeF loopRange = RangeF.Empty;
|
|
|
|
if (_itemsToLoopOn.Any())
|
|
{
|
|
var itemResizing = _itemsToLoopOn.FirstOrDefault(item => item.IsCurrentControl && item.DraggingEdges.IsIn(Edge.Left, Edge.Right));
|
|
if (itemResizing != null)
|
|
{
|
|
if (itemResizing.DraggingEdges == Edge.Left)
|
|
{
|
|
loopRange = new RangeF(itemResizing.Time, itemResizing.Time + DefaultLoopDuration);
|
|
}
|
|
else
|
|
{
|
|
loopRange = new RangeF(itemResizing.EndTime - DefaultLoopDuration, itemResizing.EndTime);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float min = _itemsToLoopOn.Min(x => x.Time);
|
|
float max = _itemsToLoopOn.Max(x => x.EndTime);
|
|
loopRange = new RangeF(min, max);
|
|
}
|
|
}
|
|
|
|
if (!loopRange.IsEmpty)
|
|
{
|
|
// Allow a minimal duration on markers (items without duration).
|
|
if (loopRange.Max - loopRange.Min < MinimalLoopDuration)
|
|
{
|
|
loopRange = new RangeF(loopRange.Min - MinimalLoopDuration, loopRange.Max + MinimalLoopDuration);
|
|
}
|
|
|
|
if (!Equals(_loop.Range, loopRange))
|
|
{
|
|
_loop.Range = loopRange;
|
|
}
|
|
}
|
|
else if (hadLoop)
|
|
{
|
|
_loop.Range = null;
|
|
}
|
|
}
|
|
|
|
void Selection_CollectionChanged(object sender, CollectionChangedEventArgs<WindowlessControl> e)
|
|
{
|
|
UpdateLoop();
|
|
}
|
|
|
|
void EditionOptions_LoopOnSelectionChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateLoop();
|
|
}
|
|
|
|
void toLoop_BoundsChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateLoop();
|
|
}
|
|
|
|
private void toLoop_IsDraggingChanged(object sender, EventArgs e)
|
|
{
|
|
UpdateLoop();
|
|
}
|
|
}
|
|
} |