169 lines
6.3 KiB
C#
169 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
using JD.Application.View.Timeline;
|
|
using JD.Application.View.WindowLess;
|
|
using JD.Audio.Annotations;
|
|
using JD.Kernel.Structs;
|
|
using TeaBox;
|
|
|
|
namespace JD.Application.View.Tracks
|
|
{
|
|
/// <summary>
|
|
/// Paints the color in the background of the tracks.
|
|
/// </summary>
|
|
public class SongBackground : OverlappingTrack
|
|
{
|
|
/// <summary>
|
|
/// Constructor.
|
|
/// </summary>
|
|
public SongBackground(global::JD.Sequencers.Times.Timeline timeline)
|
|
: base(timeline)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// When set, the colors are only paint inside the active area.
|
|
/// </summary>
|
|
public Range<BeatUnit> ActiveArea
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
if (Wave != null)
|
|
{
|
|
PaintSongParts(e, Bounds, Wave.Annotations, Timeline);
|
|
PaintVideoSections(e, Bounds, Wave.Annotations, Timeline);
|
|
|
|
var bounds = Bounds;
|
|
bounds.Height--; // Do not paint over the track line.
|
|
bounds.Intersect(e.ClipRectangle);
|
|
BeatsGrid.PaintMeasure(e.Graphics, bounds, Timeline);
|
|
base.OnPaint(e);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Paints each part of the song with a light gradient that spans through all tracks.
|
|
/// </summary>
|
|
public virtual void PaintSongParts(PaintEventArgs eventArgs, Rectangle bounds, AnnotationCollection annotations, global::JD.Sequencers.Times.Timeline timeline, int alpha = 255)
|
|
{
|
|
var sections = annotations.SongSections;
|
|
|
|
for (int i = 0; i < sections.Count; i++)
|
|
{
|
|
SongSection section = sections[i];
|
|
BeatUnit end = timeline.Wave().UnitConverter.End(section);
|
|
|
|
int colorModulation = CountSameSectionType(i, sections)%2 == 0 ? 0 : 35;
|
|
Color baseColor = sections[i].Type.Color().Add(colorModulation);
|
|
|
|
Color colorWithAlpha = Color.FromArgb(alpha, baseColor);
|
|
|
|
var sectionRange = new Range<BeatUnit>(section.Time, end);
|
|
sectionRange = ClampToActiveArea(sectionRange);
|
|
|
|
if (!sectionRange.IsEmpty)
|
|
{
|
|
PaintSection(eventArgs, timeline, bounds, colorWithAlpha, sectionRange);
|
|
}
|
|
}
|
|
|
|
PaintActiveArea(eventArgs, bounds, timeline);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Paints the start beat/end beat section on the track
|
|
/// </summary>
|
|
private void PaintVideoSections(PaintEventArgs eventArgs, Rectangle bounds, AnnotationCollection annotations, global::JD.Sequencers.Times.Timeline timeline)
|
|
{
|
|
var sections = annotations.SongSections;
|
|
|
|
if (sections.Count > 0)
|
|
{
|
|
var videoIntro = ClampToActiveArea(new Range<BeatUnit>(annotations.StartBeat, sections[0].Time));
|
|
PaintSection(eventArgs, timeline, bounds, Color.SlateGray, videoIntro);
|
|
|
|
var videoOutro = ClampToActiveArea(new Range<BeatUnit>(timeline.Wave().UnitConverter.End(sections[sections.Count - 1]), annotations.EndBeat));
|
|
PaintSection(eventArgs, timeline, bounds, Color.SlateGray, videoOutro);
|
|
}
|
|
}
|
|
|
|
protected void PaintActiveArea(PaintEventArgs eventArgs, Rectangle bounds, global::JD.Sequencers.Times.Timeline timeline)
|
|
{
|
|
if (!ActiveArea.IsEmpty)
|
|
{
|
|
PaintSection(eventArgs, timeline, bounds, Color.Gray, new Range<BeatUnit>(timeline.VisibleStartBeat(), ActiveArea.Min));
|
|
PaintSection(eventArgs, timeline, bounds, Color.Gray, new Range<BeatUnit>(ActiveArea.Max, timeline.VisibleEndBeat()));
|
|
|
|
using (var pen = new Pen(Color.Black, 2))
|
|
{
|
|
int x = timeline.TimeToPixel(ActiveArea.Min);
|
|
eventArgs.Graphics.DrawLine(pen, x, bounds.Top, x, bounds.Bottom);
|
|
|
|
x = timeline.TimeToPixel(ActiveArea.Max);
|
|
eventArgs.Graphics.DrawLine(pen, x, bounds.Top, x, bounds.Bottom);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void PaintSection(PaintEventArgs eventArgs, global::JD.Sequencers.Times.Timeline timeline, Rectangle backGroundBounds, Color color, Range<BeatUnit> sectionRange)
|
|
{
|
|
PaintSection(eventArgs, backGroundBounds, color, timeline.TimeToPixel(sectionRange.Min), timeline.TimeToPixel(sectionRange.Max));
|
|
}
|
|
|
|
protected Range<BeatUnit> ClampToActiveArea(Range<BeatUnit> range)
|
|
{
|
|
var activeArea = ActiveArea;
|
|
|
|
if (activeArea.IsEmpty)
|
|
{
|
|
return range;
|
|
}
|
|
|
|
return activeArea.ClampRange(range);
|
|
}
|
|
|
|
protected static void PaintSection(PaintEventArgs eventArgs, Rectangle backGroundBounds, Color color, int pixelStart, int pixelEnd)
|
|
{
|
|
var toPaint = backGroundBounds;
|
|
toPaint.X = pixelStart;
|
|
toPaint.Width = pixelEnd - pixelStart;
|
|
|
|
if (toPaint.IntersectsWith(eventArgs.ClipRectangle))
|
|
{
|
|
using (var brush = CreateBrush(backGroundBounds, color))
|
|
{
|
|
eventArgs.Graphics.FillRectangle(brush, toPaint);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected static int CountSameSectionType(int songSectionIndex, IList<SongSection> sections)
|
|
{
|
|
SongSectionType type = sections[songSectionIndex].Type;
|
|
|
|
int i = songSectionIndex - 1;
|
|
while (i >= 0 && sections[i].Type == type)
|
|
{
|
|
i--;
|
|
}
|
|
return songSectionIndex - i - 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use a small gradient going from lighter to darker.
|
|
/// </summary>
|
|
private static LinearGradientBrush CreateBrush(Rectangle bounds, Color baseColor)
|
|
{
|
|
return new LinearGradientBrush(new Rectangle(0, bounds.Top, 1, bounds.Height),
|
|
baseColor.Add(40),
|
|
baseColor.Add(-25), LinearGradientMode.Vertical);
|
|
}
|
|
}
|
|
}
|