diff --git a/Glamourer/Gui/Equipment/EquipmentDrawer.cs b/Glamourer/Gui/Equipment/EquipmentDrawer.cs index 75ca0ab..3b33f8a 100644 --- a/Glamourer/Gui/Equipment/EquipmentDrawer.cs +++ b/Glamourer/Gui/Equipment/EquipmentDrawer.cs @@ -14,7 +14,6 @@ using Glamourer.Unlocks; using ImGuiNET; using OtterGui; using OtterGui.Raii; -using OtterGui.Widgets; using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; @@ -26,7 +25,7 @@ public class EquipmentDrawer private const float DefaultWidth = 280; private readonly ItemManager _items; - private readonly FilterComboColors _stainCombo; + private readonly GlamourerColorCombo _stainCombo; private readonly StainData _stainData; private readonly ItemCombo[] _itemCombo; private readonly Dictionary _weaponCombo; @@ -39,17 +38,15 @@ public class EquipmentDrawer private float _requiredComboWidth; public EquipmentDrawer(FavoriteManager favorites, IDataManager gameData, ItemManager items, CodeService codes, TextureService textures, - Configuration config, - GPoseService gPose) + Configuration config, GPoseService gPose) { - _items = items; - _codes = codes; - _textures = textures; - _config = config; - _gPose = gPose; - _stainData = items.Stains; - _stainCombo = new FilterComboColors(DefaultWidth - 20, - _stainData.Data.Prepend(new KeyValuePair(0, ("None", 0, false))), Glamourer.Log); + _items = items; + _codes = codes; + _textures = textures; + _config = config; + _gPose = gPose; + _stainData = items.Stains; + _stainCombo = new GlamourerColorCombo(DefaultWidth - 20, _stainData, favorites); _itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log, favorites)).ToArray(); _weaponCombo = new Dictionary(FullEquipTypeExtensions.WeaponTypes.Count * 2); foreach (var type in Enum.GetValues()) diff --git a/Glamourer/Gui/Equipment/GlamourerColorCombo.cs b/Glamourer/Gui/Equipment/GlamourerColorCombo.cs new file mode 100644 index 0000000..5cdb6d4 --- /dev/null +++ b/Glamourer/Gui/Equipment/GlamourerColorCombo.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Dalamud.Interface; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using Glamourer.Unlocks; +using ImGuiNET; +using OtterGui.Widgets; +using Penumbra.GameData.Data; +using Penumbra.GameData.Structs; + +namespace Glamourer.Gui.Equipment; + +public sealed class GlamourerColorCombo : FilterComboColors +{ + private readonly FavoriteManager _favorites; + + public GlamourerColorCombo(float comboWidth, StainData stains, FavoriteManager favorites) + : base(comboWidth, CreateFunc(stains, favorites), Glamourer.Log) + => _favorites = favorites; + + protected override bool DrawSelectable(int globalIdx, bool selected) + { + using (var space = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGuiHelpers.ScaledVector2(4, 0))) + { + if (globalIdx == 0) + { + using var font = ImRaii.PushFont(UiBuilder.IconFont); + ImGui.Dummy(ImGui.CalcTextSize(FontAwesomeIcon.Star.ToIconString())); + } + else + { + UiHelpers.DrawFavoriteStar(_favorites, (StainId)Items[globalIdx].Key); + } + + ImGui.SameLine(); + } + + var buttonWidth = ImGui.GetContentRegionAvail().X; + var totalWidth = ImGui.GetContentRegionMax().X; + using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(buttonWidth / 2 / totalWidth, 0.5f)); + + return base.DrawSelectable(globalIdx, selected); + } + + private static Func>> CreateFunc(StainData stains, + FavoriteManager favorites) + => () => stains.Data.Select(kvp => (kvp, favorites.Contains((StainId)kvp.Key))).OrderBy(p => !p.Item2).Select(p => p.kvp) + .Prepend(new KeyValuePair(0, ("None", 0, false))).ToList(); +} diff --git a/Glamourer/Gui/UiHelpers.cs b/Glamourer/Gui/UiHelpers.cs index 3bb4c3a..8299e43 100644 --- a/Glamourer/Gui/UiHelpers.cs +++ b/Glamourer/Gui/UiHelpers.cs @@ -143,4 +143,27 @@ public static class UiHelpers return false; } + + public static bool DrawFavoriteStar(FavoriteManager favorites, StainId stain) + { + var favorite = favorites.Contains(stain); + var hovering = ImGui.IsMouseHoveringRect(ImGui.GetCursorScreenPos(), + ImGui.GetCursorScreenPos() + new Vector2(ImGui.GetFrameHeight())); + + using var font = ImRaii.PushFont(UiBuilder.IconFont); + using var c = ImRaii.PushColor(ImGuiCol.Text, + hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value()); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString()); + if (ImGui.IsItemClicked()) + { + if (favorite) + favorites.Remove(stain); + else + favorites.TryAdd(stain); + return true; + } + + return false; + } } diff --git a/Glamourer/Unlocks/FavoriteManager.cs b/Glamourer/Unlocks/FavoriteManager.cs index 4cd98c8..a96ae35 100644 --- a/Glamourer/Unlocks/FavoriteManager.cs +++ b/Glamourer/Unlocks/FavoriteManager.cs @@ -5,7 +5,6 @@ using System.Linq; using Dalamud.Interface.Internal.Notifications; using Glamourer.Services; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using OtterGui.Classes; using Penumbra.GameData.Structs; @@ -13,8 +12,10 @@ namespace Glamourer.Unlocks; public class FavoriteManager : ISavable { - private readonly SaveService _saveService; - private readonly HashSet _favorites = new(); + private const int CurrentVersion = 1; + private readonly SaveService _saveService; + private readonly HashSet _favorites = new(); + private readonly HashSet _favoriteColors = new(); public FavoriteManager(SaveService saveService) { @@ -30,9 +31,23 @@ public class FavoriteManager : ISavable try { - var text = File.ReadAllText(file); - var array = JsonConvert.DeserializeObject(text) ?? Array.Empty(); - _favorites.UnionWith(array.Select(i => (ItemId)i)); + var text = File.ReadAllText(file); + if (text.StartsWith('[')) + { + LoadV0(text); + } + else + { + var load = JsonConvert.DeserializeObject(text); + switch (load.Version) + { + case 1: + _favorites.UnionWith(load.FavoriteItems.Select(i => (ItemId)i)); + _favoriteColors.UnionWith(load.FavoriteColors.Select(i => (StainId)i)); + break; + default: throw new Exception($"Unknown Version {load.Version}"); + } + } } catch (Exception ex) { @@ -40,6 +55,13 @@ public class FavoriteManager : ISavable } } + private void LoadV0(string text) + { + var array = JsonConvert.DeserializeObject(text) ?? Array.Empty(); + _favorites.UnionWith(array.Select(i => (ItemId)i)); + Save(); + } + public string ToFilename(FilenameService fileNames) => fileNames.FavoriteFile; @@ -52,10 +74,20 @@ public class FavoriteManager : ISavable { Formatting = Formatting.Indented, }; + j.WriteStartObject(); + j.WritePropertyName(nameof(LoadStruct.Version)); + j.WriteValue(CurrentVersion); + j.WritePropertyName(nameof(LoadStruct.FavoriteItems)); j.WriteStartArray(); foreach (var item in _favorites) j.WriteValue(item.Id); j.WriteEndArray(); + j.WritePropertyName(nameof(LoadStruct.FavoriteColors)); + j.WriteStartArray(); + foreach (var stain in _favoriteColors) + j.WriteValue(stain.Id); + j.WriteEndArray(); + j.WriteEndObject(); } public bool TryAdd(EquipItem item) @@ -70,6 +102,18 @@ public class FavoriteManager : ISavable return true; } + public bool TryAdd(Stain stain) + => TryAdd(stain.RowIndex); + + public bool TryAdd(StainId stain) + { + if (stain.Id == 0 || !_favoriteColors.Add(stain)) + return false; + + Save(); + return true; + } + public bool Remove(EquipItem item) => Remove(item.ItemId); @@ -82,15 +126,37 @@ public class FavoriteManager : ISavable return true; } - public IEnumerator GetEnumerator() - => _favorites.GetEnumerator(); + public bool Remove(Stain stain) + => Remove(stain.RowIndex); - public int Count - => _favorites.Count; + public bool Remove(StainId stain) + { + if (!_favoriteColors.Remove(stain)) + return false; + + Save(); + return true; + } public bool Contains(EquipItem item) => _favorites.Contains(item.ItemId); + public bool Contains(Stain stain) + => _favoriteColors.Contains(stain.RowIndex); + public bool Contains(ItemId item) => _favorites.Contains(item); + + public bool Contains(StainId stain) + => _favoriteColors.Contains(stain); + + private struct LoadStruct + { + public int Version = CurrentVersion; + public uint[] FavoriteItems = Array.Empty(); + public byte[] FavoriteColors = Array.Empty(); + + public LoadStruct() + { } + } } diff --git a/OtterGui b/OtterGui index a4f9b28..b09bbcc 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit a4f9b285c82f84ff0841695c0787dbba93afc59b +Subproject commit b09bbcc276363bc994d90b641871e6280898b6e5