diff --git a/HellionChat/Configuration.cs b/HellionChat/Configuration.cs index b46cb68..6326650 100755 --- a/HellionChat/Configuration.cs +++ b/HellionChat/Configuration.cs @@ -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 { diff --git a/HellionChat/Ui/Components/Settings/SettingsWidgets.cs b/HellionChat/Ui/Components/Settings/SettingsWidgets.cs new file mode 100644 index 0000000..d650bed --- /dev/null +++ b/HellionChat/Ui/Components/Settings/SettingsWidgets.cs @@ -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 + where T : struct, Enum +{ + internal static readonly T[] All = Enum.GetValues(); +} + +// 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 get, Action set) + { + var current = get(); + if (!ImGui.Checkbox(label, ref current)) + return; + + set(current); + _plugin.SaveConfig(); + } + + internal void SliderFloat( + string label, + Func get, + Action 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 get, + Action 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( + string label, + Func get, + Action set, + Func labelFor, + float width = 200f + ) + where T : struct, Enum + { + var values = EnumValues.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.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(); + } +} diff --git a/HellionChat/Ui/Components/Settings/Tabs/AboutTab.cs b/HellionChat/Ui/Components/Settings/Tabs/AboutTab.cs index 647429a..cfce8ef 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/AboutTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/AboutTab.cs @@ -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 get, Action 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 diff --git a/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs b/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs index 38398a8..7148506 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/ChannelsTab.cs @@ -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(); - 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 get, Action set) - { - var current = get(); - if (ImGui.Checkbox(label, ref current)) - { - set(current); - _plugin.SaveConfig(); - } - } - - private void DrawSliderInt(string label, Func get, Action 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(); - } } diff --git a/HellionChat/Ui/Components/Settings/Tabs/ChatTab.cs b/HellionChat/Ui/Components/Settings/Tabs/ChatTab.cs index 68fdf4e..f46d551 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/ChatTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/ChatTab.cs @@ -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(); - 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(); - 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(); - 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 get, Action set) - { - var current = get(); - if (ImGui.Checkbox(label, ref current)) - { - set(current); - _plugin.SaveConfig(); - } - } } diff --git a/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs b/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs index 6e83f84..c8713a7 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs @@ -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 get, Action set) - { - var current = get(); - if (ImGui.Checkbox(label, ref current)) - { - set(current); - _plugin.SaveConfig(); - } - } - - private void DrawSliderInt(string label, Func get, Action 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(); - } } diff --git a/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs b/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs index 36b15de..4387b5f 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs @@ -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 get, Action set) - { - var current = get(); - if (ImGui.Checkbox(label, ref current)) - { - set(current); - _plugin.SaveConfig(); - } - } - - private void DrawSlider(string label, Func get, Action 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 diff --git a/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs b/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs index 19806b2..92391ca 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs @@ -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(); - 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 get, Action set) - { - var current = get(); - if (ImGui.Checkbox(label, ref current)) - { - set(current); - _plugin.SaveConfig(); - } - } - - private void DrawSlider(string label, Func get, Action 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 get, Action 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(); - } }