diff --git a/Glamourer/Configuration.cs b/Glamourer/Configuration.cs index 2f925a3..0f8d75a 100644 --- a/Glamourer/Configuration.cs +++ b/Glamourer/Configuration.cs @@ -18,27 +18,28 @@ public class Configuration : IPluginConfiguration, ISavable [JsonIgnore] public readonly EphemeralConfig Ephemeral; - public bool UseRestrictedGearProtection { get; set; } = false; - public bool OpenFoldersByDefault { get; set; } = false; - public bool AutoRedrawEquipOnChanges { get; set; } = false; - public bool EnableAutoDesigns { get; set; } = true; - public bool HideApplyCheckmarks { get; set; } = false; - public bool SmallEquip { get; set; } = false; - public bool UnlockedItemMode { get; set; } = false; - public byte DisableFestivals { get; set; } = 1; - public bool EnableGameContextMenu { get; set; } = true; - public bool HideWindowInCutscene { get; set; } = false; - public bool ShowAutomationSetEditing { get; set; } = true; - public bool ShowAllAutomatedApplicationRules { get; set; } = true; - public bool ShowUnlockedItemWarnings { get; set; } = true; - public bool RevertManualChangesOnZoneChange { get; set; } = false; - public bool ShowQuickBarInTabs { get; set; } = true; - public bool OpenWindowAtStart { get; set; } = false; - public bool UseAdvancedParameters { get; set; } = true; - public bool ShowPalettePlusImport { get; set; } = true; - public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY); - public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); - public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; + public bool UseRestrictedGearProtection { get; set; } = false; + public bool OpenFoldersByDefault { get; set; } = false; + public bool AutoRedrawEquipOnChanges { get; set; } = false; + public bool EnableAutoDesigns { get; set; } = true; + public bool HideApplyCheckmarks { get; set; } = false; + public bool SmallEquip { get; set; } = false; + public bool UnlockedItemMode { get; set; } = false; + public byte DisableFestivals { get; set; } = 1; + public bool EnableGameContextMenu { get; set; } = true; + public bool HideWindowInCutscene { get; set; } = false; + public bool ShowAutomationSetEditing { get; set; } = true; + public bool ShowAllAutomatedApplicationRules { get; set; } = true; + public bool ShowUnlockedItemWarnings { get; set; } = true; + public bool RevertManualChangesOnZoneChange { get; set; } = false; + public bool ShowQuickBarInTabs { get; set; } = true; + public bool OpenWindowAtStart { get; set; } = false; + public bool UseAdvancedParameters { get; set; } = true; + public bool ShowRevertAdvancedParametersButton { get; set; } = true; + public bool ShowPalettePlusImport { get; set; } = true; + public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY); + public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); + public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; [JsonConverter(typeof(SortModeConverter))] [JsonProperty(Order = int.MaxValue)] diff --git a/Glamourer/Gui/DesignQuickBar.cs b/Glamourer/Gui/DesignQuickBar.cs index 0e361a1..f6e73f9 100644 --- a/Glamourer/Gui/DesignQuickBar.cs +++ b/Glamourer/Gui/DesignQuickBar.cs @@ -16,7 +16,7 @@ using Penumbra.GameData.Actors; namespace Glamourer.Gui; -public class DesignQuickBar : Window, IDisposable +public sealed class DesignQuickBar : Window, IDisposable { private ImGuiWindowFlags GetFlags => _config.Ephemeral.LockDesignQuickBar @@ -32,6 +32,7 @@ public class DesignQuickBar : Window, IDisposable private readonly ImRaii.Style _windowPadding = new(); private readonly ImRaii.Color _windowColor = new(); private DateTime _keyboardToggle = DateTime.UnixEpoch; + private int _numButtons = 0; public DesignQuickBar(Configuration config, DesignCombo designCombo, StateManager stateManager, IKeyState keyState, ObjectManager objects, AutoDesignApplier autoDesignApplier) @@ -60,7 +61,7 @@ public class DesignQuickBar : Window, IDisposable public override void PreDraw() { Flags = GetFlags; - Size = new Vector2(12 * ImGui.GetFrameHeight(), ImGui.GetFrameHeight()); + UpdateWidth(); _windowPadding.Push(ImGuiStyleVar.WindowPadding, new Vector2(ImGuiHelpers.GlobalScale * 4)) .Push(ImGuiStyleVar.WindowBorderSize, 0); @@ -75,6 +76,12 @@ public class DesignQuickBar : Window, IDisposable _windowColor.Dispose(); } + public void DrawAtEnd(float yPos) + { + var width = UpdateWidth(); + ImGui.SetCursorPos(new Vector2(ImGui.GetWindowContentRegionMax().X - width, yPos - ImGuiHelpers.GlobalScale)); + Draw(); + } public override void Draw() => Draw(ImGui.GetContentRegionAvail().X); @@ -82,20 +89,19 @@ public class DesignQuickBar : Window, IDisposable private void Draw(float width) { _objects.Update(); - using var group = ImRaii.Group(); - var spacing = ImGui.GetStyle().ItemInnerSpacing; - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); - var contentRegion = width; - var buttonSize = new Vector2(ImGui.GetFrameHeight()); - var comboSize = contentRegion - 3 * buttonSize.X - 3 * spacing.X; + using var group = ImRaii.Group(); + var spacing = ImGui.GetStyle().ItemInnerSpacing; + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); + var buttonSize = new Vector2(ImGui.GetFrameHeight()); + var comboSize = width - _numButtons * (buttonSize.X + spacing.X); _designCombo.Draw(comboSize); PrepareButtons(); ImGui.SameLine(); DrawApplyButton(buttonSize); ImGui.SameLine(); DrawRevertButton(buttonSize); - ImGui.SameLine(); DrawRevertAutomationButton(buttonSize); + DrawRevertAdvancedCustomization(buttonSize); } private ActorIdentifier _playerIdentifier; @@ -111,10 +117,8 @@ public class DesignQuickBar : Window, IDisposable _objects.Update(); (_playerIdentifier, _playerData) = _objects.PlayerData; (_targetIdentifier, _targetData) = _objects.TargetData; - if (!_stateManager.TryGetValue(_playerIdentifier, out _playerState)) - _playerState = null; - if (!_stateManager.TryGetValue(_targetIdentifier, out _targetState)) - _targetState = null; + _playerState = _stateManager.GetValueOrDefault(_playerIdentifier); + _targetState = _stateManager.GetValueOrDefault(_targetIdentifier); } private void DrawApplyButton(Vector2 size) @@ -183,52 +187,79 @@ public class DesignQuickBar : Window, IDisposable if (available == 0) tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked."; - var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available); + var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.UndoAlt, buttonSize, tooltip, available); if (clicked) _stateManager.ResetState(state!, StateChanged.Source.Manual); } public void DrawRevertAutomationButton(Vector2 buttonSize) { + if (!_config.EnableAutoDesigns) + return; + var available = 0; var tooltip = string.Empty; - if (!_config.EnableAutoDesigns) - { - tooltip = "Automation is not enabled, you can not reset to automation state."; - } - else - { - if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) - { - available |= 1; - tooltip = "Left-Click: Revert the player character to their automation state."; - } - if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) - { - if (available != 0) - tooltip += '\n'; - available |= 2; - tooltip += $"Right-Click: Revert {_targetIdentifier} to their automation state."; - } - - if (available == 0) - tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked."; + if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) + { + available |= 1; + tooltip = "Left-Click: Revert the player character to their automation state."; } + if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) + { + if (available != 0) + tooltip += '\n'; + available |= 2; + tooltip += $"Right-Click: Revert {_targetIdentifier} to their automation state."; + } + + if (available == 0) + tooltip = "Neither player character nor target are available, have state modified by Glamourer, or their state is locked."; + + ImGui.SameLine(); var (clicked, id, data, state) = ResolveTarget(FontAwesomeIcon.SyncAlt, buttonSize, tooltip, available); if (!clicked) - { } - else + return; + + foreach (var actor in data.Objects) { - foreach (var actor in data.Objects) - { - _autoDesignApplier.ReapplyAutomation(actor, id, state!); - _stateManager.ReapplyState(actor); - } + _autoDesignApplier.ReapplyAutomation(actor, id, state!); + _stateManager.ReapplyState(actor); } } + public void DrawRevertAdvancedCustomization(Vector2 buttonSize) + { + if (!_config.ShowRevertAdvancedParametersButton || !_config.UseAdvancedParameters) + return; + + var available = 0; + var tooltip = string.Empty; + + if (_playerIdentifier.IsValid && _playerState is { IsLocked: false } && _playerData.Valid) + { + available |= 1; + tooltip = "Left-Click: Revert the advanced customizations of the player character to their game state."; + } + + if (_targetIdentifier.IsValid && _targetState is { IsLocked: false } && _targetData.Valid) + { + if (available != 0) + tooltip += '\n'; + available |= 2; + tooltip += $"Right-Click: Revert the advanced customizations of {_targetIdentifier} to their game state."; + } + + if (available == 0) + tooltip = "Neither player character nor target are available or their state is locked."; + + ImGui.SameLine(); + var (clicked, _, _, state) = ResolveTarget(FontAwesomeIcon.Palette, buttonSize, tooltip, available); + if (clicked) + _stateManager.ResetAdvancedState(state!, StateChanged.Source.Manual); + } + private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip, int available) { @@ -251,11 +282,24 @@ public class DesignQuickBar : Window, IDisposable _config.Ephemeral.Save(); } - public bool CheckKeyState(ModifiableHotkey key, bool noKey) + private bool CheckKeyState(ModifiableHotkey key, bool noKey) { if (key.Hotkey == VirtualKey.NO_KEY) return noKey; return _keyState[key.Hotkey] && key.Modifier1.IsActive() && key.Modifier2.IsActive(); } + + private float UpdateWidth() + { + _numButtons = (_config.EnableAutoDesigns, _config is { ShowRevertAdvancedParametersButton: true, UseAdvancedParameters: true }) switch + { + (true, true) => 4, + (false, true) => 3, + (true, false) => 3, + (false, false) => 2, + }; + Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X, ImGui.GetFrameHeight()); + return Size.Value.X; + } } diff --git a/Glamourer/Gui/MainWindow.cs b/Glamourer/Gui/MainWindow.cs index 0ce4147..6f09d04 100644 --- a/Glamourer/Gui/MainWindow.cs +++ b/Glamourer/Gui/MainWindow.cs @@ -105,10 +105,7 @@ public class MainWindow : Window, IDisposable } if (_config.ShowQuickBarInTabs) - { - ImGui.SetCursorPos(new Vector2(ImGui.GetWindowContentRegionMax().X - 10 * ImGui.GetFrameHeight(), yPos - ImGuiHelpers.GlobalScale)); - _quickBar.Draw(); - } + _quickBar.DrawAtEnd(yPos); } private ReadOnlySpan ToLabel(TabType type) diff --git a/Glamourer/Gui/Tabs/SettingsTab.cs b/Glamourer/Gui/Tabs/SettingsTab.cs index 75ee642..edca6b9 100644 --- a/Glamourer/Gui/Tabs/SettingsTab.cs +++ b/Glamourer/Gui/Tabs/SettingsTab.cs @@ -164,6 +164,9 @@ public class SettingsTab( config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v); if (config.UseAdvancedParameters) { + Checkbox("Show Revert Advanced Customizations Button in Quick Design Bar", + "Show a button to revert only advanced customizations on your character or a target in the quick design bar.", + config.ShowRevertAdvancedParametersButton, v => config.ShowRevertAdvancedParametersButton = v); Checkbox("Show Palette+ Import Button", "Show the import button that allows you to import Palette+ palettes onto a design in the Advanced Customization options section for designs.", config.ShowPalettePlusImport, v => config.ShowPalettePlusImport = v); diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs index bb99396..c506389 100644 --- a/Glamourer/State/StateManager.cs +++ b/Glamourer/State/StateManager.cs @@ -309,7 +309,8 @@ public class StateManager( } /// Change the crest of an equipment piece. - public void ChangeCustomizeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, StateChanged.Source source, uint key = 0) + public void ChangeCustomizeParameter(ActorState state, CustomizeParameterFlag flag, CustomizeParameterValue value, + StateChanged.Source source, uint key = 0) { if (!_editor.ChangeParameter(state, flag, value, source, out var old, key)) return; @@ -501,7 +502,25 @@ public class StateManager( Glamourer.Log.Verbose( $"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]"); - _event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors, null); + _event.Invoke(StateChanged.Type.Reset, source, state, actors, null); + } + + public void ResetAdvancedState(ActorState state, StateChanged.Source source, uint key = 0) + { + if (!state.Unlock(key) || !state.ModelData.IsHuman) + return; + + state.ModelData.Parameters = state.BaseData.Parameters; + + foreach (var flag in CustomizeParameterExtensions.AllFlags) + state[flag] = StateChanged.Source.Game; + + var actors = ActorData.Invalid; + if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc) + actors = _applier.ChangeParameters(state, CustomizeParameterExtensions.All, true); + Glamourer.Log.Verbose( + $"Reset advanced customization state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]"); + _event.Invoke(StateChanged.Type.Reset, source, state, actors, null); } public void ResetStateFixed(ActorState state, bool respectManualPalettes, uint key = 0)