Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions osucatch-editor-realtimeviewer/BarLineSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,29 +173,36 @@ internal static SubdivisionTier GetSubdivisionTier(BarLineMode mode)
};
}

/// <summary>模式对应的“拍线”下拉项 / 滑块提示文本。</summary>
/// <summary>
/// 模式对应的档位文字,用在快捷开关栏滑块下方的状态标签上。
/// <para />英文刻意写短(<c>1/8 beat</c> 而不是 <c>Every 1/8 beat</c>):这段文字直接决定
/// 吸附在左 / 右侧时那一列的宽度,长句子会把整列撑得很宽;缩略写法配合功能区的
/// “Bar Lines” 标题一样看得懂。设置窗口里的下拉项另有更详细的文案(含配色说明)。
/// </para>
/// </summary>
internal static string GetDisplayName(BarLineMode mode)
{
bool chinese = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName == "zh";
return mode switch
{
BarLineMode.Every4Beats => chinese ? "每4拍" : "Every 4 beats",
BarLineMode.Every2Beats => chinese ? "每2拍" : "Every 2 beats",
BarLineMode.EveryBeat => chinese ? "每拍" : "Every beat",
BarLineMode.EveryHalfBeat => chinese ? "每1/2拍" : "Every 1/2 beat",
BarLineMode.EveryThirdBeat => chinese ? "每1/3拍" : "Every 1/3 beat",
BarLineMode.EveryQuarterBeat => chinese ? "每1/4拍" : "Every 1/4 beat",
BarLineMode.EveryFifthBeat => chinese ? "每1/5拍" : "Every 1/5 beat",
BarLineMode.EverySixthBeat => chinese ? "每1/6拍" : "Every 1/6 beat",
BarLineMode.EverySeventhBeat => chinese ? "每1/7拍" : "Every 1/7 beat",
BarLineMode.EveryEighthBeat => chinese ? "每1/8拍" : "Every 1/8 beat",
_ => chinese ? "不显示" : "Hidden",
BarLineMode.Every4Beats => chinese ? "每4拍" : "4 beats",
BarLineMode.Every2Beats => chinese ? "每2拍" : "2 beats",
BarLineMode.EveryBeat => chinese ? "每拍" : "1 beat",
BarLineMode.EveryHalfBeat => chinese ? "每1/2拍" : "1/2 beat",
BarLineMode.EveryThirdBeat => chinese ? "每1/3拍" : "1/3 beat",
BarLineMode.EveryQuarterBeat => chinese ? "每1/4拍" : "1/4 beat",
BarLineMode.EveryFifthBeat => chinese ? "每1/5拍" : "1/5 beat",
BarLineMode.EverySixthBeat => chinese ? "每1/6拍" : "1/6 beat",
BarLineMode.EverySeventhBeat => chinese ? "每1/7拍" : "1/7 beat",
BarLineMode.EveryEighthBeat => chinese ? "每1/8拍" : "1/8 beat",
_ => chinese ? "不显示" : "Off",
};
}

/// <summary>
/// 拍线状态文字里的显示名称:<c>拍线:{当前拍线显示模式}</c>。
/// 只写档位、不写配色——线上什么颜色用户看一眼就知道,写进文字反而啰嗦。
/// 拍线状态文字里的显示名称:只写当前档位(如“每2拍”)。
/// 只写档位、不写配色——线上什么颜色用户看一眼就知道,写进文字反而啰嗦;
/// 也不带“拍线:”这类前缀:所在功能区本身就叫“拍线”,吸附在左 / 右侧竖排时前缀还会把整列撑宽。
/// </summary>
internal static string GetOptionName(BarLineMode mode) => GetDisplayName(mode);

Expand Down
111 changes: 94 additions & 17 deletions osucatch-editor-realtimeviewer/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ public partial class Form1 : Form
private ToolStripMenuItem? unloadTemplateStripMenuItem;
private TemplateBeatmapData? templateData;

// 快捷开关条:可吸附在菜单栏下方的工具栏行里,也可拖出为浮动小窗口
// 快捷开关条:可吸附在菜单栏下方(横排)或画布左 / 右侧(竖排),也可拖出为浮动小窗口
private QuickToggleBar? quickToggleBar;
private QuickToggleDockRow? quickToggleDockRow;
private QuickToggleDocking? quickToggleDocking;
private ToolStripMenuItem? quickToggleStripMenuItem;
private ToolStripMenuItem? quickToggleDockSideToolStripMenuItem;
private ToolStripMenuItem? quickToggleDockTopToolStripMenuItem;
private ToolStripMenuItem? quickToggleDockLeftToolStripMenuItem;
private ToolStripMenuItem? quickToggleDockRightToolStripMenuItem;

#region 快捷开关条:开关标识与功能区

Expand Down Expand Up @@ -312,16 +316,20 @@ private void Form1_Load(object sender, EventArgs e)

ReapplyBookmarkStyles();

// 快捷开关栏:恢复功能区显示状态、开关状态与停靠 / 浮动状态(浮窗要等主窗口显示出来后再弹出)
// 快捷开关栏:恢复功能区显示状态、开关状态与吸附位置 / 浮动状态(浮窗要等主窗口显示出来后再弹出)
quickToggleBar?.ApplyHiddenGroups(app.Default.QuickToggle_HiddenGroups);
quickToggleBar?.ApplyCheckedStates(app.Default.QuickToggle_States);
// ApplyCheckedStates 不触发事件,这里手动把各开关的内部状态同步过来
SetPreviewTimeFrozen(quickToggleBar?.IsChecked(FreezePreviewTimeKey) ?? false);
SyncModToggleFromMenu();
SyncLabelToggleFromMenu();
ApplyBarLineMode(BarLineSettings.CurrentMode, persist: false);
quickToggleDocking?.ApplyStartupState(app.Default.QuickToggle_Visible, app.Default.QuickToggle_Floating);
quickToggleDocking?.ApplyStartupState(
app.Default.QuickToggle_Visible,
app.Default.QuickToggle_Floating,
QuickToggleDockSideHelper.ParseDockSide(app.Default.QuickToggle_DockSide));
if (quickToggleStripMenuItem != null) quickToggleStripMenuItem.Checked = app.Default.QuickToggle_Visible;
SyncQuickToggleDockSideMenu();

// osu path
if (app.Default.osu_path == "")
Expand Down Expand Up @@ -1478,7 +1486,7 @@ private void RestoreTemplateMenuText()
}

/// <summary>
/// 创建快捷开关条(菜单栏正下方的工具栏行):吸附在工具栏与拖出为浮动小窗口之间切换。
/// 创建快捷开关条:可吸附在菜单栏下方(横排)或画布左 / 右侧(竖排),也可以拖出为浮动小窗口。
/// </summary>
private void CreateQuickToggleBar()
{
Expand All @@ -1489,20 +1497,21 @@ private void CreateQuickToggleBar()
quickToggleBar.GroupChanged += quickToggleBar_GroupChanged;

quickToggleDockRow = new QuickToggleDockRow();
quickToggleDocking = new QuickToggleDocking(this, quickToggleBar, quickToggleDockRow, menuStrip1);
quickToggleDocking = new QuickToggleDocking(this, quickToggleBar, quickToggleDockRow, menuStrip1, statusStrip1);

QuickToggleDocking docking = quickToggleDocking;
docking.StateChanged += (sender, e) =>
{
if (quickToggleStripMenuItem != null) quickToggleStripMenuItem.Checked = docking.BarVisible;
SyncQuickToggleDockSideMenu();
};

// 停靠行要排在菜单栏之后、画布之前参与停靠布局:
// WinForms 按控件集合的倒序布局停靠控件(集合末尾的控件最先被安排),
// 把行插到菜单栏原来的位置上,它才会正好占据菜单栏下方的一行,
// 而画布(Dock=Fill)在其下方填满剩余空间;否则行会盖在画布上而不是挤开画布。
// 停靠行要参与主窗口的停靠布局。它在控件集合里的位置决定它落在哪:
// 顶部吸附时排在画布之后、菜单栏之前(正好占据菜单栏下方的一行,把画布挤下去),
// 左 / 右侧吸附时排在最前面(正好夹在菜单栏与状态栏之间的左 / 右边)。
// 具体位置由停靠管理器按吸附位置安排(见 QuickToggleDocking.PlaceDockRow)。
Controls.Add(quickToggleDockRow);
Controls.SetChildIndex(quickToggleDockRow, Controls.GetChildIndex(menuStrip1));
docking.ApplyDockSide();

CreateQuickToggleMenu();
}
Expand All @@ -1523,6 +1532,8 @@ private void CreateQuickToggles()
(string freezeText, string freezeToolTip) = FreezePreviewTimeText(previewTimeFrozen);
quickToggleBar.AddStandaloneToggle(FreezePreviewTimeKey, freezeText, false);
quickToggleBar.SetToggleText(FreezePreviewTimeKey, freezeText, freezeToolTip);
// 条上这个按钮只显示图标,右键菜单里给它一个和功能区一样的“是否显示”勾选项
quickToggleBar.AddStandaloneToggleToMenu(FreezePreviewTimeKey, FreezePreviewTimeMenuText());

// ---- MOD:三个按钮单选,当前 MOD 对应的按钮保持按下(NM/EZ/HR 一看便知,不加标题) ----
QuickToggleBar.QuickToggleGroup modGroup = quickToggleBar.AddGroup(ModGroupKey, "");
Expand Down Expand Up @@ -1637,6 +1648,18 @@ private static (string Text, string ToolTip) FreezePreviewTimeText(bool frozen)
return (text, toolTip);
}

/// <summary>
/// 右键菜单里“跟随模式”勾选项的文字:和 Mod / HitObjectLabel / 拍线 一样,
/// 勾选表示这个 ⏸️ / ▶️ 按钮在快捷开关栏上显示。
/// <para />文字必须单独给:条上这个按钮只显示图标,没法拿它的 Text 当菜单项。
/// </para>
/// </summary>
private static string FreezePreviewTimeMenuText()
{
bool chinese = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName == "zh";
return chinese ? "跟随模式" : "Follow mode";
}

/// <summary>MOD 快捷按钮在当前语言下的文本(三种 MOD 名称各语言都相同)。</summary>
private static string ModToggleText(ModMode mode)
{
Expand Down Expand Up @@ -1684,12 +1707,11 @@ private static string LabelToggleToolTip(QuickLabelMode mode)
};
}

/// <summary>“拍线:{当前拍线显示模式}”文字。</summary>
private static string BarLineStatusText()
{
bool chinese = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName == "zh";
return (chinese ? "拍线:" : "Bar lines: ") + BarLineSettings.GetOptionName(BarLineSettings.CurrentMode);
}
/// <summary>
/// 功能区里显示当前拍线模式的文字:只写档位(如“每2拍”),不再带“拍线:”前缀。
/// 前缀对横排只是占地方,竖排(吸附在左 / 右侧)时更会把整列撑宽,而所在功能区本身就叫“拍线”。
/// </summary>
private static string BarLineStatusText() => BarLineSettings.GetOptionName(BarLineSettings.CurrentMode);



Expand Down Expand Up @@ -1878,7 +1900,8 @@ private void ApplyEditorTime(int editorTime)
}

/// <summary>
/// 程序内创建“快捷开关栏”菜单项(显示 / 隐藏整行)。
/// 程序内创建“快捷开关栏”菜单项(显示 / 隐藏整行)与“快捷开关栏位置”子菜单
/// (顶部横排 / 左侧竖排 / 右侧竖排),文本由语言资源按控件名应用。
/// </summary>
private void CreateQuickToggleMenu()
{
Expand All @@ -1889,10 +1912,63 @@ private void CreateQuickToggleMenu()
};
quickToggleStripMenuItem.Click += quickToggleStripMenuItem_Click;

quickToggleDockTopToolStripMenuItem = CreateQuickToggleDockSideMenuItem(
"quickToggleDockTopToolStripMenuItem", QuickToggleDockSide.Top);
quickToggleDockLeftToolStripMenuItem = CreateQuickToggleDockSideMenuItem(
"quickToggleDockLeftToolStripMenuItem", QuickToggleDockSide.Left);
quickToggleDockRightToolStripMenuItem = CreateQuickToggleDockSideMenuItem(
"quickToggleDockRightToolStripMenuItem", QuickToggleDockSide.Right);

quickToggleDockSideToolStripMenuItem = new ToolStripMenuItem
{
Name = "quickToggleDockSideToolStripMenuItem",
};
quickToggleDockSideToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[]
{
quickToggleDockTopToolStripMenuItem,
quickToggleDockLeftToolStripMenuItem,
quickToggleDockRightToolStripMenuItem,
});

// 归入 Viewer 菜单的显示选项分组(分隔线之前的最后一项)
int insertIndex = viewerToolStripMenuItem.DropDownItems.IndexOf(toolStripSeparator1);
if (insertIndex < 0) insertIndex = viewerToolStripMenuItem.DropDownItems.Count;
viewerToolStripMenuItem.DropDownItems.Insert(insertIndex, quickToggleStripMenuItem);
viewerToolStripMenuItem.DropDownItems.Insert(insertIndex + 1, quickToggleDockSideToolStripMenuItem);

SyncQuickToggleDockSideMenu();
}

private ToolStripMenuItem CreateQuickToggleDockSideMenuItem(string name, QuickToggleDockSide side)
{
ToolStripMenuItem item = new()
{
Name = name,
CheckOnClick = false,
};
item.Click += (sender, e) => SetQuickToggleDockSide(side);
return item;
}

/// <summary>选择吸附位置:立即吸附过去(正在浮动时一并吸附回主窗口)并保存。</summary>
private void SetQuickToggleDockSide(QuickToggleDockSide side)
{
if (quickToggleDocking == null) return;

quickToggleDocking.DockTo(side);
SyncQuickToggleDockSideMenu();
app.Default.Save();
}

/// <summary>把当前吸附位置同步到 Viewer 菜单里的三个勾选项(单选)。</summary>
private void SyncQuickToggleDockSideMenu()
{
if (quickToggleDocking == null) return;

QuickToggleDockSide side = quickToggleDocking.DockSide;
if (quickToggleDockTopToolStripMenuItem != null) quickToggleDockTopToolStripMenuItem.Checked = side == QuickToggleDockSide.Top;
if (quickToggleDockLeftToolStripMenuItem != null) quickToggleDockLeftToolStripMenuItem.Checked = side == QuickToggleDockSide.Left;
if (quickToggleDockRightToolStripMenuItem != null) quickToggleDockRightToolStripMenuItem.Checked = side == QuickToggleDockSide.Right;
}

private void quickToggleStripMenuItem_Click(object? sender, EventArgs e)
Expand All @@ -1916,6 +1992,7 @@ private void ApplyQuickToggleLanguage()

(string text, string toolTip) = FreezePreviewTimeText(previewTimeFrozen);
quickToggleBar.SetToggleText(FreezePreviewTimeKey, text, toolTip);
quickToggleBar.SetStandaloneToggleMenuText(FreezePreviewTimeKey, FreezePreviewTimeMenuText());

// 功能区标题(AddGroup 对已存在的功能区只更新标题)
quickToggleBar.AddGroup(ModGroupKey, "");
Expand Down
12 changes: 12 additions & 0 deletions osucatch-editor-realtimeviewer/Form1.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1009,4 +1009,16 @@
<data name="quickToggleStripMenuItem.Text" xml:space="preserve">
<value>&amp;Quick Toggle Bar</value>
</data>
<data name="quickToggleDockSideToolStripMenuItem.Text" xml:space="preserve">
<value>Quick Toggle Bar &amp;Position</value>
</data>
<data name="quickToggleDockTopToolStripMenuItem.Text" xml:space="preserve">
<value>&amp;Top of the viewer (horizontal)</value>
</data>
<data name="quickToggleDockLeftToolStripMenuItem.Text" xml:space="preserve">
<value>&amp;Left of the viewer (vertical)</value>
</data>
<data name="quickToggleDockRightToolStripMenuItem.Text" xml:space="preserve">
<value>&amp;Right of the viewer (vertical)</value>
</data>
</root>
12 changes: 12 additions & 0 deletions osucatch-editor-realtimeviewer/Form1.zh-Hans.resx
Original file line number Diff line number Diff line change
Expand Up @@ -445,4 +445,16 @@
<data name="quickToggleStripMenuItem.Text" xml:space="preserve">
<value>快捷开关栏 (&amp;Q)</value>
</data>
<data name="quickToggleDockSideToolStripMenuItem.Text" xml:space="preserve">
<value>快捷开关栏位置 (&amp;P)</value>
</data>
<data name="quickToggleDockTopToolStripMenuItem.Text" xml:space="preserve">
<value>吸附在 Viewer 顶部(横排)(&amp;T)</value>
</data>
<data name="quickToggleDockLeftToolStripMenuItem.Text" xml:space="preserve">
<value>吸附在 Viewer 左侧(竖排)(&amp;L)</value>
</data>
<data name="quickToggleDockRightToolStripMenuItem.Text" xml:space="preserve">
<value>吸附在 Viewer 右侧(竖排)(&amp;R)</value>
</data>
</root>
Loading
Loading