123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- using BeatLyrics.Tool.Dialogs;
- using BeatLyrics.Tool.Models;
- using BeatLyrics.Tool.Utils;
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Drawing;
- using System.Linq;
- using System.Windows.Forms;
- namespace BeatLyrics.Tool.UserControls
- {
- internal partial class EditorUserControl : UserControl
- {
- private const int Grab = 3;
- private LyricDetailExt _hoverObj;
- private EditSide _hoverSide;
- private Point? _downPoint;
- private int _lastValue;
- private List<LyricDetailExt> _items = new List<LyricDetailExt>();
- private bool _lockDown;
- private int _playPos;
- private float _displayScale = 0.1f;
- private SpectrumAnalyzer.SaResult[] _spectrumData;
- private int _spectrumBlockInMs;
- private enum EditSide
- {
- None,
- Right,
- Body,
- }
- public float DisplayScale
- {
- get => _displayScale;
- set
- {
- _displayScale = value;
- Invalidate();
- }
- }
- public int PlayPos
- {
- get => _playPos;
- set
- {
- _playPos = value;
- Invalidate();
- }
- }
- [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public List<LyricDetailExt> Items
- {
- get => _items;
- set
- {
- _items = value;
- Invalidate();
- }
- }
- public bool LockDown
- {
- get => _lockDown;
- set
- {
- _lockDown = value;
- Invalidate();
- }
- }
- public double MinSaFreq { get; set; } = 80;
- public double MaxSaFreq { get; set; } = 2000;
- public double MinSaValue { get; set; } = -40;
- public double MaxSaValue { get; set; } = 0;
- public event EventHandler PosChangeBegin;
- public event EventHandler<int> PosChange;
- public event EventHandler PosChangeEnd;
- public LyricDetailExt GetPlayItem()
- {
- foreach (var item in Items)
- {
- if (item.TimeMs <= PlayPos && item.TimeMs + item.DurationMs > PlayPos) return item;
- }
- return null;
- }
- public string GetPlayText() => GetPlayItem()?.Text ?? "";
- public void SetSpectrumData(SpectrumAnalyzer.SaResult[] sa, int blockInMs)
- {
- _spectrumData = sa;
- _spectrumBlockInMs = blockInMs;
- Invalidate();
- }
- public EditorUserControl()
- {
- DoubleBuffered = true;
- InitializeComponent();
- }
- protected override void OnCreateControl()
- {
- base.OnCreateControl();
- if (DesignMode)
- {
- Items = new List<LyricDetailExt>
- {
- new LyricDetailExt { TimeMs = 0, DurationMs = 250, Text = "Abc"},
- new LyricDetailExt { TimeMs = 500, DurationMs = 500, Text = "Def"},
- new LyricDetailExt { TimeMs = 2000, DurationMs = 1000, Text = "Ghi"}
- };
- }
- }
- protected override void OnResize(EventArgs e)
- {
- base.OnResize(e);
- Invalidate();
- }
- private void EditorUserControl_Paint(object sender, PaintEventArgs e)
- {
- e.Graphics.ResetTransform();
- e.Graphics.Clear(LockDown ? Color.FromKnownColor(KnownColor.Control) : Color.White);
- var mid = Width / 2;
- var t = TimeSpan.FromMilliseconds(Math.Abs(PlayPos));
- var strPos = PlayPos < 0 ? $"-{t.Minutes:00}:{t.Seconds:00}.{t.Milliseconds:000}" : $"{t.Minutes:00}:{t.Seconds:00}.{t.Milliseconds:000}";
- var strPosSize = e.Graphics.MeasureString(strPos, Font);
- var offsetLeft = -PlayPos * DisplayScale + mid;
- var offsetTop = strPosSize.Height;
- e.Graphics.TranslateTransform(offsetLeft, offsetTop);
- if (_spectrumData != null) // Draw Spectrum background
- {
- var msDurHalf = Width / DisplayScale / 2;
- var beginBlockIndex = (int)(PlayPos - msDurHalf) / _spectrumBlockInMs;
- var endBlockIndex = (int)(PlayPos + msDurHalf) / _spectrumBlockInMs;
- if (beginBlockIndex < 0) beginBlockIndex = 0;
- if (endBlockIndex > _spectrumData.Length) endBlockIndex = _spectrumData.Length;
- var scaleHeight = Height - offsetTop;
- var valueRange = MaxSaValue - MinSaValue;
- var freqRange = MaxSaFreq - MinSaFreq;
- var blockWidth = _spectrumBlockInMs * DisplayScale;
- var rects = new List<Tuple<RectangleF, byte>>();
- for (var i = beginBlockIndex; i < endBlockIndex; i++)
- {
- var posX = i * blockWidth;
- var block = _spectrumData[i];
- var freqArray = block.FreqAxis.Where(p => p > MinSaFreq && p < MaxSaFreq).ToArray();
- var height = scaleHeight / freqArray.Length;
- foreach (var freq in freqArray)
- {
- var val = block.Values[Array.IndexOf(block.FreqAxis, freq)];
- var posY = scaleHeight * (1 - (freq - MinSaFreq) / freqRange);
- if (val < MinSaValue) continue;
- byte color;
- if (val > MaxSaValue) color = 255;
- else
- {
- var ratio = (val - MinSaValue) / valueRange;
- color = (byte)(255 * ratio);
- }
- rects.Add(new Tuple<RectangleF, byte>(new RectangleF(posX, (float)posY, blockWidth, height), color));
- }
- }
- foreach (var item in rects.Where(p => p != null).GroupBy(p => p.Item2).Where(p => p.Key > 0))
- {
- using Brush brush = new SolidBrush(Color.FromArgb(255 - item.Key, 255 - item.Key, 255));
- e.Graphics.FillRectangles(brush, item.Select(p => p.Item1).ToArray());
- }
- }
- foreach (var item in Items)
- {
- item.Box.X = (int)(item.TimeMs * DisplayScale);
- item.Box.Width = (int)(item.DurationMs * DisplayScale);
- item.Box.Height = 50;
- e.Graphics.DrawRectangle(Pens.Black, item.Box);
- var ts = TimeSpan.FromMilliseconds(item.TimeMs);
- var tw = TimeSpan.FromMilliseconds(item.DurationMs);
- var state = e.Graphics.Save();
- e.Graphics.TranslateTransform(5, 5);
- e.Graphics.DrawString($"{item.Text}" +
- $"{Environment.NewLine}{tw.TotalMilliseconds:N0}" +
- $"{Environment.NewLine}{ts.Minutes:00}:{ts.Seconds:00}.{ts.Milliseconds:000}", Font, Brushes.Black, item.Box.Location);
- e.Graphics.Restore(state);
- item.Hit.Y = (int)offsetTop;
- item.Hit.X = (int)(item.Box.Left + offsetLeft);
- item.Hit.Width = item.Box.Width;
- item.Hit.Height = item.Box.Height;
- }
- e.Graphics.ResetTransform();
- e.Graphics.DrawString(strPos, Font, Brushes.Black, mid - strPosSize.Width / 2, 0);
- e.Graphics.DrawLine(Pens.Red, mid, strPosSize.Height, mid, Height);
- }
- private void EditorUserControl_MouseMove(object sender, MouseEventArgs e)
- {
- if (!_downPoint.HasValue)
- {
- if (LockDown)
- {
- Cursor = Cursors.Default;
- _hoverSide = EditSide.None;
- }
- else
- {
- LyricDetailExt hover = null;
- foreach (var item in Items)
- {
- var hBox = item.Hit;
- if (e.Y >= hBox.Top && hBox.Bottom >= e.Y && e.X > hBox.Right - Grab && e.X < hBox.Right + Grab)
- {
- Cursor = Cursors.SizeWE;
- _hoverSide = EditSide.Right;
- hover = item;
- break;
- }
- if (hBox.Contains(e.Location))
- {
- Cursor = Cursors.SizeAll;
- _hoverSide = EditSide.Body;
- hover = item;
- break;
- }
- }
- if (hover != null)
- {
- _hoverObj = hover;
- }
- else
- {
- Cursor = Cursors.Default;
- _hoverSide = EditSide.None;
- _hoverObj = null;
- }
- }
- }
- else //drag ing
- {
- var hd = _downPoint.Value.X - e.X;
- switch (_hoverSide)
- {
- case EditSide.None:
- PlayPos = (int)(_lastValue + hd / DisplayScale);
- if (PlayPos < 0) PlayPos = 0;
- OnPosChange(PlayPos);
- break;
- case EditSide.Right:
- _hoverObj.DurationMs = (int)(_lastValue - hd / DisplayScale);
- if (_hoverObj.DurationMs < 10) _hoverObj.DurationMs = 10;
- break;
- case EditSide.Body:
- _hoverObj.TimeMs = (int)(_lastValue - hd / DisplayScale);
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- Invalidate();
- }
- }
- private void EditorUserControl_MouseDown(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Right)
- {
- var ctx = new ContextMenuStrip();
- if (_hoverObj != null)
- {
- ctx.Items.Add("Set Start").Click += delegate { _hoverObj.TimeMs = PlayPos; };
- ctx.Items.Add("Set End").Click += delegate { _hoverObj.DurationMs = PlayPos - _hoverObj.TimeMs; };
- ctx.Items.Add(new ToolStripSeparator());
- ctx.Items.Add("Set Start Follow All").Click += delegate
- {
- var moveMs = _hoverObj.TimeMs - PlayPos;
- var toMove = Items.Where(p => p.TimeMs >= _hoverObj.TimeMs).ToArray();
- foreach (var item in toMove)
- {
- item.TimeMs -= moveMs;
- }
- };
- ctx.Items.Add(new ToolStripSeparator());
- if (_hoverObj == GetPlayItem())
- {
- ctx.Items.Add("Split...").Click += delegate
- {
- new SplitForm(Items, _hoverObj, PlayPos).ShowDialog(this);
- Invalidate();
- };
- ctx.Items.Add(new ToolStripSeparator());
- }
- ctx.Items.Add("Remove").Click += delegate { Items.Remove(_hoverObj); };
- }
- else
- {
- ctx.Items.Add("Add").Click += delegate
- {
- ContextDialog.PopTextBox(MousePosition, "new", (result, s) =>
- {
- if (result == DialogResult.OK)
- {
- Items.Add(new LyricDetailExt
- {
- TimeMs = (int)(e.X / DisplayScale + PlayPos - Width / 2f / DisplayScale),
- DurationMs = 1000,
- Text = s,
- Box =
- {
- Height = 50,
- }
- });
- Items = Items.OrderBy(p => p.TimeMs).ToList();
- Invalidate();
- }
- });
- };
- }
- ctx.ItemClicked += delegate
- {
- Invalidate();
- };
- ctx.Show(MousePosition);
- return;
- }
- _downPoint = e.Location;
- switch (_hoverSide)
- {
- case EditSide.None:
- _lastValue = PlayPos;
- OnPosChangeBegin();
- break;
- case EditSide.Body:
- _lastValue = _hoverObj.TimeMs;
- break;
- case EditSide.Right:
- _lastValue = _hoverObj.DurationMs;
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- private void EditorUserControl_MouseDoubleClick(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Left)
- {
- if (_hoverObj != null)
- {
- var localVar = _hoverObj;
- ContextDialog.PopTextBox(PointToScreen(localVar.Hit.Location), localVar.Text, (result, s) =>
- {
- if (result == DialogResult.OK)
- {
- localVar.Text = s;
- Invalidate();
- }
- });
- }
- }
- }
- private void EditorUserControl_MouseUp(object sender, MouseEventArgs e)
- {
- if (_hoverSide == EditSide.None) OnPosChangeEnd();
- _downPoint = null;
- _lastValue = 0;
- }
- protected virtual void OnPosChange(int e)
- {
- PosChange?.Invoke(this, e);
- }
- protected virtual void OnPosChangeBegin()
- {
- PosChangeBegin?.Invoke(this, EventArgs.Empty);
- }
- protected virtual void OnPosChangeEnd()
- {
- PosChangeEnd?.Invoke(this, EventArgs.Empty);
- }
- }
- }
|