From da2eeb3b3900edde8392ccb92efd7d32f8532df1 Mon Sep 17 00:00:00 2001 From: waynebian01 Date: Tue, 25 Aug 2026 15:58:44 +0800 Subject: [PATCH] Refactor UI components for improved theming and accessibility - Updated UiCardPanel to use UiTheme.CardCornerRadius for consistent corner styling. - Modified UiPillTab to enable TabStop and set AccessibleRole to PageTab, enhancing keyboard navigation. - Implemented keyboard handling in UiPillTab for Enter and Space keys to trigger click events. - Enhanced focus visuals in UiPillTab with focus rectangle drawing. - Introduced new constants in UiTheme for CardPadding, PageGap, ActionButtonHeight, GridRowHeight, TabBarHeight, CardCornerRadius, and ControlCornerRadius for better layout management. - Updated UnitEditorForm to utilize new theming constants and improved layout with UiCardPanel for better visual structure. - Refined action button styling in UnitEditorForm for consistent button sizes and margins. - Adjusted labeled row height in UnitEditorForm for better alignment. --- Fuyutsui/Fuyutsui.toc | 2 +- Fuyutsui/core/config.lua | 2 +- Shigure.csproj | 6 +- UI/ClassConfigEditorControl.cs | 39 +-- UI/ClassMacrosEditorControl.cs | 35 +- UI/ConditionEditorForm.cs | 94 +++-- UI/FormulaEditorForm.cs | 60 +++- UI/MainForm.cs | 65 ++-- UI/ModuleEditorControl.cs | 30 +- UI/RuleTextEditorForm.cs | 63 ++-- UI/StatusForm.cs | 623 ++++++++++++++++++++++++++++----- UI/UiCardPanel.cs | 2 +- UI/UiPillTab.cs | 34 +- UI/UiTheme.cs | 156 ++++++++- UI/UnitEditorForm.cs | 105 ++++-- 15 files changed, 1007 insertions(+), 309 deletions(-) diff --git a/Fuyutsui/Fuyutsui.toc b/Fuyutsui/Fuyutsui.toc index afcc1b60..dd1dd19f 100644 --- a/Fuyutsui/Fuyutsui.toc +++ b/Fuyutsui/Fuyutsui.toc @@ -1,7 +1,7 @@ ## Interface: 120100 ## Title: Fuyutsui -## Version: 1.2.1.10 +## Version: 1.2.1.11 ## Author: Wayne Bian ## IconTexture: Interface\AddOns\Fuyutsui\core\Spell_Misc_EmotionHappy.blp ## OptionalDeps: LibRangeCheck-3.0 diff --git a/Fuyutsui/core/config.lua b/Fuyutsui/core/config.lua index 8c897f04..93baeedf 100644 --- a/Fuyutsui/core/config.lua +++ b/Fuyutsui/core/config.lua @@ -80,7 +80,7 @@ Fuyutsui.difficultyToText = { -- 首领ID Fuyutsui.bossID = { [0] = 0, -- 未战斗 - -- 团本 + -- 虚影尖塔 [3176] = 1, -- 元首阿福扎恩 [3177] = 2, -- 弗拉希乌斯 [3179] = 3, -- 陨落之王萨哈达尔 diff --git a/Shigure.csproj b/Shigure.csproj index 0bd24453..bb8859ac 100644 --- a/Shigure.csproj +++ b/Shigure.csproj @@ -9,9 +9,9 @@ Shigure Shigure Arasaka Corporation - 1.2.1.10 - 1.2.1.10 - 1.2.1.10 + 1.2.1.11 + 1.2.1.11 + 1.2.1.11 Assets\arasaka-icon.ico PerMonitorV2 diff --git a/UI/ClassConfigEditorControl.cs b/UI/ClassConfigEditorControl.cs index 5d7f3668..d888125d 100644 --- a/UI/ClassConfigEditorControl.cs +++ b/UI/ClassConfigEditorControl.cs @@ -101,8 +101,8 @@ public sealed class ClassConfigEditorControl : UserControl RowCount = 1, Margin = new Padding(0) }; - root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 154)); - root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 196)); + root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 146)); + root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 184)); root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); Controls.Add(root); @@ -118,8 +118,8 @@ public sealed class ClassConfigEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 2, - Padding = new Padding(14), - Margin = new Padding(0, 0, 12, 0) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, UiTheme.PageGap, 0) }; panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); panel.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); @@ -161,8 +161,8 @@ public sealed class ClassConfigEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 2, - Padding = new Padding(14), - Margin = new Padding(0, 0, 12, 0) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, UiTheme.PageGap, 0) }; panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); panel.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); @@ -199,10 +199,8 @@ public sealed class ClassConfigEditorControl : UserControl private static void StyleActionButton(Button button) { - button.AutoSize = false; - button.Size = new Size(110, 36); + UiTheme.StyleActionButton(button); button.Margin = new Padding(0, 0, 0, 8); - button.TextAlign = ContentAlignment.MiddleCenter; } private Control BuildEditor() @@ -217,15 +215,15 @@ public sealed class ClassConfigEditorControl : UserControl }; root.RowStyles.Add(new RowStyle(SizeType.Absolute, 92)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 64)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 68)); var header = new UiCardPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 2, - Padding = new Padding(14, 12, 14, 12), - Margin = new Padding(0, 0, 0, 12) + Padding = new Padding(UiTheme.CardPadding, 12, UiTheme.CardPadding, 12), + Margin = new Padding(0, 0, 0, UiTheme.PageGap) }; header.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 56)); header.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); @@ -254,8 +252,8 @@ public sealed class ClassConfigEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 1, - Margin = new Padding(0, 12, 0, 0), - Padding = new Padding(14, 10, 14, 10) + Margin = new Padding(0, UiTheme.PageGap, 0, 0), + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10) }; actionRow.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); actionRow.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 228)); @@ -291,7 +289,7 @@ public sealed class ClassConfigEditorControl : UserControl RowCount = 2, Margin = new Padding(0) }; - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 42)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, UiTheme.TabBarHeight)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var tabBar = new TableLayoutPanel @@ -314,7 +312,7 @@ public sealed class ClassConfigEditorControl : UserControl ColumnCount = 1, RowCount = 1, Margin = new Padding(0), - Padding = new Padding(14) + Padding = new Padding(0) }; contentCard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); contentCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); @@ -341,6 +339,7 @@ public sealed class ClassConfigEditorControl : UserControl page.Dock = DockStyle.Fill; page.Visible = false; page.BackColor = UiTheme.SurfaceRaised; + page.Padding = new Padding(UiTheme.CardPadding); contentHost.Controls.Add(page); } @@ -971,10 +970,10 @@ public sealed class ClassConfigEditorControl : UserControl }; var up = UiTheme.CreateButton("▲", UiTheme.Field, UiTheme.Text); var down = UiTheme.CreateButton("▼", UiTheme.Field, UiTheme.Text); - up.AutoSize = false; - down.AutoSize = false; - up.Size = new Size(48, 32); - down.Size = new Size(48, 32); + UiTheme.StyleActionButton(up, 48); + UiTheme.StyleActionButton(down, 48); + up.Margin = new Padding(0, 4, 8, 4); + down.Margin = new Padding(0, 4, 0, 4); up.Click += (_, _) => MoveSelectedRow(grid, -1); down.Click += (_, _) => MoveSelectedRow(grid, 1); bar.Controls.Add(up); diff --git a/UI/ClassMacrosEditorControl.cs b/UI/ClassMacrosEditorControl.cs index 827295eb..2416b6c9 100644 --- a/UI/ClassMacrosEditorControl.cs +++ b/UI/ClassMacrosEditorControl.cs @@ -64,7 +64,7 @@ public sealed class ClassMacrosEditorControl : UserControl RowCount = 1, Margin = new Padding(0) }; - root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 154)); + root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 146)); root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); Controls.Add(root); @@ -79,8 +79,8 @@ public sealed class ClassMacrosEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 2, - Padding = new Padding(14), - Margin = new Padding(0, 0, 12, 0) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, UiTheme.PageGap, 0) }; panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); panel.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); @@ -115,10 +115,8 @@ public sealed class ClassMacrosEditorControl : UserControl private static void StyleActionButton(Button button) { - button.AutoSize = false; - button.Size = new Size(110, 36); + UiTheme.StyleActionButton(button); button.Margin = new Padding(0, 0, 0, 8); - button.TextAlign = ContentAlignment.MiddleCenter; } private Control BuildEditor() @@ -134,15 +132,15 @@ public sealed class ClassMacrosEditorControl : UserControl root.RowStyles.Add(new RowStyle(SizeType.Absolute, 92)); root.RowStyles.Add(new RowStyle(SizeType.Absolute, 36)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 64)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 68)); var header = new UiCardPanel { Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 2, - Padding = new Padding(14, 12, 14, 12), - Margin = new Padding(0, 0, 0, 12) + Padding = new Padding(UiTheme.CardPadding, 12, UiTheme.CardPadding, 12), + Margin = new Padding(0, 0, 0, UiTheme.PageGap) }; header.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 56)); header.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); @@ -182,8 +180,8 @@ public sealed class ClassMacrosEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 1, - Margin = new Padding(0, 12, 0, 0), - Padding = new Padding(14, 10, 14, 10) + Margin = new Padding(0, UiTheme.PageGap, 0, 0), + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10) }; actionRow.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); actionRow.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 228)); @@ -219,7 +217,7 @@ public sealed class ClassMacrosEditorControl : UserControl RowCount = 2, Margin = new Padding(0) }; - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 42)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, UiTheme.TabBarHeight)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var tabBar = new TableLayoutPanel @@ -242,7 +240,7 @@ public sealed class ClassMacrosEditorControl : UserControl ColumnCount = 1, RowCount = 1, Margin = new Padding(0), - Padding = new Padding(14) + Padding = new Padding(0) }; contentCard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); contentCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); @@ -267,6 +265,7 @@ public sealed class ClassMacrosEditorControl : UserControl page.Dock = DockStyle.Fill; page.Visible = false; page.BackColor = UiTheme.SurfaceRaised; + page.Padding = new Padding(UiTheme.CardPadding); contentHost.Controls.Add(page); } @@ -318,7 +317,7 @@ public sealed class ClassMacrosEditorControl : UserControl BackColor = UiTheme.SurfaceRaised, Margin = new Padding(0) }; - root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 196)); + root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 184)); root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); root.Controls.Add(BuildDynamicSpecSidebar(), 0, 0); @@ -509,10 +508,10 @@ public sealed class ClassMacrosEditorControl : UserControl }; var up = UiTheme.CreateButton("▲", UiTheme.Field, UiTheme.Text); var down = UiTheme.CreateButton("▼", UiTheme.Field, UiTheme.Text); - up.AutoSize = false; - down.AutoSize = false; - up.Size = new Size(48, 32); - down.Size = new Size(48, 32); + UiTheme.StyleActionButton(up, 48); + UiTheme.StyleActionButton(down, 48); + up.Margin = new Padding(0, 4, 8, 4); + down.Margin = new Padding(0, 4, 0, 4); up.Click += (_, _) => MoveSelectedRow(grid, -1); down.Click += (_, _) => MoveSelectedRow(grid, 1); bar.Controls.Add(up); diff --git a/UI/ConditionEditorForm.cs b/UI/ConditionEditorForm.cs index 306b6220..03e47676 100644 --- a/UI/ConditionEditorForm.cs +++ b/UI/ConditionEditorForm.cs @@ -314,7 +314,8 @@ public sealed class ConditionEditorForm : Form { Text = "编辑条件"; Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point); - BackColor = UiTheme.Background; + AutoScaleMode = AutoScaleMode.Dpi; + BackColor = UiTheme.Surface; ForeColor = UiTheme.Text; var initialHeight = _allowSubConditions ? 650 : 460; ClientSize = new Size(1080, initialHeight); @@ -328,8 +329,8 @@ public sealed class ConditionEditorForm : Form var root = new TableLayoutPanel { Dock = DockStyle.Fill, - BackColor = UiTheme.Background, - Padding = new Padding(12, 10, 12, 10), + BackColor = UiTheme.Surface, + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10), ColumnCount = 1 }; Controls.Add(root); @@ -338,15 +339,11 @@ public sealed class ConditionEditorForm : Form var rowIndex = 0; root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - root.Controls.Add(_conditionsGrid, 0, rowIndex++); - - // 「添加条件」紧贴主条件行下方, 明确它作用于上面的主条件(而非子条件)。 - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 48)); - root.Controls.Add(BuildAddConditionRow(), 0, rowIndex++); + root.Controls.Add(BuildConditionsCard(), 0, rowIndex++); if (_allowSubConditions) { - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 188)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 200)); root.Controls.Add(BuildSubConditionsPanel(), 0, rowIndex++); } @@ -355,23 +352,50 @@ public sealed class ConditionEditorForm : Form _previewLabel.TextAlign = ContentAlignment.MiddleLeft; _previewLabel.AutoEllipsis = true; _previewLabel.Margin = new Padding(0); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); - root.Controls.Add(_previewLabel, 0, rowIndex++); + var previewCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding, 6, UiTheme.CardPadding, 6), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 1 + }; + previewCard.Controls.Add(_previewLabel, 0, 0); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 48)); + root.Controls.Add(previewCard, 0, rowIndex++); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 40)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 56)); root.Controls.Add(BuildActionRow(), 0, rowIndex++); root.RowCount = rowIndex; } + private Control BuildConditionsCard() + { + var card = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 2 + }; + card.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + card.RowStyles.Add(new RowStyle(SizeType.Absolute, 44)); + _conditionsGrid.Margin = new Padding(0); + card.Controls.Add(_conditionsGrid, 0, 0); + card.Controls.Add(BuildAddConditionRow(), 0, 1); + return card; + } + // 子条件区: 标题 + 暗色列表 + 添加/编辑/删除。每条子条件本身也是一条完整条件, // 通过嵌套的(无子条件区的)条件编辑弹窗来编辑。 private Control BuildSubConditionsPanel() { - var panel = new TableLayoutPanel + var panel = new UiCardPanel { Dock = DockStyle.Fill, - BackColor = UiTheme.Background, - Margin = new Padding(0, 4, 0, 4), + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), ColumnCount = 2, RowCount = 2 }; @@ -392,10 +416,8 @@ public sealed class ConditionEditorForm : Form panel.SetColumnSpan(title, 2); _subList.Dock = DockStyle.Fill; - _subList.BackColor = UiTheme.Field; - _subList.ForeColor = UiTheme.Text; - _subList.BorderStyle = BorderStyle.FixedSingle; - _subList.IntegralHeight = false; + UiTheme.StyleListBox(_subList, Font); + _subList.BackColor = UiTheme.Surface; _subList.Margin = new Padding(0, 0, 12, 0); _subList.DoubleClick += (_, _) => EditSelectedSubCondition(); panel.Controls.Add(_subList, 0, 1); @@ -405,7 +427,7 @@ public sealed class ConditionEditorForm : Form Dock = DockStyle.Fill, FlowDirection = FlowDirection.TopDown, WrapContents = false, - BackColor = UiTheme.Background, + BackColor = Color.Transparent, Margin = new Padding(0), Padding = new Padding(0, 0, 4, 0) }; @@ -940,8 +962,8 @@ public sealed class ConditionEditorForm : Form Dock = DockStyle.Fill, FlowDirection = FlowDirection.LeftToRight, WrapContents = false, - BackColor = UiTheme.Background, - Margin = new Padding(0, 4, 0, 4) + BackColor = Color.Transparent, + Margin = new Padding(0, 8, 0, 0) }; var addButton = UiTheme.CreateButton("添加条件", UiTheme.Field, UiTheme.Text); @@ -955,8 +977,9 @@ public sealed class ConditionEditorForm : Form var row = AddRow(null); RefreshConnectors(); UpdatePreview(); - _conditionsGrid.CurrentCell = row.Cells[TypeColumn]; - _conditionsGrid.BeginEdit(true); + ShowConditionComboDropDown( + row.Index, + _conditionsGrid.Columns[TypeColumn]!.Index); }; panel.Controls.Add(addButton); return panel; @@ -964,36 +987,35 @@ public sealed class ConditionEditorForm : Form private Control BuildActionRow() { - var row = new TableLayoutPanel + var row = new UiCardPanel { Dock = DockStyle.Fill, - BackColor = UiTheme.Background, Margin = new Padding(0), + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10), ColumnCount = 2, RowCount = 1 }; row.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); - row.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 170)); + row.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 184)); + row.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var rightButtons = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.RightToLeft, WrapContents = false, - BackColor = UiTheme.Background, + BackColor = Color.Transparent, Margin = new Padding(0) }; - var okButton = UiTheme.CreateButton("确定", UiTheme.Accent, Color.Black); - okButton.Width = 72; - okButton.Height = 30; - okButton.Margin = new Padding(6, 4, 0, 0); + var okButton = UiTheme.CreateButton("确定", UiTheme.ButtonKind.Primary); + UiTheme.StyleActionButton(okButton, 80); + okButton.Margin = new Padding(8, 0, 0, 0); okButton.Click += (_, _) => TryConfirm(); - var cancelButton = UiTheme.CreateButton("取消", UiTheme.Field, UiTheme.Text); - cancelButton.Width = 72; - cancelButton.Height = 30; - cancelButton.Margin = new Padding(6, 4, 0, 0); + var cancelButton = UiTheme.CreateButton("取消", UiTheme.ButtonKind.Secondary); + UiTheme.StyleActionButton(cancelButton, 80); + cancelButton.Margin = new Padding(8, 0, 0, 0); cancelButton.Click += (_, _) => DialogResult = DialogResult.Cancel; rightButtons.Controls.Add(okButton); diff --git a/UI/FormulaEditorForm.cs b/UI/FormulaEditorForm.cs index 1e247387..24375bd8 100644 --- a/UI/FormulaEditorForm.cs +++ b/UI/FormulaEditorForm.cs @@ -24,7 +24,8 @@ public sealed class FormulaEditorForm : Form { Text = "编辑公式"; Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point); - BackColor = UiTheme.Background; + AutoScaleMode = AutoScaleMode.Dpi; + BackColor = UiTheme.Surface; ForeColor = UiTheme.Text; ClientSize = new Size(760, 260); FormBorderStyle = FormBorderStyle.FixedDialog; @@ -36,55 +37,78 @@ public sealed class FormulaEditorForm : Form var root = new TableLayoutPanel { Dock = DockStyle.Fill, - BackColor = UiTheme.Background, - Padding = new Padding(12), + BackColor = UiTheme.Surface, + Padding = new Padding(UiTheme.CardPadding, 12, UiTheme.CardPadding, 12), ColumnCount = 1, RowCount = 2 }; root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 40)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 56)); Controls.Add(root); _formulaBox.Multiline = true; _formulaBox.ScrollBars = ScrollBars.Vertical; _formulaBox.Text = FormulaText; _formulaBox.Dock = DockStyle.Fill; - _formulaBox.Margin = new Padding(0, 0, 0, 8); + _formulaBox.Margin = new Padding(0); UiTheme.StyleTextBox(_formulaBox); - root.Controls.Add(_formulaBox, 0, 0); + var editorCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 2 + }; + editorCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); + editorCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + editorCard.Controls.Add(UiTheme.CreateSectionTitle(Font, "公式表达式"), 0, 0); + editorCard.Controls.Add(_formulaBox, 0, 1); + root.Controls.Add(editorCard, 0, 0); root.Controls.Add(BuildActionRow(), 0, 1); } private Control BuildActionRow() { - var row = new FlowLayoutPanel + var row = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10), + Margin = new Padding(0), + ColumnCount = 2, + RowCount = 1 + }; + row.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + row.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 184)); + row.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + + var actions = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.RightToLeft, WrapContents = false, - BackColor = UiTheme.Background, + BackColor = Color.Transparent, Margin = new Padding(0) }; - var okButton = UiTheme.CreateButton("确定", UiTheme.Accent, Color.Black); - okButton.Width = 72; - okButton.Height = 30; - okButton.Margin = new Padding(6, 6, 0, 0); + var okButton = UiTheme.CreateButton("确定", UiTheme.ButtonKind.Primary); + UiTheme.StyleActionButton(okButton, 84); + okButton.Margin = new Padding(8, 0, 0, 0); okButton.Click += (_, _) => { FormulaText = _formulaBox.Text.Trim(); DialogResult = DialogResult.OK; }; - var cancelButton = UiTheme.CreateButton("取消", UiTheme.Field, UiTheme.Text); - cancelButton.Width = 72; - cancelButton.Height = 30; - cancelButton.Margin = new Padding(6, 6, 0, 0); + var cancelButton = UiTheme.CreateButton("取消", UiTheme.ButtonKind.Secondary); + UiTheme.StyleActionButton(cancelButton, 84); + cancelButton.Margin = new Padding(8, 0, 0, 0); cancelButton.Click += (_, _) => DialogResult = DialogResult.Cancel; - row.Controls.Add(okButton); - row.Controls.Add(cancelButton); + actions.Controls.Add(okButton); + actions.Controls.Add(cancelButton); + row.Controls.Add(actions, 1, 0); AcceptButton = okButton; CancelButton = cancelButton; return row; diff --git a/UI/MainForm.cs b/UI/MainForm.cs index 6c278cd2..159859db 100644 --- a/UI/MainForm.cs +++ b/UI/MainForm.cs @@ -741,32 +741,15 @@ public sealed class MainForm : Form, IMessageFilter }; panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50)); panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50)); - const int settingsCardHeight = 232; - const int settingsCardGap = 14; - const int settingsActionButtonHeight = 36; - // 第一行包含 14px 下间距;第二行无需间距,因此卡片的实际高度均为 232px。 + const int settingsCardHeight = 190; + const int settingsCardGap = UiTheme.PageGap; + const int settingsActionButtonHeight = UiTheme.ActionButtonHeight; panel.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsCardHeight + settingsCardGap)); panel.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsCardHeight + settingsCardGap)); panel.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsCardHeight)); - Label CreateTitle(string text) => new() - { - Text = text, - Dock = DockStyle.Fill, - ForeColor = UiTheme.Text, - Font = new Font(Font.FontFamily, 11F, FontStyle.Bold), - TextAlign = ContentAlignment.MiddleLeft, - Margin = new Padding(0) - }; - Label CreateDescription(string text) => new() - { - Text = text, - Dock = DockStyle.Fill, - ForeColor = UiTheme.Muted, - AutoEllipsis = true, - TextAlign = ContentAlignment.MiddleLeft, - Margin = new Padding(0) - }; + Label CreateTitle(string text) => UiTheme.CreateSectionTitle(Font, text); + Label CreateDescription(string text) => UiTheme.CreateDescription(text); Label CreateSettingLabel(string text) => new() { Text = text, @@ -781,13 +764,13 @@ public sealed class MainForm : Form, IMessageFilter Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 4, - Padding = new Padding(18), - Margin = new Padding(0, 0, 7, 14) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, settingsCardGap / 2, settingsCardGap) }; inputCard.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100)); inputCard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); inputCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 32)); - inputCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + inputCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); inputCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight + 8)); inputCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight + 8)); inputCard.Controls.Add(CreateTitle("输入与运行"), 0, 0); @@ -822,11 +805,11 @@ public sealed class MainForm : Form, IMessageFilter Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 4, - Padding = new Padding(18), - Margin = new Padding(7, 0, 0, 14) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(settingsCardGap / 2, 0, 0, settingsCardGap) }; configCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 32)); - configCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + configCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); configCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); configCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight)); configCard.Controls.Add(CreateTitle("配置同步"), 0, 0); @@ -852,13 +835,13 @@ public sealed class MainForm : Form, IMessageFilter Dock = DockStyle.Fill, ColumnCount = 2, RowCount = 4, - Padding = new Padding(18), - Margin = new Padding(0, 0, 7, settingsCardGap) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, settingsCardGap / 2, settingsCardGap) }; moduleCard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); - moduleCard.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 140)); + moduleCard.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 132)); moduleCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 32)); - moduleCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + moduleCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); moduleCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight)); moduleCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); moduleCard.Controls.Add(CreateTitle("模块选择"), 0, 0); @@ -902,11 +885,11 @@ public sealed class MainForm : Form, IMessageFilter Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 4, - Padding = new Padding(18), - Margin = new Padding(7, 0, 0, settingsCardGap) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(settingsCardGap / 2, 0, 0, settingsCardGap) }; getModulesCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 32)); - getModulesCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + getModulesCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); getModulesCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); getModulesCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight)); getModulesCard.Controls.Add(CreateTitle("获取模块"), 0, 0); @@ -969,11 +952,11 @@ public sealed class MainForm : Form, IMessageFilter Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 4, - Padding = new Padding(18), - Margin = new Padding(0, 0, 7, 0) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, settingsCardGap / 2, 0) }; layoutCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 32)); - layoutCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + layoutCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); layoutCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); layoutCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight)); layoutCard.Controls.Add(CreateTitle("界面布局"), 0, 0); @@ -1019,11 +1002,11 @@ public sealed class MainForm : Form, IMessageFilter Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 4, - Padding = new Padding(18), - Margin = new Padding(7, 0, 0, 0) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(settingsCardGap / 2, 0, 0, 0) }; closeBehaviorCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 32)); - closeBehaviorCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + closeBehaviorCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); closeBehaviorCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); closeBehaviorCard.RowStyles.Add(new RowStyle(SizeType.Absolute, settingsActionButtonHeight)); closeBehaviorCard.Controls.Add(CreateTitle("点击 X 时(关闭窗口按钮)"), 0, 0); diff --git a/UI/ModuleEditorControl.cs b/UI/ModuleEditorControl.cs index fc6c3fbc..f2b5ff9f 100644 --- a/UI/ModuleEditorControl.cs +++ b/UI/ModuleEditorControl.cs @@ -151,7 +151,7 @@ public sealed class ModuleEditorControl : UserControl RowCount = 2, Margin = new Padding(0) }; - root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 300)); + root.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 280)); root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); root.RowStyles.Add(new RowStyle(SizeType.Absolute, ModuleFooterBarHeight)); @@ -168,8 +168,8 @@ public sealed class ModuleEditorControl : UserControl var sidebar = new UiCardPanel { Dock = DockStyle.Fill, - Padding = new Padding(14), - Margin = new Padding(0, 0, 12, 12), + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, UiTheme.PageGap, UiTheme.PageGap), ColumnCount = 1, RowCount = 1 }; @@ -193,8 +193,8 @@ public sealed class ModuleEditorControl : UserControl var footer = new UiCardPanel { Dock = DockStyle.Fill, - Padding = new Padding(14, 10, 14, 10), - Margin = new Padding(0, 0, 12, 0), + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10), + Margin = new Padding(0, 0, UiTheme.PageGap, 0), ColumnCount = 3, RowCount = 1 }; @@ -258,7 +258,7 @@ public sealed class ModuleEditorControl : UserControl Dock = DockStyle.Fill, BackColor = UiTheme.Surface, Padding = new Padding(0), - Margin = new Padding(0, 0, 0, 12), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), ColumnCount = 1, RowCount = 3 }; @@ -277,13 +277,13 @@ public sealed class ModuleEditorControl : UserControl var root = new TableLayoutPanel { Dock = DockStyle.Fill, - Margin = new Padding(0, 12, 0, 0), + Margin = new Padding(0, UiTheme.PageGap, 0, 0), Padding = new Padding(0), BackColor = UiTheme.Surface, ColumnCount = 1, RowCount = 2 }; - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 42)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, UiTheme.TabBarHeight)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var tabBar = new TableLayoutPanel @@ -390,7 +390,7 @@ public sealed class ModuleEditorControl : UserControl BackColor = UiTheme.SurfaceRaised, ColumnCount = 1, RowCount = 4, - Padding = new Padding(14), + Padding = new Padding(UiTheme.CardPadding), Margin = new Padding(0) }; @@ -415,7 +415,7 @@ public sealed class ModuleEditorControl : UserControl BackColor = UiTheme.SurfaceRaised, ColumnCount = 1, RowCount = 1, - Padding = new Padding(14), + Padding = new Padding(UiTheme.CardPadding), Margin = new Padding(0) }; @@ -432,7 +432,7 @@ public sealed class ModuleEditorControl : UserControl BackColor = UiTheme.SurfaceRaised, ColumnCount = 2, RowCount = 1, - Padding = new Padding(14), + Padding = new Padding(UiTheme.CardPadding), Margin = new Padding(0) }; panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); @@ -499,8 +499,8 @@ public sealed class ModuleEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 4, RowCount = 2, - Padding = new Padding(14, 10, 14, 8), - Margin = new Padding(0, 0, 0, 12) + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 8), + Margin = new Padding(0, 0, 0, UiTheme.PageGap) }; // 名称/作者各占剩余宽度的一半, 两个输入框等宽并铺满窗口。 row.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 58)); @@ -551,7 +551,7 @@ public sealed class ModuleEditorControl : UserControl Dock = DockStyle.Fill, ColumnCount = 12, RowCount = 2, - Padding = new Padding(14), + Padding = new Padding(UiTheme.CardPadding), Margin = new Padding(0) }; foreach (var label in matchLabels) @@ -3161,7 +3161,7 @@ public sealed class ModuleEditorControl : UserControl ColumnCount = 3, RowCount = 1, Margin = new Padding(0), - Padding = new Padding(14, 10, 14, 10) + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10) }; row.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 148)); row.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); diff --git a/UI/RuleTextEditorForm.cs b/UI/RuleTextEditorForm.cs index 71b5a392..7d3842cc 100644 --- a/UI/RuleTextEditorForm.cs +++ b/UI/RuleTextEditorForm.cs @@ -27,7 +27,8 @@ internal sealed class RuleTextEditorForm : Form { Text = "编辑规则注释"; Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point); - BackColor = UiTheme.Background; + AutoScaleMode = AutoScaleMode.Dpi; + BackColor = UiTheme.Surface; ForeColor = UiTheme.Text; ClientSize = new Size(760, 380); MinimumSize = new Size(620, 320); @@ -40,46 +41,66 @@ internal sealed class RuleTextEditorForm : Form var root = new TableLayoutPanel { Dock = DockStyle.Fill, - BackColor = UiTheme.Background, - Padding = new Padding(14, 12, 14, 12), + BackColor = UiTheme.Surface, + Padding = new Padding(UiTheme.CardPadding, 12, UiTheme.CardPadding, 12), ColumnCount = 1, - RowCount = 3 + RowCount = 2 }; - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 50)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 56)); Controls.Add(root); - root.Controls.Add(CreateLabel("注释"), 0, 0); ConfigureMultilineTextBox(_commentBox, wordWrap: true); - _commentBox.Margin = new Padding(0, 0, 0, 8); - root.Controls.Add(_commentBox, 0, 1); + _commentBox.Margin = new Padding(0); + var editorCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 2 + }; + editorCard.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); + editorCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + editorCard.Controls.Add(UiTheme.CreateSectionTitle(Font, "规则注释"), 0, 0); + editorCard.Controls.Add(_commentBox, 0, 1); + root.Controls.Add(editorCard, 0, 0); + + var actionCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Margin = Padding.Empty, + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10), + ColumnCount = 2, + RowCount = 1 + }; + actionCard.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + actionCard.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 184)); + actionCard.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var actions = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.RightToLeft, WrapContents = false, - BackColor = UiTheme.Background, - Margin = Padding.Empty, - Padding = new Padding(0, 8, 0, 0) + BackColor = Color.Transparent, + Margin = Padding.Empty }; - var saveButton = UiTheme.CreateButton("保存", UiTheme.Accent, Color.Black); - saveButton.AutoSize = false; - saveButton.Size = new Size(84, 36); - saveButton.Margin = Padding.Empty; + var saveButton = UiTheme.CreateButton("保存", UiTheme.ButtonKind.Primary); + UiTheme.StyleActionButton(saveButton, 84); + saveButton.Margin = new Padding(8, 0, 0, 0); saveButton.Click += (_, _) => SaveAndClose(); - var cancelButton = UiTheme.CreateButton("取消", UiTheme.Field, UiTheme.Text); - cancelButton.AutoSize = false; - cancelButton.Size = new Size(84, 36); - cancelButton.Margin = new Padding(0, 0, 10, 0); + var cancelButton = UiTheme.CreateButton("取消", UiTheme.ButtonKind.Secondary); + UiTheme.StyleActionButton(cancelButton, 84); + cancelButton.Margin = new Padding(8, 0, 0, 0); cancelButton.Click += (_, _) => DialogResult = DialogResult.Cancel; actions.Controls.Add(saveButton); actions.Controls.Add(cancelButton); - root.Controls.Add(actions, 0, 2); + actionCard.Controls.Add(actions, 1, 0); + root.Controls.Add(actionCard, 0, 1); AcceptButton = saveButton; CancelButton = cancelButton; diff --git a/UI/StatusForm.cs b/UI/StatusForm.cs index 0c81d25f..879d4e84 100644 --- a/UI/StatusForm.cs +++ b/UI/StatusForm.cs @@ -15,6 +15,8 @@ internal enum SettingsPage Party, Logic, Logs, + BossNumbers, + CommonFields, About } @@ -28,6 +30,8 @@ internal enum SettingsNavIcon Party, Logic, Logs, + BossNumbers, + CommonFields, About } @@ -37,6 +41,171 @@ public sealed class StatusForm : Form private const int AboutWatermarkSize = 440; private const int AboutWatermarkTopMargin = 16; private const float AboutWatermarkOpacity = 0.08F; + private const int BossNumberCardWidth = 400; + + private static readonly IReadOnlyList CurrentSeasonDungeonNames = + [ + "烈毒之渊", + "潮缚石窟", + "毒牙祭坛", + "纳洛拉克的洞穴", + "密谋小径", + "夺目谷", + "诸王之眠", + "红玉新生法池", + "虚空之痕竞技场", + "塞塔里斯神庙" + ]; + + private static readonly IReadOnlyList BossNumberGroups = + [ + new(string.Empty, + [ + new("虚影尖塔", + [ + new(1, "元首阿福扎恩", 1), + new(2, "弗拉希乌斯", 2), + new(3, "陨落之王萨哈达尔", 3), + new(4, "威厄高尔和艾佐拉克", 4), + new(5, "光盲先锋军", 5), + new(6, "宇宙之冕", 6) + ]), + new("梦境裂隙", [new(1, "奇美鲁斯,未梦之神", 7)]), + new("奎尔丹纳斯岛", + [ + new(1, "贝洛朗,奥的子嗣", 8), + new(2, "至暗之夜降临", 9) + ]), + new("世界", + [ + new(1, "鲁阿夏尔", 10), + new(2, "索姆贝兰", 11), + new(3, "普雷达萨斯", 12), + new(4, "克拉格平", 13) + ]), + new("孢陨幽境", [new(1, "腐沼", 14)]), + new("潮缚石窟", [new(1, "尼姆瑞莎·唤波者", 15)]), + new("烈毒之渊", + [ + new(1, "盘魂者内克扎莉", 16), + new(2, "陵寝哨兵", 17), + new(3, "迷失的探险者", 18), + new(4, "万毒邪祟者瓦什尼克", 19), + new(5, "斯索拉克", 20), + new(6, "双子毒牙", 21), + new(7, "盘卷祭坛", 22), + new(8, "乌拉特克", 23) + ]) + ]), + new("大米", + [ + new("节点希纳斯", + [ + new(1, "核技工程长卡斯雷瑟", 51), + new(2, "核心守卫奈萨拉", 52), + new(3, "洛萨克森", 53) + ]), + new("迈萨拉洞窟", + [ + new(1, "姆罗金和内克拉克斯", 54), + new(2, "沃达扎", 55), + new(3, "拉克图尔,聚魂之器", 56) + ]), + new("风行者之塔", + [ + new(1, "烬晓", 57), + new(2, "被遗弃的二人组", 58), + new(3, "指挥官克罗鲁科", 59), + new(4, "无眠之心", 60) + ]), + new("魔导师平台", + [ + new(1, "奥能金刚库斯托斯", 61), + new(2, "瑟拉奈尔·日鞭", 62), + new(3, "吉美尔鲁斯", 63), + new(4, "迪詹崔乌斯", 64) + ]), + new("执政团之座", + [ + new(1, "晋升者祖拉尔", 65), + new(2, "萨普瑞什", 66), + new(3, "总督奈扎尔", 67), + new(4, "鲁拉", 68) + ]), + new("艾杰斯亚学院", + [ + new(1, "维克萨姆斯", 69), + new(2, "茂林古树", 70), + new(3, "克罗兹", 71), + new(4, "多拉苟萨的回响", 72) + ]), + new("萨隆矿坑", + [ + new(1, "熔炉之主加弗斯特", 73), + new(2, "伊克和科瑞克", 74), + new(3, "天灾领主泰兰努斯", 75) + ]), + new("通天峰", + [ + new(1, "兰吉特", 76), + new(2, "阿拉卡纳斯", 77), + new(3, "鲁克兰", 78), + new(4, "高阶贤者维里克斯", 79) + ]), + new("毒牙祭坛", + [ + new(1, "拉维", 80), + new(2, "扭缠盘蛇", 81), + new(3, "祖尔加", 82) + ]), + new("纳洛拉克的洞穴", + [ + new(1, "囤宝狂人", 83), + new(2, "寒冬哨兵", 84), + new(3, "纳洛拉克", 85) + ]), + new("密谋小径", + [ + new(1, "凯斯媞亚·魔力之心", 86), + new(2, "赞恩·刃悲", 87), + new(3, "歼灭者萨祖克斯", 88), + new(4, "利希尔·烬怒", 89) + ]), + new("夺目谷", + [ + new(1, "光明众花", 90), + new(2, "圣光猎手伊库兹", 91), + new(3, "护光者鲁伊亚", 92), + new(4, "兹欧凯特", 93) + ]), + new("诸王之眠", + [ + new(1, "黄金风蛇", 94), + new(2, "部族议会", 95), + new(3, "殓尸者姆沁巴", 96), + new(4, "达萨大王", 97) + ]), + new("红玉新生法池", + [ + new(1, "梅莉杜莎·寒妆", 98), + new(2, "柯姬雅·焰蹄", 99), + new(3, "基拉卡与厄克哈特·风脉", 100) + ]), + new("虚空之痕竞技场", + [ + new(1, "塔兹拉尔", 101), + new(2, "阿特洛苏斯", 102), + new(3, "煞戎努斯", 103) + ]), + new("塞塔里斯神庙", + [ + new(1, "阿德里斯和阿斯匹克斯", 104), + new(2, "米利克萨", 105), + new(3, "加瓦兹特", 106), + new(4, "塞塔里斯的化身", 107) + ]) + ]) + ]; private readonly List<(SettingsNavButton Button, Control View, SettingsPage Page)> _navItems = new(); private readonly Dictionary _listCounts = new(); @@ -138,22 +307,22 @@ public sealed class StatusForm : Form _moduleHost = CreatePageHost(); _aboutHost = CreatePageHost(); - _stateList = UiTheme.CreateListView(Font, "status-state", - new UiTheme.ListColumn("#", 48, 48, FixedWidth: true), - new UiTheme.ListColumn("名称", 110, 260), - new UiTheme.ListColumn("值", 100, 900, FillRemaining: true)); - _auraList = UiTheme.CreateListView(Font, "status-aura", - new UiTheme.ListColumn("#", 48, 48, FixedWidth: true), - new UiTheme.ListColumn("光环", 120, 300), - new UiTheme.ListColumn("值", 96, 900, FillRemaining: true)); - _dynamicUnitList = UiTheme.CreateListView(Font, "status-dynamic-unit", - new UiTheme.ListColumn("类型", 72, 160), - new UiTheme.ListColumn("名称", 92, 280), - new UiTheme.ListColumn("值", 96, 900, FillRemaining: true)); - _spellList = UiTheme.CreateListView(Font, "status-spell", - new UiTheme.ListColumn("#", 48, 48, FixedWidth: true), - new UiTheme.ListColumn("技能", 120, 300), - new UiTheme.ListColumn("状态", 100, 900, FillRemaining: true)); + _stateList = UiTheme.CreateListView(Font, "status-state-v2", + new UiTheme.ListColumn("#", 28, 28, FixedWidth: true), + new UiTheme.ListColumn("名称", 40, 220), + new UiTheme.ListColumn("值", 40, 900, FillRemaining: true)); + _auraList = UiTheme.CreateListView(Font, "status-aura-v2", + new UiTheme.ListColumn("#", 28, 28, FixedWidth: true), + new UiTheme.ListColumn("光环", 40, 260), + new UiTheme.ListColumn("值", 40, 900, FillRemaining: true)); + _dynamicUnitList = UiTheme.CreateListView(Font, "status-dynamic-unit-v2", + new UiTheme.ListColumn("类型", 40, 140), + new UiTheme.ListColumn("名称", 40, 240), + new UiTheme.ListColumn("值", 40, 900, FillRemaining: true)); + _spellList = UiTheme.CreateListView(Font, "status-spell-v2", + new UiTheme.ListColumn("#", 28, 28, FixedWidth: true), + new UiTheme.ListColumn("技能", 40, 260), + new UiTheme.ListColumn("状态", 40, 900, FillRemaining: true)); _partyList = UiTheme.CreateListView(Font, "status-party", new UiTheme.ListColumn("单位", 120, 180, FixedWidth: true), @@ -179,7 +348,7 @@ public sealed class StatusForm : Form { Dock = DockStyle.Fill, BackColor = UiTheme.Surface, - Padding = new Padding(20), + Padding = new Padding(16), Margin = new Padding(0) }; @@ -194,8 +363,11 @@ public sealed class StatusForm : Form AddNavItem(nav, SettingsPage.Party, SettingsNavIcon.Party, "队伍", CreatePageShell("队伍", "当前队伍单位与扫描字段摘要", BuildSection("队伍成员", _partyList, "实时队伍数据"))); AddNavItem(nav, SettingsPage.Logic, SettingsNavIcon.Logic, "逻辑", CreatePageShell("逻辑", "运行时推荐目标与调试值", BuildSection("逻辑信息", _unitInfoList, "当前模块的决策输出"))); AddNavItem(nav, SettingsPage.Logs, SettingsNavIcon.Logs, "日志", CreatePageShell("日志", "运行、模块匹配与施放记录", BuildLogPage())); + AddNavGroup(nav, "说明"); + AddNavItem(nav, SettingsPage.BossNumbers, SettingsNavIcon.BossNumbers, "首领编号", CreatePageShell("首领编号", "副本首领的序号、名称与扫描编号", BuildBossNumbersPage())); + AddNavItem(nav, SettingsPage.CommonFields, SettingsNavIcon.CommonFields, "常用字段", CreatePageShell("常用字段", "模块条件可用的状态字段参考", BuildCommonFieldsPanel())); AddNavGroup(nav, "系统"); - AddNavItem(nav, SettingsPage.About, SettingsNavIcon.About, "关于", CreatePageShell("关于", "应用信息与状态字段参考", _aboutHost)); + AddNavItem(nav, SettingsPage.About, SettingsNavIcon.About, "关于", CreatePageShell("关于", "应用信息", _aboutHost)); _aboutHost.Controls.Add(BuildAboutPanel()); root.Controls.Add(navShell, 0, 0); @@ -224,12 +396,12 @@ public sealed class StatusForm : Form BackColor = UiTheme.Background, ColumnCount = 1, RowCount = 3, - Padding = new Padding(12, 16, 12, 12), + Padding = new Padding(12, 10, 12, 8), Margin = new Padding(0) }; - shell.RowStyles.Add(new RowStyle(SizeType.Absolute, 74)); + shell.RowStyles.Add(new RowStyle(SizeType.Absolute, 54)); shell.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - shell.RowStyles.Add(new RowStyle(SizeType.Absolute, 34)); + shell.RowStyles.Add(new RowStyle(SizeType.Absolute, 20)); var brand = new TableLayoutPanel { @@ -309,40 +481,47 @@ public sealed class StatusForm : Form RowCount = 2, Margin = new Padding(0) }; - // 预留标题实际高度与 header 的 14px 下边距,避免高 DPI 下标题被裁切。 - shell.RowStyles.Add(new RowStyle(SizeType.Absolute, hasSubtitle ? 84 : 60)); + // 所有页面统一使用单行页头,标题与说明文字保持各自原有字号。 + shell.RowStyles.Add(new RowStyle(SizeType.Absolute, 50)); shell.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var header = new TableLayoutPanel { Dock = DockStyle.Fill, BackColor = UiTheme.Surface, - ColumnCount = 1, - RowCount = hasSubtitle ? 2 : 1, - Margin = new Padding(0, 0, 0, 14) + ColumnCount = hasSubtitle ? 2 : 1, + RowCount = 1, + Margin = new Padding(0, 0, 0, UiTheme.PageGap) }; - header.RowStyles.Add(new RowStyle(SizeType.Absolute, 46)); + header.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + header.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + if (hasSubtitle) + { + header.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + } + header.Controls.Add(new Label { Text = title, Dock = DockStyle.Fill, + AutoSize = true, ForeColor = UiTheme.Text, Font = new Font(Font.FontFamily, 16F, FontStyle.Bold), - TextAlign = ContentAlignment.MiddleLeft, - Margin = new Padding(0) + TextAlign = ContentAlignment.BottomLeft, + Margin = new Padding(0, 0, hasSubtitle ? 14 : 0, 0) }, 0, 0); if (hasSubtitle) { - header.RowStyles.Add(new RowStyle(SizeType.Absolute, 24)); header.Controls.Add(new Label { Text = subtitle, Dock = DockStyle.Fill, + AutoEllipsis = true, ForeColor = UiTheme.Muted, Font = new Font(Font.FontFamily, 9.5F, FontStyle.Regular), - TextAlign = ContentAlignment.MiddleLeft, + TextAlign = ContentAlignment.BottomLeft, Margin = new Padding(0) - }, 0, 1); + }, 1, 0); } shell.Controls.Add(header, 0, 0); @@ -362,24 +541,61 @@ public sealed class StatusForm : Form RowCount = 1, Margin = new Padding(0) }; - for (var i = 0; i < 4; i++) - { - statusSplit.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25)); - } - statusSplit.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - var state = BuildSection("状态", _stateList, "基础字段与当前模块"); - state.Margin = new Padding(0, 0, 6, 0); - var aura = BuildSection("光环", _auraList, "光环数值状态"); - aura.Margin = new Padding(6, 0, 6, 0); - var spell = BuildSection("技能", _spellList, "冷却与可用状态"); - spell.Margin = new Padding(6, 0, 6, 0); - var units = BuildSection("动态单位", _dynamicUnitList, "模块运行时计算值"); - units.Margin = new Padding(6, 0, 0, 0); - statusSplit.Controls.Add(state, 0, 0); - statusSplit.Controls.Add(aura, 1, 0); - statusSplit.Controls.Add(spell, 2, 0); - statusSplit.Controls.Add(units, 3, 0); + var sections = new[] + { + BuildSection("状态", _stateList, "基础字段与当前模块"), + BuildSection("光环", _auraList, "光环数值状态"), + BuildSection("技能", _spellList, "冷却与可用状态"), + BuildSection("动态单位", _dynamicUnitList, "模块运行时计算值") + }; + bool? usingCompactLayout = null; + + void ApplyLayout() + { + // 四张卡片需要为三列表头保留可读宽度;不足时切成 2×2,避免原生横向滚动条。 + // ClientSize 已是当前 WinForms 布局坐标,不再二次按 DPI 放大断点。 + var compact = statusSplit.ClientSize.Width < 1100; + if (usingCompactLayout == compact) + { + return; + } + + usingCompactLayout = compact; + statusSplit.SuspendLayout(); + statusSplit.Controls.Clear(); + statusSplit.ColumnStyles.Clear(); + statusSplit.RowStyles.Clear(); + statusSplit.ColumnCount = compact ? 2 : 4; + statusSplit.RowCount = compact ? 2 : 1; + for (var column = 0; column < statusSplit.ColumnCount; column++) + { + statusSplit.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F / statusSplit.ColumnCount)); + } + + for (var row = 0; row < statusSplit.RowCount; row++) + { + statusSplit.RowStyles.Add(new RowStyle(SizeType.Percent, 100F / statusSplit.RowCount)); + } + + for (var i = 0; i < sections.Length; i++) + { + var column = compact ? i % 2 : i; + var row = compact ? i / 2 : 0; + sections[i].Margin = new Padding( + column == 0 ? 0 : UiTheme.PageGap / 2, + row == 0 ? 0 : UiTheme.PageGap / 2, + column == statusSplit.ColumnCount - 1 ? 0 : UiTheme.PageGap / 2, + row == statusSplit.RowCount - 1 ? 0 : UiTheme.PageGap / 2); + statusSplit.Controls.Add(sections[i], column, row); + } + + statusSplit.ResumeLayout(true); + } + + statusSplit.SizeChanged += (_, _) => ApplyLayout(); + statusSplit.HandleCreated += (_, _) => BeginInvoke(ApplyLayout); + ApplyLayout(); return statusSplit; } @@ -390,11 +606,11 @@ public sealed class StatusForm : Form Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 3, - Padding = new Padding(16), + Padding = new Padding(UiTheme.CardPadding), Margin = new Padding(0) }; - section.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); - section.RowStyles.Add(new RowStyle(SizeType.Absolute, 24)); + section.RowStyles.Add(new RowStyle(SizeType.Absolute, 28)); + section.RowStyles.Add(new RowStyle(SizeType.Absolute, 22)); section.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var heading = new TableLayoutPanel @@ -428,6 +644,7 @@ public sealed class StatusForm : Form TextAlign = ContentAlignment.MiddleCenter, Margin = new Padding(4, 2, 0, 2) }; + UiTheme.ApplyControlRoundedRegion(countLabel, UiTheme.ControlCornerRadius); _listCounts[listView] = countLabel; heading.Controls.Add(countLabel, 1, 0); } @@ -443,7 +660,7 @@ public sealed class StatusForm : Form }, 0, 1); content.Dock = DockStyle.Fill; - content.Margin = new Padding(0, 12, 0, 0); + content.Margin = new Padding(0, 8, 0, 0); section.Controls.Add(content, 0, 2); return section; } @@ -455,10 +672,10 @@ public sealed class StatusForm : Form Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 2, - Padding = new Padding(16), + Padding = new Padding(UiTheme.CardPadding), Margin = new Padding(0) }; - card.RowStyles.Add(new RowStyle(SizeType.Absolute, 44)); + card.RowStyles.Add(new RowStyle(SizeType.Absolute, 42)); card.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); var toolbar = new FlowLayoutPanel @@ -470,6 +687,7 @@ public sealed class StatusForm : Form Margin = new Padding(0) }; var copyButton = UiTheme.CreateButton("复制全部", UiTheme.ButtonKind.Secondary); + UiTheme.StyleActionButton(copyButton, 96); copyButton.Margin = new Padding(0, 0, 8, 6); copyButton.Click += (_, _) => { @@ -479,17 +697,16 @@ public sealed class StatusForm : Form } }; var clearButton = UiTheme.CreateButton("清空显示", UiTheme.ButtonKind.Danger); + UiTheme.StyleActionButton(clearButton, 96); clearButton.Margin = new Padding(0, 0, 16, 6); clearButton.Click += (_, _) => _logTextBox.Clear(); var autoScroll = new CheckBox { Text = "自动滚动", Checked = true, - AutoSize = true, - ForeColor = UiTheme.Text, - BackColor = UiTheme.SurfaceRaised, Margin = new Padding(0, 8, 0, 0) }; + UiTheme.StyleCheckBox(autoScroll, UiTheme.SurfaceRaised); autoScroll.CheckedChanged += (_, _) => _autoScrollLog = autoScroll.Checked; toolbar.Controls.Add(copyButton); toolbar.Controls.Add(clearButton); @@ -595,12 +812,12 @@ public sealed class StatusForm : Form { Text = text, AutoSize = false, - Size = new Size(192, 30), + Size = new Size(192, 25), ForeColor = UiTheme.Muted, Font = new Font(Font.FontFamily, 9F, FontStyle.Bold), - TextAlign = ContentAlignment.BottomLeft, - Padding = new Padding(10, 0, 0, 4), - Margin = new Padding(0, nav.Controls.Count == 0 ? 0 : 10, 0, 3) + TextAlign = ContentAlignment.MiddleLeft, + Padding = new Padding(10, 0, 0, 0), + Margin = new Padding(0, nav.Controls.Count == 0 ? 0 : 6, 0, 2) }); } @@ -614,9 +831,9 @@ public sealed class StatusForm : Form { Text = text, AutoSize = false, - Size = new Size(192, 44), + Size = new Size(192, 39), Font = new Font(Font.FontFamily, 10F, FontStyle.Regular), - Margin = new Padding(0, 0, 0, 3), + Margin = new Padding(0, 0, 0, 1), Cursor = Cursors.Hand, TabStop = true, AccessibleName = text @@ -642,6 +859,204 @@ public sealed class StatusForm : Form } } + private Control BuildBossNumbersPage() + { + var scrollHost = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = UiTheme.Surface, + Margin = new Padding(0) + }; + + var cards = new TableLayoutPanel + { + Dock = DockStyle.None, + Anchor = AnchorStyles.Top | AnchorStyles.Left, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + BackColor = UiTheme.Surface, + ColumnCount = 4, + RowCount = 0, + MinimumSize = new Size(BossNumberCardWidth * 4 + UiTheme.PageGap * 3, 0), + Padding = new Padding(0), + Margin = new Padding(0) + }; + + var allDungeons = BossNumberGroups + .SelectMany(group => group.Dungeons) + .ToDictionary(dungeon => dungeon.Name, StringComparer.Ordinal); + var currentSeasonNames = CurrentSeasonDungeonNames.ToHashSet(StringComparer.Ordinal); + IReadOnlyList seasonGroups = + [ + new("当前赛季", CurrentSeasonDungeonNames.Select(name => allDungeons[name]).ToArray()), + new("第一赛季", BossNumberGroups + .SelectMany(group => group.Dungeons) + .Where(dungeon => !currentSeasonNames.Contains(dungeon.Name)) + .ToArray()) + ]; + + var seasonViews = seasonGroups + .Select(group => + { + var title = new Label + { + Text = group.Title, + AutoSize = true, + ForeColor = UiTheme.Text, + BackColor = Color.Transparent, + Font = new Font(Font.FontFamily, 12F, FontStyle.Bold) + }; + var groupCards = group.Dungeons.Select(CreateBossNumberCard).ToArray(); + foreach (var card in groupCards) + { + card.Margin = new Padding(0, 0, 0, UiTheme.PageGap); + } + + return (Title: title, Cards: groupCards); + }) + .ToArray(); + + void ApplyLayout() + { + const int columnCount = 4; + cards.SuspendLayout(); + cards.Controls.Clear(); + cards.ColumnStyles.Clear(); + cards.RowStyles.Clear(); + cards.ColumnCount = columnCount; + cards.RowCount = 0; + for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) + { + var columnWidth = BossNumberCardWidth + + (columnIndex < columnCount - 1 ? UiTheme.PageGap : 0); + cards.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, columnWidth)); + } + + var row = 0; + var column = 0; + foreach (var (title, groupCards) in seasonViews) + { + if (column != 0) + { + row++; + column = 0; + } + + cards.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + cards.RowCount = row + 1; + title.Margin = new Padding(2, row == 0 ? 0 : UiTheme.PageGap, 0, UiTheme.PageGap); + cards.Controls.Add(title, 0, row); + cards.SetColumnSpan(title, columnCount); + row++; + + foreach (var card in groupCards) + { + if (cards.RowStyles.Count <= row) + { + cards.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + cards.RowCount = row + 1; + } + + cards.Controls.Add(card, column, row); + + column++; + if (column == columnCount) + { + column = 0; + row++; + } + } + } + + cards.ResumeLayout(true); + } + + scrollHost.Controls.Add(cards); + ApplyLayout(); + return scrollHost; + } + + private Control CreateBossNumberCard(BossDungeon dungeon) + { + var card = new UiCardPanel + { + AutoSize = false, + Size = new Size( + BossNumberCardWidth, + UiTheme.CardPadding * 2 + 34 + (dungeon.Bosses.Count + 1) * 28), + ColumnCount = 1, + RowCount = 2, + Padding = new Padding(UiTheme.CardPadding), + MinimumSize = new Size(0, 0) + }; + card.RowStyles.Add(new RowStyle(SizeType.Absolute, 34)); + card.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + card.Controls.Add(new Label + { + Text = dungeon.Name, + Dock = DockStyle.Fill, + ForeColor = UiTheme.Accent, + BackColor = Color.Transparent, + Font = new Font(Font.FontFamily, 10F, FontStyle.Bold), + TextAlign = ContentAlignment.MiddleLeft, + Margin = new Padding(0) + }, 0, 0); + + var table = new TableLayoutPanel + { + Dock = DockStyle.Top, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + BackColor = Color.Transparent, + ColumnCount = 3, + RowCount = dungeon.Bosses.Count + 1, + Margin = new Padding(0) + }; + table.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 64)); + table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + table.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 64)); + AddBossNumberCell(table, "序号", 0, 0, UiTheme.Muted, FontStyle.Bold, ContentAlignment.MiddleCenter); + AddBossNumberCell(table, "名称", 1, 0, UiTheme.Muted, FontStyle.Bold, ContentAlignment.MiddleLeft); + AddBossNumberCell(table, "编号", 2, 0, UiTheme.Muted, FontStyle.Bold, ContentAlignment.MiddleCenter); + + for (var index = 0; index < dungeon.Bosses.Count; index++) + { + var boss = dungeon.Bosses[index]; + var tableRow = index + 1; + AddBossNumberCell(table, boss.Sequence.ToString(), 0, tableRow, UiTheme.Muted, FontStyle.Regular, ContentAlignment.MiddleCenter); + AddBossNumberCell(table, boss.Name, 1, tableRow, UiTheme.Text, FontStyle.Regular, ContentAlignment.MiddleLeft); + AddBossNumberCell(table, boss.Number.ToString(), 2, tableRow, UiTheme.Accent, FontStyle.Regular, ContentAlignment.MiddleCenter); + } + + card.Controls.Add(table, 0, 1); + return card; + } + + private void AddBossNumberCell( + TableLayoutPanel table, + string text, + int column, + int row, + Color color, + FontStyle style, + ContentAlignment alignment) + { + table.Controls.Add(new Label + { + Text = text, + Dock = DockStyle.Fill, + AutoSize = false, + Height = 28, + AutoEllipsis = true, + ForeColor = color, + BackColor = Color.Transparent, + Font = new Font(Font.FontFamily, 9F, style), + TextAlign = alignment, + Margin = new Padding(column == 1 ? 6 : 0, 0, column == 1 ? 6 : 0, 0) + }, column, row); + } + private Control BuildAboutPanel() { var scrollHost = new WatermarkPanel( @@ -663,13 +1078,11 @@ public sealed class StatusForm : Form AutoSizeMode = AutoSizeMode.GrowAndShrink, BackColor = Color.Transparent, ColumnCount = 1, - RowCount = 3, + RowCount = 1, Padding = new Padding(0), Margin = new Padding(0) }; panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - panel.RowStyles.Add(new RowStyle(SizeType.AutoSize)); var infoCard = new UiCardPanel { @@ -677,8 +1090,8 @@ public sealed class StatusForm : Form Dock = DockStyle.Top, ColumnCount = 1, RowCount = 2, - Padding = new Padding(14), - Margin = new Padding(0, 0, 0, 12) + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0) }; infoCard.RowStyles.Add(new RowStyle(SizeType.AutoSize)); infoCard.RowStyles.Add(new RowStyle(SizeType.AutoSize)); @@ -690,7 +1103,7 @@ public sealed class StatusForm : Form BackColor = Color.Transparent, ColumnCount = 1, RowCount = 2, - Margin = new Padding(0, 0, 0, 16) + Margin = new Padding(0, 0, 0, UiTheme.PageGap) }; heading.RowStyles.Add(new RowStyle(SizeType.AutoSize)); heading.RowStyles.Add(new RowStyle(SizeType.AutoSize)); @@ -744,21 +1157,25 @@ public sealed class StatusForm : Form infoCard.Controls.Add(details, 0, 1); panel.Controls.Add(infoCard, 0, 0); - panel.Controls.Add(new Label + scrollHost.Controls.Add(panel); + return scrollHost; + } + + private Control BuildCommonFieldsPanel() + { + var scrollHost = new Panel { - Text = "可用状态字段", - AutoSize = true, - ForeColor = UiTheme.Text, - BackColor = Color.Transparent, - Font = new Font(Font.FontFamily, 12F, FontStyle.Bold), - Margin = new Padding(2, 6, 0, 12) - }, 0, 1); + Dock = DockStyle.Fill, + BackColor = UiTheme.Surface, + AutoScroll = true, + Margin = new Padding(0) + }; var fields = new TableLayoutPanel { AutoSize = true, Dock = DockStyle.Top, - BackColor = Color.Transparent, + BackColor = UiTheme.Surface, ColumnCount = 2, RowCount = 3, Margin = new Padding(0) @@ -769,7 +1186,7 @@ public sealed class StatusForm : Form fields.RowStyles.Add(new RowStyle(SizeType.AutoSize)); fields.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - fields.Controls.Add(CreateAboutFieldCard( + fields.Controls.Add(CreateCommonFieldCard( "状态", [ "有效性", "战斗时间", "移动", "生命值", "一键辅助", "插入法术", @@ -779,7 +1196,7 @@ public sealed class StatusForm : Form "酒池", "符文", "姿态", "神圣军备", "自律", "英勇打击", "收割者战刃" ], 150), 0, 0); - fields.Controls.Add(CreateAboutFieldCard( + fields.Controls.Add(CreateCommonFieldCard( "能量", [ "法力值", "怒气值", "集中值", "能量值", "符文", "符文能量", @@ -787,40 +1204,39 @@ public sealed class StatusForm : Form "连击点", "神圣能量", "精华能量", "灵魂碎片", "真气", "增压层数" ], 150), 1, 0); - fields.Controls.Add(CreateAboutFieldCard( + fields.Controls.Add(CreateCommonFieldCard( "配置开关", ["爆发开关", "AOE开关", "输出模式", "爆发药水开关", "延迟"], 92), 0, 1); - fields.Controls.Add(CreateAboutFieldCard( + fields.Controls.Add(CreateCommonFieldCard( "物品", ["治疗药水", "魔法药水", "治疗石", "鲁莽药水", "圣光潜力"], 92), 1, 1); - fields.Controls.Add(CreateAboutFieldCard( + fields.Controls.Add(CreateCommonFieldCard( "目标", ["类型", "生命值", "距离", "施法(倒计时)", "施法(正计时)", "施法可打断", "引导", "引导可打断"], 104), 0, 2); - fields.Controls.Add(CreateAboutFieldCard( + fields.Controls.Add(CreateCommonFieldCard( "焦点", ["类型", "生命值", "距离", "施法(倒计时)", "施法(正计时)", "施法可打断", "引导", "引导可打断"], 104), 1, 2); - panel.Controls.Add(fields, 0, 2); - scrollHost.Controls.Add(panel); + scrollHost.Controls.Add(fields); return scrollHost; } private static string GetEmbeddedResourceName(string resourcePath) => $"{typeof(StatusForm).Namespace}.{resourcePath}"; - private Control CreateAboutFieldCard(string title, IReadOnlyList items, int minimumHeight) + private Control CreateCommonFieldCard(string title, IReadOnlyList items, int minimumHeight) { var card = new UiCardPanel { Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 2, - Padding = new Padding(14), - Margin = new Padding(0, 0, 12, 12), + Padding = new Padding(UiTheme.CardPadding), + Margin = new Padding(0, 0, UiTheme.PageGap, UiTheme.PageGap), MinimumSize = new Size(0, minimumHeight) }; card.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); @@ -832,7 +1248,7 @@ public sealed class StatusForm : Form Dock = DockStyle.Fill, ForeColor = UiTheme.Accent, BackColor = Color.Transparent, - Font = new Font(Font.FontFamily, 10.5F, FontStyle.Bold), + Font = new Font(Font.FontFamily, 10F, FontStyle.Bold), TextAlign = ContentAlignment.MiddleLeft, Margin = new Padding(0) }, 0, 0); @@ -843,7 +1259,7 @@ public sealed class StatusForm : Form AutoSize = false, ForeColor = UiTheme.Text, BackColor = Color.Transparent, - Font = new Font(Font.FontFamily, 9.5F, FontStyle.Regular), + Font = new Font(Font.FontFamily, 9F, FontStyle.Regular), TextAlign = ContentAlignment.TopLeft, Margin = new Padding(0, 6, 0, 0) }, 0, 1); @@ -891,7 +1307,7 @@ public sealed class StatusForm : Form BackColor = Color.Transparent, AutoEllipsis = true, TextAlign = ContentAlignment.MiddleLeft, - Margin = new Padding(0, 0, 18, 14) + Margin = new Padding(0, 0, 18, 8) }, 0, row); var valueLabel = new Label { @@ -902,7 +1318,7 @@ public sealed class StatusForm : Form ForeColor = UiTheme.Text, BackColor = Color.Transparent, TextAlign = ContentAlignment.MiddleLeft, - Margin = new Padding(0, 0, 0, 14) + Margin = new Padding(0, 0, 0, 8) }; _toolTip.SetToolTip(valueLabel, tooltip ?? value); panel.Controls.Add(valueLabel, 1, row); @@ -1589,6 +2005,19 @@ public sealed class StatusForm : Form graphics.DrawLine(pen, x + w * 0.32f, y + h * 0.52f, x + w * 0.68f, y + h * 0.52f); graphics.DrawLine(pen, x + w * 0.32f, y + h * 0.70f, x + w * 0.58f, y + h * 0.70f); break; + case SettingsNavIcon.BossNumbers: + graphics.DrawRectangle(pen, x + w * 0.12f, y + h * 0.12f, w * 0.76f, h * 0.76f); + graphics.DrawLine(pen, x + w * 0.38f, y + h * 0.27f, x + w * 0.31f, y + h * 0.73f); + graphics.DrawLine(pen, x + w * 0.65f, y + h * 0.27f, x + w * 0.58f, y + h * 0.73f); + graphics.DrawLine(pen, x + w * 0.25f, y + h * 0.43f, x + w * 0.72f, y + h * 0.43f); + graphics.DrawLine(pen, x + w * 0.22f, y + h * 0.59f, x + w * 0.69f, y + h * 0.59f); + break; + case SettingsNavIcon.CommonFields: + graphics.DrawRectangle(pen, x + w * 0.12f, y + h * 0.12f, w * 0.76f, h * 0.76f); + graphics.DrawLine(pen, x + w * 0.34f, y + h * 0.12f, x + w * 0.34f, y + h * 0.88f); + graphics.DrawLine(pen, x + w * 0.12f, y + h * 0.38f, x + w * 0.88f, y + h * 0.38f); + graphics.DrawLine(pen, x + w * 0.12f, y + h * 0.63f, x + w * 0.88f, y + h * 0.63f); + break; case SettingsNavIcon.About: graphics.DrawEllipse(pen, x + w * 0.12f, y + h * 0.12f, w * 0.76f, h * 0.76f); graphics.FillEllipse(brush, x + w * 0.46f, y + h * 0.28f, w * 0.08f, h * 0.08f); @@ -1604,4 +2033,10 @@ public sealed class StatusForm : Form graphics.FillEllipse(brush, x + width * knobPosition - knobSize / 2, y - knobSize / 2, knobSize, knobSize); } } + + private sealed record BossNumberGroup(string Title, IReadOnlyList Dungeons); + + private sealed record BossDungeon(string Name, IReadOnlyList Bosses); + + private sealed record BossNumberEntry(int Sequence, string Name, int Number); } diff --git a/UI/UiCardPanel.cs b/UI/UiCardPanel.cs index fee6183e..3658721d 100644 --- a/UI/UiCardPanel.cs +++ b/UI/UiCardPanel.cs @@ -6,7 +6,7 @@ namespace Shigure; internal sealed class UiCardPanel : TableLayoutPanel { private Color _fillColor = UiTheme.SurfaceRaised; - private int _cornerRadius = 10; + private int _cornerRadius = UiTheme.CardCornerRadius; public UiCardPanel() { diff --git a/UI/UiPillTab.cs b/UI/UiPillTab.cs index 1ae8ee25..2bdb2c99 100644 --- a/UI/UiPillTab.cs +++ b/UI/UiPillTab.cs @@ -27,7 +27,8 @@ internal sealed class UiPillTab : Control BackColor = Color.Transparent; ForeColor = UiTheme.Muted; Margin = new Padding(3, 2, 3, 2); - TabStop = false; + TabStop = true; + AccessibleRole = AccessibleRole.PageTab; } [Browsable(false)] @@ -82,6 +83,29 @@ internal sealed class UiPillTab : Control } } + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.KeyCode is Keys.Enter or Keys.Space) + { + OnClick(EventArgs.Empty); + e.Handled = true; + e.SuppressKeyPress = true; + } + } + + protected override void OnGotFocus(EventArgs e) + { + base.OnGotFocus(e); + Invalidate(); + } + + protected override void OnLostFocus(EventArgs e) + { + base.OnLostFocus(e); + Invalidate(); + } + protected override void OnPaint(PaintEventArgs e) { var graphics = e.Graphics; @@ -98,7 +122,7 @@ internal sealed class UiPillTab : Control if (fill.A > 0) { - using var path = UiTheme.CreateRoundedRectanglePath(bounds, UiTheme.Scale(this, 8)); + using var path = UiTheme.CreateRoundedRectanglePath(bounds, UiTheme.Scale(this, UiTheme.ControlCornerRadius)); using var brush = new SolidBrush(fill); graphics.FillPath(brush, path); if (_selected) @@ -125,5 +149,11 @@ internal sealed class UiPillTab : Control | TextFormatFlags.SingleLine | TextFormatFlags.EndEllipsis | TextFormatFlags.NoPrefix); + + if (Focused && ShowFocusCues) + { + var focusBounds = Rectangle.Inflate(bounds, -4, -4); + ControlPaint.DrawFocusRectangle(graphics, focusBounds, UiTheme.Text, fill); + } } } diff --git a/UI/UiTheme.cs b/UI/UiTheme.cs index 5bc02364..d175b0c3 100644 --- a/UI/UiTheme.cs +++ b/UI/UiTheme.cs @@ -8,6 +8,14 @@ namespace Shigure; internal static class UiTheme { + public const int PageGap = 12; + public const int CardPadding = 14; + public const int ActionButtonHeight = 36; + public const int GridRowHeight = 40; + public const int TabBarHeight = 42; + public const int CardCornerRadius = 10; + public const int ControlCornerRadius = 8; + private static readonly Dictionary ClassIcons = new(); private static readonly Dictionary<(int ClassId, int SpecId), Image?> SpecIcons = new(); private static readonly ConditionalWeakTable ListColumnLayouts = new(); @@ -229,7 +237,50 @@ internal static class UiTheme button.FlatAppearance.BorderColor = backColor == Accent ? Accent : Border; button.FlatAppearance.MouseOverBackColor = backColor == Accent ? Color.FromArgb(112, 234, 221) : Hover; button.FlatAppearance.MouseDownBackColor = backColor == Accent ? Color.FromArgb(62, 194, 181) : Pressed; - ApplyControlRoundedRegion(button, 8); + ApplyControlRoundedRegion(button, ControlCornerRadius); + + if (backColor == Accent) + { + // WinForms ignores ForeColor for a disabled flat button and falls back to + // the system disabled-text color, which is nearly black on our dark theme. + button.Paint += (_, e) => PaintDisabledPrimaryButton(button, e); + } + + button.EnabledChanged += (_, _) => + { + button.Cursor = button.Enabled ? Cursors.Hand : Cursors.Default; + button.ForeColor = button.Enabled ? foreColor : Muted; + button.BackColor = button.Enabled ? backColor : SurfaceRaised; + button.FlatAppearance.BorderColor = button.Enabled ? (backColor == Accent ? Accent : Border) : Border; + button.Invalidate(); + }; + } + + private static void PaintDisabledPrimaryButton(Button button, PaintEventArgs e) + { + if (button.Enabled || button.ClientSize.Width <= 1 || button.ClientSize.Height <= 1) + { + return; + } + + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + var bounds = new Rectangle(0, 0, button.ClientSize.Width - 1, button.ClientSize.Height - 1); + using var path = CreateRoundedRectanglePath(bounds, Scale(button, ControlCornerRadius)); + using var backgroundBrush = new SolidBrush(SurfaceRaised); + using var borderPen = new Pen(Border); + e.Graphics.FillPath(backgroundBrush, path); + e.Graphics.DrawPath(borderPen, path); + TextRenderer.DrawText( + e.Graphics, + button.Text, + button.Font, + button.ClientRectangle, + Muted, + TextFormatFlags.HorizontalCenter + | TextFormatFlags.VerticalCenter + | TextFormatFlags.SingleLine + | TextFormatFlags.EndEllipsis + | TextFormatFlags.NoPadding); } public static Button CreateButton(string text, ButtonKind kind) @@ -368,6 +419,12 @@ internal static class UiTheme textBox.BackColor = Field; textBox.ForeColor = Text; textBox.BorderStyle = BorderStyle.FixedSingle; + textBox.Margin = new Padding(0); + textBox.EnabledChanged += (_, _) => + { + textBox.BackColor = textBox.Enabled ? Field : SurfaceRaised; + textBox.ForeColor = textBox.Enabled ? Text : Muted; + }; } public static void StyleNumericUpDown(NumericUpDown numeric) @@ -375,6 +432,12 @@ internal static class UiTheme numeric.BackColor = Field; numeric.ForeColor = Text; numeric.BorderStyle = BorderStyle.FixedSingle; + numeric.Margin = new Padding(0); + numeric.EnabledChanged += (_, _) => + { + numeric.BackColor = numeric.Enabled ? Field : SurfaceRaised; + numeric.ForeColor = numeric.Enabled ? Text : Muted; + }; } public static void StyleCheckedListBox(CheckedListBox listBox) @@ -387,6 +450,56 @@ internal static class UiTheme listBox.ItemHeight = Math.Max(30, listBox.Font.Height + 14); } + public static void StyleCheckBox(CheckBox checkBox, Color? backColor = null) + { + checkBox.AutoSize = true; + checkBox.ForeColor = Text; + checkBox.BackColor = backColor ?? Color.Transparent; + checkBox.Cursor = Cursors.Hand; + checkBox.FlatStyle = FlatStyle.Flat; + checkBox.FlatAppearance.BorderColor = Border; + checkBox.FlatAppearance.CheckedBackColor = AccentSoft; + checkBox.FlatAppearance.MouseOverBackColor = Hover; + checkBox.UseVisualStyleBackColor = false; + checkBox.EnabledChanged += (_, _) => + { + checkBox.Cursor = checkBox.Enabled ? Cursors.Hand : Cursors.Default; + checkBox.ForeColor = checkBox.Enabled ? Text : Muted; + }; + } + + public static void StyleActionButton(Button button, int width = 110) + { + button.AutoSize = false; + button.Size = new Size(width, ActionButtonHeight); + button.TextAlign = ContentAlignment.MiddleCenter; + } + + public static Label CreateSectionTitle(Font baseFont, string text) + => new() + { + Text = text, + Dock = DockStyle.Fill, + ForeColor = Text, + BackColor = Color.Transparent, + Font = new Font(baseFont.FontFamily, 10F, FontStyle.Bold), + TextAlign = ContentAlignment.MiddleLeft, + AutoEllipsis = true, + Margin = new Padding(0) + }; + + public static Label CreateDescription(string text) + => new() + { + Text = text, + Dock = DockStyle.Fill, + ForeColor = Muted, + BackColor = Color.Transparent, + TextAlign = ContentAlignment.MiddleLeft, + AutoEllipsis = true, + Margin = new Padding(0) + }; + public static void StyleComboBox(ComboBox comboBox) { comboBox.DropDownStyle = ComboBoxStyle.DropDownList; @@ -396,6 +509,8 @@ internal static class UiTheme comboBox.DrawMode = DrawMode.OwnerDrawFixed; comboBox.ItemHeight = Math.Max(28, comboBox.Font.Height + 12); comboBox.DropDownHeight = 320; + comboBox.Margin = new Padding(0); + comboBox.EnabledChanged += (_, _) => comboBox.Invalidate(); comboBox.DrawItem += (_, e) => { @@ -407,12 +522,23 @@ internal static class UiTheme var isSelected = (e.State & DrawItemState.Selected) == DrawItemState.Selected; var isEditBox = (e.State & DrawItemState.ComboBoxEdit) == DrawItemState.ComboBoxEdit; - using (var background = new SolidBrush(isEditBox ? Field : isSelected ? Hover : Surface)) + var backgroundColor = !comboBox.Enabled + ? SurfaceRaised + : isEditBox + ? Field + : isSelected + ? Hover + : Surface; + using (var background = new SolidBrush(backgroundColor)) { e.Graphics.FillRectangle(background, e.Bounds); } - var textColor = !isEditBox && isSelected ? Accent : Text; + var textColor = !comboBox.Enabled + ? Muted + : !isEditBox && isSelected + ? Accent + : Text; var textBounds = new Rectangle(e.Bounds.X + 8, e.Bounds.Y, e.Bounds.Width - 8, e.Bounds.Height); TextRenderer.DrawText( e.Graphics, @@ -444,6 +570,7 @@ internal static class UiTheme Scale(listBox, logicalItemHeight), font.Height + Scale(listBox, 14)); + var hoveredIndex = -1; listBox.DrawItem += (_, e) => { if (e.Index < 0) @@ -454,6 +581,8 @@ internal static class UiTheme var selected = (e.State & DrawItemState.Selected) == DrawItemState.Selected; var backgroundColor = selected ? Hover + : e.Index == hoveredIndex + ? SurfaceRaised : e.Index % 2 == 0 ? listBox.BackColor : RowAlt; @@ -523,6 +652,23 @@ internal static class UiTheme selected ? Text : Muted, TextFormatFlags.VerticalCenter | TextFormatFlags.Left | TextFormatFlags.EndEllipsis); }; + + listBox.MouseMove += (_, e) => + { + var index = listBox.IndexFromPoint(e.Location); + if (index == hoveredIndex) + { + return; + } + + hoveredIndex = index; + listBox.Invalidate(); + }; + listBox.MouseLeave += (_, _) => + { + hoveredIndex = -1; + listBox.Invalidate(); + }; } public static void StyleClassIconListBox( @@ -900,7 +1046,7 @@ internal static class UiTheme grid.DefaultCellStyle.WrapMode = DataGridViewTriState.False; grid.AlternatingRowsDefaultCellStyle.BackColor = RowAlt; grid.AlternatingRowsDefaultCellStyle.ForeColor = Text; - grid.RowTemplate.Height = Math.Max(40, grid.Font.Height + 16); + grid.RowTemplate.Height = Math.Max(GridRowHeight, grid.Font.Height + 16); grid.RowHeadersVisible = false; grid.AllowUserToResizeRows = false; grid.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal; @@ -910,7 +1056,7 @@ internal static class UiTheme { var verticalPadding = Scale(grid, 12); grid.ColumnHeadersHeight = Math.Max(Scale(grid, 38), grid.Font.Height + verticalPadding); - grid.RowTemplate.Height = Math.Max(Scale(grid, 40), grid.Font.Height + verticalPadding); + grid.RowTemplate.Height = Math.Max(Scale(grid, GridRowHeight), grid.Font.Height + verticalPadding); foreach (DataGridViewRow row in grid.Rows) { if (!row.IsNewRow) diff --git a/UI/UnitEditorForm.cs b/UI/UnitEditorForm.cs index 26993439..11e071a8 100644 --- a/UI/UnitEditorForm.cs +++ b/UI/UnitEditorForm.cs @@ -146,7 +146,8 @@ public sealed class UnitEditorForm : Form { Text = "编辑单位"; Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point); - BackColor = UiTheme.Background; + AutoScaleMode = AutoScaleMode.Dpi; + BackColor = UiTheme.Surface; ForeColor = UiTheme.Text; ClientSize = new Size(RowWidth + 36, 534); FormBorderStyle = FormBorderStyle.FixedDialog; @@ -158,16 +159,15 @@ public sealed class UnitEditorForm : Form var root = new TableLayoutPanel { Dock = DockStyle.Fill, - BackColor = UiTheme.Background, - Padding = new Padding(14, 12, 14, 12), + BackColor = UiTheme.Surface, + Padding = new Padding(UiTheme.CardPadding, 12, UiTheme.CardPadding, 12), ColumnCount = 1, - RowCount = 5 + RowCount = 4 }; - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 38)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 112)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 26)); - root.RowStyles.Add(new RowStyle(SizeType.Absolute, 42)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 48)); + root.RowStyles.Add(new RowStyle(SizeType.Absolute, 56)); Controls.Add(root); UiTheme.StyleComboBox(_categoryBox); @@ -189,27 +189,56 @@ public sealed class UnitEditorForm : Form UpdateHealthNameState(); }; - root.Controls.Add(BuildSplitRow("类别", _categoryBox, "选择器", _selectorBox), 0, 0); - root.Controls.Add(BuildNameRow(), 0, 1); + var headerCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(4), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 2 + }; + headerCard.RowStyles.Add(new RowStyle(SizeType.Percent, 50)); + headerCard.RowStyles.Add(new RowStyle(SizeType.Percent, 50)); + headerCard.Controls.Add(BuildSplitRow("类别", _categoryBox, "选择器", _selectorBox), 0, 0); + headerCard.Controls.Add(BuildNameRow(), 0, 1); + root.Controls.Add(headerCard, 0, 0); _paramPanel.Dock = DockStyle.Fill; - _paramPanel.BackColor = UiTheme.SurfaceRaised; + _paramPanel.BackColor = Color.Transparent; _paramPanel.FlowDirection = FlowDirection.TopDown; _paramPanel.WrapContents = false; _paramPanel.AutoScroll = true; - _paramPanel.Margin = new Padding(0, 8, 0, 6); - _paramPanel.Padding = new Padding(8, 6, 8, 6); + _paramPanel.Margin = new Padding(0); + _paramPanel.Padding = new Padding(4, 6, 4, 6); BuildParamRows(); - root.Controls.Add(_paramPanel, 0, 2); + var paramsCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(4), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 1 + }; + paramsCard.Controls.Add(_paramPanel, 0, 0); + root.Controls.Add(paramsCard, 0, 1); _previewLabel.Dock = DockStyle.Fill; _previewLabel.ForeColor = UiTheme.Muted; _previewLabel.TextAlign = ContentAlignment.MiddleLeft; _previewLabel.AutoEllipsis = true; - _previewLabel.Margin = new Padding(2, 2, 2, 0); - root.Controls.Add(_previewLabel, 0, 3); + _previewLabel.Margin = new Padding(0); + var previewCard = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding, 6, UiTheme.CardPadding, 6), + Margin = new Padding(0, 0, 0, UiTheme.PageGap), + ColumnCount = 1, + RowCount = 1 + }; + previewCard.Controls.Add(_previewLabel, 0, 0); + root.Controls.Add(previewCard, 0, 2); - root.Controls.Add(BuildActionRow(), 0, 4); + root.Controls.Add(BuildActionRow(), 0, 3); PopulateSelectors(); } @@ -260,8 +289,7 @@ public sealed class UnitEditorForm : Form _roleBox.SelectedIndex = 0; _reverseBox.Text = "取逆序最后一个匹配单位"; - _reverseBox.ForeColor = UiTheme.Text; - _reverseBox.BackColor = UiTheme.SurfaceRaised; + UiTheme.StyleCheckBox(_reverseBox, UiTheme.SurfaceRaised); _reverseBox.AutoSize = false; _reverseBox.TextAlign = ContentAlignment.MiddleLeft; @@ -329,29 +357,40 @@ public sealed class UnitEditorForm : Form private Control BuildActionRow() { - var row = new FlowLayoutPanel + var row = new UiCardPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(UiTheme.CardPadding, 10, UiTheme.CardPadding, 10), + Margin = new Padding(0), + ColumnCount = 2, + RowCount = 1 + }; + row.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + row.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 184)); + row.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + + var actions = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.RightToLeft, WrapContents = false, - BackColor = UiTheme.Background, + BackColor = Color.Transparent, Margin = new Padding(0) }; - var okButton = UiTheme.CreateButton("确定", UiTheme.Accent, Color.Black); - okButton.Width = 76; - okButton.Height = 30; - okButton.Margin = new Padding(6, 6, 0, 0); + var okButton = UiTheme.CreateButton("确定", UiTheme.ButtonKind.Primary); + UiTheme.StyleActionButton(okButton, 84); + okButton.Margin = new Padding(8, 0, 0, 0); okButton.Click += (_, _) => OnConfirm(); - var cancelButton = UiTheme.CreateButton("取消", UiTheme.Field, UiTheme.Text); - cancelButton.Width = 76; - cancelButton.Height = 30; - cancelButton.Margin = new Padding(6, 6, 0, 0); + var cancelButton = UiTheme.CreateButton("取消", UiTheme.ButtonKind.Secondary); + UiTheme.StyleActionButton(cancelButton, 84); + cancelButton.Margin = new Padding(8, 0, 0, 0); cancelButton.Click += (_, _) => DialogResult = DialogResult.Cancel; - row.Controls.Add(okButton); - row.Controls.Add(cancelButton); + actions.Controls.Add(okButton); + actions.Controls.Add(cancelButton); + row.Controls.Add(actions, 1, 0); AcceptButton = okButton; CancelButton = cancelButton; return row; @@ -1226,7 +1265,7 @@ public sealed class UnitEditorForm : Form return Math.Clamp(value, (int)box.Minimum, (int)box.Maximum); } - private static Panel BuildLabeledRow(string label, Control control, int height = 32) + private static Panel BuildLabeledRow(string label, Control control, int height = 44) { var panel = new Panel { @@ -1241,7 +1280,7 @@ public sealed class UnitEditorForm : Form Text = label, ForeColor = UiTheme.Muted, TextAlign = ContentAlignment.MiddleLeft, - Bounds = new Rectangle(0, 4, LabelWidth, 24), + Bounds = new Rectangle(0, height > 50 ? 4 : Math.Max(0, (height - 24) / 2), LabelWidth, 24), AutoEllipsis = true };