1
0
mirror of synced 2024-11-30 22:17:17 +01:00
TaikoSoundEditor/Commons/Controls/MusicOrderViewer.cs

584 lines
19 KiB
C#
Raw Normal View History

2023-07-28 21:28:05 +02:00
using System.Diagnostics;
using System.Drawing.Drawing2D;
using TaikoSoundEditor.Data;
2023-10-01 18:40:41 +02:00
using TaikoSoundEditor.Commons.Extensions;
2023-07-28 21:28:05 +02:00
using TaikoSoundEditor.Properties;
2023-10-01 18:40:41 +02:00
using TaikoSoundEditor.Commons.Utils;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using System.Linq;
using System;
using TaikoSoundEditor.Collections;
using System.Text.RegularExpressions;
2023-10-01 18:40:41 +02:00
namespace TaikoSoundEditor.Commons.Controls
2023-07-28 21:28:05 +02:00
{
public partial class MusicOrderViewer : UserControl
{
public MusicOrderViewer()
{
InitializeComponent();
typeof(Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.SetValue(MusicOrdersPanel, true);
2023-07-28 21:28:05 +02:00
}
internal WordList WordList { get; set; }
2023-10-01 18:40:41 +02:00
public List<SongCard> SongCards { get; } = new List<SongCard>();
2023-07-28 21:28:05 +02:00
2023-10-01 18:40:41 +02:00
public void AddSong(IMusicOrder mo)
2023-07-28 21:28:05 +02:00
{
2023-08-16 18:40:36 +02:00
var songCard = new SongCard(WordList, mo);
if (Config.MusicOrderSort == Config.MusicOrderSortValueNone)
{
SongCards.Add(songCard);
}
else if (Config.MusicOrderSort == Config.MusicOrderSortValueId)
{
SongCards.Add(songCard);
SongCards.Sort((c1, c2) => c1.MusicOrder.UniqueId.CompareTo(c2.MusicOrder.UniqueId));
2023-08-16 18:40:36 +02:00
}
else if (Config.MusicOrderSort == Config.MusicOrderSortValueGenre)
{
var firstInGenre = SongCards.Find(c => c.MusicOrder.Genre == mo.Genre);
if (firstInGenre == null)
{
SongCards.Add(songCard);
}
else
{
var index = SongCards.IndexOf(firstInGenre);
SongCards.Insert(index, songCard);
}
}
CurrentPage = CurrentPage;
2023-07-28 21:28:05 +02:00
}
2023-08-16 19:18:20 +02:00
public void RemoveAllSongs(int uniqueId)
{
SongCards.RemoveAll(c => c.MusicOrder.UniqueId == uniqueId);
Selection.RemoveWhere(c => c.MusicOrder.UniqueId == uniqueId);
CutSelection.RemoveWhere(c => c.MusicOrder.UniqueId == uniqueId);
PasteActive = CutSelection.Count > 0;
CutActive = RemoveActive = Selection.Count > 0;
if (!PasteActive) PasteMode = false;
CurrentPage = CurrentPage;
Invalidate();
}
2023-10-01 18:40:41 +02:00
public void RemoveSong(IMusicOrder mo)
2023-07-29 07:58:11 +02:00
{
SongCards.RemoveAll(c => c.MusicOrder == mo);
Selection.RemoveWhere(c => c.MusicOrder == mo);
CutSelection.RemoveWhere(c => c.MusicOrder == mo);
PasteActive = CutSelection.Count > 0;
2023-07-29 08:53:20 +02:00
CutActive = RemoveActive = Selection.Count > 0;
2023-07-29 07:58:11 +02:00
if (!PasteActive) PasteMode = false;
2023-07-29 08:53:20 +02:00
CurrentPage = CurrentPage;
2023-07-29 07:58:11 +02:00
Invalidate();
}
2023-07-28 21:28:05 +02:00
private int _CurrentPage = 0;
public int CurrentPage
{
get => _CurrentPage;
set
{
2023-07-29 08:53:20 +02:00
_CurrentPage = value.Clamp(0, PagesCount - 1);
2023-07-28 21:28:05 +02:00
PageLabel.Text = $"Page {_CurrentPage + 1} of {PagesCount}";
MusicOrdersPanel.Invalidate();
LeftButton.Enabled = _CurrentPage > 0;
RightButton.Enabled = _CurrentPage < PagesCount - 1;
}
}
public int PagesCount => (SongCards.Count + ItemsPerPage - 1) / ItemsPerPage;
private int _ItemsPerRow = 4;
private int _ItemsPerCol = 5;
public int ItemsPerRow
{
get => _ItemsPerRow;
set
{
_ItemsPerRow = value;
MusicOrdersPanel.Invalidate();
}
}
public int ItemsPerCol
{
get => _ItemsPerCol;
set
{
_ItemsPerCol = value;
MusicOrdersPanel.Invalidate();
}
}
public int ItemsPerPage => ItemsPerRow * ItemsPerCol;
private static int ItemsPadding = 3;
public void RefreshMusicOrdersPanel(Graphics g)
{
var cards = SongCards.Skip(CurrentPage * ItemsPerPage).Take(ItemsPerPage).ToArray();
int itemW = MusicOrdersPanel.Width / ItemsPerRow - 2 * ItemsPadding;
int itemH = MusicOrdersPanel.Height / ItemsPerCol - 2 * ItemsPadding;
var cursor = MusicOrdersPanel.PointToClient(Cursor.Position);
for (int r = 0; r < ItemsPerCol; r++)
{
for (int c = 0; c < ItemsPerRow; c++)
{
int index = r * ItemsPerRow + c;
var rect = new Rectangle(
c * (itemW + 2 * ItemsPadding) + ItemsPadding,
r * (itemH + 2 * ItemsPadding) + ItemsPadding,
itemW,
itemH);
if (index >= cards.Length)
{
if (index == cards.Length && rect.Contains(cursor) && PasteMode)
{
g.DrawLine(Pens.Black, rect.Left - 2, rect.Top, rect.Left - 2, rect.Top + rect.Height);
}
break;
}
var card = cards[index];
g.FillRectangle(new SolidBrush(card.Color), rect);
if(card.IsSelected)
{
g.DrawRectangle(Pens.Blue, rect.Left - 1, rect.Top - 1, rect.Width + 1, rect.Height + 1);
g.DrawRectangle(Pens.Green, rect.Left - 2, rect.Top - 2, rect.Width + 3, rect.Height + 3);
g.FillRectangle(new SolidBrush(Color.FromArgb(128, Color.White)), rect);
}
if(card.IsCut)
{
g.FillRectangle(new HatchBrush(HatchStyle.ForwardDiagonal, Color.White, card.Color), rect);
}
if (rect.Contains(cursor))
{
if (PasteMode)
{
g.DrawLine(Pens.Black, rect.Left - 2, rect.Top, rect.Left - 2, rect.Top + rect.Height);
}
else
{
g.FillRectangle(new SolidBrush(Color.FromArgb(192, Color.White)), rect);
}
}
var cardInfo = $"{card.Id} ({card.Genre})\n{card.Title}\n{card.Subtitle}";
g.DrawString(cardInfo, Font, Brushes.Black, rect);
}
}
}
2023-07-30 07:32:58 +02:00
private void MusicOrdersPanel_Resize(object sender, EventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
MusicOrdersPanel.Invalidate();
2023-07-30 07:32:58 +02:00
});
2023-07-28 21:28:05 +02:00
2023-07-30 07:32:58 +02:00
private void MusicOrdersPanel_Paint(object sender, PaintEventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
RefreshMusicOrdersPanel(e.Graphics);
2023-07-30 07:32:58 +02:00
});
2023-07-28 21:28:05 +02:00
private void LeftButton_Click(object sender, EventArgs e)
{
if (CurrentPage > 0) CurrentPage--;
}
private void RightButton_Click(object sender, EventArgs e)
{
if (CurrentPage < PagesCount - 1) CurrentPage++;
}
2023-07-30 07:32:58 +02:00
private void MusicOrdersPanel_MouseMove(object sender, MouseEventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
Invalidate();
2023-07-30 07:32:58 +02:00
});
2023-07-28 21:28:05 +02:00
2023-07-30 07:32:58 +02:00
private void MusicOrdersPanel_MouseLeave(object sender, EventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
Invalidate();
2023-07-30 07:32:58 +02:00
});
2023-07-28 21:28:05 +02:00
2023-10-01 18:40:41 +02:00
public HashSet<SongCard> Selection = new HashSet<SongCard>();
public HashSet<SongCard> CutSelection = new HashSet<SongCard>();
2023-07-28 21:28:05 +02:00
2023-07-30 07:32:58 +02:00
private void MusicOrdersPanel_MouseDown(object sender, MouseEventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
if (e.Button == MouseButtons.Right)
{
Select();
var cursor = e.Location;
2023-07-28 21:28:05 +02:00
int itemW = MusicOrdersPanel.Width / ItemsPerRow;
int itemH = MusicOrdersPanel.Height / ItemsPerCol;
2023-07-28 21:28:05 +02:00
int row = cursor.Y / itemH;
int col = cursor.X / itemW;
//Debug.WriteLine($"{row} {col}");
2023-07-28 21:28:05 +02:00
if (row < 0 || row >= ItemsPerCol || col < 0 || col >= ItemsPerRow)
return;
var index = CurrentPage * ItemsPerPage + row * ItemsPerRow + col;
if (index < 0 || index > SongCards.Count) return;
2023-07-28 21:28:05 +02:00
CardToClone = SongCards[index];
GenreCloneMenuStrip.Show(MusicOrdersPanel, cursor);
}
else
2023-07-28 21:28:05 +02:00
{
if (e.Button != MouseButtons.Left) return;
Select();
var cursor = e.Location;
2023-07-28 21:28:05 +02:00
int itemW = MusicOrdersPanel.Width / ItemsPerRow;
int itemH = MusicOrdersPanel.Height / ItemsPerCol;
int row = cursor.Y / itemH;
int col = cursor.X / itemW;
//Debug.WriteLine($"{row} {col}");
2023-07-28 21:28:05 +02:00
if (row < 0 || row >= ItemsPerCol || col < 0 || col >= ItemsPerRow)
return;
var index = CurrentPage * ItemsPerPage + row * ItemsPerRow + col;
if (PasteMode)
2023-07-28 21:28:05 +02:00
{
if (index < 0 || index > SongCards.Count) return;
SongCard before = null, after = null;
for (int i = index; i < SongCards.Count; i++)
if (!SongCards[i].IsCut)
{
before = SongCards[i];
break;
}
for (int i = index - 1; i >= 0; i--)
if (!SongCards[i].IsCut)
{
after = SongCards[i];
break;
}
string message = "Do you want to move the selected songs?";
if (before != null)
2023-07-28 21:28:05 +02:00
{
if (after != null && before != after)
{
message = $"Do you want to move the selected songs before {before.Id} and after {after.Id}?";
}
else
{
message = $"Do you want to move the selected songs before {before.Id}?";
}
2023-07-28 21:28:05 +02:00
}
else if (after != null)
2023-07-28 21:28:05 +02:00
{
message = $"Do you want to move the selected songs after {after.Id}?";
2023-07-28 21:28:05 +02:00
}
if (MessageBox.Show(message, "Move songs?", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
2023-07-28 21:28:05 +02:00
SongCards.RemoveAll(CutSelection.Contains);
var ix = after != null ? SongCards.IndexOf(after) + 1 : before != null ? SongCards.IndexOf(before) : 0;
SongCards.InsertRange(ix, CutSelection);
2023-07-28 21:28:05 +02:00
foreach (var c in CutSelection) c.IsCut = false;
CutSelection.Clear();
PasteMode = false;
PasteActive = false;
CutActive = RemoveActive = false;
MusicOrdersPanel.Invalidate();
2023-07-28 21:28:05 +02:00
return;
}
2023-07-28 21:28:05 +02:00
if (index < 0 || index >= SongCards.Count) return;
2023-07-28 21:28:05 +02:00
var card = SongCards[index];
2023-07-28 21:28:05 +02:00
if (Form.ModifierKeys == Keys.Control)
2023-07-28 21:28:05 +02:00
{
if (card.IsSelected)
{
card.IsSelected = false;
Selection.Remove(card);
}
else
{
card.IsSelected = true;
Selection.Add(card);
}
MusicOrdersPanel.Invalidate();
2023-07-28 21:28:05 +02:00
}
else
{
foreach (var sel in Selection)
{
sel.IsSelected = false;
}
Selection.Clear();
2023-07-28 21:28:05 +02:00
card.IsSelected = true;
Selection.Add(card);
MusicOrdersPanel.Invalidate();
2023-07-28 21:28:05 +02:00
}
CutActive = RemoveActive = Selection.Count > 0;
2023-07-28 21:28:05 +02:00
}
2023-07-30 07:32:58 +02:00
});
2023-07-28 21:28:05 +02:00
private bool _CutActive = false;
public bool CutActive
{
get => _CutActive;
set
{
_CutActive = value;
CutButton.BackgroundImage = CutActive ? Resources.ic_cut : Resources.ic_cut_gs;
CutButton.Enabled = CutActive;
}
}
private bool _PasteActive = false;
public bool PasteActive
{
get => _PasteActive;
set
{
_PasteActive = value;
PasteButton.BackgroundImage = PasteActive ? Resources.ic_paste : Resources.ic_paste_gs;
PasteButton.Enabled = PasteActive;
}
}
2023-07-29 08:53:20 +02:00
private bool _RemoveActive=false;
public bool RemoveActive
{
get => _RemoveActive;
set
{
_RemoveActive = value;
RemoveButton.BackgroundImage = RemoveActive ? Resources.ic_remove : Resources.ic_remove_gs;
RemoveButton.Enabled = RemoveActive;
}
}
2023-07-30 07:32:58 +02:00
private void CutButton_Click(object sender, EventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
PasteMode = false;
2023-07-30 07:32:58 +02:00
foreach (var card in CutSelection)
2023-07-28 21:28:05 +02:00
{
card.IsCut = false;
}
CutSelection.Clear();
2023-07-30 07:32:58 +02:00
foreach (var card in Selection)
2023-07-28 21:28:05 +02:00
{
card.IsCut = true;
card.IsSelected = false;
CutSelection.Add(card);
}
Selection.Clear();
PasteActive = CutSelection.Count > 0;
2023-07-29 08:53:20 +02:00
CutActive = RemoveActive = Selection.Count > 0;
2023-07-28 21:28:05 +02:00
MusicOrdersPanel.Invalidate();
2023-07-30 07:32:58 +02:00
});
2023-07-28 21:28:05 +02:00
private bool _PasteMode = false;
public bool PasteMode
{
get => _PasteMode;
set
{
_PasteMode = value;
PasteButton.FlatAppearance.BorderSize = _PasteMode ? 1 : 0;
}
2023-07-30 07:32:58 +02:00
}
2023-07-29 08:53:20 +02:00
2023-07-28 21:28:05 +02:00
2023-07-30 07:32:58 +02:00
private void PasteButton_Click(object sender, EventArgs e) => ExceptionGuard.Run(() =>
2023-07-28 21:28:05 +02:00
{
PasteMode = !PasteMode;
foreach (var card in Selection)
card.IsSelected = false;
Selection.Clear();
2023-07-29 08:53:20 +02:00
CutActive = RemoveActive = false;
MusicOrdersPanel.Invalidate();
2023-07-30 07:32:58 +02:00
});
2023-07-29 08:53:20 +02:00
public bool SongExists(int uniqueId) => SongCards.Any(c => c.MusicOrder.UniqueId == uniqueId);
2023-07-30 07:32:58 +02:00
private void RemoveButton_Click(object sender, EventArgs e) => ExceptionGuard.Run(() =>
2023-07-29 08:53:20 +02:00
{
var toRemove = Selection.ToList();
if (Selection.Count == 0)
return;
2023-07-30 07:32:58 +02:00
var message = $"Are you sure you want to remove {toRemove.Count} song{(toRemove.Count != 1 ? "s" : "")}?";
2023-07-29 08:53:20 +02:00
if (MessageBox.Show(message, "Remove?", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
2023-07-30 07:32:58 +02:00
foreach (var card in Selection)
2023-07-29 08:53:20 +02:00
{
SongCards.Remove(card);
CutSelection.Remove(card);
SongRemoved?.Invoke(this, card.MusicOrder);
}
Selection.Clear();
CutActive = RemoveActive = false;
PasteActive = CutSelection.Count > 0;
if (!PasteActive) PasteMode = false;
CurrentPage = CurrentPage;
2023-07-28 21:28:05 +02:00
MusicOrdersPanel.Invalidate();
2023-07-30 07:32:58 +02:00
});
2023-07-29 08:53:20 +02:00
2023-10-01 18:40:41 +02:00
public delegate void OnSongRemoved(MusicOrderViewer sender, IMusicOrder mo);
2023-07-29 08:53:20 +02:00
public event OnSongRemoved SongRemoved;
private void ListStartButton_Click(object sender, EventArgs e)
{
CurrentPage = 0;
MusicOrdersPanel.Invalidate();
}
private void ListEndButton_Click(object sender, EventArgs e)
{
CurrentPage = PagesCount - 1;
MusicOrdersPanel.Invalidate();
}
private void Left10Button_Click(object sender, EventArgs e)
{
CurrentPage -= 10;
MusicOrdersPanel.Invalidate();
}
private void Right10Button_Click(object sender, EventArgs e)
{
CurrentPage += 10;
MusicOrdersPanel.Invalidate();
}
2023-10-01 18:40:41 +02:00
public bool Locate(IMusicOrder mo)
{
var card = SongCards.Where(c => c.MusicOrder == mo).FirstOrDefault();
if (card == null) return false;
var index = SongCards.IndexOf(card);
Select(index);
return true;
}
private void Select(int index)
{
CurrentPage = index / ItemsPerPage;
SongCards[index].IsSelected = true;
Selection.Add(SongCards[index]);
CutActive = RemoveActive = true;
MusicOrdersPanel.Invalidate();
}
2023-10-01 18:40:41 +02:00
public delegate void OnSongDoubleClick(MusicOrderViewer sender, IMusicOrder mo);
public event OnSongDoubleClick SongDoubleClick;
2023-07-29 10:06:11 +02:00
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
2023-07-29 10:06:11 +02:00
if (keyData == (Keys.Control | Keys.X) || keyData == (Keys.Control | Keys.C))
{
//MessageBox.Show("Here?");
if(CutActive)
{
CutButton_Click(null, null);
}
return true;
}
if (keyData == (Keys.Control | Keys.V))
{
if(PasteActive)
{
PasteButton_Click(null, null);
}
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void MusicOrdersPanel_DoubleClick(object sender, EventArgs e)
{
var cursor = MusicOrdersPanel.PointToClient(Cursor.Position);
int itemW = MusicOrdersPanel.Width / ItemsPerRow;
int itemH = MusicOrdersPanel.Height / ItemsPerCol;
int row = cursor.Y / itemH;
int col = cursor.X / itemW;
//MessageBox.Show($"{row} {col}");
if (row < 0 || row >= ItemsPerCol || col < 0 || col >= ItemsPerRow)
return;
var index = CurrentPage * ItemsPerPage + row * ItemsPerRow + col;
//MessageBox.Show($"{index}");
if (index < 0 || index > SongCards.Count) return;
SongDoubleClick?.Invoke(this, SongCards[index].MusicOrder);
}
private SongCard CardToClone = null;
private void GenreCloneToolStripMenuItem_Click(object sender, EventArgs e)
{
if (CardToClone == null) return;
var genre = (Genre)Enum.Parse(typeof(Genre), (sender as ToolStripMenuItem).Text);
//MessageBox.Show(genre.ToString());
2023-10-01 18:40:41 +02:00
var newMO = DatatableTypes.Clone(CardToClone.MusicOrder);
newMO.Genre = genre;
AddSong(newMO);
}
2023-07-28 21:28:05 +02:00
}
}