using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using JD.Application.View.Timeline; using JD.Audio.Annotations; using JD.Collections.Extensions; using JD.Maths.Utils; using JD.VideoPlayer.Project; using TeaBox; using JD.Serialization; namespace JD.Timeline.View.ClipView.Widgets { public class DanceEditorClipWidget : ClipWidget { #region Variables private List _toolbarItems = new List(); protected static readonly Color SelectionBorderColor = Color.FromArgb(255, 200, 0); protected static readonly Color SelectionFillColor = Color.FromArgb(100, SelectionBorderColor); protected static readonly Pen SelectionBorderPen = new Pen(SelectionBorderColor, 2); protected static readonly Pen PlayingBorderPen = new Pen(Color.Firebrick, 2); protected static readonly Color WarningFillColor = Color.FromArgb(255, 255, 0); #endregion #region Constructor public DanceEditorClipWidget(Clip model) : base(model) { } #endregion #region Properties public List ToolbarItems { get { return _toolbarItems; } set { _toolbarItems = value; } } /// /// Whether the timeline cursors is currently over the clip. /// protected bool IsPlaying { get { var currentBeat = Timeline.BeatFromTimeUnit(Timeline.TimeCursor.Time).Value; return currentBeat.IsBetween(Model.StartBeat, Model.StopBeat); } } #endregion #region Methods /// /// Default painting for Dance Editor clips /// protected override void OnPaint(PaintEventArgs e) { SetupBounds(); var graphics = e.Graphics; if (Model.CollisionsWithOther) { DrawClipWithWarning(graphics); return; } FillBackground(graphics, Bounds, BackgroundColor); DrawClipType(Model.Type, graphics); if (Selected) { FillBackground(graphics, Bounds, SelectionFillColor); DrawRectangle(graphics, Bounds, SelectionBorderPen); } else { DrawEdge(graphics, Bounds); } OnPaintChildControls(e); } /// /// Method used to draw clip when there is a warning /// protected void DrawClipWithWarning(Graphics graphics, int additionalOffsetX = 0, int additionalOffsetY = 0) { var image = Properties.Resources.Icon_16x16_warning; var imageBounds = new Rectangle(Bounds.X + 2 + additionalOffsetX, Bounds.Top + 2 + additionalOffsetY, image.Width, image.Height); ; int right = Bounds.Right; if (imageBounds.Right > right) { imageBounds.Width -= imageBounds.Right - right; } if (image != null) { graphics.DrawImageUnscaledAndClipped(image, imageBounds); } DrawNotificationIcons(graphics); } /// /// Drawing of notification icons /// protected void DrawNotificationIcons(Graphics graphics) { foreach (var icon in ToolbarItems.Where(x => x.IsVisible())) { var bounds = GetBounds(icon); if (bounds.Width > 0) { graphics.DrawImage(icon.Bitmap(), bounds); } } } /// /// Returns the bounds of the notification icon. Used for drawing and mouse interaction. /// protected Rectangle GetBounds(ToolbarItem icon) { var icons = ToolbarItems.Where(x => x.IsVisible()).ToList(); while (icons.Count > 0 && icons.Sum(x => x.Width) > Bounds.Width) { var iconToRemove = icons.MaxElement(x => x.Priority); if (iconToRemove != null) { icons.Remove(iconToRemove); } } if (!icons.Contains(icon)) return new Rectangle(0,0,0,0); int left = Bounds.Right; foreach (var notificationIcon in icons) { left -= notificationIcon.Width; if (notificationIcon == icon) break; } return new Rectangle(left, Bounds.Top, icon.Width, icon.Height); } /// /// Handles click on notification icons /// public override void OnMouseClick(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { foreach (var notificationIcon in ToolbarItems) { if (GetBounds(notificationIcon).Contains(e.Location)) { ToolbarItem icon = notificationIcon; if (icon.OnClick != null) { TeaBox.ObjectModel.Application.Main.Dispatcher.DispatchAsync(() => icon.OnClick(),forceAsync: true); } } } } base.OnMouseClick(e); } #endregion #region Video Preview private float _lastPaintBeat; protected void PaintPictogram(Graphics graphics) { var destBounds = Bounds; destBounds.Height -= 10; destBounds.Y += 5; var currentBeat = Timeline.BeatFromTimeUnit(Timeline.TimeCursor.Time).Value; var isPlaying = IsPlaying; var wasPlaying = _lastPaintBeat.IsBetween(Model.StartBeat, Model.StopBeat); // While playing, refresh the cursor when moving over the clip. if (Math.Abs(_lastPaintBeat - currentBeat) > 0.001 && (isPlaying || wasPlaying)) { Invalidate(); } _lastPaintBeat = currentBeat; var beatToPaint = GetBeatToPaint(currentBeat); Model.Tape.VideoSpriteSheet().Paint(graphics, new BeatUnit(beatToPaint), destBounds); } protected virtual float GetBeatToPaint(float currentBeat) { if (currentBeat.IsBetween(Model.StartBeat, Model.StopBeat) && !IsDragging) { return currentBeat; } return Model.StartBeat; } #endregion } #region NotificationIcon /// /// Represents a notification icon on widget's top-right corner /// public class ToolbarItem { private Func _bitmap; public Func Bitmap { get { return _bitmap; } set { _bitmap = value; Width = value().Width; Height = value().Height; } } public int Width { get; private set; } public int Height { get; private set; } public Func IsVisible = () => true; public System.Action OnClick = () => { }; public uint Priority { get; set; } } #endregion }