diff --git a/AetherBags/Addons/AddonInventoryWindow.cs b/AetherBags/Addons/AddonInventoryWindow.cs index 51492f1..432a24d 100644 --- a/AetherBags/Addons/AddonInventoryWindow.cs +++ b/AetherBags/Addons/AddonInventoryWindow.cs @@ -19,6 +19,7 @@ public class AddonInventoryWindow : NativeAddon { private WrappingGridNode _categoriesNode = null!; private TextInputWithHintNode _searchInputNode = null!; + private InventoryFooterNode _footerNode = null!; // Window constraints private const float MinWindowWidth = 300; @@ -50,18 +51,26 @@ public class AddonInventoryWindow : NativeAddon Size = size, OnInputReceived = _ => RefreshCategories(false), }; - _searchInputNode.AttachNode(this); + _footerNode = new InventoryFooterNode + { + Size = ContentSize with { Y = 28 }, + SlotAmountText = InventoryState.GetEmptyItemSlotsString() + }; + _footerNode.AttachNode(this); + Services.AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, "Inventory", OnInventoryUpdate); addon->SubscribeAtkArrayData(1, (int)NumberArrayType.Inventory); RefreshCategories(); + base.OnSetup(addon); } protected override unsafe void OnUpdate(AtkUnitBase* addon) { - + // Haven't needed it yet but just in case. + base.OnUpdate(addon); } private void OnInventoryUpdate(AddonEvent type, AddonArgs args) @@ -70,6 +79,7 @@ public class AddonInventoryWindow : NativeAddon } protected override unsafe void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData) { + base.OnRequestedUpdate(addon, numberArrayData, stringArrayData); RefreshCategories(); } @@ -133,11 +143,13 @@ public class AddonInventoryWindow : NativeAddon { SetWindowSize(width, height); _categoriesNode.Size = ContentSize; + _footerNode.Size = ContentSize with { Y = 28 }; _categoriesNode.RecalculateLayout(); } protected override unsafe void OnFinalize(AtkUnitBase* addon) { + base.OnFinalize(addon); Services.AddonLifecycle.UnregisterListener(OnInventoryUpdate); addon->UnsubscribeAtkArrayData(1, (int)NumberArrayType.Inventory); } diff --git a/AetherBags/Inventory/CurrencyInfo.cs b/AetherBags/Inventory/CurrencyInfo.cs new file mode 100644 index 0000000..2a2c76e --- /dev/null +++ b/AetherBags/Inventory/CurrencyInfo.cs @@ -0,0 +1,8 @@ +namespace AetherBags.Currency; + +public class CurrencyInfo +{ + public required int Amount { get; set; } + public required uint ItemId { get; set; } + public required uint IconId { get; set; } +} \ No newline at end of file diff --git a/AetherBags/Inventory/InventoryState.cs b/AetherBags/Inventory/InventoryState.cs index f6ff412..f158d9c 100644 --- a/AetherBags/Inventory/InventoryState.cs +++ b/AetherBags/Inventory/InventoryState.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using AetherBags.Currency; using Dalamud.Game.Inventory; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.UI.Agent; @@ -108,6 +109,19 @@ public static unsafe class InventoryState }; } + private static uint GetEmptyItemSlots() => InventoryManager.Instance()->GetEmptySlotsInBag(); + private static uint GetUsedItemSlots() => 140 - GetEmptyItemSlots(); + public static string GetEmptyItemSlotsString() => $"{GetUsedItemSlots()}/140"; + + public static CurrencyInfo GetCurrencyInfo(uint itemId) + { + return new CurrencyInfo + { + Amount = InventoryManager.Instance()->GetInventoryItemCount(1), + ItemId = itemId, + IconId = Services.DataManager.GetExcelSheet().GetRow(itemId).Icon + }; + } } \ No newline at end of file diff --git a/AetherBags/Nodes/CurrencyNode.cs b/AetherBags/Nodes/CurrencyNode.cs new file mode 100644 index 0000000..94ad96d --- /dev/null +++ b/AetherBags/Nodes/CurrencyNode.cs @@ -0,0 +1,47 @@ +using System.Numerics; +using AetherBags.Currency; +using FFXIVClientStructs.FFXIV.Component.GUI; +using KamiToolKit.Classes; +using KamiToolKit.Nodes; +using Lumina.Excel.Sheets; + +namespace AetherBags.Nodes; + +public class CurrencyNode : SimpleComponentNode +{ + private IconImageNode iconImageNode; + private TextNode countNode; + + public CurrencyNode() + { + iconImageNode = new IconImageNode + { + FitTexture = true + }; + iconImageNode.AttachNode(this); + + + countNode = new TextNode + { + TextFlags = TextFlags.Emboss, + TextColor = ColorHelper.GetColor(8), + TextOutlineColor = ColorHelper.GetColor(7), + FontSize = 14, + }; + countNode.AttachNode(this); + } + + public required CurrencyInfo Currency { + get; + set { + field = value; + iconImageNode.IconId = value.IconId; + countNode.String = value.Amount.ToString("N0"); + + countNode.Size = new Vector2(120.0f, 28.0f); + countNode.Origin = countNode.Size / 2.0f; + countNode.Position = new Vector2(26.0f, 0.0f); + iconImageNode.Size = new Vector2(24f); + } + } +} \ No newline at end of file diff --git a/AetherBags/Nodes/InventoryFooterNode.cs b/AetherBags/Nodes/InventoryFooterNode.cs new file mode 100644 index 0000000..eaaf7ec --- /dev/null +++ b/AetherBags/Nodes/InventoryFooterNode.cs @@ -0,0 +1,51 @@ +using System.Numerics; +using AetherBags.Currency; +using AetherBags.Inventory; +using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Component.GUI; +using KamiToolKit.Classes; +using KamiToolKit.Nodes; +using Lumina.Excel.Sheets; + +namespace AetherBags.Nodes; + +public sealed class InventoryFooterNode : SimpleComponentNode +{ + private readonly TextNode _slotAmountTextNode; + private readonly CurrencyNode _currencyNode; + + public InventoryFooterNode() + { + _slotAmountTextNode = new TextNode + { + Position = new Vector2(Size.X - 10, 0), + Size = new Vector2(82, 20), + AlignmentType = AlignmentType.Right, + FontType = FontType.MiedingerMed, + TextFlags = TextFlags.Glare, + TextColor = ColorHelper.GetColor(50), + TextOutlineColor = ColorHelper.GetColor(32) // Could also be Color 65 + }; + _slotAmountTextNode.AttachNode(this); + + _currencyNode = new CurrencyNode + { + Size = new Vector2(120, 28), + Currency = InventoryState.GetCurrencyInfo(1) + }; + _currencyNode.AttachNode(this); + } + + public string SlotAmountText + { + get => _slotAmountTextNode.String; + set => _slotAmountTextNode.String = value; + } + + protected override void OnSizeChanged() { + base.OnSizeChanged(); + + _slotAmountTextNode.Position = new Vector2(Size.X - _slotAmountTextNode.Size.X - 10, 0); + _currencyNode.Position = new Vector2(0, 0); + } +} \ No newline at end of file