diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 716d5ede..2125315e 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -37,7 +37,7 @@ namespace Penumbra public Dictionary< string, string > ModSortOrder { get; set; } = new(); public bool InvertModListOrder { internal get; set; } - public Vector2 ManageModsButtonOffset { get; set; } = Vector2.Zero; + public Vector2 ManageModsButtonOffset { get; set; } = 50 * Vector2.One; public static Configuration Load() { diff --git a/Penumbra/UI/LaunchButton.cs b/Penumbra/UI/LaunchButton.cs index 0c8c05d9..18ca07bb 100644 --- a/Penumbra/UI/LaunchButton.cs +++ b/Penumbra/UI/LaunchButton.cs @@ -1,56 +1,59 @@ -using System.Numerics; +using Dalamud.Interface; using ImGuiNET; +using Penumbra.UI.Custom; -namespace Penumbra.UI +namespace Penumbra.UI; + +public partial class SettingsInterface { - public partial class SettingsInterface + private class ManageModsButton { - private class ManageModsButton + // magic numbers + private const int Width = 200; + private const int Height = 45; + private const string MenuButtonsName = "Penumbra Menu Buttons"; + private const string MenuButtonLabel = "Manage Mods"; + + private const ImGuiWindowFlags ButtonFlags = + ImGuiWindowFlags.AlwaysAutoResize + | ImGuiWindowFlags.NoBackground + | ImGuiWindowFlags.NoDecoration + | ImGuiWindowFlags.NoMove + | ImGuiWindowFlags.NoScrollbar + | ImGuiWindowFlags.NoResize + | ImGuiWindowFlags.NoFocusOnAppearing + | ImGuiWindowFlags.NoSavedSettings; + + private readonly SettingsInterface _base; + + public ManageModsButton( SettingsInterface ui ) + => _base = ui; + + internal bool ForceDraw = false; + + public void Draw() { - // magic numbers - private const int Padding = 50; - private const int Width = 200; - private const int Height = 45; - private const string MenuButtonsName = "Penumbra Menu Buttons"; - private const string MenuButtonLabel = "Manage Mods"; - - private static readonly Vector2 WindowSize = new( Width, Height ); - private static readonly Vector2 WindowPosOffset = new( Padding + Width, Padding + Height ); - - private const ImGuiWindowFlags ButtonFlags = - ImGuiWindowFlags.AlwaysAutoResize - | ImGuiWindowFlags.NoBackground - | ImGuiWindowFlags.NoDecoration - | ImGuiWindowFlags.NoMove - | ImGuiWindowFlags.NoScrollbar - | ImGuiWindowFlags.NoResize - | ImGuiWindowFlags.NoSavedSettings; - - private readonly SettingsInterface _base; - - public ManageModsButton( SettingsInterface ui ) - => _base = ui; - - public void Draw() + if( !ForceDraw && ( Dalamud.Conditions.Any() || _base._menu.Visible ) ) { - if( Dalamud.Conditions.Any() || _base._menu.Visible ) - { - return; - } - - var ss = ImGui.GetMainViewport().Size + ImGui.GetMainViewport().Pos; - ImGui.SetNextWindowViewport( ImGui.GetMainViewport().ID ); - - ImGui.SetNextWindowPos( ss - WindowPosOffset + Penumbra.Config.ManageModsButtonOffset, ImGuiCond.Always ); - - if( ImGui.Begin( MenuButtonsName, ButtonFlags ) - && ImGui.Button( MenuButtonLabel, WindowSize ) ) - { - _base.FlipVisibility(); - } - - ImGui.End(); + return; } + + using var color = ImGuiRaii.PushColor( ImGuiCol.Button, 0xFF0000C8, ForceDraw ); + + var ss = ImGui.GetMainViewport().Size + ImGui.GetMainViewport().Pos; + ImGui.SetNextWindowViewport( ImGui.GetMainViewport().ID ); + + var windowSize = ImGuiHelpers.ScaledVector2( Width, Height ); + + ImGui.SetNextWindowPos( ss - windowSize - Penumbra.Config.ManageModsButtonOffset * ImGuiHelpers.GlobalScale, ImGuiCond.Always ); + + if( ImGui.Begin( MenuButtonsName, ButtonFlags ) + && ImGui.Button( MenuButtonLabel, windowSize ) ) + { + _base.FlipVisibility(); + } + + ImGui.End(); } } } \ No newline at end of file diff --git a/Penumbra/UI/MenuTabs/TabSettings.cs b/Penumbra/UI/MenuTabs/TabSettings.cs index f5b6ffe6..f61783dd 100644 --- a/Penumbra/UI/MenuTabs/TabSettings.cs +++ b/Penumbra/UI/MenuTabs/TabSettings.cs @@ -12,324 +12,325 @@ using Penumbra.Mods; using Penumbra.UI.Custom; using Penumbra.Util; -namespace Penumbra.UI +namespace Penumbra.UI; + +public partial class SettingsInterface { - public partial class SettingsInterface + private class TabSettings { - private class TabSettings + private const string LabelTab = "Settings"; + private const string LabelRootFolder = "Root Folder"; + private const string LabelTempFolder = "Temporary Folder"; + private const string LabelRediscoverButton = "Rediscover Mods"; + private const string LabelOpenFolder = "Open Mods Folder"; + private const string LabelOpenTempFolder = "Open Temporary Folder"; + private const string LabelEnabled = "Enable Mods"; + private const string LabelEnabledPlayerWatch = "Enable automatic Character Redraws"; + private const string LabelWaitFrames = "Wait Frames"; + private const string LabelSortFoldersFirst = "Sort Mod Folders Before Mods"; + private const string LabelScaleModSelector = "Scale Mod Selector With Window Size"; + private const string LabelShowAdvanced = "Show Advanced Settings"; + private const string LabelLogLoadedFiles = "Log all loaded files"; + private const string LabelDisableNotifications = "Disable filesystem change notifications"; + private const string LabelEnableHttpApi = "Enable HTTP API"; + private const string LabelReloadResource = "Reload Player Resource"; + private const string LabelManageModsOffset = "\"Manage mods\"-Button Offset"; + + private readonly SettingsInterface _base; + private readonly Configuration _config; + private bool _configChanged; + private string _newModDirectory; + private string _newTempDirectory; + + + public TabSettings( SettingsInterface ui ) { - private const string LabelTab = "Settings"; - private const string LabelRootFolder = "Root Folder"; - private const string LabelTempFolder = "Temporary Folder"; - private const string LabelRediscoverButton = "Rediscover Mods"; - private const string LabelOpenFolder = "Open Mods Folder"; - private const string LabelOpenTempFolder = "Open Temporary Folder"; - private const string LabelEnabled = "Enable Mods"; - private const string LabelEnabledPlayerWatch = "Enable automatic Character Redraws"; - private const string LabelWaitFrames = "Wait Frames"; - private const string LabelSortFoldersFirst = "Sort Mod Folders Before Mods"; - private const string LabelScaleModSelector = "Scale Mod Selector With Window Size"; - private const string LabelShowAdvanced = "Show Advanced Settings"; - private const string LabelLogLoadedFiles = "Log all loaded files"; - private const string LabelDisableNotifications = "Disable filesystem change notifications"; - private const string LabelEnableHttpApi = "Enable HTTP API"; - private const string LabelReloadResource = "Reload Player Resource"; - private const string LabelManageModsOffset = "\"Manage mods\" title screen button offset"; + _base = ui; + _config = Penumbra.Config; + _configChanged = false; + _newModDirectory = _config.ModDirectory; + _newTempDirectory = _config.TempDirectory; + } - private readonly SettingsInterface _base; - private readonly Configuration _config; - private bool _configChanged; - private string _newModDirectory; - private string _newTempDirectory; + private static bool DrawPressEnterWarning( string old, float? width = null ) + { + const uint red = 0xFF202080; + using var color = ImGuiRaii.PushColor( ImGuiCol.Button, red ); + var w = Vector2.UnitX * ( width ?? ImGui.CalcItemWidth() ); + return ImGui.Button( $"Press Enter or Click Here to Save (Current Directory: {old})", w ); + } - - public TabSettings( SettingsInterface ui ) + private void DrawRootFolder() + { + var save = ImGui.InputText( LabelRootFolder, ref _newModDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue ); + if( _config.ModDirectory == _newModDirectory || !_newModDirectory.Any() ) { - _base = ui; - _config = Penumbra.Config; - _configChanged = false; - _newModDirectory = _config.ModDirectory; + return; + } + + if( save || DrawPressEnterWarning( _config.ModDirectory ) ) + { + _base._menu.InstalledTab.Selector.ClearSelection(); + _base._modManager.DiscoverMods( _newModDirectory ); + _base._menu.InstalledTab.Selector.Cache.TriggerListReset(); + _newModDirectory = _config.ModDirectory; + } + } + + private void DrawTempFolder() + { + ImGui.SetNextItemWidth( 400 * ImGuiHelpers.GlobalScale ); + ImGui.BeginGroup(); + var save = ImGui.InputText( LabelTempFolder, ref _newTempDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue ); + + ImGuiCustom.HoverTooltip( "The folder used to store temporary meta manipulation files.\n" + + "Leave this blank if you have no reason not to.\n" + + "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n" + + "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." ); + + ImGui.SameLine(); + if( ImGui.Button( LabelOpenTempFolder ) ) + { + if( !Directory.Exists( _base._modManager.TempPath.FullName ) || !_base._modManager.TempWritable ) + { + return; + } + + Process.Start( new ProcessStartInfo( _base._modManager.TempPath.FullName ) + { + UseShellExecute = true, + } ); + } + + ImGui.EndGroup(); + if( _newTempDirectory == _config.TempDirectory ) + { + return; + } + + if( save || DrawPressEnterWarning( _config.TempDirectory, 400 ) ) + { + _base._modManager.SetTempDirectory( _newTempDirectory ); _newTempDirectory = _config.TempDirectory; } + } - private static bool DrawPressEnterWarning( string old, float? width = null ) + private void DrawRediscoverButton() + { + if( ImGui.Button( LabelRediscoverButton ) ) { - const uint red = 0xFF202080; - using var color = ImGuiRaii.PushColor( ImGuiCol.Button, red ); - var w = Vector2.UnitX * ( width ?? ImGui.CalcItemWidth() ); - return ImGui.Button( $"Press Enter or Click Here to Save (Current Directory: {old})", w ); + _base._menu.InstalledTab.Selector.ClearSelection(); + _base._modManager.DiscoverMods(); + _base._menu.InstalledTab.Selector.Cache.TriggerListReset(); } + } - private void DrawRootFolder() + private void DrawOpenModsButton() + { + if( ImGui.Button( LabelOpenFolder ) ) { - var save = ImGui.InputText( LabelRootFolder, ref _newModDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue ); - if( _config.ModDirectory == _newModDirectory || !_newModDirectory.Any() ) + if( !Directory.Exists( _config.ModDirectory ) || !Service< ModManager >.Get().Valid ) { return; } - if( save || DrawPressEnterWarning( _config.ModDirectory ) ) + Process.Start( new ProcessStartInfo( _config.ModDirectory ) { - _base._menu.InstalledTab.Selector.ClearSelection(); - _base._modManager.DiscoverMods( _newModDirectory ); - _base._menu.InstalledTab.Selector.Cache.TriggerListReset(); - _newModDirectory = _config.ModDirectory; - } + UseShellExecute = true, + } ); + } + } + + private void DrawEnabledBox() + { + var enabled = _config.IsEnabled; + if( ImGui.Checkbox( LabelEnabled, ref enabled ) ) + { + _base._penumbra.SetEnabled( enabled ); + } + } + + private void DrawShowAdvancedBox() + { + var showAdvanced = _config.ShowAdvanced; + if( ImGui.Checkbox( LabelShowAdvanced, ref showAdvanced ) ) + { + _config.ShowAdvanced = showAdvanced; + _configChanged = true; + } + } + + private void DrawManageModsButtonOffsetButton() + { + var manageModsButtonOffset = _config.ManageModsButtonOffset; + ImGui.SetNextItemWidth( 150 * ImGuiHelpers.GlobalScale ); + if( ImGui.DragFloat2( LabelManageModsOffset, ref manageModsButtonOffset, 1f ) ) + { + _config.ManageModsButtonOffset = manageModsButtonOffset; + _configChanged = true; } - private void DrawTempFolder() + _base._manageModsButton.ForceDraw = ImGui.IsItemActive(); + } + + private void DrawSortFoldersFirstBox() + { + var foldersFirst = _config.SortFoldersFirst; + if( ImGui.Checkbox( LabelSortFoldersFirst, ref foldersFirst ) ) { - ImGui.SetNextItemWidth( 400 * ImGuiHelpers.GlobalScale ); - ImGui.BeginGroup(); - var save = ImGui.InputText( LabelTempFolder, ref _newTempDirectory, 255, ImGuiInputTextFlags.EnterReturnsTrue ); + _config.SortFoldersFirst = foldersFirst; + _base._menu.InstalledTab.Selector.Cache.TriggerListReset(); + _configChanged = true; + } + } - ImGuiCustom.HoverTooltip( "The folder used to store temporary meta manipulation files.\n" - + "Leave this blank if you have no reason not to.\n" - + "A folder 'penumbrametatmp' will be created as a subdirectory to the specified directory.\n" - + "If none is specified (i.e. this is blank) this folder will be created in the root folder instead." ); + private void DrawScaleModSelectorBox() + { + var scaleModSelector = _config.ScaleModSelector; + if( ImGui.Checkbox( LabelScaleModSelector, ref scaleModSelector ) ) + { + _config.ScaleModSelector = scaleModSelector; + _configChanged = true; + } + } - ImGui.SameLine(); - if( ImGui.Button( LabelOpenTempFolder ) ) + private void DrawLogLoadedFilesBox() + { + ImGui.Checkbox( LabelLogLoadedFiles, ref _base._penumbra.ResourceLoader.LogAllFiles ); + ImGui.SameLine(); + var regex = _base._penumbra.ResourceLoader.LogFileFilter?.ToString() ?? string.Empty; + var tmp = regex; + if( ImGui.InputTextWithHint( "##LogFilter", "Matching this Regex...", ref tmp, 64 ) && tmp != regex ) + { + try { - if( !Directory.Exists( _base._modManager.TempPath.FullName ) || !_base._modManager.TempWritable ) - { - return; - } - - Process.Start( new ProcessStartInfo( _base._modManager.TempPath.FullName ) - { - UseShellExecute = true, - } ); + var newRegex = tmp.Length > 0 ? new Regex( tmp, RegexOptions.Compiled ) : null; + _base._penumbra.ResourceLoader.LogFileFilter = newRegex; } - - ImGui.EndGroup(); - if( _newTempDirectory == _config.TempDirectory ) + catch( Exception e ) { - return; - } - - if( save || DrawPressEnterWarning( _config.TempDirectory, 400 ) ) - { - _base._modManager.SetTempDirectory( _newTempDirectory ); - _newTempDirectory = _config.TempDirectory; + PluginLog.Debug( "Could not create regex:\n{Exception}", e ); } } + } - private void DrawRediscoverButton() + private void DrawDisableNotificationsBox() + { + var fsWatch = _config.DisableFileSystemNotifications; + if( ImGui.Checkbox( LabelDisableNotifications, ref fsWatch ) ) { - if( ImGui.Button( LabelRediscoverButton ) ) + _config.DisableFileSystemNotifications = fsWatch; + _configChanged = true; + } + } + + private void DrawEnableHttpApiBox() + { + var http = _config.EnableHttpApi; + if( ImGui.Checkbox( LabelEnableHttpApi, ref http ) ) + { + if( http ) { - _base._menu.InstalledTab.Selector.ClearSelection(); - _base._modManager.DiscoverMods(); - _base._menu.InstalledTab.Selector.Cache.TriggerListReset(); + _base._penumbra.CreateWebServer(); } + else + { + _base._penumbra.ShutdownWebServer(); + } + + _config.EnableHttpApi = http; + _configChanged = true; + } + } + + private void DrawEnabledPlayerWatcher() + { + var enabled = _config.EnablePlayerWatch; + if( ImGui.Checkbox( LabelEnabledPlayerWatch, ref enabled ) ) + { + _config.EnablePlayerWatch = enabled; + _configChanged = true; + Penumbra.PlayerWatcher.SetStatus( enabled ); } - private void DrawOpenModsButton() - { - if( ImGui.Button( LabelOpenFolder ) ) - { - if( !Directory.Exists( _config.ModDirectory ) || !Service< ModManager >.Get().Valid ) - { - return; - } + ImGuiCustom.HoverTooltip( + "If this setting is enabled, penumbra will keep tabs on characters that have a corresponding collection setup in the Collections tab.\n" + + "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip." ); - Process.Start( new ProcessStartInfo( _config.ModDirectory ) - { - UseShellExecute = true, - } ); - } + if( !_config.EnablePlayerWatch || !_config.ShowAdvanced ) + { + return; } - private void DrawEnabledBox() + var waitFrames = _config.WaitFrames; + ImGui.SameLine(); + ImGui.SetNextItemWidth( 50 ); + if( ImGui.InputInt( LabelWaitFrames, ref waitFrames, 0, 0 ) + && waitFrames != _config.WaitFrames + && waitFrames > 0 + && waitFrames < 3000 ) { - var enabled = _config.IsEnabled; - if( ImGui.Checkbox( LabelEnabled, ref enabled ) ) - { - _base._penumbra.SetEnabled( enabled ); - } + _base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames; + _config.WaitFrames = waitFrames; + _configChanged = true; } - private void DrawShowAdvancedBox() + ImGuiCustom.HoverTooltip( + "The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n" + + "Keep this as low as possible while producing stable results." ); + } + + private static void DrawReloadResourceButton() + { + if( ImGui.Button( LabelReloadResource ) ) { - var showAdvanced = _config.ShowAdvanced; - if( ImGui.Checkbox( LabelShowAdvanced, ref showAdvanced ) ) - { - _config.ShowAdvanced = showAdvanced; - _configChanged = true; - } + Service< ResidentResources >.Get().ReloadPlayerResources(); + } + } + + private void DrawAdvancedSettings() + { + DrawTempFolder(); + DrawLogLoadedFilesBox(); + DrawDisableNotificationsBox(); + DrawEnableHttpApiBox(); + DrawReloadResourceButton(); + } + + public void Draw() + { + if( !ImGui.BeginTabItem( LabelTab ) ) + { + return; } - private void DrawManageModsButtonOffset() + using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); + + DrawRootFolder(); + + DrawRediscoverButton(); + ImGui.SameLine(); + DrawOpenModsButton(); + + ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); + DrawEnabledBox(); + DrawEnabledPlayerWatcher(); + + ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); + DrawScaleModSelectorBox(); + DrawSortFoldersFirstBox(); + DrawManageModsButtonOffsetButton(); + DrawShowAdvancedBox(); + + if( _config.ShowAdvanced ) { - var manageModsButtonOffset = _config.ManageModsButtonOffset; - ImGui.SetNextItemWidth( 150f ); - if( ImGui.DragFloat2( LabelManageModsOffset, ref manageModsButtonOffset, 1f ) ) - { - _config.ManageModsButtonOffset = manageModsButtonOffset; - _configChanged = true; - } + DrawAdvancedSettings(); } - private void DrawSortFoldersFirstBox() + if( _configChanged ) { - var foldersFirst = _config.SortFoldersFirst; - if( ImGui.Checkbox( LabelSortFoldersFirst, ref foldersFirst ) ) - { - _config.SortFoldersFirst = foldersFirst; - _base._menu.InstalledTab.Selector.Cache.TriggerListReset(); - _configChanged = true; - } - } - - private void DrawScaleModSelectorBox() - { - var scaleModSelector = _config.ScaleModSelector; - if( ImGui.Checkbox( LabelScaleModSelector, ref scaleModSelector ) ) - { - _config.ScaleModSelector = scaleModSelector; - _configChanged = true; - } - } - - private void DrawLogLoadedFilesBox() - { - ImGui.Checkbox( LabelLogLoadedFiles, ref _base._penumbra.ResourceLoader.LogAllFiles ); - ImGui.SameLine(); - var regex = _base._penumbra.ResourceLoader.LogFileFilter?.ToString() ?? string.Empty; - var tmp = regex; - if( ImGui.InputTextWithHint( "##LogFilter", "Matching this Regex...", ref tmp, 64 ) && tmp != regex ) - { - try - { - var newRegex = tmp.Length > 0 ? new Regex( tmp, RegexOptions.Compiled ) : null; - _base._penumbra.ResourceLoader.LogFileFilter = newRegex; - } - catch( Exception e ) - { - PluginLog.Debug( "Could not create regex:\n{Exception}", e ); - } - } - } - - private void DrawDisableNotificationsBox() - { - var fsWatch = _config.DisableFileSystemNotifications; - if( ImGui.Checkbox( LabelDisableNotifications, ref fsWatch ) ) - { - _config.DisableFileSystemNotifications = fsWatch; - _configChanged = true; - } - } - - private void DrawEnableHttpApiBox() - { - var http = _config.EnableHttpApi; - if( ImGui.Checkbox( LabelEnableHttpApi, ref http ) ) - { - if( http ) - { - _base._penumbra.CreateWebServer(); - } - else - { - _base._penumbra.ShutdownWebServer(); - } - - _config.EnableHttpApi = http; - _configChanged = true; - } - } - - private void DrawEnabledPlayerWatcher() - { - var enabled = _config.EnablePlayerWatch; - if( ImGui.Checkbox( LabelEnabledPlayerWatch, ref enabled ) ) - { - _config.EnablePlayerWatch = enabled; - _configChanged = true; - Penumbra.PlayerWatcher.SetStatus( enabled ); - } - - ImGuiCustom.HoverTooltip( - "If this setting is enabled, penumbra will keep tabs on characters that have a corresponding collection setup in the Collections tab.\n" - + "Penumbra will try to automatically redraw those characters using their collection when they first appear in an instance, or when they change their current equip." ); - - if( !_config.EnablePlayerWatch || !_config.ShowAdvanced ) - { - return; - } - - var waitFrames = _config.WaitFrames; - ImGui.SameLine(); - ImGui.SetNextItemWidth( 50 ); - if( ImGui.InputInt( LabelWaitFrames, ref waitFrames, 0, 0 ) - && waitFrames != _config.WaitFrames - && waitFrames > 0 - && waitFrames < 3000 ) - { - _base._penumbra.ObjectReloader.DefaultWaitFrames = waitFrames; - _config.WaitFrames = waitFrames; - _configChanged = true; - } - - ImGuiCustom.HoverTooltip( - "The number of frames penumbra waits after some events (like zone changes) until it starts trying to redraw actors again, in a range of [1, 3001].\n" - + "Keep this as low as possible while producing stable results." ); - } - - private static void DrawReloadResourceButton() - { - if( ImGui.Button( LabelReloadResource ) ) - { - Service< ResidentResources >.Get().ReloadPlayerResources(); - } - } - - private void DrawAdvancedSettings() - { - DrawTempFolder(); - DrawLogLoadedFilesBox(); - DrawDisableNotificationsBox(); - DrawEnableHttpApiBox(); - DrawReloadResourceButton(); - } - - public void Draw() - { - if( !ImGui.BeginTabItem( LabelTab ) ) - { - return; - } - - using var raii = ImGuiRaii.DeferredEnd( ImGui.EndTabItem ); - - DrawRootFolder(); - - DrawRediscoverButton(); - ImGui.SameLine(); - DrawOpenModsButton(); - - ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); - DrawEnabledBox(); - DrawEnabledPlayerWatcher(); - - ImGuiCustom.VerticalDistance( DefaultVerticalSpace ); - DrawScaleModSelectorBox(); - DrawSortFoldersFirstBox(); - DrawManageModsButtonOffset(); - DrawShowAdvancedBox(); - - if( _config.ShowAdvanced ) - { - DrawAdvancedSettings(); - } - - if( _configChanged ) - { - _config.Save(); - _configChanged = false; - } + _config.Save(); + _configChanged = false; } } }