refactor(settings): merge the duplicated tab helpers
Six tabs carried a byte-identical DrawToggle, four a byte-identical slider, and five hand-rolled the same enum combo loop. 281 lines out, 82 in. The combos were not only duplicated, they were wasteful: each one called Enum.GetValues inside Draw, so every open settings window allocated five arrays per frame for sets that cannot change at runtime. EnumValues<T> reads them once per closed generic, and the label array is one buffer shared by all of them. Two behaviours are now uniform rather than accidental. The range check on the selected index existed in exactly one of the five and is now in all of them, and the tell auto-open combo lost its inline literal array in favour of a Name extension like its seven peers -- still English, but at least in the place the localisation pass will look. SettingsWidgets is constructed by each tab rather than injected. The tabs are DI singletons and a seventh constructor signature change buys nothing here. One visible difference: the tell auto-open combo was 220px wide against 200 for every other combo in the window. It is 200 now.
This commit is contained in:
@@ -456,6 +456,23 @@ public enum TellAutoOpenMode
|
||||
Popout,
|
||||
}
|
||||
|
||||
public static class TellAutoOpenModeExt
|
||||
{
|
||||
// The only display name set still in English. It sat inline in ChannelsTab
|
||||
// as a literal array, which is why it was missed when the rest moved into
|
||||
// resources; here it is at least in the same place as its peers for the
|
||||
// localisation pass to pick up.
|
||||
public static string Name(this TellAutoOpenMode mode) =>
|
||||
mode switch
|
||||
{
|
||||
TellAutoOpenMode.Off => "Off",
|
||||
TellAutoOpenMode.Sidebar => "Sidebar",
|
||||
TellAutoOpenMode.TopTab => "Top tab",
|
||||
TellAutoOpenMode.Popout => "Popout",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null),
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public enum MainWindowLayoutMode
|
||||
{
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
||||
namespace HellionChat.Ui.Components.Settings;
|
||||
|
||||
// Enum.GetValues allocates a fresh array on every call, and the settings tabs
|
||||
// were calling it inside Draw -- once per combo, every frame the window is open.
|
||||
// The set cannot change at runtime, so it is read once per closed generic.
|
||||
internal static class EnumValues<T>
|
||||
where T : struct, Enum
|
||||
{
|
||||
internal static readonly T[] All = Enum.GetValues<T>();
|
||||
}
|
||||
|
||||
// The four controls every settings tab draws. Six tabs carried a byte-identical
|
||||
// DrawToggle, four a byte-identical slider, and five hand-rolled the same combo
|
||||
// loop with different widths.
|
||||
//
|
||||
// Deliberately constructed by the tabs rather than injected: the tabs are DI
|
||||
// singletons, and a new constructor parameter on all seven of them buys nothing
|
||||
// here beyond a wider blast radius.
|
||||
internal sealed class SettingsWidgets
|
||||
{
|
||||
private readonly Plugin _plugin;
|
||||
|
||||
// Shared across every combo. ImGui.Combo copies the strings it needs before
|
||||
// returning, so the buffer is free again by the time the next call runs.
|
||||
private string[] _labelScratch = new string[8];
|
||||
|
||||
internal SettingsWidgets(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
internal void Toggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (!ImGui.Checkbox(label, ref current))
|
||||
return;
|
||||
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
|
||||
internal void SliderFloat(
|
||||
string label,
|
||||
Func<float> get,
|
||||
Action<float> set,
|
||||
float min,
|
||||
float max,
|
||||
float width = 200f
|
||||
)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
// Sliders report a change every frame while dragging; deferring the write
|
||||
// to release turns ~30 full-config disk writes per second into one.
|
||||
if (ImGui.SliderFloat(label, ref current, min, max, "%.2f"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
|
||||
internal void SliderInt(
|
||||
string label,
|
||||
Func<int> get,
|
||||
Action<int> set,
|
||||
int min,
|
||||
int max,
|
||||
float width = 200f
|
||||
)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(width);
|
||||
if (ImGui.SliderInt(label, ref current, min, max, "%d"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
|
||||
// labelFor is a parameter rather than a constraint because the display names
|
||||
// live in extension methods, which bind statically and cannot be reached
|
||||
// through a generic type parameter.
|
||||
internal void EnumCombo<T>(
|
||||
string label,
|
||||
Func<T> get,
|
||||
Action<T> set,
|
||||
Func<T, string> labelFor,
|
||||
float width = 200f
|
||||
)
|
||||
where T : struct, Enum
|
||||
{
|
||||
var values = EnumValues<T>.All;
|
||||
if (values.Length == 0)
|
||||
return;
|
||||
|
||||
if (_labelScratch.Length < values.Length)
|
||||
_labelScratch = new string[values.Length];
|
||||
|
||||
var current = get();
|
||||
var selected = 0;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
_labelScratch[i] = labelFor(values[i]);
|
||||
if (EqualityComparer<T>.Default.Equals(values[i], current))
|
||||
selected = i;
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
if (!ImGui.Combo(label, ref selected, _labelScratch, values.Length))
|
||||
return;
|
||||
|
||||
// The scratch buffer can be longer than the value set, so a stale index
|
||||
// from a previous, larger combo must not reach the setter.
|
||||
if (selected < 0 || selected >= values.Length)
|
||||
return;
|
||||
|
||||
set(values[selected]);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ internal sealed class AboutTab
|
||||
{
|
||||
private readonly FontManager _fonts;
|
||||
private readonly Plugin _plugin;
|
||||
private readonly SettingsWidgets _w;
|
||||
private readonly HonorificService _honorific;
|
||||
private readonly ThemeRegistry _themes;
|
||||
private readonly IPlatformUtil _platformUtil;
|
||||
@@ -30,6 +31,7 @@ internal sealed class AboutTab
|
||||
{
|
||||
_fonts = fonts;
|
||||
_plugin = plugin;
|
||||
_w = new SettingsWidgets(plugin);
|
||||
_honorific = honorific;
|
||||
_themes = themes;
|
||||
_platformUtil = platformUtil;
|
||||
@@ -103,7 +105,7 @@ internal sealed class AboutTab
|
||||
|
||||
ImGui.TextUnformatted(HellionStrings.Settings_Integrations_Honorific_SectionHeader);
|
||||
DrawHonorificStatus();
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
HellionStrings.Settings_Integrations_Honorific_Toggle,
|
||||
() => Plugin.Config.ShowHonorificTitleInHeader,
|
||||
v => Plugin.Config.ShowHonorificTitleInHeader = v
|
||||
@@ -222,16 +224,6 @@ internal sealed class AboutTab
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawToggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (ImGui.Checkbox(label, ref current))
|
||||
{
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
// URLs are exclusively hardcoded BrandingLinks/IntegrationLinks constants,
|
||||
// validated to http/https at module-init. OpenLink centralises the browser
|
||||
// open on an off-draw thread (it internally uses the same ShellExecute, so
|
||||
|
||||
@@ -5,46 +5,48 @@ namespace HellionChat.Ui.Components.Settings.Tabs;
|
||||
internal sealed class ChannelsTab
|
||||
{
|
||||
private readonly Plugin _plugin;
|
||||
private readonly SettingsWidgets _w;
|
||||
|
||||
public ChannelsTab(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
_w = new SettingsWidgets(plugin);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (ImGui.CollapsingHeader("Tab management", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Enable auto-tell tabs",
|
||||
() => Plugin.Config.EnableAutoTellTabs,
|
||||
v => Plugin.Config.EnableAutoTellTabs = v
|
||||
);
|
||||
DrawSliderInt(
|
||||
_w.SliderInt(
|
||||
"Auto-tell tabs limit",
|
||||
() => Plugin.Config.AutoTellTabsLimit,
|
||||
v => Plugin.Config.AutoTellTabsLimit = v,
|
||||
1,
|
||||
50
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Compact display",
|
||||
() => Plugin.Config.AutoTellTabsCompactDisplay,
|
||||
v => Plugin.Config.AutoTellTabsCompactDisplay = v
|
||||
);
|
||||
DrawSliderInt(
|
||||
_w.SliderInt(
|
||||
"History preload",
|
||||
() => Plugin.Config.AutoTellTabsHistoryPreload,
|
||||
v => Plugin.Config.AutoTellTabsHistoryPreload = v,
|
||||
0,
|
||||
200
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Show greeted toggle",
|
||||
() => Plugin.Config.AutoTellTabsShowGreetedToggle,
|
||||
v => Plugin.Config.AutoTellTabsShowGreetedToggle = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Open as popout",
|
||||
() => Plugin.Config.AutoTellTabsOpenAsPopout,
|
||||
v => Plugin.Config.AutoTellTabsOpenAsPopout = v
|
||||
@@ -53,8 +55,13 @@ internal sealed class ChannelsTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Tell auto-open mode", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawTellAutoOpenModeCombo();
|
||||
DrawToggle(
|
||||
_w.EnumCombo(
|
||||
"Tell auto-open mode",
|
||||
() => Plugin.Config.TellAutoOpenMode,
|
||||
v => Plugin.Config.TellAutoOpenMode = v,
|
||||
v => v.Name()
|
||||
);
|
||||
_w.Toggle(
|
||||
"Switch to the tab on every tell",
|
||||
() => Plugin.Config.TellAutoOpenSwitchAlways,
|
||||
v => Plugin.Config.TellAutoOpenSwitchAlways = v
|
||||
@@ -67,7 +74,7 @@ internal sealed class ChannelsTab
|
||||
// so the slider cannot drift away from the clamp in Sidebar.GetWidth.
|
||||
// The stored value is unscaled; display scaling is applied where the
|
||||
// sidebar is drawn.
|
||||
DrawSliderInt(
|
||||
_w.SliderInt(
|
||||
"Sidebar width",
|
||||
() => Plugin.Config.SidebarWidth,
|
||||
v => Plugin.Config.SidebarWidth = v,
|
||||
@@ -76,52 +83,4 @@ internal sealed class ChannelsTab
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTellAutoOpenModeCombo()
|
||||
{
|
||||
var labels = new[] { "Off", "Sidebar", "Top tab", "Popout" };
|
||||
var values = Enum.GetValues<TellAutoOpenMode>();
|
||||
var current = Plugin.Config.TellAutoOpenMode;
|
||||
var selected = 0;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
if (values[i] == current)
|
||||
{
|
||||
selected = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(220);
|
||||
if (ImGui.Combo("Tell auto-open mode", ref selected, labels, labels.Length))
|
||||
{
|
||||
if (selected >= 0 && selected < values.Length)
|
||||
{
|
||||
Plugin.Config.TellAutoOpenMode = values[selected];
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawToggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (ImGui.Checkbox(label, ref current))
|
||||
{
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSliderInt(string label, Func<int> get, Action<int> set, int min, int max)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(200);
|
||||
// Sliders report a change every frame while dragging; deferring the write
|
||||
// to release turns ~30 full-config disk writes per second into one.
|
||||
if (ImGui.SliderInt(label, ref current, min, max, "%d"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,53 +7,72 @@ namespace HellionChat.Ui.Components.Settings.Tabs;
|
||||
internal sealed class ChatTab
|
||||
{
|
||||
private readonly Plugin _plugin;
|
||||
private readonly SettingsWidgets _w;
|
||||
|
||||
public ChatTab(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
_w = new SettingsWidgets(plugin);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (ImGui.CollapsingHeader("Display modes", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Compact density (card vs compact)",
|
||||
() => Plugin.Config.UseCompactDensity,
|
||||
v => Plugin.Config.UseCompactDensity = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"More compact pretty mode",
|
||||
() => Plugin.Config.MoreCompactPretty,
|
||||
v => Plugin.Config.MoreCompactPretty = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Prettier timestamps",
|
||||
() => Plugin.Config.PrettierTimestamps,
|
||||
v => Plugin.Config.PrettierTimestamps = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Hide same timestamps",
|
||||
() => Plugin.Config.HideSameTimestamps,
|
||||
v => Plugin.Config.HideSameTimestamps = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"24-hour clock",
|
||||
() => Plugin.Config.Use24HourClock,
|
||||
v => Plugin.Config.Use24HourClock = v
|
||||
);
|
||||
DrawWorldSuffixCombo();
|
||||
DrawNameFormCombo();
|
||||
_w.EnumCombo(
|
||||
HellionStrings.Settings_Chat_WorldSuffix_Name,
|
||||
() => Plugin.Config.WorldSuffixMode,
|
||||
v => Plugin.Config.WorldSuffixMode = v,
|
||||
v => v.Name()
|
||||
);
|
||||
ImGuiUtil.HelpMarker(HellionStrings.Settings_Chat_WorldSuffix_Description);
|
||||
_w.EnumCombo(
|
||||
HellionStrings.Settings_Chat_NameForm_Name,
|
||||
() => Plugin.Config.NameFormMode,
|
||||
v => Plugin.Config.NameFormMode = v,
|
||||
v => v.Name()
|
||||
);
|
||||
ImGuiUtil.HelpMarker(HellionStrings.Settings_Chat_NameForm_Description);
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Command help"))
|
||||
{
|
||||
DrawCommandHelpSideCombo();
|
||||
_w.EnumCombo(
|
||||
"Command help side",
|
||||
() => Plugin.Config.CommandHelpSide,
|
||||
v => Plugin.Config.CommandHelpSide = v,
|
||||
v => v.Name()
|
||||
);
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Plugin disclosure"))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
HellionStrings.Settings_Chat_NotifyPluginDisclosure_Name,
|
||||
() => Plugin.Config.NotifyPluginDisclosure,
|
||||
v => Plugin.Config.NotifyPluginDisclosure = v
|
||||
@@ -61,99 +80,4 @@ internal sealed class ChatTab
|
||||
ImGuiUtil.HelpMarker(HellionStrings.Settings_Chat_NotifyPluginDisclosure_Description);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCommandHelpSideCombo()
|
||||
{
|
||||
var current = Plugin.Config.CommandHelpSide;
|
||||
var values = Enum.GetValues<CommandHelpSide>();
|
||||
var labels = new string[values.Length];
|
||||
var selected = 0;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
labels[i] = values[i].Name();
|
||||
if (values[i] == current)
|
||||
{
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(200);
|
||||
if (ImGui.Combo("Command help side", ref selected, labels, labels.Length))
|
||||
{
|
||||
Plugin.Config.CommandHelpSide = values[selected];
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawWorldSuffixCombo()
|
||||
{
|
||||
var current = Plugin.Config.WorldSuffixMode;
|
||||
var values = Enum.GetValues<WorldSuffixMode>();
|
||||
var labels = new string[values.Length];
|
||||
var selected = 0;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
labels[i] = values[i].Name();
|
||||
if (values[i] == current)
|
||||
{
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(200);
|
||||
if (
|
||||
ImGui.Combo(
|
||||
HellionStrings.Settings_Chat_WorldSuffix_Name,
|
||||
ref selected,
|
||||
labels,
|
||||
labels.Length
|
||||
)
|
||||
)
|
||||
{
|
||||
Plugin.Config.WorldSuffixMode = values[selected];
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
ImGuiUtil.HelpMarker(HellionStrings.Settings_Chat_WorldSuffix_Description);
|
||||
}
|
||||
|
||||
private void DrawNameFormCombo()
|
||||
{
|
||||
var current = Plugin.Config.NameFormMode;
|
||||
var values = Enum.GetValues<NameFormMode>();
|
||||
var labels = new string[values.Length];
|
||||
var selected = 0;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
labels[i] = values[i].Name();
|
||||
if (values[i] == current)
|
||||
{
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(200);
|
||||
if (
|
||||
ImGui.Combo(
|
||||
HellionStrings.Settings_Chat_NameForm_Name,
|
||||
ref selected,
|
||||
labels,
|
||||
labels.Length
|
||||
)
|
||||
)
|
||||
{
|
||||
Plugin.Config.NameFormMode = values[selected];
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
ImGuiUtil.HelpMarker(HellionStrings.Settings_Chat_NameForm_Description);
|
||||
}
|
||||
|
||||
private void DrawToggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (ImGui.Checkbox(label, ref current))
|
||||
{
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,24 @@ namespace HellionChat.Ui.Components.Settings.Tabs;
|
||||
internal sealed class DataPrivacyTab
|
||||
{
|
||||
private readonly Plugin _plugin;
|
||||
private readonly SettingsWidgets _w;
|
||||
|
||||
public DataPrivacyTab(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
_w = new SettingsWidgets(plugin);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (ImGui.CollapsingHeader("Logging", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Enable retention sweep",
|
||||
() => Plugin.Config.RetentionEnabled,
|
||||
v => Plugin.Config.RetentionEnabled = v
|
||||
);
|
||||
DrawSliderInt(
|
||||
_w.SliderInt(
|
||||
"Default retention (days)",
|
||||
() => Plugin.Config.RetentionDefaultDays,
|
||||
v => Plugin.Config.RetentionDefaultDays = v,
|
||||
@@ -43,13 +45,13 @@ internal sealed class DataPrivacyTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Privacy filter", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Enable privacy filter",
|
||||
() => Plugin.Config.PrivacyFilterEnabled,
|
||||
v => Plugin.Config.PrivacyFilterEnabled = v
|
||||
);
|
||||
DrawPrivacyPersistChannelsGrid();
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Persist unknown channels",
|
||||
() => Plugin.Config.PrivacyPersistUnknownChannels,
|
||||
v => Plugin.Config.PrivacyPersistUnknownChannels = v
|
||||
@@ -93,26 +95,4 @@ internal sealed class DataPrivacyTab
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawToggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (ImGui.Checkbox(label, ref current))
|
||||
{
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSliderInt(string label, Func<int> get, Action<int> set, int min, int max)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(200);
|
||||
// Sliders report a change every frame while dragging; deferring the write
|
||||
// to release turns ~30 full-config disk writes per second into one.
|
||||
if (ImGui.SliderInt(label, ref current, min, max, "%d"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace HellionChat.Ui.Components.Settings.Tabs;
|
||||
internal sealed class GeneralTab
|
||||
{
|
||||
private readonly Plugin _plugin;
|
||||
private readonly SettingsWidgets _w;
|
||||
private readonly FontManager _fonts;
|
||||
|
||||
// Sorted once: the 25 endonyms are fixed literals, so the order never
|
||||
@@ -18,6 +19,7 @@ internal sealed class GeneralTab
|
||||
public GeneralTab(Plugin plugin, FontManager fonts)
|
||||
{
|
||||
_plugin = plugin;
|
||||
_w = new SettingsWidgets(plugin);
|
||||
_fonts = fonts;
|
||||
}
|
||||
|
||||
@@ -33,17 +35,17 @@ internal sealed class GeneralTab
|
||||
{
|
||||
if (ImGui.CollapsingHeader("Behavior", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Reduce motion (no theme crossfade)",
|
||||
() => Plugin.Config.ReduceMotion,
|
||||
v => Plugin.Config.ReduceMotion = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Print changelog on update",
|
||||
() => Plugin.Config.PrintChangelog,
|
||||
v => Plugin.Config.PrintChangelog = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Show novice network",
|
||||
() => Plugin.Config.ShowNoviceNetwork,
|
||||
v => Plugin.Config.ShowNoviceNetwork = v
|
||||
@@ -71,7 +73,7 @@ internal sealed class GeneralTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Notifications", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
Language.Options_PlaySounds_Name,
|
||||
() => Plugin.Config.PlaySounds,
|
||||
v => Plugin.Config.PlaySounds = v
|
||||
@@ -81,7 +83,7 @@ internal sealed class GeneralTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Volumes", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawSlider(
|
||||
_w.SliderFloat(
|
||||
"Custom sound volume",
|
||||
() => Plugin.Config.CustomSoundVolume,
|
||||
v => Plugin.Config.CustomSoundVolume = v,
|
||||
@@ -177,28 +179,6 @@ internal sealed class GeneralTab
|
||||
ImGuiUtil.HelpMarker(tip);
|
||||
}
|
||||
|
||||
private void DrawToggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (ImGui.Checkbox(label, ref current))
|
||||
{
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSlider(string label, Func<float> get, Action<float> set, float min, float max)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(200);
|
||||
// Sliders report a change every frame while dragging; deferring the write
|
||||
// to release turns ~30 full-config disk writes per second into one.
|
||||
if (ImGui.SliderFloat(label, ref current, min, max, "%.2f"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
|
||||
// Wires the already-present ImGuiUtil.KeybindInput capture widget (dead/unwired
|
||||
// since the v1.6.0 rewrite) back into the settings, so ChatTabForward/Backward
|
||||
// are bindable again. ConfigKeyBind is a reference type, so a capture (new
|
||||
|
||||
@@ -5,10 +5,12 @@ namespace HellionChat.Ui.Components.Settings.Tabs;
|
||||
internal sealed class WindowTab
|
||||
{
|
||||
private readonly Plugin _plugin;
|
||||
private readonly SettingsWidgets _w;
|
||||
|
||||
public WindowTab(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
_w = new SettingsWidgets(plugin);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
@@ -30,17 +32,17 @@ internal sealed class WindowTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Window style", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Show title bar",
|
||||
() => Plugin.Config.ShowTitleBar,
|
||||
v => Plugin.Config.ShowTitleBar = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Show title bar for pop-outs",
|
||||
() => Plugin.Config.ShowPopOutTitleBar,
|
||||
v => Plugin.Config.ShowPopOutTitleBar = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Show hide button",
|
||||
() => Plugin.Config.ShowHideButton,
|
||||
v => Plugin.Config.ShowHideButton = v
|
||||
@@ -49,14 +51,14 @@ internal sealed class WindowTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Opacity", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawSlider(
|
||||
_w.SliderFloat(
|
||||
"Window opacity",
|
||||
() => Plugin.Config.WindowOpacity,
|
||||
v => Plugin.Config.WindowOpacity = v,
|
||||
0.1f,
|
||||
1f
|
||||
);
|
||||
DrawSlider(
|
||||
_w.SliderFloat(
|
||||
"Inactive opacity",
|
||||
() => Plugin.Config.WindowOpacityInactive,
|
||||
v => Plugin.Config.WindowOpacityInactive = v,
|
||||
@@ -67,17 +69,17 @@ internal sealed class WindowTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Resize behavior", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Allow movement",
|
||||
() => Plugin.Config.CanMove,
|
||||
v => Plugin.Config.CanMove = v
|
||||
);
|
||||
DrawToggle(
|
||||
_w.Toggle(
|
||||
"Allow resize",
|
||||
() => Plugin.Config.CanResize,
|
||||
v => Plugin.Config.CanResize = v
|
||||
);
|
||||
DrawSliderInt(
|
||||
_w.SliderInt(
|
||||
"Sidebar auto-switch threshold (px)",
|
||||
() => Plugin.Config.SidebarAutoSwitchThresholdPx,
|
||||
v => Plugin.Config.SidebarAutoSwitchThresholdPx = v,
|
||||
@@ -88,69 +90,17 @@ internal sealed class WindowTab
|
||||
|
||||
if (ImGui.CollapsingHeader("Input preview"))
|
||||
{
|
||||
DrawPreviewPositionCombo();
|
||||
DrawToggle(
|
||||
_w.EnumCombo(
|
||||
"Preview position",
|
||||
() => Plugin.Config.PreviewPosition,
|
||||
v => Plugin.Config.PreviewPosition = v,
|
||||
v => v.Name()
|
||||
);
|
||||
_w.Toggle(
|
||||
"Only show preview when typing",
|
||||
() => Plugin.Config.OnlyPreviewIf,
|
||||
v => Plugin.Config.OnlyPreviewIf = v
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPreviewPositionCombo()
|
||||
{
|
||||
var current = Plugin.Config.PreviewPosition;
|
||||
var values = Enum.GetValues<PreviewPosition>();
|
||||
var labels = new string[values.Length];
|
||||
var selected = 0;
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
labels[i] = values[i].Name();
|
||||
if (values[i] == current)
|
||||
{
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(200);
|
||||
if (ImGui.Combo("Preview position", ref selected, labels, labels.Length))
|
||||
{
|
||||
Plugin.Config.PreviewPosition = values[selected];
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawToggle(string label, Func<bool> get, Action<bool> set)
|
||||
{
|
||||
var current = get();
|
||||
if (ImGui.Checkbox(label, ref current))
|
||||
{
|
||||
set(current);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSlider(string label, Func<float> get, Action<float> set, float min, float max)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(200);
|
||||
// Sliders report a change every frame while dragging; deferring the write
|
||||
// to release turns ~30 full-config disk writes per second into one.
|
||||
if (ImGui.SliderFloat(label, ref current, min, max, "%.2f"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
|
||||
private void DrawSliderInt(string label, Func<int> get, Action<int> set, int min, int max)
|
||||
{
|
||||
var current = get();
|
||||
ImGui.SetNextItemWidth(200);
|
||||
// Sliders report a change every frame while dragging; deferring the write
|
||||
// to release turns ~30 full-config disk writes per second into one.
|
||||
if (ImGui.SliderInt(label, ref current, min, max, "%d"))
|
||||
set(current);
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user