JD2022-TU1/main/tools/framework/JD.Timeline/Dance/PictogramScrollingPad.cs

163 lines
6.6 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using JD.Application.Utils;
using JD.Core.Collections;
using JD.Kernel.Structs;
using JD.Timeline.Document;
using JD.Timeline.Model.Clips;
using JD.Timeline.View.ClipView;
using TeaBox;
using TeaBox.ObjectModel;
using JD.Serialization;
using LinearGradientBrush = System.Drawing.Drawing2D.LinearGradientBrush;
namespace JD.Timeline.Dance
{
public class PictogramScrollingPad : AbstractPadContent
{
private readonly PictogramScrollingControl _control = new PictogramScrollingControl();
public PictogramScrollingPad()
{
TeaBox.ObjectModel.Application.Main.Views.SelectedItemChanged += Views_SelectedItemChanged;
Views_SelectedItemChanged(null, null);
}
public override Control Control
{
get { return _control; }
}
#region Methods
private void Views_SelectedItemChanged(object sender, EventArgs e)
{
var view = TeaBox.ObjectModel.Application.Main.Views.SelectedItem as TapeDocumentView;
if (view != null)
{
_control.ClipViewControl = view.ClipView;
}
else
{
_control.ClipViewControl = null;
}
}
#endregion
}
class PictogramScrollingControl : Control
{
private ClipViewControl _clipViewControl;
public PictogramScrollingControl()
{
//BackColor = System.Drawing.Color.DarkGray;
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw |
ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer, true);
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.FillRectangle(new LinearGradientBrush(Bounds, System.Drawing.Color.WhiteSmoke, System.Drawing.Color.FromArgb(200, 235, 245), LinearGradientMode.Vertical), Bounds);
if (ClipViewControl == null)
return;
var scrollDurationInBeats = (float)PictogramScrollingUtils.GetScrollDurationInBeats(ClipViewControl.Player.CurrentTime, ClipViewControl.Tape.TryGetWave().UnitConverter);
var beatRange = new Range<float>(ClipViewControl.Player.CurrentTime, ClipViewControl.Player.CurrentTime + scrollDurationInBeats);
//We compute the range in beats of every pictograms
var pictoRanges = from clip in ClipViewControl.Tape.Clips.OfType<PictogramClip>()
let stopBeat = clip.StartBeat + PictogramScrollingUtils.GetBeatsPerPixel(_clipViewControl.Tape.DancePlayersCount, clip.StartBeat, _clipViewControl.Tape.TryGetWave().UnitConverter) * clip.Model.BitmapHandler().PictoExpectedSize.Width
select new
{
Clip = clip,
Range = new Range<float>(clip.StartBeat, (float)stopBeat)
};
//We check wich pictograms have to be painted
var pictosToDisplay = pictoRanges.Where(x => beatRange.Intersects(x.Range));
foreach (var picto in pictosToDisplay)
{
//When the control is small we use the pictogram thumbnail instead of the full resolution one
var bitmap = Size.Height > 200 ? picto.Clip.Model.BitmapHandler().Bitmap : picto.Clip.Model.BitmapHandler().BitmapThumbnail;
if (bitmap == null)
continue;
lock (bitmap)
{
try
{
//We compute all the pixels coordinates of the pictogram in current control
var x = Size.Width * (picto.Clip.StartBeat - beatRange.Min) / beatRange.Width();
var width = Size.Width * picto.Range.Width() / beatRange.Width();
var heigth = width * bitmap.Height / bitmap.Width;
var y = (Size.Height - heigth) / 2F;
//We compute the progress of the disappearing of the pictogram, and apply opacity modification and vertical translation
//in case it's disappearing
float disappearProgress = x < 0 ? -x / width : 0;
float opacity = Math.Min(1, 1 - 1.8F * disappearProgress);
if (disappearProgress > 0)
{
x = 0;
y -= 0.4F * heigth * disappearProgress;
}
//We apply an opacity on the bitmap
var colormatrix = new ColorMatrix { Matrix33 = opacity };
var imgAttribute = new ImageAttributes();
imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
pe.Graphics.DrawImage(bitmap, new Rectangle((int)x, (int)y, (int)width, (int)heigth), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, imgAttribute);
}
catch (InvalidOperationException)
{
// Image is not thread safe,
// when used in another thread that does not lock, just do not paint!
}
}
}
}
public ClipViewControl ClipViewControl
{
get { return _clipViewControl; }
set
{
if (_clipViewControl != null)
{
_clipViewControl.Player.TimeChanged -= Player_TimeChanged;
_clipViewControl.Tape.Clips.ItemChanged -= Clips_ItemChanged;
}
_clipViewControl = value;
if (_clipViewControl != null)
{
_clipViewControl.Player.TimeChanged += Player_TimeChanged;
_clipViewControl.Tape.Clips.ItemChanged += Clips_ItemChanged;
}
Invalidate();
}
}
void Clips_ItemChanged(object sender, ItemChangedEventArgs<Clip> args)
{
//When the start time of a clip change, we want to refresh the painting
if (args.PropertyName == "StartTime")
{
Invalidate();
}
}
void Player_TimeChanged(object sender, EventArgs e)
{
Invalidate();
}
}
}