superstar_v2/OverlayFormObj/OverlayForm.cs

2012 lines
76 KiB
C#
Raw Normal View History

2025-04-07 16:54:10 +08:00
using System.IO;
using System.Timers;
using DBObj;
using DualScreenDemo;
namespace OverlayFormObj
{
public partial class OverlayForm : Form
{
private string marqueeText = "這是跑馬燈文字示例 - 歡迎使用MediaPlayerForm!";
private Color marqueeTextColor = Color.White;
private string marqueeTextSecondLine = "";
private string marqueeTextThirdLine = "";
private int marqueeXPos;
private int marqueeXPosSecondLine;
private int marqueeXPosThirdLine;
private System.Windows.Forms.Timer marqueeTimer;
private Image backgroundImage;
private Image firstStickerImage;
private Image secondStickerImage;
private float firstStickerXPos;
private float secondStickerXPos;
private float imageYPos;
private int screenHeight;
private int topMargin;
private int bottomMargin;
public static System.Windows.Forms.Timer displayTimer = new System.Windows.Forms.Timer();
public static System.Timers.Timer songDisplayTimer = new System.Timers.Timer();
public static System.Timers.Timer unifiedTimer;
private System.Windows.Forms.Timer stickerTimer1 = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer stickerTimer2 = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer keyUpTimer = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer keyDownTimer = new System.Windows.Forms.Timer();
public Label standardKeyLabel;
private System.Windows.Forms.Timer standardKeyTimer = new System.Windows.Forms.Timer();
private System.Windows.Forms.Timer messageTimer = new System.Windows.Forms.Timer();
public Label maleKeyLabel;
public Label messageLabel;
private System.Windows.Forms.Timer maleKeyTimer;
public Label femaleKeyLabel;
private System.Windows.Forms.Timer femaleKeyTimer;
private System.Windows.Forms.Timer secondLineTimer;
private DateTime secondLineStartTime;
private const int secondLineDuration = 20000;
private Image qrCodeImage;
private bool showQRCode;
private System.Windows.Forms.Timer segmentSwitchTimer = new System.Windows.Forms.Timer();
private int currentSegmentIndex = 0;
private List<string> textSegments = new List<string>();
public enum MarqueeStartPosition
{
Middle,
Right
}
private static OverlayForm _mainForm;
public static OverlayForm MainForm
{
get { return _mainForm; }
private set { _mainForm = value; }
}
public static OverlayForm Instance { get; private set; }
2025-04-07 16:54:10 +08:00
public OverlayForm()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
MainForm = this;
Instance = this;
2025-04-07 16:54:10 +08:00
InitializeFormSettings();
ConfigureTimers();
InitializeLabels();
ConfigureSegmentTimer();
2025-04-10 14:16:34 +08:00
imageYPos = (screenHeight / 3) - 1024 / 6;
2025-04-07 16:54:10 +08:00
}
private void ConfigureSegmentTimer()
{
segmentSwitchTimer.Interval = 3000;
segmentSwitchTimer.Tick += (sender, e) =>
{
if (textSegments.Count > 1)
{
currentSegmentIndex = (currentSegmentIndex + 1) % textSegments.Count;
blackBackgroundPanel.Invalidate();
}
};
}
private void SplitSecondLineText(string text)
{
textSegments.Clear();
if (string.IsNullOrEmpty(text))
{
return;
}
if (text.Length <= 16)
{
textSegments.Add(text);
}
else
{
for (int i = 0; i < text.Length; i += 16)
{
int length = Math.Min(16, text.Length - i);
textSegments.Add(text.Substring(i, length));
}
}
currentSegmentIndex = 0;
}
private void InitializeMaleKeyTimer()
{
maleKeyTimer = new System.Windows.Forms.Timer();
maleKeyTimer.Interval = 3000;
maleKeyTimer.Tick += (s, e) =>
{
HideAllLabels();
};
}
private void InitializeFemaleKeyTimer()
{
femaleKeyTimer = new System.Windows.Forms.Timer();
femaleKeyTimer.Interval = 3000;
femaleKeyTimer.Tick += (s, e) =>
{
HideAllLabels();
};
}
private void AddCenteredPicture(Bitmap bitmap, int y)
{
int x = (this.Width - bitmap.Width) / 2;
AddPicture(bitmap, x, y);
}
private void AddPicture(Bitmap bitmap, int x, int y)
{
PictureBox pictureBox = new PictureBox
{
Image = bitmap,
Size = bitmap.Size,
BackColor = Color.Transparent,
Location = new Point(x, y)
};
this.Controls.Add(pictureBox);
pictureBox.BringToFront();
}
private Bitmap GenerateTextImage(string text, Font font, Color textColor, Color backgroundColor)
{
SizeF textSize;
using (Bitmap tempBitmap = new Bitmap(1, 1))
using (Graphics tempGraphics = Graphics.FromImage(tempBitmap))
{
textSize = tempGraphics.MeasureString(text, font);
}
// 創建一個稍大的位圖尺寸,以容納描邊
int padding = 4; // 描邊寬度
Bitmap bitmap = new Bitmap((int)textSize.Width + padding * 2, (int)textSize.Height + padding * 2);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(backgroundColor);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// 先繪製黑色描邊
using (Brush outlineBrush = new SolidBrush(Color.Black))
{
for (int x = -2; x <= 2; x++)
{
for (int y = -2; y <= 2; y++)
{
if (x != 0 || y != 0)
{
graphics.DrawString(text, font, outlineBrush,
new PointF(padding + x, padding + y));
}
}
}
}
// 繪製中心文字
using (Brush textBrush = new SolidBrush(textColor))
{
graphics.DrawString(text, font, textBrush,
new PointF(padding, padding));
}
}
// 修剪圖片邊緣空白
return TrimBitmap(bitmap);
}
private Bitmap TrimBitmap(Bitmap source)
{
Rectangle rect = FindContentBounds(source);
if (rect.Width == 0 || rect.Height == 0)
return source; // 防止圖片完全空白時崩潰
Bitmap trimmedBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(trimmedBitmap))
{
g.DrawImage(source, 0, 0, rect, GraphicsUnit.Pixel);
}
return trimmedBitmap;
}
private Rectangle FindContentBounds(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
int top = 0, left = 0, bottom = height - 1, right = width - 1;
bool found = false;
// 找到頂邊界
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (bmp.GetPixel(x, y).A > 0)
{
top = y;
found = true;
break;
}
}
if (found) break;
}
found = false;
// 找到底邊界
for (int y = height - 1; y >= 0; y--)
{
for (int x = 0; x < width; x++)
{
if (bmp.GetPixel(x, y).A > 0)
{
bottom = y;
found = true;
break;
}
}
if (found) break;
}
found = false;
// 找到左邊界
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (bmp.GetPixel(x, y).A > 0)
{
left = x;
found = true;
break;
}
}
if (found) break;
}
found = false;
// 找到右邊界
for (int x = width - 1; x >= 0; x--)
{
for (int y = 0; y < height; y++)
{
if (bmp.GetPixel(x, y).A > 0)
{
right = x;
found = true;
break;
}
}
if (found) break;
}
return Rectangle.FromLTRB(left, top, right + 1, bottom + 1);
}
public static void DisplayNumberAtTopLeft(string newText)
{
if (MainForm != null)
{
MainForm.Invoke(new System.Action(() =>
{
string currentText = MainForm.displayLabel.Text;
MainForm.nextSongLabel.Visible = false;
string combinedText = currentText + newText;
if (combinedText.Length > 6)
{
combinedText = combinedText.Substring(0, 6);
}
MainForm.displayLabel.Text = combinedText;
MainForm.nextSongLabel.Visible = false;
displayTimer.Stop();
displayTimer.Start();
}));
}
}
private void InitializeFormSettings()
{
this.FormBorderStyle = FormBorderStyle.None;
this.TopMost = true;
this.BackColor = Color.Magenta;
this.TransparencyKey = this.BackColor;
this.Height = 50;
if (Screen.AllScreens.Length > 1)
{
var secondaryScreen = Screen.AllScreens[1];
this.Width = secondaryScreen.Bounds.Width;
this.Location = new Point(secondaryScreen.Bounds.Location.X, this.Location.Y);
screenHeight = secondaryScreen.Bounds.Height;
topMargin = screenHeight / 3;
bottomMargin = screenHeight * 2 / 3;
}
else
{
this.Width = Screen.PrimaryScreen.Bounds.Width;
this.screenHeight = Screen.PrimaryScreen.Bounds.Height;
}
marqueeXPos = this.Width;
marqueeXPosSecondLine = 7 * this.Width / 8;
marqueeXPosThirdLine = this.Width;
marqueeTimer = new System.Windows.Forms.Timer();
marqueeTimer.Interval = 20;
marqueeTimer.Tick += MarqueeTimer_Tick;
marqueeTimer.Start();
secondLineTimer = new System.Windows.Forms.Timer();
secondLineTimer.Interval = 100;
secondLineTimer.Tick += SecondLineTimer_Tick;
try
{
2025-04-09 11:46:18 +08:00
string filePath = Path.Combine(Application.StartupPath,"txt","WelcomeMessage.txt");
2025-04-07 16:54:10 +08:00
marqueeText = File.ReadAllText(filePath);
}
catch (Exception ex)
{
Console.WriteLine("Error reading marquee text from file: " + ex.Message);
marqueeText = "這是跑馬燈文字示例 - 歡迎使用MediaPlayerForm!";
}
this.DoubleBuffered = true;
}
private void ConfigureTimers()
{
displayTimer.Interval = 15000;
displayTimer.Tick += DisplayTimer_Tick;
songDisplayTimer = new System.Timers.Timer(30000);
songDisplayTimer.Elapsed += new ElapsedEventHandler(SongDisplayTimer_Elapsed);
songDisplayTimer.AutoReset = true;
songDisplayTimer.Enabled = true;
unifiedTimer = new System.Timers.Timer(15000);
unifiedTimer.Elapsed += new ElapsedEventHandler(UnifiedTimer_Elapsed);
unifiedTimer.AutoReset = true;
unifiedTimer.Enabled = true;
stickerTimer1.Interval = 15000;
stickerTimer1.Tick += (sender, e) => {
lock (imageLock)
{
firstStickerImage = null;
this.Invalidate();
}
2025-04-09 11:23:22 +08:00
2025-04-07 16:54:10 +08:00
stickerTimer1.Stop();
HideImages();
};
stickerTimer2.Interval = 15000;
stickerTimer2.Tick += (sender, e) => {
lock (imageLock)
{
secondStickerImage = null;
this.Invalidate();
}
2025-04-09 11:23:22 +08:00
2025-04-07 16:54:10 +08:00
stickerTimer2.Stop();
HideImages();
};
}
private static void DisplayTimer_Tick(object sender, EventArgs e)
{
if (MainForm.InvokeRequired)
{
MainForm.Invoke(new System.Action(() =>
{
MainForm.displayLabel.Text = "";
MainForm.nextSongLabel.Visible = true; // 显示 nextSongLabel
}));
}
else
{
MainForm.displayLabel.Text = "";
MainForm.nextSongLabel.Visible = true; // 显示 nextSongLabel
}
displayTimer.Stop(); // 停止计时器
}
// 當 songDisplayTimer 計時完成時會呼叫此函式
2025-04-07 16:54:10 +08:00
private static void SongDisplayTimer_Elapsed(object sender, EventArgs e)
{
// 檢查是否需要跨執行緒操作 UI 控制項
2025-04-07 16:54:10 +08:00
if (MainForm.InvokeRequired)
{
// 如果目前不在 UI 執行緒上,必須透過 Invoke 安全執行 UI 更新邏輯
2025-04-07 16:54:10 +08:00
Console.WriteLine("SongDisplayTimer_Tick invoked on UI thread.");
MainForm.Invoke(new System.Action(() =>
{
// 清除目前歌曲的顯示標籤文字
2025-04-07 16:54:10 +08:00
MainForm.songDisplayLabel.Text = "";
// 顯示下一首歌的標籤
MainForm.nextSongLabel.Visible = true;
2025-04-07 16:54:10 +08:00
}));
}
else
{
// 如果已經在 UI 執行緒,就直接更新 UI 控制項
2025-04-07 16:54:10 +08:00
Console.WriteLine("SongDisplayTimer_Tick invoked on background thread.");
MainForm.songDisplayLabel.Text = "";
MainForm.nextSongLabel.Visible = true;
2025-04-07 16:54:10 +08:00
}
// 停止計時器,避免重複觸發
2025-04-07 16:54:10 +08:00
songDisplayTimer.Stop();
}
2025-04-07 16:54:10 +08:00
private readonly object _lockObject = new object();
2025-05-26 15:21:07 +08:00
private bool _handlingTimeout = false;
2025-04-07 16:54:10 +08:00
private async void UnifiedTimer_Elapsed(object sender, EventArgs e)
{
2025-05-26 15:21:07 +08:00
if (_handlingTimeout) return;
_handlingTimeout = true;
2025-04-07 16:54:10 +08:00
2025-05-26 15:21:07 +08:00
try
{
if (MainForm.InvokeRequired)
{
MainForm.BeginInvoke((Action)(() => UnifiedTimer_Elapsed(sender, e)));
return;
}
displayLabel.Text = "";
2025-04-07 16:54:10 +08:00
2025-05-26 15:21:07 +08:00
switch (CurrentUIState)
{
case UIState.SelectingLanguage:
case UIState.SelectingArtistCategory:
case UIState.SelectingAction:
case UIState.SelectingSong:
case UIState.SelectingArtist:
case UIState.PlayHistory:
SetUIState(UIState.Initial);
await HandleTimeout("操作逾時,已返回主畫面");
break;
}
}
finally
2025-04-07 16:54:10 +08:00
{
2025-05-26 15:21:07 +08:00
_handlingTimeout = false;
2025-04-07 16:54:10 +08:00
}
}
private async Task HandleTimeout(string message)
{
Console.WriteLine("HandleTimeout called with message: " + message);
2025-05-26 15:21:07 +08:00
unifiedTimer.Stop();
2025-04-07 16:54:10 +08:00
SetUIState(UIState.Initial);
2025-05-26 15:21:07 +08:00
//DisplayMessage(message, 2000);
CommandHandler._indataHistory.Clear(); // 清空歷史紀錄
2025-04-07 16:54:10 +08:00
await Task.Delay(2000);
}
private void DisplayMessage(string message, int duration)
{
MainForm.nextSongLabel.Visible = false;
displayLabel.Text = message;
unifiedTimer.Interval = duration;
unifiedTimer.Start();
}
private void HideImages()
{
bool anyStickersActive = false;
lock (imageLock)
{
if (firstStickerImage != null)
{
firstStickerImage = null;
stickerTimer1.Stop();
anyStickersActive = true;
}
if (secondStickerImage != null)
{
secondStickerImage = null;
stickerTimer2.Stop();
anyStickersActive = true;
}
if (!anyStickersActive)
{
backgroundImage = null;
}
this.Invalidate();
}
}
public void UpdateSongDisplayLabel(string newText)
{
songDisplayLabel.Text = newText;
songDisplayLabel.Font = new Font("Arial", 125);
songDisplayLabel.ForeColor = Color.White;
songDisplayTimer.Stop();
songDisplayTimer.Start();
this.Invalidate();
}
private void SecondLineTimer_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - secondLineStartTime).TotalMilliseconds >= secondLineDuration)
{
marqueeTextSecondLine = "";
secondLineTimer.Stop();
}
}
public void ResetMarqueeTextToWelcomeMessage()
{
try
{
2025-04-09 11:46:18 +08:00
string filePath = Path.Combine(Application.StartupPath,"txt","WelcomeMessage.txt");
2025-04-07 16:54:10 +08:00
string welcomeMessage = File.ReadAllText(filePath);
this.UpdateMarqueeText(welcomeMessage, MarqueeStartPosition.Right, Color.White);
}
catch (Exception ex)
{
Console.WriteLine("Error reading marquee text from file: " + ex.Message);
}
}
protected override void OnPaint(PaintEventArgs e)
{
blackBackgroundPanel.SendToBack();
base.OnPaint(e);
using (Font largeFont = new Font("微軟正黑體", 34, FontStyle.Bold))
using (Brush whiteBrush = new SolidBrush(Color.White))
using (Brush limeGreenBrush = new SolidBrush(Color.LimeGreen))
using (Brush marqueeBrush = new SolidBrush(marqueeTextColor))
using (Brush backgroundBrush = new SolidBrush(Color.FromArgb(255, 0, 0, 0)))
{
SizeF textSize = e.Graphics.MeasureString(marqueeText, largeFont);
float yPosition1 = 10;
float yPosition2 = 55;
float yPosition3 = 100;
e.Graphics.FillRectangle(backgroundBrush, marqueeXPos, yPosition1, textSize.Width, textSize.Height);
e.Graphics.DrawString(marqueeText, largeFont, marqueeBrush, new PointF(marqueeXPos, yPosition1));
Rectangle clipRect = new Rectangle((int)(this.Width / 8), (int)yPosition2, (int)(3 * this.Width / 4), (int)textSize.Height);
Region originalClip = e.Graphics.Clip;
e.Graphics.SetClip(clipRect);
SizeF textSizeSecondLine = e.Graphics.MeasureString(marqueeTextSecondLine, largeFont);
float centeredXPos = (this.Width - textSizeSecondLine.Width) / 2;
e.Graphics.FillRectangle(backgroundBrush, centeredXPos, yPosition2, textSizeSecondLine.Width, textSizeSecondLine.Height);
e.Graphics.DrawString(marqueeTextSecondLine, largeFont, limeGreenBrush, new PointF(centeredXPos, yPosition2));
e.Graphics.Clip = originalClip;
if (string.IsNullOrEmpty(marqueeTextSecondLine))
{
SizeF textSizeThirdLine = e.Graphics.MeasureString(marqueeTextThirdLine, largeFont);
e.Graphics.FillRectangle(backgroundBrush, marqueeXPosThirdLine, yPosition2, textSizeThirdLine.Width, textSizeThirdLine.Height);
e.Graphics.DrawString(marqueeTextThirdLine, largeFont, whiteBrush, new PointF(marqueeXPosThirdLine, yPosition2));
}
else
{
SizeF textSizeThirdLine = e.Graphics.MeasureString(marqueeTextThirdLine, largeFont);
e.Graphics.FillRectangle(backgroundBrush, marqueeXPosThirdLine, yPosition3, textSizeThirdLine.Width, textSizeThirdLine.Height);
e.Graphics.DrawString(marqueeTextThirdLine, largeFont, whiteBrush, new PointF(marqueeXPosThirdLine, yPosition3));
}
}
lock (imageLock)
{
if (backgroundImage != null)
{
e.Graphics.DrawImage(backgroundImage, new Rectangle(25, 100, this.Width - 50, (int)(this.Height * 2 / 3) - 100));
}
if (firstStickerImage != null)
{
e.Graphics.DrawImage(firstStickerImage, firstStickerXPos, imageYPos);
}
if (secondStickerImage != null)
{
e.Graphics.DrawImage(secondStickerImage, secondStickerXPos, imageYPos);
}
if (showQRCode && qrCodeImage != null)
{
int qrCodeSize = screenHeight / 6;
int qrCodeX = 10;
int qrCodeY = this.Height - qrCodeSize - 20;
Rectangle qrCodeRect = new Rectangle(qrCodeX, qrCodeY, qrCodeSize, qrCodeSize);
e.Graphics.DrawImage(qrCodeImage, qrCodeRect);
}
}
// 確保跑馬燈第二行在最前
// blackBackgroundPanel.SendToBack();
}
public void DisplayBarrage(string text)
{
if (this.InvokeRequired)
{
this.Invoke(new System.Action(() => DisplayBarrage(text)));
return;
}
Random rnd = new Random();
for (int i = 0; i < 30; i++)
{
Label lblBarrage = new Label
{
Text = text,
AutoSize = true,
ForeColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256)),
Font = new Font("Arial", rnd.Next(10, 50)),
Location = new Point(rnd.Next(0, this.Width), rnd.Next(0, this.Height))
};
this.Controls.Add(lblBarrage);
lblBarrage.BringToFront();
System.Windows.Forms.Timer moveTimer = new System.Windows.Forms.Timer { Interval = 50 };
moveTimer.Tick += (sender, e) =>
{
lblBarrage.Left -= 5;
if (lblBarrage.Right < 0)
{
lblBarrage.Dispose();
moveTimer.Dispose();
}
};
moveTimer.Start();
int duration = rnd.Next(3000, 7000);
System.Windows.Forms.Timer durationTimer = new System.Windows.Forms.Timer { Interval = duration };
durationTimer.Tick += (sender, e) =>
{
if (moveTimer.Enabled)
{
moveTimer.Stop();
moveTimer.Dispose();
}
this.Controls.Remove(lblBarrage);
lblBarrage.Dispose();
durationTimer.Stop();
durationTimer.Dispose();
};
durationTimer.Start();
}
}
public void DisplaySticker(string stickerId)
{
2025-04-14 14:17:06 +08:00
//Console.WriteLine("Attempting to display sticker.");
2025-04-07 16:54:10 +08:00
this.Invoke((MethodInvoker)delegate {
Console.WriteLine("Form Width: " + this.Width);
Console.WriteLine("Form Height: " + this.Height);
2025-04-10 14:16:34 +08:00
string imagePath = String.Format("{0}\\themes\\superstar\\superstar-pic\\{1}.png", Application.StartupPath, stickerId);
2025-04-07 16:54:10 +08:00
Console.WriteLine("Image path: " + imagePath);
try
{
Image newSticker = Image.FromFile(imagePath);
lock (imageLock)
{
if (firstStickerImage == null)
{
firstStickerImage = newSticker;
2025-04-09 11:23:22 +08:00
firstStickerXPos = this.Width / 2 - firstStickerImage.Width / 2;
2025-04-07 16:54:10 +08:00
stickerTimer1.Start();
}
else if (secondStickerImage == null)
{
firstStickerXPos = this.Width * 3 / 10f - firstStickerImage.Width / 8;
secondStickerImage = newSticker;
secondStickerXPos = this.Width * 7 / 10f - secondStickerImage.Width / 8;
backgroundImage = null;
stickerTimer2.Start();
}
else
{
firstStickerImage = secondStickerImage;
firstStickerXPos = this.Width * 3 / 10f - firstStickerImage.Width / 8;
secondStickerImage = newSticker;
secondStickerXPos = this.Width * 7 / 10f - secondStickerImage.Width / 8;
stickerTimer2.Start();
}
}
this.Invalidate();
}
catch (Exception ex)
{
Console.WriteLine("Error loading sticker image: " + ex.Message);
}
});
}
public static string ReadSongNumber()
{
string songNumber = MainForm.displayLabel.Text;
MainForm.nextSongLabel.Visible = false;
return songNumber;
}
private List<SongData> LanguageSongList;
public enum UIState
{
Initial,
SelectingLanguage,
SelectingSong,
SelectingAction,
PlayingSong,
SelectingArtistCategory,
SelectingStrokeCount,
SelectingArtist,
PlayHistory
}
public enum Category
{
NewSongs,
HotSongs,
Artists
}
public static UIState CurrentUIState = UIState.Initial;
private string currentLanguage = "";
public static Category CurrentCategory { get; set; }
private SongData selectedSong;
public static void SetUIState(UIState newState)
{
CurrentUIState = newState;
displayTimer.Stop();
switch (newState)
{
case UIState.Initial:
foreach (var control in MainForm.Controls.OfType<Control>().ToArray())
{
if (control != MainForm.displayLabel &&
control != MainForm.pauseLabel &&
control != MainForm.muteLabel &&
control != MainForm.volumeUpLabel &&
control != MainForm.volumeDownLabel &&
control != MainForm.micUpLabel &&
control != MainForm.micDownLabel &&
control != MainForm.standardKeyLabel &&
control != MainForm.keyUpLabel &&
control != MainForm.keyDownLabel &&
control != MainForm.maleKeyLabel &&
control != MainForm.femaleKeyLabel &&
control != MainForm.squareLabel &&
control != MainForm.professionalLabel &&
control != MainForm.standardLabel &&
control != MainForm.singDownLabel &&
control != MainForm.brightLabel &&
control != MainForm.softLabel &&
control != MainForm.autoLabel &&
control != MainForm.romanticLabel &&
control != MainForm.dynamicLabel &&
control != MainForm.tintLabel &&
control != MainForm.blackBackgroundPanel &&
2025-05-26 15:21:07 +08:00
control != MainForm.nextSongLabel)
2025-04-07 16:54:10 +08:00
{
MainForm.Controls.Remove(control);
2025-05-26 15:21:07 +08:00
// control.Dispose();
control.Visible = false;
2025-04-07 16:54:10 +08:00
}
}
MainForm.displayLabel.Text = "";
CommandHandler.readyForSongListInput = false;
unifiedTimer.Stop();
break;
case UIState.SelectingLanguage:
unifiedTimer.Interval = 10000;
unifiedTimer.Enabled = true;
unifiedTimer.Start();
break;
case UIState.SelectingSong:
unifiedTimer.Interval = 10000;
unifiedTimer.Enabled = true;
unifiedTimer.Start();
break;
case UIState.SelectingArtistCategory:
unifiedTimer.Interval = 10000;
unifiedTimer.Enabled = true;
unifiedTimer.Start();
break;
case UIState.SelectingStrokeCount:
unifiedTimer.Interval = 10000;
unifiedTimer.Enabled = true;
unifiedTimer.Start();
break;
case UIState.SelectingArtist:
unifiedTimer.Interval = 10000;
unifiedTimer.Enabled = true;
unifiedTimer.Start();
break;
case UIState.PlayHistory:
unifiedTimer.Interval = 10000;
unifiedTimer.Enabled = true;
unifiedTimer.Start();
break;
default:
break;
}
}
int number;
int inputNumber;
public void OnUserInput(string input)
{
bool isNumber = int.TryParse(input, out number);
if (isNumber)
{
if (CurrentCategory == Category.NewSongs)
{
switch (CurrentUIState)
{
case UIState.SelectingLanguage:
HandleLanguageSelection(number);
break;
case UIState.SelectingSong:
HandleSongSelection(number);
break;
default:
displayLabel.Text = "無效的狀態";
displayLabel.BringToFront();
break;
}
}
else if (CurrentCategory == Category.HotSongs)
{
switch (CurrentUIState)
{
case UIState.SelectingLanguage:
HandleLanguageSelection(number);
break;
case UIState.SelectingSong:
HandleSongSelection(number);
break;
default:
displayLabel.Text = "無效的狀態";
displayLabel.BringToFront();
break;
}
}
else if (CurrentCategory == Category.Artists)
{
switch (CurrentUIState)
{
case UIState.SelectingArtistCategory:
ProcessArtistCategorySelection(number);
break;
case UIState.SelectingStrokeCount:
ProcessStrokeCountSelection(number);
break;
case UIState.SelectingArtist:
HandleArtistSelection(number);
break;
case UIState.SelectingSong:
HandleSongSelection(number);
break;
default:
displayLabel.Text = "無效的狀態";
displayLabel.BringToFront();
break;
}
}
}
else if (input == "a")
{
try
{
if (CurrentUIState == UIState.SelectingSong)
{
Console.WriteLine("Current State is SelectingSong, ready to process song selection.");
Console.WriteLine("Number: " + inputNumber);
int songIndex = (currentPage - 1) * songsPerPage + (inputNumber - 1);
Console.WriteLine("Calculated Song Index: " + songIndex + ", Total Songs: " + totalSongs);
if (songIndex >= 0 && songIndex < totalSongs)
{
selectedSong = LanguageSongList[songIndex];
2025-05-26 15:21:07 +08:00
Console.WriteLine("Adding song to playlist A: " + LanguageSongList[songIndex].Song + " " + selectedSong.SongFilePathHost1);
2025-04-07 16:54:10 +08:00
// DisplayActionWithSong(currentPage, songIndex, "點播");
AddSongToPlaylist(selectedSong);
}
else
{
Console.WriteLine("Song index out of range.");
}
}
}
catch (Exception ex)
{
Console.WriteLine("An error occurred while processing input 'a': " + ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
else if (input == "b")
{
if (CurrentUIState == UIState.SelectingSong)
{
Console.WriteLine("Current State is SelectingSong, ready to process song selection.");
int songIndex = (currentPage - 1) * songsPerPage + (inputNumber - 1);
Console.WriteLine("Calculated Song Index: " + songIndex + ", Total Songs: " + totalSongs);
if (songIndex < totalSongs)
{
selectedSong = LanguageSongList[songIndex];
2025-05-26 15:21:07 +08:00
Console.WriteLine("Adding song to playlist B: " + LanguageSongList[songIndex].Song + " " + selectedSong.SongFilePathHost1 );
2025-04-07 16:54:10 +08:00
// DisplayActionWithSong(currentPage, songIndex, "插播");
InsertSongToPlaylist(selectedSong);
}
else
{
Console.WriteLine("Song index out of range.");
}
}
}
}
private void HandleLanguageSelection(int number)
{
switch (number)
{
case 1:
currentLanguage = "國語";
break;
case 2:
currentLanguage = "台語";
break;
case 3:
currentLanguage = "粵語";
break;
case 4:
2025-05-20 16:16:27 +08:00
currentLanguage = "英語";
2025-04-07 16:54:10 +08:00
break;
case 5:
currentLanguage = "日語";
break;
case 6:
currentLanguage = "韓語";
break;
default:
displayLabel.Text = "輸入錯誤!!!";
displayLabel.BringToFront();
OverlayForm.displayTimer.Start();
return;
}
Console.WriteLine("Language selected: " + currentLanguage);
DisplaySongsInLanguage(currentLanguage, CurrentCategory);
CurrentUIState = UIState.SelectingSong;
Console.WriteLine("State changed to SelectingSong");
}
private Artist selectedArtist;
private void HandleArtistSelection(int number)
{
int artistIndex = (currentPage - 1) * artistsPerPage + (number - 1);
inputNumber = number;
if (artistIndex < totalArtists)
{
selectedArtist = currentArtistList[artistIndex];
currentLanguage = selectedArtist.Name;
SetUIState(UIState.SelectingSong);
string query = $"SELECT * FROM song_library_cache WHERE artistA ='{selectedArtist.Name}' OR artistB='{selectedArtist.Name}' ORDER BY song_counts DESC;";
LanguageSongList = PrimaryForm.Instance.SearchSongs_Mysql(query);
//LanguageSongList = SongListManager.Instance.GetSongsByArtist(selectedArtist.Name);
2025-04-07 16:54:10 +08:00
currentPage = 1;
totalSongs = LanguageSongList.Count;
DisplaySongs(currentPage);
}
else
{
Console.WriteLine("Song index out of range.");
}
}
private void HandleSongSelection(int number)
{
Console.WriteLine("Current State is SelectingSong, ready to process song selection.");
int songIndex = (currentPage - 1) * songsPerPage + (number - 1);
inputNumber = number;
Console.WriteLine("Calculated Song Index: " + songIndex + ", Total Songs: " + totalSongs);
if (songIndex < totalSongs)
{
2025-05-26 15:21:07 +08:00
selectedSong = LanguageSongList[songIndex];
Console.WriteLine("Adding song to playlist C: " + LanguageSongList[songIndex].Song + " " + selectedSong.SongFilePathHost1);
2025-04-07 16:54:10 +08:00
2025-05-26 15:21:07 +08:00
// DisplaySongsWithArrows(currentPage, songIndex);
AddSongToPlaylist(selectedSong);
2025-04-07 16:54:10 +08:00
}
else
{
Console.WriteLine("Song index out of range.");
}
}
private string currentArtistCategory;
private void ProcessArtistCategorySelection(int number)
{
switch (number)
{
case 1:
currentArtistCategory = "男";
break;
case 2:
currentArtistCategory = "女";
break;
case 3:
currentArtistCategory = "團";
break;
case 4:
currentArtistCategory = "外";
break;
case 5:
currentArtistCategory = "全部";
break;
default:
Console.WriteLine("Invalid selection");
return;
}
ClearDisplay();
DisplayStrokeCountOptions();
}
private void ClearDisplay()
{
foreach (var control in this.Controls.OfType<Control>().ToArray())
{
if (control != displayLabel &&
control != pauseLabel &&
control != muteLabel &&
control != volumeUpLabel &&
control != volumeDownLabel &&
control != micUpLabel &&
control != micDownLabel &&
control != standardKeyLabel &&
control != keyUpLabel &&
control != keyDownLabel &&
control != maleKeyLabel &&
control != femaleKeyLabel &&
control != squareLabel &&
control != professionalLabel &&
control != standardLabel &&
control != singDownLabel &&
control != brightLabel &&
control != softLabel &&
control != autoLabel &&
control != romanticLabel &&
control != dynamicLabel &&
control != tintLabel &&
control != blackBackgroundPanel &&
control != nextSongLabel)
{
this.Controls.Remove(control);
control.Dispose();
}
}
}
public void UpdateHistoryLabel(List<SongData> historySongs, List<PlayState> playStates, int currentPage, int totalPages)
{
// 移除畫面上所有現有的 PictureBox用於刷新內容
this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
2025-04-07 16:54:10 +08:00
// 建立標題文字,例如 "已點歌曲 (1 / 3)"
string headerText = $"已點歌曲 ({currentPage} / {totalPages})";
Font headerFont = new Font("Microsoft JhengHei", 50, FontStyle.Bold);
2025-04-07 16:54:10 +08:00
// 將標題文字轉為圖片
Bitmap headerBitmap = GenerateTextImage(headerText, headerFont, Color.White, Color.Transparent);
2025-04-07 16:54:10 +08:00
// 將標題圖片置中顯示在 Y=150 的位置
AddCenteredPicture(headerBitmap, 150);
// 設定歌名顯示的起始 Y 座標
int startY = 230;
// 歌名之間的垂直間距
int verticalSpacing = 6;
// 左右邊界,用來對齊歌名與狀態文字的位置
int leftMargin = 100;
int rightMargin = this.Width - 100;
// 逐一繪製歷史歌曲列表
for (int i = 0; i < historySongs.Count; i++)
{
var song = historySongs[i]; // 歌曲資料
var state = playStates[i]; // 對應的播放狀態
string status; // 播放狀態文字(如「播放中」)
Color textColor; // 對應的顏色
// 根據播放狀態決定狀態文字與顏色
switch (state)
{
case PlayState.Played:
status = "(播畢)";
textColor = Color.FromArgb(200, 75, 125); // 播畢顏色:紫紅色
break;
case PlayState.Playing:
status = "(播放中)";
textColor = Color.LimeGreen; // 播放中顏色:亮綠
break;
case PlayState.NotPlayed:
status = "";
textColor = Color.White; // 尚未播放:白色
break;
default:
status = "";
textColor = Color.White;
break;
}
// 建立顯示的歌曲文字,例如 "1. 我的歌"
string songText = $"{i + 1}. {song.Song}";
Font songFont = new Font("Microsoft JhengHei", 50, FontStyle.Bold);
// 將歌名轉成圖片
Bitmap songBitmap = GenerateTextImage(songText, songFont, textColor, Color.Transparent);
2025-04-07 16:54:10 +08:00
Bitmap statusBitmap = null;
// 如果有狀態文字,則也轉成圖片
if (!string.IsNullOrEmpty(status))
{
Font statusFont = new Font("Microsoft JhengHei", 50, FontStyle.Bold);
statusBitmap = GenerateTextImage(status, statusFont, textColor, Color.Transparent);
}
2025-04-07 16:54:10 +08:00
// 計算目前這首歌的 Y 座標位置
int fixedRowHeight = 80;
int y = startY + i * (fixedRowHeight + verticalSpacing);
//int y = startY + i * (songBitmap.Height + verticalSpacing);
2025-04-07 16:54:10 +08:00
// 加入歌名圖片到畫面左側
AddPicture(songBitmap, leftMargin, y);
// 若有狀態圖片,則加入到畫面右側
if (statusBitmap != null)
{
int statusX = rightMargin - statusBitmap.Width;
AddPicture(statusBitmap, statusX, y);
}
}
}
2025-04-07 16:54:10 +08:00
public void UpdateDisplayLabels(string[] messages)//新歌歌星排行首頁
{
// 移除畫面上現有的所有 PictureBox舊的文字圖片
2025-04-07 16:54:10 +08:00
this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
// 如果沒有訊息內容,直接跳出,不進行後續繪製
2025-04-07 16:54:10 +08:00
if (messages.Length == 0) return;
// 設定主標題字體大小
int mainTitleFontSize = 60;
// 設定選項字體大小
int optionFontSize = 50;
// 每行之間的垂直間距(像素)
int lineSpacing = 15;
2025-04-07 16:54:10 +08:00
// 取得主標題文字(第一行)
2025-04-07 16:54:10 +08:00
string mainTitle = messages[0];
// 建立主標題用的字型:微軟正黑體、粗體
2025-04-07 16:54:10 +08:00
Font mainTitleFont = new Font("Microsoft JhengHei", mainTitleFontSize, FontStyle.Bold);
// 使用自定義方法產生主標題的文字圖像(白色字+透明底)
2025-04-07 16:54:10 +08:00
Bitmap mainTitleBitmap = GenerateTextImage(mainTitle, mainTitleFont, Color.White, Color.Transparent);
// 主標題起始的 Y 座標
2025-04-07 16:54:10 +08:00
int startY = 130;
// 將主標題圖片水平置中並加入畫面
2025-04-07 16:54:10 +08:00
AddCenteredPicture(mainTitleBitmap, startY);
// 更新 Y 座標位置,準備繪製下一區塊(選項),加上主標題高度與間距
2025-04-07 16:54:10 +08:00
startY += mainTitleBitmap.Height + lineSpacing;
// 取得剩下的訊息文字(第二行起):當作選項
2025-04-07 16:54:10 +08:00
string[] options = messages.Skip(1).ToArray();
// 選項的起始 Y 座標
2025-04-07 16:54:10 +08:00
int optionsStartY = startY;
// 每欄最多可放幾個項目(以兩欄平均分配)
2025-04-07 16:54:10 +08:00
int maxItemsPerColumn = (int)Math.Ceiling(options.Length / 2.0);
// 設定左右欄的 X 座標(用於放置圖片)
int leftColumnX = 200;
2025-04-07 16:54:10 +08:00
int rightColumnX = this.Width / 2 + 150;
// 開始逐一處理每個選項
2025-04-07 16:54:10 +08:00
for (int i = 0; i < options.Length; i++)
{
// 設定每個選項的字型
2025-04-07 16:54:10 +08:00
Font optionFont = new Font("Microsoft JhengHei", optionFontSize, FontStyle.Bold);
// 建立文字對應的圖像(白色字+透明底)
2025-04-07 16:54:10 +08:00
Bitmap optionBitmap = GenerateTextImage(options[i], optionFont, Color.White, Color.Transparent);
// 根據目前索引,決定放在左欄還是右欄
2025-04-07 16:54:10 +08:00
int x = (i < maxItemsPerColumn) ? leftColumnX : rightColumnX;
// 決定目前這張圖的 Y 座標位置(依序向下排列)
2025-04-07 16:54:10 +08:00
int currentY = optionsStartY + ((i % maxItemsPerColumn) * (optionBitmap.Height + lineSpacing));
// 加入圖片到畫面上
2025-04-07 16:54:10 +08:00
AddPicture(optionBitmap, x, currentY);
}
2025-04-07 16:54:10 +08:00
}
private string strokeRange;
private int totalArtists = 0;
private const int artistsPerPage = 8;
2025-04-07 16:54:10 +08:00
private List<Artist> currentArtistList = new List<Artist>();
private void ProcessStrokeCountSelection(int number)
{
List<Artist> selectedArtists = null;
var manager =new ArtistManager();
2025-04-07 16:54:10 +08:00
switch (number)
{
case 1:
selectedArtists = manager.GetArtistsByCategoryAndStrokeCountRange(currentArtistCategory ,0, 3);
2025-04-07 16:54:10 +08:00
strokeRange = "00~03";
break;
case 2:
selectedArtists = manager.GetArtistsByCategoryAndStrokeCountRange(currentArtistCategory, 4, 7);
2025-04-07 16:54:10 +08:00
strokeRange = "04~07";
break;
case 3:
selectedArtists = manager.GetArtistsByCategoryAndStrokeCountRange(currentArtistCategory, 8, 11);
2025-04-07 16:54:10 +08:00
strokeRange = "08~11";
break;
case 4:
selectedArtists = manager.GetArtistsByCategoryAndStrokeCountRange(currentArtistCategory, 12, 15);
2025-04-07 16:54:10 +08:00
strokeRange = "12~15";
break;
case 5:
selectedArtists = manager.GetArtistsByCategoryAndStrokeCountRange(currentArtistCategory, 16, int.MaxValue);
2025-04-07 16:54:10 +08:00
strokeRange = "16以上";
break;
default:
Console.WriteLine("Invalid selection");
return;
}
if (selectedArtists != null && selectedArtists.Count > 0)
{
SetUIState(OverlayForm.UIState.SelectingArtist);
DisplayArtists(selectedArtists, currentPage);
}
else
{
Console.WriteLine("No artists found for the selected stroke count range.");
}
}
private void DisplayArtists(List<Artist> artists, int page)//歌星點進去後的畫面
{
currentArtistList = artists;
totalArtists = artists.Count;
if (artists == null || artists.Count == 0)
{
Console.WriteLine("Artist list is null or empty.");
return;
}
this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
int artistsPerColumn = 4;
2025-04-07 16:54:10 +08:00
int startIndex = (page - 1) * artistsPerPage;
int endIndex = Math.Min(startIndex + artistsPerPage, artists.Count);
int totalPages = (int)Math.Ceiling((double)artists.Count / artistsPerPage);
string categoryDisplayText = currentArtistCategory switch
{
"男" => "男歌星",
"女" => "女歌星",
"團" => "團體",
"外" => "外語",
"全部" => "全部",
_ => currentArtistCategory
};
string headerText = String.Format("{0} -- {1} ({2} / {3})", categoryDisplayText, strokeRange, page, totalPages);
Font headerFont = new Font("Microsoft JhengHei", 50, FontStyle.Bold);
Bitmap headerBitmap = GenerateTextImage(headerText, headerFont, Color.White, Color.Transparent);
AddCenteredPicture(headerBitmap, 150);
int startY = 250;
int verticalSpacing = 15;
int leftColumnX = 200; // 左邊列的起始 X 偏移量
int rightColumnX = this.Width / 2 + 150; // 右邊列的起始 X 偏移量
for (int i = startIndex; i < endIndex; i++)
{
int artistNumber = i - startIndex + 1;
string artistNumberText = $"{artistNumber}.";
string artistNameText = artists[i].Name;
Font numberFont = new Font("Microsoft JhengHei", 45 , FontStyle.Bold);
Bitmap numberBitmap = GenerateTextImage(artistNumberText, numberFont, Color.White, Color.Transparent);
Font nameFont = new Font("Microsoft JhengHei", 45, FontStyle.Bold);
Bitmap nameBitmap = GenerateTextImage(artistNameText, nameFont, Color.White, Color.Transparent);
int x = (i - startIndex) < artistsPerColumn ? leftColumnX : rightColumnX;
int y = startY + ((i - startIndex) % artistsPerColumn) * (numberBitmap.Height + verticalSpacing);
AddPicture(numberBitmap, x, y);
AddPicture(nameBitmap, x + numberBitmap.Width, y);
}
}
private void DisplayStrokeCountOptions()
{
string categoryDisplayText;
switch (currentArtistCategory)
{
case "男":
categoryDisplayText = "男歌星";
break;
case "女":
categoryDisplayText = "女歌星";
break;
case "團":
categoryDisplayText = "團體";
break;
case "外":
categoryDisplayText = "外語";
break;
case "全部":
categoryDisplayText = "全部";
break;
default:
categoryDisplayText = currentArtistCategory;
break;
}
string[] messages = new string[]
{
categoryDisplayText,
"1. 0~3",
"2. 4~7",
"3. 8~11",
"4. 12~15",
"5. 16以上"
};
SetUIState(OverlayForm.UIState.SelectingStrokeCount);
UpdateDisplayLabels(messages);
}
private void DisplaySongsInLanguage(string language, Category category)
{
string sqlQuery;
2025-04-07 16:54:10 +08:00
if (category == Category.NewSongs)
{
sqlQuery = $"SELECT * FROM song_library_cache WHERE language_name = '{language}' ORDER BY add_date DESC LIMIT {PrimaryForm.ReadNewSongLimit()}";
}
else if (category == Category.HotSongs)
{
2025-05-26 15:21:07 +08:00
sqlQuery = $"SELECT * FROM song_library_cache WHERE language_name = '{language}' ORDER BY song_counts DESC LIMIT {PrimaryForm.ReadHotSongLimit()}";
}
else
{
ClearDisplay();
displayLabel.Text = "無效的類別";
return;
}
2025-04-07 16:54:10 +08:00
var songsInLanguage = PrimaryForm.Instance.SearchSongs_Mysql(sqlQuery);
2025-04-07 16:54:10 +08:00
if (songsInLanguage == null || songsInLanguage.Count == 0)
{
ClearDisplay();
displayLabel.Text = $"{language} - 熱門中未找到歌曲";
LanguageSongList = null;
totalSongs = 0;
currentPage = 0;
return;
}
LanguageSongList = songsInLanguage;
totalSongs = songsInLanguage.Count;
currentPage = 1;
ClearDisplay();
DisplaySongs(currentPage);
}
2025-05-21 10:29:18 +08:00
// 歌庫路徑調整
2025-04-07 16:54:10 +08:00
public void AddSongToPlaylist(SongData songData)
{
try
{
var filePath1 = songData.SongFilePathHost1;
var filePath2 = songData.SongFilePathHost2;
2025-05-21 10:29:18 +08:00
// 之後還要設計成本地的資料夾位置
var filename = songData.FileName;
bool checkpath = false;
string pathToPlay = "";
if (File.Exists(filename))
2025-04-07 16:54:10 +08:00
{
2025-05-21 10:29:18 +08:00
pathToPlay = filename;
checkpath = true;
PrimaryForm.WriteLog(String.Format("{0} Using local file: {1}", songData.Song,filename));
}
else if (File.Exists(filePath1))
{
pathToPlay = filePath1;
checkpath = true;
PrimaryForm.WriteLog(String.Format("{0} Using Host1 file: {1}", songData.Song, filePath1));
}
else if (File.Exists(filePath2))
{
pathToPlay = filePath2;
checkpath = true;
PrimaryForm.WriteLog(String.Format("{0} Using Host2 file: {1}", songData.Song, filePath2));
2025-04-07 16:54:10 +08:00
}
else
{
2025-05-21 10:29:18 +08:00
PrimaryForm.WriteLog(String.Format("File not found on hosts: {0}, {1} and {2}", filename, filePath1, filePath2));
}
if (checkpath)
{
//做判定 決定pathToPlay值
//pathToPlay = File.Exists(filePath1) ? filePath1 : filePath2;
2025-04-07 16:54:10 +08:00
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
PrimaryForm.userRequestedSongs.Add(songData);
PrimaryForm.playedSongsHistory.Add(songData);
PrimaryForm.playStates.Add(wasEmpty ? PlayState.Playing : PlayState.NotPlayed);
// 刷新頁面
2025-05-08 11:45:47 +08:00
2025-05-21 10:29:18 +08:00
if (PrimaryForm.Instance.multiPagePanel.get_currentSongList() == PrimaryForm.playedSongsHistory)
PrimaryForm.Instance.multiPagePanel.LoadSongs(PrimaryForm.Instance.currentSongList);
2025-04-07 16:54:10 +08:00
if (wasEmpty)
{
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs);
2025-05-21 10:29:18 +08:00
PrimaryForm.currentSongIndexInHistory += 1;
2025-04-07 16:54:10 +08:00
}
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
PrimaryForm.PrintPlayingSongList();
2025-05-14 11:18:01 +08:00
// 點播次數+1
PrimaryForm.Instance.AddSongCount(songData.SongNumber);
2025-04-07 16:54:10 +08:00
}
}
catch (Exception ex)
{
Console.WriteLine("Error occurred: " + ex.Message);
}
}
public void InsertSongToPlaylist(SongData songData)
{
try
{
// 從 songData 中取得兩個可能的檔案路徑主機1與主機2
2025-04-07 16:54:10 +08:00
var filePath1 = songData.SongFilePathHost1;
var filePath2 = songData.SongFilePathHost2;
// 檢查兩個主機上的檔案是否皆不存在
2025-04-07 16:54:10 +08:00
if (!File.Exists(filePath1) && !File.Exists(filePath2))
{
// 若兩個都找不到,寫入 Log 並不加入歌單
2025-04-07 16:54:10 +08:00
PrimaryForm.WriteLog(String.Format("File not found on both hosts: {0} and {1}", filePath1, filePath2));
}
else
{
// 若其中一個存在,就用第一個存在的那個檔案
2025-04-07 16:54:10 +08:00
var pathToPlay = File.Exists(filePath1) ? filePath1 : filePath2;
Console.WriteLine("path to play" + pathToPlay);
// 檢查目前使用者歌單是否為空
2025-04-07 16:54:10 +08:00
bool wasEmpty = PrimaryForm.userRequestedSongs.Count == 0;
if (wasEmpty)
{
// 若是空的,代表是第一首歌,直接加入並設為正在播放
PrimaryForm.userRequestedSongs.Add(songData); // 加入播放清單
VideoPlayerForm.Instance.SetPlayingSongList(PrimaryForm.userRequestedSongs); // 傳給播放器
PrimaryForm.playedSongsHistory.Add(songData); // 加入播放歷史
PrimaryForm.playStates.Add(PlayState.Playing); // 設定狀態為正在播放
PrimaryForm.currentSongIndexInHistory += 1; // 歷史索引 +1
2025-04-07 16:54:10 +08:00
}
else if (PrimaryForm.userRequestedSongs.Count == 1)
{
// 若清單中已有一首,插入新歌在 index 1 (即目前播放之後的位置)
2025-04-07 16:54:10 +08:00
PrimaryForm.userRequestedSongs.Insert(1, songData);
PrimaryForm.playedSongsHistory.Insert(PrimaryForm.currentSongIndexInHistory + 1, songData);
PrimaryForm.playStates.Insert(PrimaryForm.currentSongIndexInHistory + 1, PlayState.NotPlayed); // 尚未播放
2025-04-07 16:54:10 +08:00
}
else
{
// 若清單中超過一首,同樣插入在 index 1也是在當前歌曲之後的位置
2025-04-07 16:54:10 +08:00
PrimaryForm.userRequestedSongs.Insert(1, songData);
PrimaryForm.playedSongsHistory.Insert(PrimaryForm.currentSongIndexInHistory + 1, songData);
PrimaryForm.playStates.Insert(PrimaryForm.currentSongIndexInHistory + 1, PlayState.NotPlayed);
}
// 更新下一首即將播放的資訊(畫面或播放器邏輯用)
2025-04-07 16:54:10 +08:00
VideoPlayerForm.Instance.UpdateNextSongFromPlaylist();
// 印出目前播放清單資訊到畫面或 console
2025-04-07 16:54:10 +08:00
PrimaryForm.PrintPlayingSongList();
}
}
catch (Exception ex)
{
// 捕捉所有例外並印出錯誤訊息(避免整個流程當掉)
2025-04-07 16:54:10 +08:00
Console.WriteLine("Error occurred: " + ex.Message);
}
}
// 測試
2025-04-07 16:54:10 +08:00
public int currentPage = 1;
public int songsPerPage = 5;
public int totalSongs = 0;
public void DisplaySongs(int page)
{
// 檢查 LanguageSongList 是否為空,避免發生錯誤
if (LanguageSongList == null || LanguageSongList.Count == 0)
{
Console.WriteLine("LanguageSongList is null or empty.");
return;
}
// 清除介面上所有 PictureBox 控件,避免重複顯示舊的內容
this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
// 每列顯示 5 首歌
int songsPerColumn = 5;
// 計算當前頁面的起始與結束索引
int startIndex = (page - 1) * songsPerPage;
int endIndex = Math.Min(startIndex + songsPerPage, LanguageSongList.Count);
// 計算總頁數
int totalPages = (int)Math.Ceiling((double)LanguageSongList.Count / songsPerPage);
// 根據當前分類選擇標題文字
string categoryText = OverlayForm.CurrentCategory switch
{
OverlayForm.Category.NewSongs => "新歌",
OverlayForm.Category.HotSongs => "熱門",
_ => ""
};
// 設定標題格式,包含語言、分類與當前頁碼
string headerText = $"{currentLanguage} - {categoryText} ({page} / {totalPages})";
// 設定標題的字體樣式
Font headerFont = new Font("Microsoft JhengHei", 60, FontStyle.Bold);
// 生成標題圖片
Bitmap headerBitmap = GenerateTextImage(headerText, headerFont, Color.White, Color.Transparent);
// 顯示標題圖片,垂直置於 150px 處
AddCenteredPicture(headerBitmap, 150);
// 設定歌名顯示區域的起始 Y 位置
int startY = 250;
// 左列與右列的 X 位置
int leftColumnX = 100;
int rightColumnX = this.Width / 2 + 100;
// 計算當前頁面最大歌名和歌手文字長度,決定適合的字體大小
int maxSongLength = 0;
int maxArtistLength = 0;
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Song}";
string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
: LanguageSongList[i].ArtistA;
maxSongLength = Math.Max(maxSongLength, songText.Length);
maxArtistLength = Math.Max(maxArtistLength, artistText.Length);
}
// 根據最大字數決定適當的字體大小
int songFontSize = maxSongLength > 20 ? 35 : 45;
int artistFontSize = maxArtistLength > 20 ? 30 : 35;
// 設定歌曲行間距
int verticalSpacing = songFontSize == 30 ? 25 : 10;
// 設定統一的行高
int rowHeight = 0;
// 計算行高
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Song}";
string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
: LanguageSongList[i].ArtistA;
Font songFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
Font artistFont = new Font("Microsoft JhengHei", artistFontSize, FontStyle.Bold);
Bitmap songBitmap = GenerateTextImage(songText, songFont, Color.White, Color.Transparent);
Bitmap artistBitmap = GenerateTextImage(artistText, artistFont, Color.White, Color.Transparent);
rowHeight = Math.Max(rowHeight, Math.Max(songBitmap.Height, artistBitmap.Height));
}
// 依據計算出的行高,逐行顯示歌曲與歌手名稱
for (int i = startIndex; i < endIndex; i++)
{
int songNumber = i - startIndex + 1;
string songText = $"{songNumber}. {LanguageSongList[i].Song}";
string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
: LanguageSongList[i].ArtistA;
Font songFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
Font artistFont = new Font("Microsoft JhengHei", artistFontSize, FontStyle.Bold);
Bitmap songBitmap = GenerateTextImage(songText, songFont, Color.White, Color.Transparent);
Bitmap artistBitmap = GenerateTextImage(artistText, artistFont, Color.White, Color.Transparent);
// 根據索引決定左側或右側顯示
int x = (i - startIndex) < songsPerColumn ? leftColumnX : rightColumnX;
// 計算 Y 位置
int y = startY + ((i - startIndex) % songsPerColumn) * (rowHeight + verticalSpacing);
// 顯示歌曲名稱圖片
AddPicture(songBitmap, x, y);
// 顯示歌手名稱圖片(稍微右移)
AddPicture(artistBitmap, x + songBitmap.Width + 20, y);
}
}
public void DisplaySongsWithArrows(int page, int highlightIndex)
{
// 檢查 LanguageSongList 是否為空,避免發生錯誤
if (LanguageSongList == null || LanguageSongList.Count == 0)
{
Console.WriteLine("Error: LanguageSongList is null or empty.");
return;
}
// 清除介面上所有 PictureBox 控件,避免重複顯示舊的內容
this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
// 每列顯示 5 首歌
int songsPerColumn = 5;
// 計算當前頁面的起始與結束索引
int startIndex = (page - 1) * songsPerPage;
int endIndex = Math.Min(startIndex + songsPerPage, LanguageSongList.Count);
// 計算總頁數
int totalPages = (int)Math.Ceiling((double)LanguageSongList.Count / songsPerPage);
// 根據當前分類選擇標題文字
string categoryText = OverlayForm.CurrentCategory switch
{
OverlayForm.Category.NewSongs => "新歌",
OverlayForm.Category.HotSongs => "熱門",
_ => ""
};
// 設定標題格式,包含語言、分類與當前頁碼
string headerText = $"{currentLanguage} - {categoryText} ({page} / {totalPages})";
// 設定標題的字體樣式
Font headerFont = new Font("Microsoft JhengHei", 60, FontStyle.Bold);
// 生成標題圖片
Bitmap headerBitmap = GenerateTextImage(headerText, headerFont, Color.White, Color.Transparent);
// 顯示標題圖片,垂直置於 150px 處
AddCenteredPicture(headerBitmap, 150);
// 設定歌名顯示區域的起始 Y 位置
int startY = 250;
// 左列與右列的 X 位置
int leftColumnX = 100;
int rightColumnX = this.Width / 2 + 100;
// 找到當前頁面中最長的 songText 和 artistText 長度
int maxSongLength = 0;
int maxArtistLength = 0;
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Song}";
string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
: LanguageSongList[i].ArtistA;
maxSongLength = Math.Max(maxSongLength, songText.Length);
maxArtistLength = Math.Max(maxArtistLength, artistText.Length);
}
// 動態調整字體大小
int songFontSize = maxSongLength > 20 ? 35 : 45;
int artistFontSize = maxArtistLength > 20 ? 30 : 35;
int verticalSpacing = songFontSize == 30 ? 25 : 10;
// 統一行高計算
int rowHeight = 0;
for (int i = startIndex; i < endIndex; i++)
{
string songText = $"{i - startIndex + 1}. {LanguageSongList[i].Song}";
string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
: LanguageSongList[i].ArtistA;
Font tempSongFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
Font tempArtistFont = new Font("Microsoft JhengHei", artistFontSize, FontStyle.Bold);
Bitmap tempSongBitmap = GenerateTextImage(songText, tempSongFont, Color.White, Color.Transparent);
Bitmap tempArtistBitmap = GenerateTextImage(artistText, tempArtistFont, Color.White, Color.Transparent);
rowHeight = Math.Max(rowHeight, Math.Max(tempSongBitmap.Height, tempArtistBitmap.Height));
}
// 依據計算出的行高,逐行顯示歌曲與歌手名稱
for (int i = startIndex; i < endIndex; i++)
{
int songNumber = i - startIndex + 1;
string songText = $"{songNumber}. {LanguageSongList[i].Song}";
string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
: LanguageSongList[i].ArtistA;
// 設定顏色,選中的索引顯示為亮綠色
Color songColor = (i == highlightIndex) ? Color.LimeGreen : Color.White;
Color artistColor = (i == highlightIndex) ? Color.LimeGreen : Color.White;
Font songFont = new Font("Microsoft JhengHei", songFontSize, FontStyle.Bold);
Bitmap songBitmap = GenerateTextImage(songText, songFont, songColor, Color.Transparent);
Font artistFont = new Font("Microsoft JhengHei", artistFontSize, FontStyle.Bold);
Bitmap artistBitmap = GenerateTextImage(artistText, artistFont, artistColor, Color.Transparent);
int x = (i - startIndex) < songsPerColumn ? leftColumnX : rightColumnX;
int y = startY + ((i - startIndex) % songsPerColumn) * (rowHeight + verticalSpacing);
// 顯示歌曲名稱圖片
AddPicture(songBitmap, x, y);
// 顯示歌手名稱圖片(稍微右移)
AddPicture(artistBitmap, x + songBitmap.Width + 20, y);
}
}
public void DisplayActionWithSong(int page, int songIndex, string actionType)
{
// try
// {
// if (LanguageSongList == null || LanguageSongList.Count == 0)
// {
// Console.WriteLine("Error: LanguageSongList is null or empty.");
// return;
// }
// SongData song = LanguageSongList[songIndex];
// this.Controls.OfType<PictureBox>().ToList().ForEach(p => this.Controls.Remove(p));
// int songsPerColumn = 5;
// int startIndex = (page - 1) * songsPerPage;
// int endIndex = Math.Min(startIndex + songsPerPage, LanguageSongList.Count);
// int totalPages = (int)Math.Ceiling((double)LanguageSongList.Count / songsPerPage);
// string headerText = $"{actionType}: {song.ArtistA} - {song.Song} ({page} / {totalPages})";
// Font headerFont = new Font("Microsoft JhengHei", 40, FontStyle.Bold);
// Color headerColor = actionType == "點播" ? Color.LimeGreen : Color.Yellow;
// Bitmap headerBitmap = GenerateTextImage(headerText, headerFont, headerColor, Color.Transparent);
// AddCenteredPicture(headerBitmap, 150);
// int startY = 250;
// int verticalSpacing = 10;
// int leftColumnX = 200;
// int rightColumnX = this.Width / 2 + 150;
// for (int i = startIndex; i < endIndex; i++)
// {
// int songNumber = i - startIndex + 1;
// string songText = $"{songNumber}. {LanguageSongList[i].Song}";
// string artistText = !string.IsNullOrWhiteSpace(LanguageSongList[i].ArtistB)
// ? $"{LanguageSongList[i].ArtistA} - {LanguageSongList[i].ArtistB}"
// : LanguageSongList[i].ArtistA;
// Font songFont = new Font("Microsoft JhengHei", 40, FontStyle.Bold);
// Bitmap songBitmap = GenerateTextImage(songText, songFont, Color.White, Color.Transparent);
// Font artistFont = new Font("Microsoft JhengHei", 30, FontStyle.Bold);
// Bitmap artistBitmap = GenerateTextImage(artistText, artistFont, Color.White, Color.Transparent);
// int x = (i - startIndex) < songsPerColumn ? leftColumnX : rightColumnX;
// int y = startY + ((i - startIndex) % songsPerColumn) * (songBitmap.Height + verticalSpacing);
// AddPicture(songBitmap, x, y);
// AddPicture(artistBitmap, x + songBitmap.Width + 20, y);
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Error in DisplayActionWithSong: {ex.Message}");
// Console.WriteLine(ex.StackTrace);
// }
}
public void NextPage()
{
unifiedTimer.Stop();
if (CurrentUIState == UIState.SelectingArtist)
{
if (currentPage * artistsPerPage < totalArtists)
{
currentPage++;
DisplayArtists(currentArtistList, currentPage);
}
}
else
{
if (currentPage * songsPerPage < totalSongs)
{
currentPage++;
DisplaySongs(currentPage);
}
}
unifiedTimer.Start();
}
public void PreviousPage()
{
unifiedTimer.Stop();
if (CurrentUIState == UIState.SelectingArtist)
{
if (currentPage > 1)
{
currentPage--;
DisplayArtists(currentArtistList, currentPage);
}
}
else
{
if (currentPage > 1)
{
currentPage--;
DisplaySongs(currentPage);
}
}
unifiedTimer.Start();
}
}
}