JD2022-TU1/main/tools/framework/JD.Application.TeaBox/View/AutoLoopBehavior.cs

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();
}
}
}