Files
Shigure/UI/UnitEditorForm.cs
waynebian01 da2eeb3b39 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.
2026-08-25 15:58:44 +08:00

1388 lines
51 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Drawing;
namespace Shigure;
/// <summary>
/// 动态单位 / 数量字段的编辑弹窗: 选择类别(单位/数量)与选择器, 按所选类型动态显隐参数控件。
/// 光环候选来自当前职业/专精的 group 字段。校验名称非空、唯一、非纯数字、不含 '.'/'$'。
/// </summary>
public sealed class UnitEditorForm : Form
{
private const int RowWidth = 800;
private const int LabelWidth = 132;
private const int ControlLeft = LabelWidth + 10;
private static readonly RoleOption[] RoleOptions =
[
new("坦克 (1)", 1),
new("治疗 (2)", 2),
new("输出 (3)", 3)
];
private static readonly DispelTypeOption[] DispelTypeOptions =
[
new("1: 魔法", 1),
new("2: 诅咒", 2),
new("3: 疾病", 3),
new("4: 中毒", 4)
];
private static readonly LowestHealthAuraFilterItem[] LowestHealthAuraFilterOptions =
[
new("不筛选光环", LowestHealthAuraFilterKind.None),
new("带任一光环", LowestHealthAuraFilterKind.WithAnyAura),
new("不带任一光环", LowestHealthAuraFilterKind.WithoutAnyAura),
new("不带某光环", LowestHealthAuraFilterKind.WithoutAura),
new("带某光环", LowestHealthAuraFilterKind.WithAura),
new("某光环值等于", LowestHealthAuraFilterKind.WithAuraCount)
];
private static readonly LowestHealthRoleFilterItem[] LowestHealthRoleFilterOptions =
[
new("不筛选职责", null),
new("包含某职责", UnitRoleFilterKind.Include),
new("不含某职责", UnitRoleFilterKind.Exclude)
];
private static readonly SelectorItem[] UnitSelectors =
[
new("生命值最低", UnitSelectorKind.LowestHealth),
new("治疗吸收最高", UnitSelectorKind.HighestHealingAbsorb),
new("按职责", UnitSelectorKind.UnitWithRole),
new("按职责且不带某光环", UnitSelectorKind.UnitWithRoleWithoutAura),
new("带某光环(持续最久)", UnitSelectorKind.UnitWithAura),
new("带某驱散类型", UnitSelectorKind.UnitWithDispelType)
];
private static readonly CountItem[] CountSelectors =
[
new("血量 - 低于阈值", CountKind.UnitsBelowHealth),
new("血量 - 低于阈值不带某光环", CountKind.UnitsWithoutAuraBelowHealth),
new("血量 - 低于阈值带某光环", CountKind.UnitsWithAuraBelowHealth),
new("治疗吸收 - 大于阈值", CountKind.UnitsAboveHealingAbsorb),
new("治疗吸收 - 大于阈值不带某光环", CountKind.UnitsWithoutAuraAboveHealingAbsorb),
new("治疗吸收 - 大于阈值带某光环", CountKind.UnitsWithAuraAboveHealingAbsorb),
new("光环 - 带某光环", CountKind.UnitsWithAura)
];
private static readonly ThresholdModeItem[] ThresholdModeOptions =
[
new("固定阈值", false),
new("动态阈值", true)
];
private readonly IReadOnlyList<string> _auraFields;
private readonly IReadOnlyList<string> _thresholdFields;
private readonly HashSet<string> _takenNames;
private readonly Label _healthNameLabel = new();
private readonly TextBox _nameBox = new();
private readonly TextBox _healthNameBox = new();
private readonly ComboBox _categoryBox = new();
private readonly ComboBox _selectorBox = new();
private readonly ComboBox _lowestHealthAuraFilterBox = new();
private readonly ComboBox _lowestHealthRoleFilterBox = new();
private readonly FlowLayoutPanel _paramPanel = new();
private readonly Label _previewLabel = new();
private readonly ToolTip _toolTip = new();
private readonly NumericUpDown _thresholdBox = new();
private readonly ComboBox _thresholdModeBox = new();
private readonly ComboBox _thresholdFieldBox = new();
private readonly ComboBox _roleBox = new();
private readonly CheckBox _reverseBox = new();
private readonly ComboBox _auraBox = new();
private readonly CheckedListBox _aurasBox = new();
private readonly NumericUpDown _auraCountBox = new();
private readonly ComboBox _dispelTypeBox = new();
private Panel _thresholdModeRow = null!;
private Panel _thresholdRow = null!;
private Label _thresholdLabel = null!;
private Panel _thresholdFieldRow = null!;
private Panel _lowestHealthAuraFilterRow = null!;
private Panel _lowestHealthRoleFilterRow = null!;
private Panel _roleRow = null!;
private Panel _reverseRow = null!;
private Panel _auraRow = null!;
private Panel _aurasRow = null!;
private Panel _auraCountRow = null!;
private Panel _dispelRow = null!;
private bool _usesHealingAbsorbThreshold;
public ModuleUnit? ResultUnit { get; private set; }
public ModuleCountField? ResultCount { get; private set; }
public UnitEditorForm(
IReadOnlyList<string> auraFields,
IReadOnlyList<string> thresholdFields,
IReadOnlyCollection<string> takenNames,
ModuleUnit? existingUnit,
ModuleCountField? existingCount)
{
_auraFields = auraFields;
_thresholdFields = thresholdFields;
_takenNames = new HashSet<string>(takenNames, StringComparer.OrdinalIgnoreCase);
InitializeComponent();
Seed(existingUnit, existingCount);
UpdateParamVisibility();
UpdateHealthNameState();
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
UiTheme.ApplyDarkTitleBar(this);
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
_nameBox.Focus();
_nameBox.SelectAll();
}
private void InitializeComponent()
{
Text = "编辑单位";
Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
AutoScaleMode = AutoScaleMode.Dpi;
BackColor = UiTheme.Surface;
ForeColor = UiTheme.Text;
ClientSize = new Size(RowWidth + 36, 534);
FormBorderStyle = FormBorderStyle.FixedDialog;
MaximizeBox = false;
MinimizeBox = false;
ShowInTaskbar = false;
StartPosition = FormStartPosition.CenterParent;
var root = new TableLayoutPanel
{
Dock = DockStyle.Fill,
BackColor = UiTheme.Surface,
Padding = new Padding(UiTheme.CardPadding, 12, UiTheme.CardPadding, 12),
ColumnCount = 1,
RowCount = 4
};
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 112));
root.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 48));
root.RowStyles.Add(new RowStyle(SizeType.Absolute, 56));
Controls.Add(root);
UiTheme.StyleComboBox(_categoryBox);
_categoryBox.DropDownWidth = 180;
_categoryBox.Items.AddRange(["单位 (可作目标)", "数量 (仅条件)"]);
_categoryBox.SelectedIndex = 0;
_categoryBox.SelectedIndexChanged += (_, _) =>
{
PopulateSelectors();
UpdateParamVisibility();
UpdateHealthNameState();
};
UiTheme.StyleComboBox(_selectorBox);
_selectorBox.DropDownWidth = 360;
_selectorBox.SelectedIndexChanged += (_, _) =>
{
UpdateParamVisibility();
UpdateHealthNameState();
};
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 = Color.Transparent;
_paramPanel.FlowDirection = FlowDirection.TopDown;
_paramPanel.WrapContents = false;
_paramPanel.AutoScroll = true;
_paramPanel.Margin = new Padding(0);
_paramPanel.Padding = new Padding(4, 6, 4, 6);
BuildParamRows();
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(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, 3);
PopulateSelectors();
}
private void BuildParamRows()
{
_thresholdBox.Minimum = 1;
_thresholdBox.Maximum = int.MaxValue;
_thresholdBox.Value = 100;
UiTheme.StyleNumericUpDown(_thresholdBox);
UiTheme.StyleComboBox(_thresholdModeBox);
_thresholdModeBox.DropDownWidth = 160;
_thresholdModeBox.Items.AddRange(ThresholdModeOptions.Cast<object>().ToArray());
_thresholdModeBox.SelectedIndex = 0;
_thresholdModeBox.SelectedIndexChanged += (_, _) => UpdateParamVisibility();
UiTheme.StyleComboBox(_thresholdFieldBox);
_thresholdFieldBox.DropDownWidth = 360;
foreach (var field in _thresholdFields)
{
if (!_thresholdFieldBox.Items.Contains(field))
{
_thresholdFieldBox.Items.Add(field);
}
}
if (_thresholdFieldBox.Items.Count > 0)
{
_thresholdFieldBox.SelectedIndex = 0;
}
UiTheme.StyleComboBox(_lowestHealthAuraFilterBox);
_lowestHealthAuraFilterBox.DropDownWidth = 220;
_lowestHealthAuraFilterBox.Items.AddRange(LowestHealthAuraFilterOptions.Cast<object>().ToArray());
_lowestHealthAuraFilterBox.SelectedIndex = 0;
_lowestHealthAuraFilterBox.SelectedIndexChanged += (_, _) => UpdateParamVisibility();
UiTheme.StyleComboBox(_lowestHealthRoleFilterBox);
_lowestHealthRoleFilterBox.DropDownWidth = 220;
_lowestHealthRoleFilterBox.Items.AddRange(LowestHealthRoleFilterOptions.Cast<object>().ToArray());
_lowestHealthRoleFilterBox.SelectedIndex = 0;
_lowestHealthRoleFilterBox.SelectedIndexChanged += (_, _) => UpdateParamVisibility();
UiTheme.StyleComboBox(_roleBox);
_roleBox.DropDownWidth = 160;
_roleBox.Items.AddRange(RoleOptions.Cast<object>().ToArray());
_roleBox.SelectedIndex = 0;
_reverseBox.Text = "取逆序最后一个匹配单位";
UiTheme.StyleCheckBox(_reverseBox, UiTheme.SurfaceRaised);
_reverseBox.AutoSize = false;
_reverseBox.TextAlign = ContentAlignment.MiddleLeft;
UiTheme.StyleComboBox(_auraBox);
_auraBox.DropDownWidth = 360;
foreach (var aura in _auraFields)
{
_auraBox.Items.Add(aura);
}
if (_auraBox.Items.Count > 0)
{
_auraBox.SelectedIndex = 0;
}
UiTheme.StyleCheckedListBox(_aurasBox);
foreach (var aura in _auraFields)
{
_aurasBox.Items.Add(aura);
}
_auraCountBox.Minimum = 0;
_auraCountBox.Maximum = 100;
_auraCountBox.Value = 1;
UiTheme.StyleNumericUpDown(_auraCountBox);
UiTheme.StyleComboBox(_dispelTypeBox);
_dispelTypeBox.DropDownWidth = 180;
_dispelTypeBox.Items.AddRange(DispelTypeOptions.Cast<object>().ToArray());
_dispelTypeBox.SelectedIndex = 0;
// 参数值变化刷新底部实时预览(类别/选择器/阈值类型/光环筛选经 UpdateParamVisibility 间接刷新)。
_thresholdBox.ValueChanged += (_, _) => UpdatePreview();
_thresholdFieldBox.SelectedIndexChanged += (_, _) => UpdatePreview();
_roleBox.SelectedIndexChanged += (_, _) => UpdatePreview();
_reverseBox.CheckedChanged += (_, _) => UpdatePreview();
_auraBox.SelectedIndexChanged += (_, _) => UpdatePreview();
_auraCountBox.ValueChanged += (_, _) => UpdatePreview();
_dispelTypeBox.SelectedIndexChanged += (_, _) => UpdatePreview();
// ItemCheck 在勾选状态提交前触发, 延后到提交后再读 CheckedItems。
// Seed 期间 CheckAuras 也会触发本事件, 此时窗口句柄尚未创建, 跳过(构造末尾会统一刷新)。
_aurasBox.ItemCheck += (_, _) =>
{
if (IsHandleCreated)
{
BeginInvoke(new Action(UpdatePreview));
}
};
_thresholdModeRow = BuildLabeledRow("阈值类型", _thresholdModeBox);
_thresholdRow = BuildLabeledRow("血量阈值 (<)", _thresholdBox);
_thresholdLabel = _thresholdRow.Controls.OfType<Label>().Single();
_thresholdFieldRow = BuildLabeledRow("动态阈值", _thresholdFieldBox);
_lowestHealthAuraFilterRow = BuildLabeledRow("光环筛选", _lowestHealthAuraFilterBox);
_lowestHealthRoleFilterRow = BuildLabeledRow("职责筛选", _lowestHealthRoleFilterBox);
_roleRow = BuildLabeledRow("职责", _roleBox);
_reverseRow = BuildLabeledRow("顺序", _reverseBox);
_auraRow = BuildLabeledRow("光环", _auraBox);
_aurasRow = BuildLabeledRow("光环 (可多选)", _aurasBox, 116);
_auraCountRow = BuildLabeledRow("光环值", _auraCountBox);
_dispelRow = BuildLabeledRow("驱散类型", _dispelTypeBox);
_paramPanel.Controls.AddRange([_thresholdModeRow, _thresholdRow, _thresholdFieldRow, _lowestHealthAuraFilterRow, _lowestHealthRoleFilterRow, _roleRow, _reverseRow, _auraRow, _aurasRow, _auraCountRow, _dispelRow]);
}
private Control BuildActionRow()
{
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 = Color.Transparent,
Margin = new Padding(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.ButtonKind.Secondary);
UiTheme.StyleActionButton(cancelButton, 84);
cancelButton.Margin = new Padding(8, 0, 0, 0);
cancelButton.Click += (_, _) => DialogResult = DialogResult.Cancel;
actions.Controls.Add(okButton);
actions.Controls.Add(cancelButton);
row.Controls.Add(actions, 1, 0);
AcceptButton = okButton;
CancelButton = cancelButton;
return row;
}
private void PopulateSelectors()
{
_selectorBox.Items.Clear();
if (IsCountCategory)
{
_selectorBox.Items.AddRange(CountSelectors.Cast<object>().ToArray());
}
else
{
_selectorBox.Items.AddRange(UnitSelectors.Cast<object>().ToArray());
}
if (_selectorBox.Items.Count > 0)
{
_selectorBox.SelectedIndex = 0;
}
}
// 值名称只对"生命值最低"单位有意义(把该单位的 生命值 暴露成数值条件字段)。
private void UpdateHealthNameState()
{
var visible = SupportsHealthName();
_healthNameLabel.Visible = visible;
_healthNameBox.Visible = visible;
_healthNameBox.Enabled = visible;
if (!visible)
{
_healthNameBox.Text = string.Empty;
}
}
private void UpdateParamVisibility()
{
bool threshold = false, lowestHealthAuraFilter = false, lowestHealthRoleFilter = false, role = false, reverse = false, auraSingle = false, auraMulti = false, auraCount = false, dispel = false;
if (IsCountCategory)
{
switch ((_selectorBox.SelectedItem as CountItem)?.Kind)
{
case CountKind.UnitsBelowHealth:
threshold = true;
break;
case CountKind.UnitsWithoutAuraBelowHealth:
threshold = auraSingle = true;
break;
case CountKind.UnitsWithAuraBelowHealth:
threshold = auraSingle = true;
break;
case CountKind.UnitsWithAura:
auraSingle = true;
break;
case CountKind.UnitsAboveHealingAbsorb:
threshold = true;
break;
case CountKind.UnitsWithoutAuraAboveHealingAbsorb:
case CountKind.UnitsWithAuraAboveHealingAbsorb:
threshold = auraSingle = true;
break;
}
}
else
{
switch ((_selectorBox.SelectedItem as SelectorItem)?.Kind)
{
case UnitSelectorKind.LowestHealth:
threshold = lowestHealthAuraFilter = true;
lowestHealthRoleFilter = true;
role = SelectedLowestHealthRoleFilter() is not null;
switch (SelectedLowestHealthAuraFilter())
{
case LowestHealthAuraFilterKind.WithAnyAura:
case LowestHealthAuraFilterKind.WithoutAnyAura:
auraMulti = true;
break;
case LowestHealthAuraFilterKind.WithoutAura:
case LowestHealthAuraFilterKind.WithAura:
auraSingle = true;
break;
case LowestHealthAuraFilterKind.WithAuraCount:
auraSingle = auraCount = true;
break;
}
break;
case UnitSelectorKind.HighestHealingAbsorb:
threshold = lowestHealthAuraFilter = true;
switch (SelectedLowestHealthAuraFilter())
{
case LowestHealthAuraFilterKind.WithAnyAura:
case LowestHealthAuraFilterKind.WithoutAnyAura:
auraMulti = true;
break;
case LowestHealthAuraFilterKind.WithoutAura:
case LowestHealthAuraFilterKind.WithAura:
auraSingle = true;
break;
case LowestHealthAuraFilterKind.WithAuraCount:
auraSingle = auraCount = true;
break;
}
break;
case UnitSelectorKind.LowestHealthWithAnyAura:
case UnitSelectorKind.LowestHealthWithoutAnyAura:
threshold = auraMulti = true;
break;
case UnitSelectorKind.LowestHealthWithoutAura:
case UnitSelectorKind.LowestHealthWithAura:
threshold = auraSingle = true;
break;
case UnitSelectorKind.LowestHealthWithAuraCount:
case UnitSelectorKind.HighestHealingAbsorbWithAuraCount:
threshold = auraSingle = auraCount = true;
break;
case UnitSelectorKind.HighestHealingAbsorbWithAnyAura:
case UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura:
threshold = auraMulti = true;
break;
case UnitSelectorKind.HighestHealingAbsorbWithoutAura:
case UnitSelectorKind.HighestHealingAbsorbWithAura:
threshold = auraSingle = true;
break;
case UnitSelectorKind.UnitWithRole:
role = reverse = true;
break;
case UnitSelectorKind.UnitWithRoleWithoutAura:
role = reverse = auraSingle = true;
break;
case UnitSelectorKind.UnitWithAura:
auraSingle = true;
break;
case UnitSelectorKind.UnitWithDispelType:
dispel = true;
break;
}
}
var dynamicThreshold = IsDynamicThresholdMode();
UpdateThresholdPresentation();
_thresholdModeRow.Visible = threshold;
_thresholdRow.Visible = threshold && !dynamicThreshold;
_thresholdFieldRow.Visible = threshold && dynamicThreshold;
_lowestHealthAuraFilterRow.Visible = lowestHealthAuraFilter;
_lowestHealthRoleFilterRow.Visible = lowestHealthRoleFilter;
_roleRow.Visible = role;
_reverseRow.Visible = reverse;
_auraRow.Visible = auraSingle;
_aurasRow.Visible = auraMulti;
_auraCountRow.Visible = auraCount;
_dispelRow.Visible = dispel;
UpdatePreview();
}
private void UpdatePreview()
{
var text = BuildPreviewText();
_previewLabel.Text = string.IsNullOrEmpty(text) ? "预览: -" : $"预览: {text}";
}
// 用当前控件状态构造一个宽容的(不校验、不弹框)单位/数量, 复用 UnitSummary 渲染预览。
private string BuildPreviewText()
{
if (IsCountCategory)
{
var count = new ModuleCountField
{
Name = _nameBox.Text.Trim(),
Kind = (_selectorBox.SelectedItem as CountItem)?.Kind ?? CountKind.UnitsBelowHealth,
AuraName = SelectedAura()
};
ApplyPreviewThreshold(v => count.HealthThreshold = v, f => count.HealthThresholdField = f);
return UnitSummary.Describe(count);
}
var unit = new ModuleUnit
{
Name = _nameBox.Text.Trim(),
Kind = ResolveSelectedUnitKind(),
RoleFilter = SelectedLowestHealthRoleFilter(),
Role = SelectedRole(),
Reverse = _reverseBox.Checked,
AuraCount = (int)_auraCountBox.Value,
DispelType = SelectedDispelType()
};
unit.AuraNames = unit.Kind is UnitSelectorKind.LowestHealthWithAnyAura
or UnitSelectorKind.LowestHealthWithoutAnyAura
or UnitSelectorKind.HighestHealingAbsorbWithAnyAura
or UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura
? CheckedAuras()
: SingleAuraList();
ApplyPreviewThreshold(v => unit.HealthThreshold = v, f => unit.HealthThresholdField = f);
return UnitSummary.Describe(unit);
}
// "生命值最低"/"治疗吸收最高" 的具体子类型取决于光环筛选下拉, 与 OnConfirm 的分支保持一致。
private UnitSelectorKind ResolveSelectedUnitKind()
{
var kind = (_selectorBox.SelectedItem as SelectorItem)?.Kind ?? UnitSelectorKind.LowestHealth;
if (kind is not UnitSelectorKind.LowestHealth and not UnitSelectorKind.HighestHealingAbsorb)
{
return kind;
}
var healingAbsorb = kind == UnitSelectorKind.HighestHealingAbsorb;
return SelectedLowestHealthAuraFilter() switch
{
LowestHealthAuraFilterKind.WithAnyAura => healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithAnyAura
: UnitSelectorKind.LowestHealthWithAnyAura,
LowestHealthAuraFilterKind.WithoutAnyAura => healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura
: UnitSelectorKind.LowestHealthWithoutAnyAura,
LowestHealthAuraFilterKind.WithoutAura => healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithoutAura
: UnitSelectorKind.LowestHealthWithoutAura,
LowestHealthAuraFilterKind.WithAura => healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithAura
: UnitSelectorKind.LowestHealthWithAura,
LowestHealthAuraFilterKind.WithAuraCount => healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithAuraCount
: UnitSelectorKind.LowestHealthWithAuraCount,
_ => kind
};
}
private void ApplyPreviewThreshold(Action<int?> setFixed, Action<string?> setField)
{
if (IsDynamicThresholdMode())
{
setField(_thresholdFieldBox.SelectedItem?.ToString()?.Trim());
}
else
{
setFixed((int)_thresholdBox.Value);
}
}
private void Seed(ModuleUnit? unit, ModuleCountField? count)
{
if (count is not null)
{
_nameBox.Text = count.Name;
_categoryBox.SelectedIndex = 1;
PopulateSelectors();
SelectSelector(count.Kind);
if (count.HealthThreshold is { } th)
{
_thresholdBox.Value = Clamp(th, _thresholdBox);
}
SeedThresholdField(count.HealthThresholdField);
SelectAura(_auraBox, count.AuraName);
return;
}
if (unit is not null)
{
_nameBox.Text = unit.Name;
_healthNameBox.Text = unit.HealthName ?? string.Empty;
_categoryBox.SelectedIndex = 0;
PopulateSelectors();
SelectSelector(DisplaySelectorKind(unit.Kind));
SelectLowestHealthAuraFilter(unit.Kind);
SelectLowestHealthRoleFilter(unit.RoleFilter);
if (unit.HealthThreshold is { } th)
{
_thresholdBox.Value = Clamp(th, _thresholdBox);
}
SeedThresholdField(unit.HealthThresholdField);
if (unit.Role is { } r)
{
SelectRole(r);
}
_reverseBox.Checked = unit.Reverse;
SelectAura(_auraBox, unit.AuraNames is { Count: > 0 } ? unit.AuraNames[0] : null);
CheckAuras(unit.AuraNames);
if (unit.AuraCount is { } ac)
{
_auraCountBox.Value = Clamp(ac, _auraCountBox);
}
if (unit.DispelType is { } dt)
{
SelectDispelType(dt);
}
}
}
private void OnConfirm()
{
var name = _nameBox.Text.Trim();
if (!ValidateName(name, out var message))
{
MessageBox.Show(message, "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (IsCountCategory)
{
var kind = (_selectorBox.SelectedItem as CountItem)?.Kind ?? CountKind.UnitsBelowHealth;
var count = new ModuleCountField { Name = name, Kind = kind };
switch (kind)
{
case CountKind.UnitsBelowHealth:
if (!ApplyThreshold(count))
{
return;
}
break;
case CountKind.UnitsWithoutAuraBelowHealth:
if (!ApplyThreshold(count))
{
return;
}
count.AuraName = SelectedAura();
break;
case CountKind.UnitsWithAuraBelowHealth:
if (!ApplyThreshold(count))
{
return;
}
count.AuraName = SelectedAura();
break;
case CountKind.UnitsWithAura:
count.AuraName = SelectedAura();
break;
case CountKind.UnitsAboveHealingAbsorb:
if (!ApplyThreshold(count))
{
return;
}
break;
case CountKind.UnitsWithoutAuraAboveHealingAbsorb:
case CountKind.UnitsWithAuraAboveHealingAbsorb:
if (!ApplyThreshold(count))
{
return;
}
count.AuraName = SelectedAura();
break;
}
if (RequiresAura(kind) && string.IsNullOrEmpty(count.AuraName))
{
MessageBox.Show("请选择光环。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
ResultCount = count;
DialogResult = DialogResult.OK;
return;
}
var selectorKind = (_selectorBox.SelectedItem as SelectorItem)?.Kind ?? UnitSelectorKind.LowestHealth;
var moduleUnit = new ModuleUnit { Name = name, Kind = selectorKind };
switch (selectorKind)
{
case UnitSelectorKind.LowestHealth:
case UnitSelectorKind.HighestHealingAbsorb:
if (!ApplyThreshold(moduleUnit))
{
return;
}
var healingAbsorb = selectorKind == UnitSelectorKind.HighestHealingAbsorb;
if (!healingAbsorb && SelectedLowestHealthRoleFilter() is { } roleFilter)
{
moduleUnit.RoleFilter = roleFilter;
moduleUnit.Role = SelectedRole();
}
switch (SelectedLowestHealthAuraFilter())
{
case LowestHealthAuraFilterKind.WithAnyAura:
moduleUnit.Kind = healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithAnyAura
: UnitSelectorKind.LowestHealthWithAnyAura;
moduleUnit.AuraNames = CheckedAuras();
if (moduleUnit.AuraNames.Count == 0)
{
MessageBox.Show("请至少勾选一个光环。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
break;
case LowestHealthAuraFilterKind.WithoutAnyAura:
moduleUnit.Kind = healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura
: UnitSelectorKind.LowestHealthWithoutAnyAura;
moduleUnit.AuraNames = CheckedAuras();
if (moduleUnit.AuraNames.Count == 0)
{
MessageBox.Show("请至少勾选一个光环。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
break;
case LowestHealthAuraFilterKind.WithoutAura:
moduleUnit.Kind = healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithoutAura
: UnitSelectorKind.LowestHealthWithoutAura;
moduleUnit.AuraNames = SingleAuraList();
break;
case LowestHealthAuraFilterKind.WithAura:
moduleUnit.Kind = healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithAura
: UnitSelectorKind.LowestHealthWithAura;
moduleUnit.AuraNames = SingleAuraList();
break;
case LowestHealthAuraFilterKind.WithAuraCount:
moduleUnit.Kind = healingAbsorb
? UnitSelectorKind.HighestHealingAbsorbWithAuraCount
: UnitSelectorKind.LowestHealthWithAuraCount;
moduleUnit.AuraNames = SingleAuraList();
moduleUnit.AuraCount = (int)_auraCountBox.Value;
break;
}
break;
case UnitSelectorKind.LowestHealthWithAnyAura:
case UnitSelectorKind.LowestHealthWithoutAnyAura:
case UnitSelectorKind.HighestHealingAbsorbWithAnyAura:
case UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura:
if (!ApplyThreshold(moduleUnit))
{
return;
}
moduleUnit.AuraNames = CheckedAuras();
if (moduleUnit.AuraNames.Count == 0)
{
MessageBox.Show("请至少勾选一个光环。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
break;
case UnitSelectorKind.LowestHealthWithoutAura:
case UnitSelectorKind.LowestHealthWithAura:
case UnitSelectorKind.HighestHealingAbsorbWithoutAura:
case UnitSelectorKind.HighestHealingAbsorbWithAura:
if (!ApplyThreshold(moduleUnit))
{
return;
}
moduleUnit.AuraNames = SingleAuraList();
break;
case UnitSelectorKind.LowestHealthWithAuraCount:
case UnitSelectorKind.HighestHealingAbsorbWithAuraCount:
if (!ApplyThreshold(moduleUnit))
{
return;
}
moduleUnit.AuraNames = SingleAuraList();
moduleUnit.AuraCount = (int)_auraCountBox.Value;
break;
case UnitSelectorKind.UnitWithRole:
moduleUnit.Role = SelectedRole();
moduleUnit.Reverse = _reverseBox.Checked;
break;
case UnitSelectorKind.UnitWithRoleWithoutAura:
moduleUnit.Role = SelectedRole();
moduleUnit.Reverse = _reverseBox.Checked;
moduleUnit.AuraNames = SingleAuraList();
break;
case UnitSelectorKind.UnitWithAura:
moduleUnit.AuraNames = SingleAuraList();
break;
case UnitSelectorKind.UnitWithDispelType:
moduleUnit.DispelType = SelectedDispelType();
break;
}
if (UnitRequiresAura(moduleUnit.Kind) && (moduleUnit.AuraNames is null || moduleUnit.AuraNames.Count == 0))
{
MessageBox.Show("请选择光环。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
var healthName = SupportsHealthName() ? _healthNameBox.Text.Trim() : string.Empty;
if (healthName.Length > 0)
{
if (string.Equals(healthName, name, StringComparison.OrdinalIgnoreCase))
{
MessageBox.Show("值名称不能与名称相同。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (!ValidateName(healthName, out var healthMessage))
{
MessageBox.Show($"值名称: {healthMessage}", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
}
moduleUnit.HealthName = healthName.Length == 0 ? null : healthName;
ResultUnit = moduleUnit;
DialogResult = DialogResult.OK;
}
private bool ValidateName(string name, out string message)
{
message = string.Empty;
if (name.Length == 0)
{
message = "名称不能为空。";
return false;
}
if (name.Contains('.') || name.Contains('$'))
{
message = "名称不能包含 '.' 或 '$'。";
return false;
}
if (int.TryParse(name, out _))
{
message = "名称不能是纯数字(会与单位编号混淆)。";
return false;
}
if (_takenNames.Contains(name))
{
message = $"名称“{name}”已被其它单位/字段或状态字段占用。";
return false;
}
return true;
}
private bool IsCountCategory => _categoryBox.SelectedIndex == 1;
private bool IsDynamicThresholdMode()
=> (_thresholdModeBox.SelectedItem as ThresholdModeItem)?.UsesDynamicField == true;
private bool IsHealingAbsorbSelector()
{
if (IsCountCategory)
{
return (_selectorBox.SelectedItem as CountItem)?.Kind is
CountKind.UnitsAboveHealingAbsorb
or CountKind.UnitsWithoutAuraAboveHealingAbsorb
or CountKind.UnitsWithAuraAboveHealingAbsorb;
}
return (_selectorBox.SelectedItem as SelectorItem)?.Kind == UnitSelectorKind.HighestHealingAbsorb;
}
private void UpdateThresholdPresentation()
{
var usesHealingAbsorb = IsHealingAbsorbSelector();
if (usesHealingAbsorb != _usesHealingAbsorbThreshold)
{
if (usesHealingAbsorb)
{
_thresholdBox.Minimum = 0;
_thresholdBox.Value = 0;
}
else
{
_thresholdBox.Value = 100;
_thresholdBox.Minimum = 1;
}
_usesHealingAbsorbThreshold = usesHealingAbsorb;
}
_thresholdLabel.Text = usesHealingAbsorb
? "治疗吸收阈值 (>)"
: "血量阈值 (<)";
}
private bool ApplyThreshold(ModuleUnit unit)
{
if (TryReadThreshold(out var fixedValue, out var field))
{
unit.HealthThreshold = fixedValue;
unit.HealthThresholdField = field;
return true;
}
return false;
}
private bool ApplyThreshold(ModuleCountField count)
{
if (TryReadThreshold(out var fixedValue, out var field))
{
count.HealthThreshold = fixedValue;
count.HealthThresholdField = field;
return true;
}
return false;
}
private bool TryReadThreshold(out int? fixedValue, out string? field)
{
if (!IsDynamicThresholdMode())
{
fixedValue = (int)_thresholdBox.Value;
field = null;
return true;
}
fixedValue = null;
field = _thresholdFieldBox.SelectedItem?.ToString()?.Trim();
if (!string.IsNullOrWhiteSpace(field))
{
return true;
}
MessageBox.Show("请选择动态阈值。", "Shigure", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return false;
}
private bool SupportsHealthName()
=> !IsCountCategory
&& (_selectorBox.SelectedItem as SelectorItem)?.Kind == UnitSelectorKind.LowestHealth;
private static bool RequiresAura(CountKind kind)
=> kind is CountKind.UnitsWithoutAuraBelowHealth
or CountKind.UnitsWithAuraBelowHealth
or CountKind.UnitsWithAura
or CountKind.UnitsWithoutAuraAboveHealingAbsorb
or CountKind.UnitsWithAuraAboveHealingAbsorb;
private static bool UnitRequiresAura(UnitSelectorKind kind)
=> kind is UnitSelectorKind.LowestHealthWithAnyAura
or UnitSelectorKind.LowestHealthWithoutAnyAura
or UnitSelectorKind.LowestHealthWithoutAura
or UnitSelectorKind.LowestHealthWithAura
or UnitSelectorKind.LowestHealthWithAuraCount
or UnitSelectorKind.HighestHealingAbsorbWithAnyAura
or UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura
or UnitSelectorKind.HighestHealingAbsorbWithoutAura
or UnitSelectorKind.HighestHealingAbsorbWithAura
or UnitSelectorKind.HighestHealingAbsorbWithAuraCount
or UnitSelectorKind.UnitWithRoleWithoutAura
or UnitSelectorKind.UnitWithAura;
private string? SelectedAura() => _auraBox.SelectedItem?.ToString();
private LowestHealthAuraFilterKind SelectedLowestHealthAuraFilter()
=> (_lowestHealthAuraFilterBox.SelectedItem as LowestHealthAuraFilterItem)?.Kind
?? LowestHealthAuraFilterKind.None;
private UnitRoleFilterKind? SelectedLowestHealthRoleFilter()
=> (_lowestHealthRoleFilterBox.SelectedItem as LowestHealthRoleFilterItem)?.Kind;
private List<string> SingleAuraList()
{
var aura = SelectedAura();
return string.IsNullOrEmpty(aura) ? new List<string>() : new List<string> { aura };
}
private List<string> CheckedAuras()
{
var list = new List<string>();
foreach (var item in _aurasBox.CheckedItems)
{
if (item?.ToString() is { Length: > 0 } name)
{
list.Add(name);
}
}
return list;
}
private int SelectedRole() => (_roleBox.SelectedItem as RoleOption)?.Value ?? 1;
private int SelectedDispelType() => (_dispelTypeBox.SelectedItem as DispelTypeOption)?.Value ?? 1;
private static UnitSelectorKind DisplaySelectorKind(UnitSelectorKind kind)
=> kind is UnitSelectorKind.LowestHealthWithAnyAura
or UnitSelectorKind.LowestHealthWithoutAnyAura
or UnitSelectorKind.LowestHealthWithoutAura
or UnitSelectorKind.LowestHealthWithAura
or UnitSelectorKind.LowestHealthWithAuraCount
? UnitSelectorKind.LowestHealth
: kind is UnitSelectorKind.HighestHealingAbsorbWithAnyAura
or UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura
or UnitSelectorKind.HighestHealingAbsorbWithoutAura
or UnitSelectorKind.HighestHealingAbsorbWithAura
or UnitSelectorKind.HighestHealingAbsorbWithAuraCount
? UnitSelectorKind.HighestHealingAbsorb
: kind;
private void SelectLowestHealthAuraFilter(UnitSelectorKind kind)
{
var filter = kind switch
{
UnitSelectorKind.LowestHealthWithAnyAura => LowestHealthAuraFilterKind.WithAnyAura,
UnitSelectorKind.LowestHealthWithoutAnyAura => LowestHealthAuraFilterKind.WithoutAnyAura,
UnitSelectorKind.LowestHealthWithoutAura => LowestHealthAuraFilterKind.WithoutAura,
UnitSelectorKind.LowestHealthWithAura => LowestHealthAuraFilterKind.WithAura,
UnitSelectorKind.LowestHealthWithAuraCount => LowestHealthAuraFilterKind.WithAuraCount,
UnitSelectorKind.HighestHealingAbsorbWithAnyAura => LowestHealthAuraFilterKind.WithAnyAura,
UnitSelectorKind.HighestHealingAbsorbWithoutAnyAura => LowestHealthAuraFilterKind.WithoutAnyAura,
UnitSelectorKind.HighestHealingAbsorbWithoutAura => LowestHealthAuraFilterKind.WithoutAura,
UnitSelectorKind.HighestHealingAbsorbWithAura => LowestHealthAuraFilterKind.WithAura,
UnitSelectorKind.HighestHealingAbsorbWithAuraCount => LowestHealthAuraFilterKind.WithAuraCount,
_ => LowestHealthAuraFilterKind.None
};
for (var i = 0; i < _lowestHealthAuraFilterBox.Items.Count; i++)
{
if (_lowestHealthAuraFilterBox.Items[i] is LowestHealthAuraFilterItem item && item.Kind == filter)
{
_lowestHealthAuraFilterBox.SelectedIndex = i;
return;
}
}
_lowestHealthAuraFilterBox.SelectedIndex = 0;
}
private void SelectLowestHealthRoleFilter(UnitRoleFilterKind? kind)
{
for (var i = 0; i < _lowestHealthRoleFilterBox.Items.Count; i++)
{
if (_lowestHealthRoleFilterBox.Items[i] is LowestHealthRoleFilterItem item && item.Kind == kind)
{
_lowestHealthRoleFilterBox.SelectedIndex = i;
return;
}
}
_lowestHealthRoleFilterBox.SelectedIndex = 0;
}
private void SelectSelector(UnitSelectorKind kind)
{
for (var i = 0; i < _selectorBox.Items.Count; i++)
{
if (_selectorBox.Items[i] is SelectorItem item && item.Kind == kind)
{
_selectorBox.SelectedIndex = i;
return;
}
}
}
private void SelectSelector(CountKind kind)
{
for (var i = 0; i < _selectorBox.Items.Count; i++)
{
if (_selectorBox.Items[i] is CountItem item && item.Kind == kind)
{
_selectorBox.SelectedIndex = i;
return;
}
}
}
private void SeedThresholdField(string? field)
{
if (string.IsNullOrWhiteSpace(field))
{
SelectThresholdMode(usesDynamicField: false);
return;
}
SelectThresholdMode(usesDynamicField: true);
SelectThresholdField(field.Trim());
}
private void SelectThresholdMode(bool usesDynamicField)
{
for (var i = 0; i < _thresholdModeBox.Items.Count; i++)
{
if (_thresholdModeBox.Items[i] is ThresholdModeItem item && item.UsesDynamicField == usesDynamicField)
{
_thresholdModeBox.SelectedIndex = i;
return;
}
}
_thresholdModeBox.SelectedIndex = 0;
}
private void SelectThresholdField(string field)
{
var index = _thresholdFieldBox.Items.IndexOf(field);
if (index < 0)
{
_thresholdFieldBox.Items.Add(field);
index = _thresholdFieldBox.Items.Count - 1;
}
_thresholdFieldBox.SelectedIndex = index;
}
private void SelectRole(int role)
{
for (var i = 0; i < _roleBox.Items.Count; i++)
{
if (_roleBox.Items[i] is RoleOption option && option.Value == role)
{
_roleBox.SelectedIndex = i;
return;
}
}
}
private void SelectDispelType(int dispelType)
{
for (var i = 0; i < _dispelTypeBox.Items.Count; i++)
{
if (_dispelTypeBox.Items[i] is DispelTypeOption option && option.Value == dispelType)
{
_dispelTypeBox.SelectedIndex = i;
return;
}
}
_dispelTypeBox.SelectedIndex = 0;
}
private static void SelectAura(ComboBox box, string? aura)
{
if (string.IsNullOrEmpty(aura))
{
return;
}
var index = box.Items.IndexOf(aura);
if (index < 0)
{
box.Items.Add(aura);
index = box.Items.Count - 1;
}
box.SelectedIndex = index;
}
private void CheckAuras(List<string>? auras)
{
if (auras is null)
{
return;
}
foreach (var aura in auras)
{
var index = _aurasBox.Items.IndexOf(aura);
if (index < 0)
{
index = _aurasBox.Items.Add(aura);
}
_aurasBox.SetItemChecked(index, true);
}
}
private static decimal Clamp(int value, NumericUpDown box)
{
return Math.Clamp(value, (int)box.Minimum, (int)box.Maximum);
}
private static Panel BuildLabeledRow(string label, Control control, int height = 44)
{
var panel = new Panel
{
Width = RowWidth,
Height = height,
BackColor = UiTheme.SurfaceRaised,
Margin = new Padding(0, 1, 0, 5)
};
var labelControl = new Label
{
Text = label,
ForeColor = UiTheme.Muted,
TextAlign = ContentAlignment.MiddleLeft,
Bounds = new Rectangle(0, height > 50 ? 4 : Math.Max(0, (height - 24) / 2), LabelWidth, 24),
AutoEllipsis = true
};
control.Bounds = new Rectangle(ControlLeft, 3, RowWidth - ControlLeft, height - 6);
panel.Controls.Add(control);
panel.Controls.Add(labelControl);
return panel;
}
private Control BuildSplitRow(string labelA, Control controlA, string labelB, Control controlB)
{
var panel = new Panel
{
Dock = DockStyle.Fill,
BackColor = UiTheme.SurfaceRaised,
Margin = new Padding(0)
};
var labelAControl = new Label { Text = labelA, ForeColor = UiTheme.Muted, TextAlign = ContentAlignment.MiddleLeft, Bounds = new Rectangle(0, 5, 72, 28), AutoEllipsis = true };
controlA.Bounds = new Rectangle(80, 5, 230, 28);
var labelBControl = new Label { Text = labelB, ForeColor = UiTheme.Muted, TextAlign = ContentAlignment.MiddleLeft, Bounds = new Rectangle(330, 5, 130, 28), AutoEllipsis = true };
controlB.Bounds = new Rectangle(466, 5, RowWidth - 466, 28);
panel.Controls.Add(controlA);
panel.Controls.Add(labelAControl);
panel.Controls.Add(controlB);
panel.Controls.Add(labelBControl);
return panel;
}
private Control BuildNameRow()
{
var panel = new Panel
{
Dock = DockStyle.Fill,
BackColor = UiTheme.SurfaceRaised,
Margin = new Padding(0)
};
var nameLabel = new Label { Text = "名称", ForeColor = UiTheme.Muted, TextAlign = ContentAlignment.MiddleLeft, Bounds = new Rectangle(0, 5, 72, 28), AutoEllipsis = true };
UiTheme.StyleTextBox(_nameBox);
_nameBox.Bounds = new Rectangle(80, 5, 230, 28);
_healthNameLabel.Text = "值名称";
_healthNameLabel.ForeColor = UiTheme.Muted;
_healthNameLabel.TextAlign = ContentAlignment.MiddleLeft;
_healthNameLabel.Bounds = new Rectangle(330, 5, 130, 28);
_healthNameLabel.AutoEllipsis = true;
UiTheme.StyleTextBox(_healthNameBox);
_healthNameBox.Bounds = new Rectangle(466, 5, RowWidth - 466, 28);
_toolTip.SetToolTip(_healthNameBox, "可选:把该单位生命值暴露为同名数值条件字段(如 最低血量 < 50");
_toolTip.SetToolTip(_healthNameLabel, "可选:把该单位生命值暴露为同名数值条件字段(如 最低血量 < 50");
panel.Controls.Add(_nameBox);
panel.Controls.Add(nameLabel);
panel.Controls.Add(_healthNameBox);
panel.Controls.Add(_healthNameLabel);
return panel;
}
private sealed record SelectorItem(string Text, UnitSelectorKind Kind)
{
public override string ToString() => Text;
}
private sealed record LowestHealthAuraFilterItem(string Text, LowestHealthAuraFilterKind Kind)
{
public override string ToString() => Text;
}
private sealed record LowestHealthRoleFilterItem(string Text, UnitRoleFilterKind? Kind)
{
public override string ToString() => Text;
}
private sealed record CountItem(string Text, CountKind Kind)
{
public override string ToString() => Text;
}
private sealed record ThresholdModeItem(string Text, bool UsesDynamicField)
{
public override string ToString() => Text;
}
private sealed record RoleOption(string Text, int Value)
{
public override string ToString() => Text;
}
private sealed record DispelTypeOption(string Text, int Value)
{
public override string ToString() => Text;
}
private enum LowestHealthAuraFilterKind
{
None,
WithAnyAura,
WithoutAnyAura,
WithoutAura,
WithAura,
WithAuraCount
}
}