295 lines
7.7 KiB
C#
295 lines
7.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using JD.Collections;
|
|
using JD.Collections.Interfaces;
|
|
using JD.Kernel.StaticHelpers;
|
|
using JD.Sequencers.Times;
|
|
using JD.Sequencers.Windowlesses;
|
|
|
|
namespace JD.Sequencers.Controls
|
|
{
|
|
/// <summary>
|
|
/// A single track in the track view.
|
|
/// </summary>
|
|
public class Track : WindowlessControl
|
|
{
|
|
#region Variables
|
|
|
|
private readonly TrackItemCollection m_children;
|
|
private TrackView m_trackView;
|
|
|
|
private System.Drawing.Color m_color = SystemColors.AppWorkspace;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public Track()
|
|
{
|
|
m_children = new TrackItemCollection(Controls);
|
|
m_children.CollectionChanged += c_children_CollectionChanged;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public bool IsActiveTrack
|
|
{
|
|
get { return TrackView != null && TrackView.ActiveTrack == this; }
|
|
}
|
|
|
|
public System.Drawing.Color Color
|
|
{
|
|
get { return m_color; }
|
|
set
|
|
{
|
|
if (m_color != value)
|
|
{
|
|
m_color = value;
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
public IObservableList<TrackItem> Children
|
|
{
|
|
get { return m_children; }
|
|
}
|
|
|
|
public TrackView TrackView
|
|
{
|
|
get { return m_trackView; }
|
|
internal set
|
|
{
|
|
Throw.InvalidOperationIf(m_trackView != null && value != null, "Track is already owned by another track view");
|
|
m_trackView = value;
|
|
}
|
|
}
|
|
|
|
public Timeline Timeline
|
|
{
|
|
get { return TrackView != null ? TrackView.Timeline : null; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if the track is always on top and does not scroll.
|
|
/// </summary>
|
|
public bool Fixed
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public virtual void Initialize()
|
|
{
|
|
}
|
|
|
|
#region Painting
|
|
|
|
protected override void OnPaintSelf(System.Windows.Forms.PaintEventArgs e)
|
|
{
|
|
base.OnPaintSelf(e);
|
|
|
|
OnPaintBackground(e);
|
|
OnPaintBorder(e);
|
|
}
|
|
|
|
protected virtual void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
|
|
{
|
|
using (Brush backgroundBrush = new SolidBrush(IsActiveTrack ? System.Drawing.Color.FromArgb(50, SystemColors.Highlight) : Color))
|
|
{
|
|
e.Graphics.FillRectangle(backgroundBrush, Bounds);
|
|
}
|
|
}
|
|
|
|
protected virtual void OnPaintBorder(System.Windows.Forms.PaintEventArgs e)
|
|
{
|
|
using (var pen = new Pen(System.Drawing.Color.FromArgb(50, 0, 0, 0)))
|
|
{
|
|
e.Graphics.DrawLine(pen, Bounds.Left, Bounds.Bottom - 1, Bounds.Right, Bounds.Bottom - 1);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Layout
|
|
|
|
/// <summary>
|
|
/// Allows to automatically resize child bounds when painting
|
|
/// </summary>
|
|
public virtual void ComputeChildBounds(Graphics graphics)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called after all track size have been computed, allows to bake final position in track items.
|
|
/// </summary>
|
|
public virtual void FinalizeChildBounds(Graphics graphics)
|
|
{
|
|
}
|
|
|
|
private void RefreshChildrenBounds()
|
|
{
|
|
foreach (TrackItem item in Children)
|
|
{
|
|
RefreshTrackItemBounds(item);
|
|
}
|
|
}
|
|
|
|
private void RefreshTrackItemBounds(TrackItem item)
|
|
{
|
|
if (TrackView != null)
|
|
{
|
|
AlignTrackItemBounds(item);
|
|
}
|
|
else
|
|
{
|
|
item.Height = 0;
|
|
item.Location = new Point(item.Location.X, Bounds.Top);
|
|
}
|
|
}
|
|
|
|
protected virtual void AlignTrackItemBounds(TrackItem item)
|
|
{
|
|
switch (TrackView.TrackItemAlignment)
|
|
{
|
|
case TrackView.VerticalAlignment.Bottom:
|
|
item.Height = Height - TrackView.InnerTrackSpacing;
|
|
item.Location = new Point(item.Location.X, Bounds.Top + TrackView.InnerTrackSpacing);
|
|
break;
|
|
|
|
case TrackView.VerticalAlignment.Middle:
|
|
item.Height = Height - TrackView.InnerTrackSpacing - 1;
|
|
item.Location = new Point(item.Location.X, Bounds.Top + TrackView.InnerTrackSpacing / 2);
|
|
break;
|
|
|
|
case TrackView.VerticalAlignment.Top:
|
|
item.Height = Height - TrackView.InnerTrackSpacing;
|
|
item.Location = new Point(item.Location.X, Bounds.Top);
|
|
break;
|
|
|
|
default:
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
protected override void OnBoundsChanged(EventArgs e)
|
|
{
|
|
base.OnBoundsChanged(e);
|
|
RefreshChildrenBounds();
|
|
}
|
|
|
|
public void OnTimeScaleChanged()
|
|
{
|
|
OnVisibleRangeChanged();
|
|
}
|
|
|
|
public void OnTimeOffsetChanged()
|
|
{
|
|
OnVisibleRangeChanged();
|
|
}
|
|
|
|
protected virtual void OnVisibleRangeChanged()
|
|
{
|
|
foreach (TrackItem item in Children)
|
|
{
|
|
item.OnVisibleRangeChanged();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Event Handlers
|
|
|
|
private void c_children_CollectionChanged(object sender, CollectionChangedEventArgs<TrackItem> e)
|
|
{
|
|
m_children.Synchronize(e, RegisterTrackItem, UnregisterTrackItem);
|
|
}
|
|
|
|
private void RegisterTrackItem(TrackItem item)
|
|
{
|
|
item.Track = this;
|
|
item.Initialize();
|
|
RefreshTrackItemBounds(item);
|
|
item.SelectedChanged += item_SelectedChanged;
|
|
}
|
|
|
|
private void UnregisterTrackItem(TrackItem item)
|
|
{
|
|
item.SelectedChanged -= item_SelectedChanged;
|
|
item.Track = null;
|
|
}
|
|
|
|
private void item_SelectedChanged(object sender, EventArgs e)
|
|
{
|
|
// We sort items so that the selected item is always on top (easier to see)
|
|
TrackItem selectedItem = (TrackItem)sender;
|
|
|
|
if (selectedItem.Selected)
|
|
{
|
|
Controls.Sort(new SelectedItemComparer<WindowlessControl>(selectedItem));
|
|
}
|
|
}
|
|
|
|
#region Sorting
|
|
|
|
private class SelectedItemComparer<T> : IComparer<T>
|
|
{
|
|
#region Variables
|
|
|
|
private readonly T m_selectedItem;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public SelectedItemComparer(T selectedItem)
|
|
{
|
|
m_selectedItem = selectedItem;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Implementation of IComparer<TrackItem>
|
|
|
|
public int Compare(T x, T y)
|
|
{
|
|
bool xIsSelected = Equals(x, m_selectedItem);
|
|
bool yIsSelected = Equals(y, m_selectedItem);
|
|
|
|
if (xIsSelected)
|
|
{
|
|
return yIsSelected ? 0 : 1;
|
|
}
|
|
|
|
return yIsSelected ? -1 : 0;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Inner Types
|
|
|
|
private class TrackItemCollection : AttachedControlCollection<TrackItem>
|
|
{
|
|
public TrackItemCollection(IObservableList<WindowlessControl> originalCollection)
|
|
: base(originalCollection)
|
|
{
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|