From 59d6f50c1863497771c530f813b824e822c43462 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Tue, 10 Oct 2023 13:26:25 +0200 Subject: [PATCH] (2.x) Add icons --- ARControl/AutoRetainerControlPlugin.cs | 8 +++- ARControl/Configuration.cs | 13 ++++++- ARControl/GameData/Venture.cs | 2 + ARControl/IconCache.cs | 53 ++++++++++++++++++++++++++ ARControl/Windows/ConfigWindow.cs | 52 +++++++++++++++++++------ 5 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 ARControl/IconCache.cs diff --git a/ARControl/AutoRetainerControlPlugin.cs b/ARControl/AutoRetainerControlPlugin.cs index dac1bd0..3b141df 100644 --- a/ARControl/AutoRetainerControlPlugin.cs +++ b/ARControl/AutoRetainerControlPlugin.cs @@ -27,12 +27,14 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin private readonly Configuration _configuration; private readonly GameCache _gameCache; + private readonly IconCache _iconCache; private readonly VentureResolver _ventureResolver; private readonly ConfigWindow _configWindow; private readonly AutoRetainerApi _autoRetainerApi; public AutoRetainerControlPlugin(DalamudPluginInterface pluginInterface, IDataManager dataManager, - IClientState clientState, IChatGui chatGui, ICommandManager commandManager, IPluginLog pluginLog) + IClientState clientState, IChatGui chatGui, ICommandManager commandManager, ITextureProvider textureProvider, + IPluginLog pluginLog) { _pluginInterface = pluginInterface; _clientState = clientState; @@ -43,9 +45,10 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin _configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration { Version = 2 }; _gameCache = new GameCache(dataManager); + _iconCache = new IconCache(textureProvider); _ventureResolver = new VentureResolver(_gameCache, _pluginLog); _configWindow = - new ConfigWindow(_pluginInterface, _configuration, _gameCache, _clientState, _commandManager, _pluginLog) + new ConfigWindow(_pluginInterface, _configuration, _gameCache, _clientState, _commandManager, _iconCache, _pluginLog) { IsOpen = true }; _windowSystem.AddWindow(_configWindow); @@ -184,6 +187,7 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin _pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle; _pluginInterface.UiBuilder.Draw -= _windowSystem.Draw; + _iconCache.Dispose(); _autoRetainerApi.Dispose(); ECommonsMain.Dispose(); } diff --git a/ARControl/Configuration.cs b/ARControl/Configuration.cs index 77bdfdf..9105f7b 100644 --- a/ARControl/Configuration.cs +++ b/ARControl/Configuration.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Dalamud.Configuration; +using Dalamud.Game.Text; using Dalamud.Interface; namespace ARControl; @@ -20,6 +21,17 @@ internal sealed class Configuration : IPluginConfiguration public required ListType Type { get; set; } = ListType.CollectOneTime; public required ListPriority Priority { get; set; } = ListPriority.InOrder; public List Items { get; set; } = new(); + + public string GetIcon() + { + return Type switch + { + ListType.CollectOneTime => SeIconChar.BoxedNumber1.ToIconString(), + ListType.KeepStocked when Priority == ListPriority.Balanced => SeIconChar.EurekaLevel.ToIconString(), + ListType.KeepStocked => SeIconChar.Circle.ToIconString(), + _ => string.Empty + }; + } } public enum ListType @@ -44,7 +56,6 @@ internal sealed class Configuration : IPluginConfiguration { public required Guid Id { get; set; } public required string Name { get; set; } - public required FontAwesomeIcon Icon { get; set; } public List ItemListIds { get; set; } = new(); } diff --git a/ARControl/GameData/Venture.cs b/ARControl/GameData/Venture.cs index 433ef57..5037cbb 100644 --- a/ARControl/GameData/Venture.cs +++ b/ARControl/GameData/Venture.cs @@ -14,6 +14,7 @@ internal sealed class Venture var taskDetails = dataManager.GetExcelSheet()!.GetRow(retainerTask.Task)!; var taskParameters = retainerTask.RetainerTaskParameter.Value!; ItemId = taskDetails.Item.Row; + IconId = taskDetails.Item.Value!.Icon; Name = taskDetails.Item.Value!.Name.ToString(); Level = retainerTask.RetainerLevel; ItemLevelCombat = retainerTask.RequiredItemLevel; @@ -76,6 +77,7 @@ internal sealed class Venture } public uint ItemId { get; } + public ushort IconId { get; } public string Name { get; } public byte Level { get; } public ushort ItemLevelCombat { get; } diff --git a/ARControl/IconCache.cs b/ARControl/IconCache.cs new file mode 100644 index 0000000..ccc9c07 --- /dev/null +++ b/ARControl/IconCache.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Dalamud.Interface.Internal; +using Dalamud.Plugin.Services; + +namespace ARControl; + +internal sealed class IconCache : IDisposable +{ + private readonly ITextureProvider _textureProvider; + private readonly Dictionary _textureWraps = new(); + + public IconCache(ITextureProvider textureProvider) + { + _textureProvider = textureProvider; + } + + public IDalamudTextureWrap? GetIcon(uint iconId) + { + if (_textureWraps.TryGetValue(iconId, out TextureContainer? container)) + return container.Texture; + + var iconTex = _textureProvider.GetIcon(iconId); + if (iconTex != null) + { + if (iconTex.ImGuiHandle != nint.Zero) + { + _textureWraps[iconId] = new TextureContainer { Texture = iconTex }; + return iconTex; + } + + iconTex.Dispose(); + } + + _textureWraps[iconId] = new TextureContainer { Texture = null }; + return null; + } + + public void Dispose() + { + foreach (TextureContainer container in _textureWraps.Values) + container.Dispose(); + + _textureWraps.Clear(); + } + + private sealed class TextureContainer : IDisposable + { + public required IDalamudTextureWrap? Texture { get; init; } + + public void Dispose() => Texture?.Dispose(); + } +} diff --git a/ARControl/Windows/ConfigWindow.cs b/ARControl/Windows/ConfigWindow.cs index 52da773..109cfa7 100644 --- a/ARControl/Windows/ConfigWindow.cs +++ b/ARControl/Windows/ConfigWindow.cs @@ -7,6 +7,7 @@ using Dalamud.Game.Text; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Components; +using Dalamud.Interface.Internal; using Dalamud.Interface.Windowing; using Dalamud.Plugin; using Dalamud.Plugin.Services; @@ -18,6 +19,7 @@ namespace ARControl.Windows; internal sealed class ConfigWindow : Window { + // TODO This should also allow retainers under max level private const byte MaxLevel = 90; private static readonly Vector4 ColorGreen = ImGuiColors.HealerGreen; @@ -31,6 +33,7 @@ internal sealed class ConfigWindow : Window private readonly GameCache _gameCache; private readonly IClientState _clientState; private readonly ICommandManager _commandManager; + private readonly IconCache _iconCache; private readonly IPluginLog _pluginLog; private readonly Dictionary _currentEditPopups = new(); @@ -51,6 +54,7 @@ internal sealed class ConfigWindow : Window GameCache gameCache, IClientState clientState, ICommandManager commandManager, + IconCache iconCache, IPluginLog pluginLog) : base("ARC###ARControlConfig") { @@ -59,6 +63,7 @@ internal sealed class ConfigWindow : Window _gameCache = gameCache; _clientState = clientState; _commandManager = commandManager; + _iconCache = iconCache; _pluginLog = pluginLog; SizeConstraints = new() @@ -80,7 +85,7 @@ internal sealed class ConfigWindow : Window } } - private unsafe void DrawVentureLists() + private void DrawVentureLists() { if (ImGui.BeginTabItem("Venture Lists")) { @@ -102,7 +107,10 @@ internal sealed class ConfigWindow : Window DrawVentureListEditorPopup(list, ref listToDelete); ImGui.SameLine(); - if (ImGui.CollapsingHeader($"{list.Name} {(list.Type == Configuration.ListType.CollectOneTime ? SeIconChar.BoxedNumber1.ToIconChar() : SeIconChar.Circle.ToIconChar())}")) + + string label = $"{list.Name} {list.GetIcon()}"; + + if (ImGui.CollapsingHeader(label)) { ImGui.Indent(30); DrawVentureListItemSelection(list); @@ -257,10 +265,10 @@ internal sealed class ConfigWindow : Window private void DrawVentureListItemSelection(Configuration.ItemList list) { ImGuiEx.SetNextItemFullWidth(); - if (ImGui.BeginCombo($"##VentureSelection{list.Id}", "Add Item...")) + if (ImGui.BeginCombo($"##VentureSelection{list.Id}", "Add Venture...", ImGuiComboFlags.HeightLarge)) { ImGuiEx.SetNextItemFullWidth(); - ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256); + ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256, ImGuiInputTextFlags.AutoSelectAll); foreach (var ventures in _gameCache.Ventures .Where(x => x.Name.ToLower().Contains(_searchString.ToLower())) @@ -270,6 +278,14 @@ internal sealed class ConfigWindow : Window .GroupBy(x => x.ItemId)) { var venture = ventures.First(); + IDalamudTextureWrap? icon = _iconCache.GetIcon(venture.IconId); + if (icon != null) + { + ImGui.Image(icon.ImGuiHandle, new Vector2(23, 23)); + ImGui.SameLine(); + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3); + } + if (ImGui.Selectable( $"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})##SelectVenture{venture.RowId}")) { @@ -278,7 +294,6 @@ internal sealed class ConfigWindow : Window ItemId = venture.ItemId, RemainingQuantity = 0, }); - _searchString = string.Empty; Save(); } } @@ -286,7 +301,7 @@ internal sealed class ConfigWindow : Window ImGui.EndCombo(); } - ImGui.Separator(); + ImGui.Spacing(); Configuration.QueuedItem? itemToRemove = null; Configuration.QueuedItem? itemToAdd = null; @@ -299,6 +314,13 @@ internal sealed class ConfigWindow : Window var ventures = _gameCache.Ventures.Where(x => x.ItemId == item.ItemId).ToList(); var venture = ventures.First(); + IDalamudTextureWrap? icon = _iconCache.GetIcon(venture.IconId); + if (icon != null) + { + ImGui.Image(icon.ImGuiHandle, new Vector2(23, 23)); + ImGui.SameLine(0, 3); + } + ImGui.SetNextItemWidth(130); int quantity = item.RemainingQuantity; if (ImGui.InputInt($"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})", @@ -349,6 +371,7 @@ internal sealed class ConfigWindow : Window if (list.Items.Count > 0 && list.Type == Configuration.ListType.CollectOneTime) { + ImGui.Spacing(); ImGui.BeginDisabled(list.Items.All(x => x.RemainingQuantity > 0)); if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Remove all finished items")) { @@ -356,8 +379,8 @@ internal sealed class ConfigWindow : Window Save(); } ImGui.EndDisabled(); - ImGui.Spacing(); } + ImGui.Spacing(); } private void DrawCharacters() @@ -479,8 +502,14 @@ internal sealed class ConfigWindow : Window ImGui.BeginDisabled(retainer.Level < MaxLevel); bool managed = retainer.Managed && retainer.Level == MaxLevel; - ImGui.Text(_gameCache.Jobs[retainer.Job]); - ImGui.SameLine(); + + IDalamudTextureWrap? icon = _iconCache.GetIcon(62000 + retainer.Job); + if (icon != null) + { + ImGui.Image(icon.ImGuiHandle, new Vector2(23, 23)); + ImGui.SameLine(); + } + if (ImGui.Checkbox($"{retainer.Name}###Retainer{retainer.Name}{retainer.DisplayOrder}", ref managed)) { @@ -643,7 +672,6 @@ internal sealed class ConfigWindow : Window { Id = Guid.NewGuid(), Name = _newGroup.Name, - Icon = FontAwesomeIcon.None, ItemListIds = new(), }); @@ -868,8 +896,8 @@ internal sealed class ConfigWindow : Window var list = itemLists[listIndex].List; ImGui.Indent(30); ImGui.Text(list.Type == Configuration.ListType.CollectOneTime - ? $"{SeIconChar.BoxedNumber1.ToIconString()} Items on this list will be collected once." - : $"{SeIconChar.Circle.ToIconString()} Items on this list will be kept in stock on each character."); + ? $"{list.GetIcon()} Items on this list will be collected once." + : $"{list.GetIcon()} Items on this list will be kept in stock on each character."); ImGui.Spacing(); foreach (var item in list.Items) {