From 1fefe7366c07afc43ec91328123b58f45aa4e749 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 5 Feb 2024 15:21:29 +0100 Subject: [PATCH] MouseWheels are pretty great. --- Glamourer/Designs/Design.cs | 4 + Glamourer/Designs/DesignManager.cs | 12 +++ Glamourer/Events/DesignChanged.cs | 3 + .../CustomizationDrawer.Color.cs | 5 + .../Customization/CustomizationDrawer.Icon.cs | 12 ++- .../CustomizationDrawer.Simple.cs | 102 ++++++++++++------ Glamourer/Gui/DesignCombo.cs | 100 ++++++++++------- Glamourer/Gui/DesignQuickBar.cs | 7 +- .../Gui/Equipment/GlamourerColorCombo.cs | 5 +- Glamourer/Gui/Equipment/ItemCombo.cs | 2 +- Glamourer/Gui/Equipment/WeaponCombo.cs | 2 +- .../Gui/Tabs/AutomationTab/HumanNpcCombo.cs | 2 +- Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs | 2 +- .../Gui/Tabs/DesignTab/DesignColorCombo.cs | 9 +- .../Gui/Tabs/DesignTab/DesignDetailTab.cs | 15 ++- .../Gui/Tabs/DesignTab/DesignLinkDrawer.cs | 2 +- Glamourer/Gui/Tabs/DesignTab/ModCombo.cs | 2 +- .../Gui/Tabs/DesignTab/MultiDesignPanel.cs | 43 +++++++- Glamourer/Gui/Tabs/NpcCombo.cs | 2 +- Glamourer/Services/ServiceManager.cs | 3 +- OtterGui | 2 +- Penumbra.GameData | 2 +- 22 files changed, 250 insertions(+), 88 deletions(-) diff --git a/Glamourer/Designs/Design.cs b/Glamourer/Designs/Design.cs index 89dd62f..20d85e7 100644 --- a/Glamourer/Designs/Design.cs +++ b/Glamourer/Designs/Design.cs @@ -26,6 +26,7 @@ public sealed class Design : DesignBase, ISavable { Tags = [.. other.Tags]; Description = other.Description; + QuickDesign = other.QuickDesign; AssociatedMods = new SortedList(other.AssociatedMods); } @@ -39,6 +40,7 @@ public sealed class Design : DesignBase, ISavable public string Description { get; internal set; } = string.Empty; public string[] Tags { get; internal set; } = []; public int Index { get; internal set; } + public bool QuickDesign { get; internal set; } = true; public string Color { get; internal set; } = string.Empty; public SortedList AssociatedMods { get; private set; } = []; public LinkContainer Links { get; private set; } = []; @@ -64,6 +66,7 @@ public sealed class Design : DesignBase, ISavable ["Name"] = Name.Text, ["Description"] = Description, ["Color"] = Color, + ["QuickDesign"] = QuickDesign, ["Tags"] = JArray.FromObject(Tags), ["WriteProtected"] = WriteProtected(), ["Equipment"] = SerializeEquipment(), @@ -124,6 +127,7 @@ public sealed class Design : DesignBase, ISavable Description = json["Description"]?.ToObject() ?? string.Empty, Tags = ParseTags(json), LastEdit = json["LastEdit"]?.ToObject() ?? creationDate, + QuickDesign = json["QuickDesign"]?.ToObject() ?? true, }; if (design.LastEdit < creationDate) design.LastEdit = creationDate; diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs index c3d8664..da6ed90 100644 --- a/Glamourer/Designs/DesignManager.cs +++ b/Glamourer/Designs/DesignManager.cs @@ -284,6 +284,18 @@ public sealed class DesignManager : DesignEditor DesignChanged.Invoke(DesignChanged.Type.WriteProtection, design, value); } + /// Set the quick design bar display status of a design. + public void SetQuickDesign(Design design, bool value) + { + if (value == design.QuickDesign) + return; + + design.QuickDesign = value; + SaveService.QueueSave(design); + Glamourer.Log.Debug($"Set design {design.Identifier} to {(!value ? "no longer be " : string.Empty)} displayed in the quick design bar."); + DesignChanged.Invoke(DesignChanged.Type.QuickDesignBar, design, value); + } + #endregion #region Edit Application Rules diff --git a/Glamourer/Events/DesignChanged.cs b/Glamourer/Events/DesignChanged.cs index f3ebb5f..81d56e4 100644 --- a/Glamourer/Events/DesignChanged.cs +++ b/Glamourer/Events/DesignChanged.cs @@ -92,6 +92,9 @@ public sealed class DesignChanged() /// An existing design changed its write protection status. Data is the new value [bool]. WriteProtection, + /// An existing design changed its display status for the quick design bar. Data is the new value [bool]. + QuickDesignBar, + /// An existing design changed one of the meta flags. Data is the flag, whether it was about their applying and the new value [(MetaFlag, bool, bool)]. Other, } diff --git a/Glamourer/Gui/Customization/CustomizationDrawer.Color.cs b/Glamourer/Gui/Customization/CustomizationDrawer.Color.cs index f3753ae..ff6e0c5 100644 --- a/Glamourer/Gui/Customization/CustomizationDrawer.Color.cs +++ b/Glamourer/Gui/Customization/CustomizationDrawer.Color.cs @@ -23,6 +23,11 @@ public partial class CustomizationDrawer { if (ImGui.ColorButton($"{_customize[index].Value}##color", color, ImGuiColorEditFlags.None, _framedIconSize)) ImGui.OpenPopup(ColorPickerPopupName); + else if (current >= 0 && CaptureMouseWheel(ref current, 0, _currentCount)) + { + var data = _set.Data(_currentIndex, current, _customize.Face); + UpdateValue(data.Value); + } } var npc = false; diff --git a/Glamourer/Gui/Customization/CustomizationDrawer.Icon.cs b/Glamourer/Gui/Customization/CustomizationDrawer.Icon.cs index 4e0f3de..c0c45d2 100644 --- a/Glamourer/Gui/Customization/CustomizationDrawer.Icon.cs +++ b/Glamourer/Gui/Customization/CustomizationDrawer.Icon.cs @@ -18,8 +18,9 @@ public partial class CustomizationDrawer using var bigGroup = ImRaii.Group(); var label = _currentOption; - var current = _set.DataByValue(index, _currentByte, out var custom, _customize.Face); - var npc = false; + var current = _set.DataByValue(index, _currentByte, out var custom, _customize.Face); + var originalCurrent = current; + var npc = false; if (current < 0) { label = $"{_currentOption} (NPC)"; @@ -32,7 +33,14 @@ public partial class CustomizationDrawer using (_ = ImRaii.Disabled(_locked || _currentIndex is CustomizeIndex.Face && _lockedRedraw)) { if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize)) + { ImGui.OpenPopup(IconSelectorPopup); + } + else if (originalCurrent >= 0 && CaptureMouseWheel(ref current, 0, _currentCount)) + { + var data = _set.Data(_currentIndex, current, _customize.Face); + UpdateValue(data.Value); + } } ImGuiUtil.HoverIconTooltip(icon, _iconSize); diff --git a/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs b/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs index 02d4def..3a8e021 100644 --- a/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs +++ b/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs @@ -1,6 +1,7 @@ using ImGuiNET; using OtterGui; using OtterGui.Raii; +using OtterGuiInternal; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; @@ -34,7 +35,8 @@ public partial class CustomizationDrawer { var tmp = (int)_currentByte.Value; ImGui.SetNextItemWidth(_comboSelectorSize); - if (ImGui.SliderInt("##slider", ref tmp, 0, _currentCount - 1, "%i", ImGuiSliderFlags.AlwaysClamp)) + if (ImGui.SliderInt("##slider", ref tmp, 0, _currentCount - 1, "%i", ImGuiSliderFlags.AlwaysClamp) + || CaptureMouseWheel(ref tmp, 0, _currentCount - 1)) UpdateValue((CustomizeValue)tmp); } @@ -42,11 +44,10 @@ public partial class CustomizationDrawer { var tmp = (int)_currentByte.Value; ImGui.SetNextItemWidth(_inputIntSize); + var cap = ImGui.GetIO().KeyCtrl ? byte.MaxValue : _currentCount - 1; if (ImGui.InputInt("##text", ref tmp, 1, 1)) { - var newValue = (CustomizeValue)(ImGui.GetIO().KeyCtrl - ? Math.Clamp(tmp, 0, byte.MaxValue) - : Math.Clamp(tmp, 0, _currentCount - 1)); + var newValue = (CustomizeValue)Math.Clamp(tmp, 0, cap); UpdateValue(newValue); } @@ -73,6 +74,10 @@ public partial class CustomizationDrawer else if (ImGui.GetIO().KeyCtrl) UpdateValue((CustomizeValue)value); } + else + { + CheckWheel(); + } if (!_withApply) ImGuiUtil.HoverTooltip("Hold Control to force updates with invalid/unknown options at your own risk."); @@ -81,15 +86,29 @@ public partial class CustomizationDrawer if (ImGuiUtil.DrawDisabledButton("-", new Vector2(ImGui.GetFrameHeight()), "Select the previous available option in order.", currentIndex <= 0)) UpdateValue(_set.Data(_currentIndex, currentIndex - 1, _customize.Face).Value); + else + CheckWheel(); ImGui.SameLine(); if (ImGuiUtil.DrawDisabledButton("+", new Vector2(ImGui.GetFrameHeight()), "Select the next available option in order.", currentIndex >= _currentCount - 1 || npc)) UpdateValue(_set.Data(_currentIndex, currentIndex + 1, _customize.Face).Value); + else + CheckWheel(); + return; + + void CheckWheel() + { + if (currentIndex < 0 || !CaptureMouseWheel(ref currentIndex, 0, _currentCount)) + return; + + var data = _set.Data(_currentIndex, currentIndex, _customize.Face); + UpdateValue(data.Value); + } } private void DrawListSelector(CustomizeIndex index, bool indexedBy1) { - using var id = SetId(index); + using var id = SetId(index); using var bigGroup = ImRaii.Group(); using (_ = ImRaii.Disabled(_locked)) @@ -122,29 +141,31 @@ public partial class CustomizationDrawer private void ListCombo0() { ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale); - var current = _currentByte.Value; - using var combo = ImRaii.Combo("##combo", $"{_currentOption} #{current + 1}"); - - if (!combo) - return; - - for (var i = 0; i < _currentCount; ++i) + var current = (int)_currentByte.Value; + using (var combo = ImRaii.Combo("##combo", $"{_currentOption} #{current + 1}")) { - if (ImGui.Selectable($"{_currentOption} #{i + 1}##combo", i == current)) - UpdateValue((CustomizeValue)i); + if (combo) + + for (var i = 0; i < _currentCount; ++i) + { + if (ImGui.Selectable($"{_currentOption} #{i + 1}##combo", i == current)) + UpdateValue((CustomizeValue)i); + } } + + if (CaptureMouseWheel(ref current, 0, _currentCount)) + UpdateValue((CustomizeValue)current); } private void ListInputInt0() { var tmp = _currentByte.Value + 1; ImGui.SetNextItemWidth(_inputIntSize); + var cap = ImGui.GetIO().KeyCtrl ? byte.MaxValue + 1 : _currentCount; if (ImGui.InputInt("##text", ref tmp, 1, 1)) { - var newValue = (CustomizeValue)(ImGui.GetIO().KeyCtrl - ? Math.Clamp(tmp, 1, byte.MaxValue + 1) - : Math.Clamp(tmp, 1, _currentCount)); - UpdateValue(newValue - 1); + var newValue = Math.Clamp(tmp, 1, cap); + UpdateValue((CustomizeValue)(newValue - 1)); } ImGuiUtil.HoverTooltip($"Input Range: [1, {_currentCount}]\n" @@ -154,28 +175,29 @@ public partial class CustomizationDrawer private void ListCombo1() { ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale); - var current = _currentByte.Value; - using var combo = ImRaii.Combo("##combo", $"{_currentOption} #{current}"); - - if (!combo) - return; - - for (var i = 1; i <= _currentCount; ++i) + var current = (int)_currentByte.Value; + using (var combo = ImRaii.Combo("##combo", $"{_currentOption} #{current}")) { - if (ImGui.Selectable($"{_currentOption} #{i}##combo", i == current)) - UpdateValue((CustomizeValue)i); + if (combo) + for (var i = 1; i <= _currentCount; ++i) + { + if (ImGui.Selectable($"{_currentOption} #{i}##combo", i == current)) + UpdateValue((CustomizeValue)i); + } } + + if (CaptureMouseWheel(ref current, 1, _currentCount)) + UpdateValue((CustomizeValue)current); } private void ListInputInt1() { var tmp = (int)_currentByte.Value; ImGui.SetNextItemWidth(_inputIntSize); + var (offset, cap) = ImGui.GetIO().KeyCtrl ? (0, byte.MaxValue) : (1, _currentCount); if (ImGui.InputInt("##text", ref tmp, 1, 1)) { - var newValue = (CustomizeValue)(ImGui.GetIO().KeyCtrl - ? Math.Clamp(tmp, 0, byte.MaxValue) - : Math.Clamp(tmp, 1, _currentCount)); + var newValue = (CustomizeValue)Math.Clamp(tmp, offset, cap); UpdateValue(newValue); } @@ -183,6 +205,26 @@ public partial class CustomizationDrawer + "Hold Control to force updates with invalid/unknown options at your own risk."); } + private static bool CaptureMouseWheel(ref int value, int offset, int cap) + { + if (!ImGui.IsItemHovered()) + return false; + + ImGuiInternal.ItemSetUsingMouseWheel(); + + var mw = (int)ImGui.GetIO().MouseWheel; + if (mw == 0) + return false; + + value -= offset; + value = mw switch + { + < 0 => offset + (value + cap + mw) % cap, + _ => offset + (value + mw) % cap, + }; + return true; + } + // Draw a customize checkbox. private void DrawCheckbox(CustomizeIndex idx) { diff --git a/Glamourer/Gui/DesignCombo.cs b/Glamourer/Gui/DesignCombo.cs index e255c17..f5e3272 100644 --- a/Glamourer/Gui/DesignCombo.cs +++ b/Glamourer/Gui/DesignCombo.cs @@ -1,7 +1,6 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Glamourer.Automation; -using Glamourer.GameData; using Glamourer.Designs; using Glamourer.Events; using Glamourer.Services; @@ -25,7 +24,7 @@ public abstract class DesignComboBase : FilterComboCache>, protected DesignComboBase(Func>> generator, Logger log, DesignChanged designChanged, TabSelected tabSelected, EphemeralConfig config, DesignColors designColors) - : base(generator, log) + : base(generator, MouseWheelType.Unmodified, log) { _designChanged = designChanged; TabSelected = tabSelected; @@ -38,7 +37,10 @@ public abstract class DesignComboBase : FilterComboCache>, => _config.IncognitoMode; void IDisposable.Dispose() - => _designChanged.Unsubscribe(OnDesignChange); + { + _designChanged.Unsubscribe(OnDesignChange); + GC.SuppressFinalize(this); + } protected override bool DrawSelectable(int globalIdx, bool selected) { @@ -118,63 +120,87 @@ public abstract class DesignComboBase : FilterComboCache>, { case DesignChanged.Type.Created: case DesignChanged.Type.Renamed: - Cleanup(); - break; + case DesignChanged.Type.ChangedColor: case DesignChanged.Type.Deleted: - Cleanup(); - if (CurrentSelection?.Item1 == design) + case DesignChanged.Type.QuickDesignBar: + var priorState = IsInitialized; + if (priorState) + Cleanup(); + CurrentSelectionIdx = Items.IndexOf(s => ReferenceEquals(s.Item1, CurrentSelection?.Item1)); + if (CurrentSelectionIdx >= 0) { - CurrentSelectionIdx = Items.Count > 0 ? 0 : -1; - CurrentSelection = Items[CurrentSelectionIdx]; + CurrentSelection = Items[CurrentSelectionIdx]; + } + else if (Items.Count > 0) + { + CurrentSelectionIdx = 0; + CurrentSelection = Items[0]; + } + else + { + CurrentSelection = null; } + if (!priorState) + Cleanup(); break; } } } -public sealed class DesignCombo : DesignComboBase +public abstract class DesignCombo : DesignComboBase { - private readonly DesignManager _manager; - - public DesignCombo(DesignManager designs, DesignFileSystem fileSystem, Logger log, DesignChanged designChanged, TabSelected tabSelected, - EphemeralConfig config, DesignColors designColors) - : base(() => designs.Designs - .Select(d => new Tuple(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty)) - .OrderBy(d => d.Item2) - .ToList(), log, designChanged, tabSelected, config, designColors) + protected DesignCombo(Logger log, DesignChanged designChanged, TabSelected tabSelected, + EphemeralConfig config, DesignColors designColors, Func>> generator) + : base(generator, log, designChanged, tabSelected, config, designColors) { - _manager = designs; - if (designs.Designs.Count == 0) + if (Items.Count == 0) return; CurrentSelection = Items[0]; CurrentSelectionIdx = 0; + base.Cleanup(); } public Design? Design => CurrentSelection?.Item1; public void Draw(float width) - { - Draw(Design, (Incognito ? Design?.Incognito : Design?.Name.Text) ?? string.Empty, width); - if (ImGui.IsItemHovered() && _manager.Designs.Count > 1) - { - var mouseWheel = -(int)ImGui.GetIO().MouseWheel % _manager.Designs.Count; - CurrentSelectionIdx = mouseWheel switch - { - < 0 when CurrentSelectionIdx < 0 => _manager.Designs.Count - 1 + mouseWheel, - < 0 => (CurrentSelectionIdx + _manager.Designs.Count + mouseWheel) % _manager.Designs.Count, - > 0 when CurrentSelectionIdx < 0 => mouseWheel, - > 0 => (CurrentSelectionIdx + mouseWheel) % _manager.Designs.Count, - _ => CurrentSelectionIdx, - }; - CurrentSelection = Items[CurrentSelectionIdx]; - } - } + => Draw(Design, (Incognito ? Design?.Incognito : Design?.Name.Text) ?? string.Empty, width); } -public sealed class RevertDesignCombo : DesignComboBase, IDisposable +public sealed class QuickDesignCombo( + DesignManager designs, + DesignFileSystem fileSystem, + Logger log, + DesignChanged designChanged, + TabSelected tabSelected, + EphemeralConfig config, + DesignColors designColors) + : DesignCombo(log, designChanged, tabSelected, config, designColors, () => + [ + .. designs.Designs + .Where(d => d.QuickDesign) + .Select(d => new Tuple(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty)) + .OrderBy(d => d.Item2), + ]); + +public sealed class LinkDesignCombo( + DesignManager designs, + DesignFileSystem fileSystem, + Logger log, + DesignChanged designChanged, + TabSelected tabSelected, + EphemeralConfig config, + DesignColors designColors) + : DesignCombo(log, designChanged, tabSelected, config, designColors, () => + [ + .. designs.Designs + .Select(d => new Tuple(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty)) + .OrderBy(d => d.Item2), + ]); + +public sealed class RevertDesignCombo : DesignComboBase { public const int RevertDesignIndex = -1228; public readonly Design RevertDesign; diff --git a/Glamourer/Gui/DesignQuickBar.cs b/Glamourer/Gui/DesignQuickBar.cs index 78e813e..1ad28b0 100644 --- a/Glamourer/Gui/DesignQuickBar.cs +++ b/Glamourer/Gui/DesignQuickBar.cs @@ -24,7 +24,7 @@ public sealed class DesignQuickBar : Window, IDisposable : ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoFocusOnAppearing; private readonly Configuration _config; - private readonly DesignCombo _designCombo; + private readonly QuickDesignCombo _designCombo; private readonly StateManager _stateManager; private readonly AutoDesignApplier _autoDesignApplier; private readonly ObjectManager _objects; @@ -34,7 +34,7 @@ public sealed class DesignQuickBar : Window, IDisposable private DateTime _keyboardToggle = DateTime.UnixEpoch; private int _numButtons; - public DesignQuickBar(Configuration config, DesignCombo designCombo, StateManager stateManager, IKeyState keyState, + public DesignQuickBar(Configuration config, QuickDesignCombo designCombo, StateManager stateManager, IKeyState keyState, ObjectManager objects, AutoDesignApplier autoDesignApplier) : base("Glamourer Quick Bar", ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoDocking) { @@ -299,7 +299,8 @@ public sealed class DesignQuickBar : Window, IDisposable (true, false) => 3, (false, false) => 2, }; - Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X, ImGui.GetFrameHeight()); + Size = new Vector2((7 + _numButtons) * ImGui.GetFrameHeight() + _numButtons * ImGui.GetStyle().ItemInnerSpacing.X, + ImGui.GetFrameHeight()); return Size.Value.X; } } diff --git a/Glamourer/Gui/Equipment/GlamourerColorCombo.cs b/Glamourer/Gui/Equipment/GlamourerColorCombo.cs index 39d63dc..3a791d0 100644 --- a/Glamourer/Gui/Equipment/GlamourerColorCombo.cs +++ b/Glamourer/Gui/Equipment/GlamourerColorCombo.cs @@ -10,7 +10,7 @@ using Penumbra.GameData.Structs; namespace Glamourer.Gui.Equipment; public sealed class GlamourerColorCombo(float _comboWidth, DictStain _stains, FavoriteManager _favorites) - : FilterComboColors(_comboWidth, CreateFunc(_stains, _favorites), Glamourer.Log) + : FilterComboColors(_comboWidth, MouseWheelType.Unmodified, CreateFunc(_stains, _favorites), Glamourer.Log) { protected override bool DrawSelectable(int globalIdx, bool selected) { @@ -36,6 +36,9 @@ public sealed class GlamourerColorCombo(float _comboWidth, DictStain _stains, Fa return base.DrawSelectable(globalIdx, selected); } + public override bool Draw(string label, uint color, string name, bool found, bool gloss, float previewWidth) + => base.Draw(label, color, name, found, gloss, previewWidth); + private static Func>> CreateFunc(DictStain stains, FavoriteManager favorites) => () => stains.Select(kvp => (kvp, favorites.Contains(kvp.Key))).OrderBy(p => !p.Item2).Select(p => p.kvp) diff --git a/Glamourer/Gui/Equipment/ItemCombo.cs b/Glamourer/Gui/Equipment/ItemCombo.cs index d9fd12a..a6f22b5 100644 --- a/Glamourer/Gui/Equipment/ItemCombo.cs +++ b/Glamourer/Gui/Equipment/ItemCombo.cs @@ -24,7 +24,7 @@ public sealed class ItemCombo : FilterComboCache public Variant CustomVariant { get; private set; } public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot, Logger log, FavoriteManager favorites) - : base(() => GetItems(favorites, items, slot), log) + : base(() => GetItems(favorites, items, slot), MouseWheelType.Unmodified, log) { _favorites = favorites; Label = GetLabel(gameData, slot); diff --git a/Glamourer/Gui/Equipment/WeaponCombo.cs b/Glamourer/Gui/Equipment/WeaponCombo.cs index 32f383b..b6c3218 100644 --- a/Glamourer/Gui/Equipment/WeaponCombo.cs +++ b/Glamourer/Gui/Equipment/WeaponCombo.cs @@ -17,7 +17,7 @@ public sealed class WeaponCombo : FilterComboCache private float _innerWidth; public WeaponCombo(ItemManager items, FullEquipType type, Logger log) - : base(() => GetWeapons(items, type), log) + : base(() => GetWeapons(items, type), MouseWheelType.Unmodified, log) { Label = GetLabel(type); SearchByParts = true; diff --git a/Glamourer/Gui/Tabs/AutomationTab/HumanNpcCombo.cs b/Glamourer/Gui/Tabs/AutomationTab/HumanNpcCombo.cs index 49feae9..530e04a 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/HumanNpcCombo.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/HumanNpcCombo.cs @@ -16,7 +16,7 @@ public sealed class HumanNpcCombo( DictBNpc bNpcs, HumanModelList humans, Logger log) - : FilterComboCache<(string Name, ObjectKind Kind, uint[] Ids)>(() => CreateList(modelCharaDict, bNpcNames, bNpcs, humans), log) + : FilterComboCache<(string Name, ObjectKind Kind, uint[] Ids)>(() => CreateList(modelCharaDict, bNpcNames, bNpcs, humans), MouseWheelType.None, log) { protected override string ToString((string Name, ObjectKind Kind, uint[] Ids) obj) => obj.Name; diff --git a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs index 0387d58..2f4e1d8 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs @@ -429,7 +429,7 @@ public class SetPanel( } private sealed class JobGroupCombo(AutoDesignManager manager, JobService jobs, Logger log) - : FilterComboCache(() => jobs.JobGroups.Values.ToList(), log) + : FilterComboCache(() => jobs.JobGroups.Values.ToList(), MouseWheelType.None, log) { public void Draw(AutoDesignSet set, AutoDesign design, int autoDesignIndex) { diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignColorCombo.cs b/Glamourer/Gui/Tabs/DesignTab/DesignColorCombo.cs index d00fea8..72d717c 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignColorCombo.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignColorCombo.cs @@ -10,8 +10,15 @@ public sealed class DesignColorCombo(DesignColors _designColors, bool _skipAutom FilterComboCache(_skipAutomatic ? _designColors.Keys.OrderBy(k => k) : _designColors.Keys.OrderBy(k => k).Prepend(DesignColors.AutomaticName), - Glamourer.Log) + MouseWheelType.Shift, Glamourer.Log) { + protected override void OnMouseWheel(string preview, ref int current, int steps) + { + if (CurrentSelectionIdx < 0) + CurrentSelectionIdx = Items.IndexOf(preview); + base.OnMouseWheel(preview, ref current, steps); + } + protected override bool DrawSelectable(int globalIdx, bool selected) { var isAutomatic = !_skipAutomatic && globalIdx == 0; diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignDetailTab.cs b/Glamourer/Gui/Tabs/DesignTab/DesignDetailTab.cs index ecbf0e7..e56ec00 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignDetailTab.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignDetailTab.cs @@ -125,10 +125,23 @@ public class DesignDetailTab Glamourer.Messager.NotificationMessage(ex, ex.Message, "Could not rename or move design", NotificationType.Error); } + ImGuiUtil.DrawFrameColumn("Quick Design Bar"); + ImGui.TableNextColumn(); + if (ImGui.RadioButton("Display##qdb", _selector.Selected.QuickDesign)) + _manager.SetQuickDesign(_selector.Selected!, true); + var hovered = ImGui.IsItemHovered(); + ImGui.SameLine(); + if (ImGui.RadioButton("Hide##qdb", !_selector.Selected.QuickDesign)) + _manager.SetQuickDesign(_selector.Selected!, false); + if (hovered || ImGui.IsItemHovered()) + ImGui.SetTooltip("Display or hide this design in your quick design bar."); + ImGuiUtil.DrawFrameColumn("Color"); var colorName = _selector.Selected!.Color.Length == 0 ? DesignColors.AutomaticName : _selector.Selected!.Color; ImGui.TableNextColumn(); - if (_colorCombo.Draw("##colorCombo", colorName, "Associate a color with this design. Right-Click to revert to automatic coloring.", + if (_colorCombo.Draw("##colorCombo", colorName, "Associate a color with this design.\n" + + "Right-Click to revert to automatic coloring.\n" + + "Hold Control and scroll the mousewheel to scroll.", width.X - ImGui.GetStyle().ItemSpacing.X - ImGui.GetFrameHeight(), ImGui.GetTextLineHeight()) && _colorCombo.CurrentSelection != null) { diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignLinkDrawer.cs b/Glamourer/Gui/Tabs/DesignTab/DesignLinkDrawer.cs index f45f936..7b996e8 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignLinkDrawer.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignLinkDrawer.cs @@ -10,7 +10,7 @@ using OtterGui.Services; namespace Glamourer.Gui.Tabs.DesignTab; -public class DesignLinkDrawer(DesignLinkManager _linkManager, DesignFileSystemSelector _selector, DesignCombo _combo) : IUiService +public class DesignLinkDrawer(DesignLinkManager _linkManager, DesignFileSystemSelector _selector, LinkDesignCombo _combo) : IUiService { private int _dragDropIndex = -1; private LinkOrder _dragDropOrder = LinkOrder.None; diff --git a/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs b/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs index 4cd899f..53501b0 100644 --- a/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs +++ b/Glamourer/Gui/Tabs/DesignTab/ModCombo.cs @@ -11,7 +11,7 @@ namespace Glamourer.Gui.Tabs.DesignTab; public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)> { public ModCombo(PenumbraService penumbra, Logger log) - : base(penumbra.GetMods, log) + : base(penumbra.GetMods, MouseWheelType.None, log) { SearchByParts = false; } diff --git a/Glamourer/Gui/Tabs/DesignTab/MultiDesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/MultiDesignPanel.cs index 474c2f4..6e5b1b1 100644 --- a/Glamourer/Gui/Tabs/DesignTab/MultiDesignPanel.cs +++ b/Glamourer/Gui/Tabs/DesignTab/MultiDesignPanel.cs @@ -3,6 +3,7 @@ using Dalamud.Interface.Utility; using Glamourer.Designs; using ImGuiNET; using OtterGui; +using OtterGui.Filesystem; using OtterGui.Raii; namespace Glamourer.Gui.Tabs.DesignTab; @@ -21,6 +22,7 @@ public class MultiDesignPanel(DesignFileSystemSelector _selector, DesignManager DrawDesignList(); var offset = DrawMultiTagger(width); DrawMultiColor(width, offset); + DrawMultiQuickDesignBar(offset); } private void DrawDesignList() @@ -35,6 +37,8 @@ public class MultiDesignPanel(DesignFileSystemSelector _selector, DesignManager var sizeMods = availableSizePercent * 35; var sizeFolders = availableSizePercent * 65; + _numQuickDesignEnabled = 0; + _numDesigns = 0; using (var table = ImRaii.Table("mods", 3, ImGuiTableFlags.RowBg)) { if (!table) @@ -61,15 +65,24 @@ public class MultiDesignPanel(DesignFileSystemSelector _selector, DesignManager ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(fullName); + + if (path is not DesignFileSystem.Leaf l2) + continue; + + ++_numDesigns; + if (l2.Value.QuickDesign) + ++_numQuickDesignEnabled; } } ImGui.Separator(); } - private string _tag = string.Empty; - private readonly List _addDesigns = []; - private readonly List<(Design, int)> _removeDesigns = []; + private string _tag = string.Empty; + private int _numQuickDesignEnabled; + private int _numDesigns; + private readonly List _addDesigns = []; + private readonly List<(Design, int)> _removeDesigns = []; private float DrawMultiTagger(Vector2 width) { @@ -110,6 +123,30 @@ public class MultiDesignPanel(DesignFileSystemSelector _selector, DesignManager return offset; } + private void DrawMultiQuickDesignBar(float offset) + { + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted("Multi QDB:"); + ImGui.SameLine(offset, ImGui.GetStyle().ItemSpacing.X); + var buttonWidth = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X) / 2, 0); + var diff = _numDesigns - _numQuickDesignEnabled; + var tt = diff == 0 + ? $"All {_numDesigns} selected designs are already displayed in the quick design bar." + : $"Display all {_numDesigns} selected designs in the quick design bar. Changes {diff} designs."; + if (ImGuiUtil.DrawDisabledButton("Display Selected Designs in QDB", buttonWidth, tt, diff == 0)) + foreach(var design in _selector.SelectedPaths.OfType()) + _editor.SetQuickDesign(design.Value, true); + + ImGui.SameLine(); + tt = _numQuickDesignEnabled == 0 + ? $"All {_numDesigns} selected designs are already hidden in the quick design bar." + : $"Hide all {_numDesigns} selected designs in the quick design bar. Changes {_numQuickDesignEnabled} designs."; + if (ImGuiUtil.DrawDisabledButton("Hide Selected Designs in QDB", buttonWidth, tt, _numQuickDesignEnabled == 0)) + foreach (var design in _selector.SelectedPaths.OfType()) + _editor.SetQuickDesign(design.Value, false); + ImGui.Separator(); + } + private void DrawMultiColor(Vector2 width, float offset) { ImGui.AlignTextToFramePadding(); diff --git a/Glamourer/Gui/Tabs/NpcCombo.cs b/Glamourer/Gui/Tabs/NpcCombo.cs index 4b1274c..86eb766 100644 --- a/Glamourer/Gui/Tabs/NpcCombo.cs +++ b/Glamourer/Gui/Tabs/NpcCombo.cs @@ -4,7 +4,7 @@ using OtterGui.Widgets; namespace Glamourer.Gui.Tabs; public class NpcCombo(NpcCustomizeSet npcCustomizeSet) - : FilterComboCache(npcCustomizeSet, Glamourer.Log) + : FilterComboCache(npcCustomizeSet, MouseWheelType.None, Glamourer.Log) { protected override string ToString(NpcData obj) => obj.Name; diff --git a/Glamourer/Services/ServiceManager.cs b/Glamourer/Services/ServiceManager.cs index dd06e3a..a5cc0ee 100644 --- a/Glamourer/Services/ServiceManager.cs +++ b/Glamourer/Services/ServiceManager.cs @@ -146,7 +146,8 @@ public static class ServiceManagerA .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/OtterGui b/OtterGui index 04eb0b5..2d8a03e 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 04eb0b5ed3930e9cb87ad00dffa9c8be90b58bb3 +Subproject commit 2d8a03eebd80e19c6936a28ab2e3a8c164cc17f3 diff --git a/Penumbra.GameData b/Penumbra.GameData index 260ac69..fb18c80 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 260ac69cd6f17050eaf9b7e0b5ce9a8843edfee4 +Subproject commit fb18c80551203a1cf6cd01ec2b0850fbc8e44240