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