superstar_v2/PrimaryFormParts/SongSearch/PrimaryForm.SongSearch.BopomofoSearch.cs

555 lines
25 KiB
C#
Raw Normal View History

2025-04-07 16:54:10 +08:00
using System.IO;
using IniParser;
using IniParser.Model;
/* Song Search with ZhuYin */
namespace DualScreenDemo
{
public partial class PrimaryForm
{
// 注音歌曲的 PictureBox
private PictureBox pictureBoxZhuYinSongs;
//存放注音按鈕的陣列
private Button[] phoneticButtonsForSongs;
//特殊功能按鈕(修改、清除、關閉)
private Button modifyButtonZhuYinSongs;
private Button clearButtonZhuYinSongs;
private Button closeButtonZhuYinSongs;
//用於顯示輸入文字的輸入框
private RichTextBox inputBoxZhuYinSongs;
/// <summary>
/// 注音歌曲搜尋按鈕點擊事件
/// </summary>
private void ZhuyinSearchSongsButton_Click(object sender, EventArgs e)
{
//更新搜尋模式按鈕的背景圖
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongActiveBackground;
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground;
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongNormalBackground;
wordCountSearchSongButton.BackgroundImage = wordCountSearchSongNormalBackground;
handWritingSearchSongButton.BackgroundImage = handWritingSearchSongNormalBackground;
numberSearchSongButton.BackgroundImage = numberSearchSongNormalBackground;
// 讀取 config.ini 並獲取注音圖片的路徑
var configData = LoadConfigData();
string imagePath = Path.Combine(Application.StartupPath, configData["ImagePaths"]["ZhuYinSongs"]);
//顯示注音歌曲圖片
ShowImageOnPictureBoxZhuYinSongs(Path.Combine(Application.StartupPath, imagePath));
//設定不同模式的UI顯示
SetWordCountSongsAndButtonsVisibility(false); // 隱藏字數搜尋相關控件
SetEnglishSongsAndButtonsVisibility(false);
SetPinYinSongsAndButtonsVisibility(false);
SetHandWritingForSongsAndButtonsVisibility(false);
SetSongIDSearchAndButtonsVisibility(false);
SetZhuYinSongsAndButtonsVisibility(true);
ResetinputBox();
pictureBoxZhuYinSongs.Visible = true;
}
/// <summary>
/// 初始化注音按鈕 (Phonetic Buttons) 並載入其對應的圖片與座標
/// <para>1. 讀取 config.ini 設定檔,獲取按鈕的相關數據 (符號、座標、圖片)</para>
/// <para>2. 解析注音符號並儲存至 phoneticSymbols 陣列</para>
/// <para>3. 解析按鈕的座標資訊,存入 phoneticButtonCoords</para>
/// <para>4. 解析按鈕的圖片 (正常狀態、按下狀態、懸停狀態),存入 phoneticButtonImages。</para>
/// <para>5. 依序建立 35 個注音按鈕,並套用對應的圖片與事件處理函數。</para>
/// </summary>
private void InitializePhoneticButtonsForSongs()
{
// 1. 從設定檔 (config.ini) 讀取配置數據,包含按鈕座標、圖片等
var data = LoadConfigData();
// 2. 讀取注音符號列表,這些符號將用於顯示在按鈕上
phoneticSymbols = LoadPhoneticSymbols(data);
// 3. 從設定檔載入 **注音按鈕的座標**,每個按鈕都有對應的 (X, Y, Width, Height)
phoneticButtonCoords = LoadButtonCoordinates(data, "PhoneticButtonCoordinates", 35);
// 4. 從設定檔載入 **注音按鈕的圖片**,每個按鈕都有正常、按下、懸停三種狀態
phoneticButtonImages = LoadButtonImages(data, "PhoneticButtonImages", 35);
// 5. 建立 35 個注音按鈕的陣列 (每個按鈕對應一個注音符號)
phoneticButtonsForSongs = new Button[35];
// 6. 迴圈建立所有的注音按鈕
for (int i = 0; i < 35; i++)
{
// 取得當前按鈕的圖片 (從已載入的 phoneticButtonImages 字典中獲取)
var buttonImages = phoneticButtonImages[$"button{i}"];
// 建立單個注音按鈕,並設定其圖片與點擊事件
CreatePhoneticButtonForSongs(
i, // 按鈕索引 (對應於 phoneticSymbols)
buttonImages.normal, // 按鈕的普通狀態圖片
buttonImages.mouseDown, // 按下時的圖片
buttonImages.mouseOver // 滑鼠懸停時的圖片
);
}
}
/// <summary>
/// 建立單個注音按鈕,並設定其圖片、大小、位置,以及滑鼠事件。
/// </summary>
/// <param name="index">按鈕索引 (對應於 phoneticSymbols)</param>
/// <param name="normalImagePath">按鈕的普通狀態圖片路徑</param>
/// <param name="mouseDownImagePath">按鈕被按下時的圖片路徑</param>
/// <param name="mouseOverImagePath">滑鼠懸停時的圖片路徑</param>
private void CreatePhoneticButtonForSongs(int index, string normalImagePath, string mouseDownImagePath, string mouseOverImagePath)
{
try
{
// 1. 創建按鈕並初始化屬性
phoneticButtonsForSongs[index] = new Button
{
Name = $"phoneticButton_{phoneticSymbols[index]}", // 設定按鈕名稱,方便識別
BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)), // 設定預設背景圖
BackgroundImageLayout = ImageLayout.Stretch, // 背景圖自動填滿按鈕
FlatStyle = FlatStyle.Flat, // 設定按鈕為扁平樣式
FlatAppearance = { BorderSize = 0 } // 移除按鈕的邊框
};
// 2. 設定按鈕的大小與位置
ResizeAndPositionButton(
phoneticButtonsForSongs[index],
phoneticButtonCoords[index].X,
phoneticButtonCoords[index].Y,
phoneticButtonCoords[index].Width,
phoneticButtonCoords[index].Height
);
// 3. 載入三種狀態的圖片
Image normalImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath));
Image mouseDownImage = Image.FromFile(Path.Combine(Application.StartupPath, mouseDownImagePath));
Image mouseOverImage = Image.FromFile(Path.Combine(Application.StartupPath, mouseOverImagePath));
// 4. 設定滑鼠事件,改變背景圖
phoneticButtonsForSongs[index].MouseDown += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = mouseDownImage;
phoneticButtonsForSongs[index].MouseUp += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = normalImage;
phoneticButtonsForSongs[index].MouseEnter += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = mouseOverImage;
phoneticButtonsForSongs[index].MouseLeave += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = normalImage;
// 5. 設定按鈕的點擊事件 (當按下按鈕時,觸發 PhoneticButton_Click)
phoneticButtonsForSongs[index].Click += PhoneticButton_Click;
// 6. 存入對應的注音符號,方便之後的處理
phoneticButtonsForSongs[index].Tag = phoneticSymbols[index];
// 7. 將按鈕加入視窗
this.Controls.Add(phoneticButtonsForSongs[index]);
}
catch (Exception ex)
{
// 例外處理,確保按鈕建立失敗時不影響其他部分
Console.WriteLine($"Error creating button at index {index}: {ex.Message}");
}
}
/// <summary>
/// 初始化注音輸入界面的所有按鈕和輸入框。
/// </summary>
private void InitializeButtonsForZhuYinSongs()
{
// 1. 從設定檔 (config.ini) 載入注音符號
LoadPhoneticSymbolsFromConfig();
// 2. 初始化 35 個注音按鈕
InitializePhoneticButtonsForSongs();
// 3. 初始化特殊按鈕 (例如:刪除、確定、返回按鈕)
InitializeSpecialButtonsForZhuYinSongs();
// 4. 初始化輸入框 (用於顯示使用者輸入的注音符號)
InitializeInputBoxZhuYinSongs();
}
/// <summary>
/// 初始化注音輸入界面的特殊按鈕,包括「修改」、「清除」和「關閉」。
/// </summary>
private void InitializeSpecialButtonsForZhuYinSongs()
{
// 1. 初始化「修改」按鈕 (刪除上一個輸入的注音符號)
InitializeModifyButtonZhuYinSongs();
// 2. 初始化「清除」按鈕 (清空所有輸入內容)
InitializeClearButtonZhuYinSongs();
// 3. 初始化「關閉」按鈕 (關閉注音輸入介面)
InitializeCloseButtonZhuYinSongs();
}
/// <summary>
/// 初始化「修改」按鈕,讓使用者可以刪除上一個輸入的注音符號。
/// </summary>
private void InitializeModifyButtonZhuYinSongs()
{
// 1. 讀取設定檔 (config.ini) 來獲取特殊按鈕的座標與圖像資訊
var data = LoadConfigData();
// 2. 從設定檔讀取「修改」按鈕的座標數據
modifyButtonZhuYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "modifyButtonZhuYinSongs");
// 3. 從設定檔讀取「修改」按鈕的圖像 (Normal、MouseOver、MouseDown)
var buttonImages = LoadButtonImages(data, "ModifyButtonImagesZhuYin");
// 4. 使用座標與圖像來建立「修改」按鈕,並綁定點擊事件
modifyButtonZhuYinSongs = CreateSpecialButton(
"btnModifyZhuYinSongs", // 按鈕名稱
modifyButtonZhuYinCoords, // 按鈕座標
buttonImages.normal, // 預設 (normal) 圖像
buttonImages.mouseOver, // 滑鼠移過 (hover) 圖像
buttonImages.mouseDown, // 按下 (pressed) 圖像
ModifyButtonZhuYinSongs_Click // 綁定按鈕點擊事件
);
}
/// <summary>
/// 「修改」按鈕的點擊事件,刪除輸入框內的最後一個注音符號。
/// </summary>
private void ModifyButtonZhuYinSongs_Click(object sender, EventArgs e)
{
// 1. 確保輸入框 (inputBoxZhuYinSongs) 存在於目前的視窗控制項中
if (this.Controls.Contains(inputBoxZhuYinSongs) && inputBoxZhuYinSongs.Text.Length > 0)
{
// 2. 刪除輸入框中的最後一個字元 (即移除最後一個注音符號)
inputBoxZhuYinSongs.Text = inputBoxZhuYinSongs.Text.Substring(0, inputBoxZhuYinSongs.Text.Length - 1);
}
}
/// <summary>
/// 初始化「清除」按鈕,並從設定檔載入其位置與圖片資源。
/// </summary>
private void InitializeClearButtonZhuYinSongs()
{
// 1. 從設定檔 (config.ini) 讀取配置數據
var data = LoadConfigData();
// 2. 讀取「清除」按鈕的座標設定 (從 "SpecialButtonCoordinates" 內的 "clearButtonZhuYinSongs" 取得)
clearButtonZhuYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "clearButtonZhuYinSongs");
// 3. 讀取「清除」按鈕的圖片 (正常、滑鼠懸停、按下狀態)
var buttonImages = LoadButtonImages(data, "ClearButtonImagesZhuYin");
// 4. 建立「清除」按鈕,並設定對應的事件處理函式 (ClearButtonZhuYinSongs_Click)
clearButtonZhuYinSongs = CreateSpecialButton(
"btnClearZhuYinSongs", // 按鈕名稱
clearButtonZhuYinCoords, // 按鈕座標與大小
buttonImages.normal, // 正常狀態圖片
buttonImages.mouseOver, // 滑鼠懸停圖片
buttonImages.mouseDown, // 按下時圖片
ClearButtonZhuYinSongs_Click // 點擊事件處理函式
);
}
/// <summary>
/// 當使用者點擊「清除」按鈕時,將輸入框 (inputBoxZhuYinSongs) 的內容清空。
/// </summary>
/// <param name="sender">觸發事件的按鈕。</param>
/// <param name="e">事件參數。</param>
private void ClearButtonZhuYinSongs_Click(object sender, EventArgs e)
{
// 1. 確保視窗內包含「注音輸入框」(inputBoxZhuYinSongs),且輸入框內有文字
if (this.Controls.Contains(inputBoxZhuYinSongs) && inputBoxZhuYinSongs.Text.Length > 0)
{
// 2. 清空輸入框內容
inputBoxZhuYinSongs.Text = "";
}
}
/// <summary>
/// 初始化注音輸入的關閉按鈕,從設定檔讀取按鈕座標與圖片,並設置點擊事件
/// </summary>
private void InitializeCloseButtonZhuYinSongs()
{
// 讀取設定檔數據
var data = LoadConfigData();
// 從設定檔讀取關閉按鈕的座標
closeButtonZhuYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "closeButtonZhuYinSongs");
// 從設定檔讀取關閉按鈕的圖片
var buttonImages = LoadButtonImages(data, "CloseButtonImagesZhuYin");
// 創建關閉按鈕並綁定點擊事件
closeButtonZhuYinSongs = CreateSpecialButton(
"btnCloseZhuYinSongs", // 按鈕名稱
closeButtonZhuYinCoords, // 按鈕座標
buttonImages.normal, // 正常狀態圖片
buttonImages.mouseOver, // 滑鼠懸停圖片
buttonImages.mouseDown, // 按下圖片
CloseButtonZhuYinSongs_Click // 綁定點擊事件
);
}
/// <summary>
/// 關閉注音輸入介面,隱藏相關 UI 元件
/// </summary>
/// <param name="sender">觸發事件的按鈕 (關閉按鈕)</param>
/// <param name="e">事件參數</param>
private void CloseButtonZhuYinSongs_Click(object sender, EventArgs e)
{
// 隱藏注音輸入的圖片
pictureBoxZhuYinSongs.Visible = false;
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground;
// 隱藏注音輸入的所有按鈕與介面元素
SetZhuYinSongsAndButtonsVisibility(false);
}
/// <summary>
/// 初始化注音輸入框 (RichTextBox),設定外觀、事件處理及位置大小
/// </summary>
private void InitializeInputBoxZhuYinSongs()
{
try
{
// 讀取輸入框的配置,例如字體、顏色、大小等
LoadInputBoxConfig();
// 建立注音輸入框並套用讀取到的設定
inputBoxZhuYinSongs = new RichTextBox
{
Name = "inputBoxZhuYinSongs",
ForeColor = inputBoxForeColor, // 設定文字顏色
Font = new Font(inputBoxFontName, inputBoxFontSize, inputBoxFontStyle), // 設定字體
ScrollBars = RichTextBoxScrollBars.None // 禁用滾動條
};
// 調整輸入框大小與位置
ResizeAndPositionControl(inputBoxZhuYinSongs, inputBoxZhuYinCoords.X, inputBoxZhuYinCoords.Y,
inputBoxZhuYinCoords.Width, inputBoxZhuYinCoords.Height);
// 設定文字變更事件,用來即時篩選歌曲
inputBoxZhuYinSongs.TextChanged += (sender, e) =>
{
string searchText = inputBoxZhuYinSongs.Text; // 取得輸入內容
// 根據輸入的注音篩選歌曲清單
var searchResults = allSongs.Where(song => song.PhoneticNotation.StartsWith(searchText)).ToList();
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
};
// 將輸入框加入到 UI 控制項
this.Controls.Add(inputBoxZhuYinSongs);
}
catch (Exception ex)
{
Console.WriteLine("Error initializing inputBoxZhuYinSongs: " + ex.Message);
}
}
/// <summary>
/// 存儲 PictureBoxZhuYinSongs 的座標與尺寸信息。
/// </summary>
/// <remarks>
/// 此元組包含以下四個值:
/// XX 座標
/// , YY 座標
/// , Width寬度
/// , Height高度
/// </remarks>
private (int X, int Y, int Width, int Height) pictureBoxZhuYinSongCoords;
/// <summary>
/// 從設定檔 (config.ini) 讀取 PictureBoxZhuYinSongs 的座標與尺寸
/// </summary>
private void LoadPictureBoxZhuYinSongCoordsFromConfig()
{
// 建立 INI 檔案解析器
var parser = new FileIniDataParser();
// 讀取 config.ini 設定檔的內容
IniData data = parser.ReadFile("config.ini");
// 取得 "PictureBoxZhuYinSongs" 段落的設定數據
var coords = data["PictureBoxZhuYinSongs"];
// 解析座標與尺寸,並存入 pictureBoxZhuYinSongCoords
pictureBoxZhuYinSongCoords = (
int.Parse(coords["X"]), // 讀取 X 座標
int.Parse(coords["Y"]), // 讀取 Y 座標
int.Parse(coords["Width"]), // 讀取寬度
int.Parse(coords["Height"]) // 讀取高度
);
}
/// <summary>
/// 在 pictureBoxZhuYinSongs 上顯示指定路徑的圖片,並根據設定調整其大小與位置。
/// </summary>
/// <param name="imagePath">要顯示的圖片檔案路徑</param>
private void ShowImageOnPictureBoxZhuYinSongs(string imagePath)
{
// 從 config.ini 讀取 PictureBox 的座標與尺寸
LoadPictureBoxZhuYinSongCoordsFromConfig();
// 讀取圖片檔案並載入 Bitmap 物件
Bitmap originalImage = new Bitmap(imagePath);
// 設定圖片顯示區域,使用從設定檔讀取的座標與尺寸
Rectangle displayArea = new Rectangle(
pictureBoxZhuYinSongCoords.X,
pictureBoxZhuYinSongCoords.Y,
pictureBoxZhuYinSongCoords.Width,
pictureBoxZhuYinSongCoords.Height
);
// 設定 PictureBox 的圖片
pictureBoxZhuYinSongs.Image = originalImage;
// 調整 PictureBox 的大小與位置,使其符合設定
ResizeAndPositionPictureBox(
pictureBoxZhuYinSongs,
displayArea.X,
displayArea.Y,
displayArea.Width,
displayArea.Height
);
// 顯示 PictureBox
pictureBoxZhuYinSongs.Visible = true;
}
/// <summary>
/// 設定注音歌曲相關的 PictureBox、按鈕和輸入框的可見性。
/// </summary>
/// <param name="isVisible">若為 true則顯示這些控件否則隱藏。</param>
private void SetZhuYinSongsAndButtonsVisibility(bool isVisible)
{
// 定義要執行的操作,設定各控件的可見性
System.Action action = () =>
{
try
{
// 暫停佈局邏輯,防止在調整控件可見性時觸發不必要的佈局計算,提升性能
SuspendLayout();
// 檢查並設定 pictureBoxZhuYinSongs 的可見性
if (pictureBoxZhuYinSongs == null)
{
Console.WriteLine("pictureBoxZhuYinSongs is null");
}
else
{
pictureBoxZhuYinSongs.Visible = isVisible;
if (isVisible) pictureBoxZhuYinSongs.BringToFront();
}
// 檢查並設定 phoneticButtonsForSongs 陣列中每個按鈕的可見性
if (phoneticButtonsForSongs == null)
{
Console.WriteLine("phoneticButtonsForSongs is null");
}
else
{
foreach (var button in phoneticButtonsForSongs)
{
if (button == null)
{
Console.WriteLine("One of the phoneticButtonsForSongs is null");
}
else
{
button.Visible = isVisible;
if (isVisible) button.BringToFront();
}
}
}
// 檢查並設定 modifyButtonZhuYinSongs 的可見性
if (modifyButtonZhuYinSongs == null)
{
Console.WriteLine("modifyButtonZhuYinSongs is null");
}
else
{
modifyButtonZhuYinSongs.Visible = isVisible;
if (isVisible) modifyButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 clearButtonZhuYinSongs 的可見性
if (clearButtonZhuYinSongs == null)
{
Console.WriteLine("clearButtonZhuYinSongs is null");
}
else
{
clearButtonZhuYinSongs.Visible = isVisible;
if (isVisible) clearButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 closeButtonZhuYinSongs 的可見性
if (closeButtonZhuYinSongs == null)
{
Console.WriteLine("closeButtonZhuYinSongs is null");
}
else
{
closeButtonZhuYinSongs.Visible = isVisible;
if (isVisible) closeButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 inputBoxZhuYinSongs 的可見性
if (inputBoxZhuYinSongs == null)
{
Console.WriteLine("inputBoxZhuYinSongs is null");
}
else
{
inputBoxZhuYinSongs.Visible = isVisible;
if (isVisible) inputBoxZhuYinSongs.BringToFront();
}
// 恢復佈局邏輯,允許佈局計算
ResumeLayout();
// 強制控件立即執行佈局邏輯,確保佈局更新立即生效
PerformLayout();
// 刷新各控件,確保其狀態立即更新
pictureBoxZhuYinSongs?.Refresh();
if (phoneticButtonsForSongs != null)
{
foreach (var button in phoneticButtonsForSongs)
{
button?.Refresh();
}
}
modifyButtonZhuYinSongs?.Refresh();
clearButtonZhuYinSongs?.Refresh();
closeButtonZhuYinSongs?.Refresh();
inputBoxZhuYinSongs?.Refresh();
}
catch (Exception ex)
{
// 捕捉並輸出異常資訊,方便除錯
Console.WriteLine("Error in SetZhuYinSongsAndButtonsVisibility: " + ex.Message);
}
};
// 如果當前執行緒需要呼叫 Invoke 方法才能修改控件,則使用 Invoke
if (this.InvokeRequired)
{
this.Invoke(action);
}
else
{
action();
}
}
}
}