From cd7a4c610bf9034d8ef0b99bc3b038d9a1ca0f98 Mon Sep 17 00:00:00 2001 From: Shawrkie Williams Date: Sun, 11 Jan 2026 11:48:54 -0500 Subject: [PATCH] Fixes category nodes going beyond the grid --- AetherBags/Addons/InventoryAddonBase.cs | 29 +++++++++--- .../Nodes/Inventory/InventoryCategoryNode.cs | 47 +++++++++++++++---- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/AetherBags/Addons/InventoryAddonBase.cs b/AetherBags/Addons/InventoryAddonBase.cs index 444e92d..eff8a21 100644 --- a/AetherBags/Addons/InventoryAddonBase.cs +++ b/AetherBags/Addons/InventoryAddonBase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Numerics; -using AetherBags.AddonLifecycles; using AetherBags.Configuration; using AetherBags.Helpers; using AetherBags.Inventory; @@ -43,8 +42,8 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow protected virtual float MaxWindowHeight => 1000; protected const float CategorySpacing = 12; - protected const float ItemSize = 40; - protected const float ItemPadding = 4; + protected const float ItemSize = 42; + protected const float ItemPadding = 5; protected const float FooterHeight = 28f; protected const float FooterTopSpacing = 4f; protected const float SettingsButtonOffset = 48f; @@ -172,7 +171,7 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow string dataFilter = config.SearchMode == SearchMode.Filter ? searchText : string.Empty; var categories = InventoryState.GetCategories(dataFilter); - float maxContentWidth = MaxWindowWidth - (ContentStartPosition.X * 2); + float maxContentWidth = CategoriesNode.Width > 0 ? CategoriesNode.Width : ContentSize.X; int maxItemsPerLine = CalculateOptimalItemsPerLine(maxContentWidth); CategoriesNode.SyncWithListDataByKey( @@ -181,10 +180,11 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow getKeyFromNode: node => node.CategorizedInventory.Key, updateNode: (node, data) => { + node.MaxWidth = maxContentWidth; node.SetCategoryData(data, Math.Min(data.Items.Count, maxItemsPerLine)); node.RefreshNodeVisuals(); }, - createNodeMethod: _ => CreateCategoryNode()); + createNodeMethod: _ => CreateCategoryNode(maxContentWidth)); if (HasPinning) { @@ -254,11 +254,12 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow BackgroundDropTarget.AttachNode(this); } - protected virtual InventoryCategoryNode CreateCategoryNode() + protected virtual InventoryCategoryNode CreateCategoryNode(float? maxWidth = null) { return new InventoryCategoryNode { Size = ContentSize with { Y = 120 }, + MaxWidth = maxWidth, OnRefreshRequested = ManualRefresh, OnDragEnd = () => InventoryOrchestrator.RefreshAll(updateMaps: true), }; @@ -340,6 +341,20 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow CategoriesNode.Position = contentPos; CategoriesNode.Size = new Vector2(contentSize.X, gridH); + + UpdateCategoryMaxWidths(contentSize.X); + } + + private void UpdateCategoryMaxWidths(float maxWidth) + { + foreach (var node in CategoriesNode.Nodes) + { + if (node is InventoryCategoryNode categoryNode && categoryNode.MaxWidth != maxWidth) + { + categoryNode.MaxWidth = maxWidth; + categoryNode.RecalculateSize(); + } + } } protected virtual void AutoSizeWindow() @@ -376,6 +391,8 @@ public abstract unsafe class InventoryAddonBase : NativeAddon, IInventoryWindow CategoriesNode.Position = ContentStartPosition; CategoriesNode.Size = new Vector2(contentWidth, gridBudget); + UpdateCategoryMaxWidths(contentWidth); + CategoriesNode.RecalculateLayout(); float requiredGridHeight = CategoriesNode.GetRequiredHeight(); diff --git a/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs b/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs index afff5fd..e1af79d 100644 --- a/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs +++ b/AetherBags/Nodes/Inventory/InventoryCategoryNode.cs @@ -30,6 +30,7 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase private const float MinWidth = 40; private float? _fixedWidth; + private float? _maxWidth; private int _hoverRefs; private bool _headerSuppressed; private bool _headerExpanded; @@ -40,6 +41,7 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase private int _lastItemCount; private ulong _lastItemsHash; private int _lastItemsPerLine; + private float? _lastMaxWidth; public event Action? HeaderHoverChanged; public Action? OnRefreshRequested { get; set; } @@ -88,6 +90,7 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase { bool categoryChanged = data.Key != _lastCategoryKey; bool itemsPerLineChanged = itemsPerLine != _lastItemsPerLine; + bool maxWidthChanged = _maxWidth != _lastMaxWidth; ulong itemsHash = ComputeItemsHash(CollectionsMarshal.AsSpan(data.Items)); bool itemsChanged = data.Items.Count != _lastItemCount || itemsHash != _lastItemsHash; @@ -96,6 +99,7 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase _lastItemCount = data.Items.Count; _lastItemsHash = itemsHash; _lastItemsPerLine = itemsPerLine; + _lastMaxWidth = _maxWidth; _categorizedInventory = data; @@ -120,7 +124,7 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase _itemGridNode.ItemsPerLine = itemsPerLine; } - if (categoryChanged || itemsChanged || itemsPerLineChanged) + if (categoryChanged || itemsChanged || itemsPerLineChanged || maxWidthChanged) { RecalculateSize(); } @@ -160,6 +164,12 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase } } + public float? MaxWidth + { + get => _maxWidth; + set => _maxWidth = value; + } + public override bool IsPinnedInConfig => CategorizedInventory.Category?.IsPinned ?? false; public void BeginHeaderHover() @@ -224,13 +234,19 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase } } - private void RecalculateSize() + public void RecalculateSize() { int itemCount = CategorizedInventory.Items.Count; + float cellW = _itemGridNode.Nodes.Count > 0 ? _itemGridNode.Nodes[0].Width : FallbackItemSize; + float cellH = _itemGridNode.Nodes.Count > 0 ? _itemGridNode.Nodes[0].Height : FallbackItemSize; + float hPad = _itemGridNode.HorizontalPadding; + float vPad = _itemGridNode.VerticalPadding; + if (itemCount == 0) { float width = _fixedWidth ?? MinWidth; + if (_maxWidth.HasValue) width = Math.Min(width, _maxWidth.Value); Size = new Vector2(width, HeaderHeight); _baseHeaderWidth = width; _itemGridNode.Position = new Vector2(0, HeaderHeight); @@ -240,21 +256,36 @@ public class InventoryCategoryNode : InventoryCategoryNodeBase } int itemsPerLine = Math.Max(1, _itemGridNode.ItemsPerLine); + + float minUsableWidth = cellW; + if (_maxWidth.HasValue && _fixedWidth is null && _maxWidth.Value >= minUsableWidth) + { + int maxColumns = (int)MathF.Floor((_maxWidth.Value + hPad) / (cellW + hPad)); + maxColumns = Math.Max(1, maxColumns); + + float widthNeeded = maxColumns * cellW + (maxColumns - 1) * hPad; + if (widthNeeded > _maxWidth.Value && maxColumns > 1) + maxColumns--; + + itemsPerLine = Math.Min(itemsPerLine, maxColumns); + } + int rows = (itemCount + itemsPerLine - 1) / itemsPerLine; int actualColumns = Math.Min(itemCount, itemsPerLine); - float cellW = _itemGridNode.Nodes.Count > 0 ? _itemGridNode.Nodes[0].Width : FallbackItemSize; - float cellH = _itemGridNode.Nodes.Count > 0 ? _itemGridNode.Nodes[0].Height : FallbackItemSize; - - float hPad = _itemGridNode.HorizontalPadding; - float vPad = _itemGridNode.VerticalPadding; - float calculatedWidth = _fixedWidth ?? Math.Max(MinWidth, actualColumns * cellW + (actualColumns - 1) * hPad); + + if (_maxWidth.HasValue && _fixedWidth is null && _maxWidth.Value >= minUsableWidth) + calculatedWidth = Math.Min(calculatedWidth, _maxWidth.Value); + float height = HeaderHeight + rows * cellH + (rows - 1) * vPad; Size = new Vector2(calculatedWidth, height); _itemGridNode.Position = new Vector2(0, HeaderHeight); _itemGridNode.Size = new Vector2(calculatedWidth, height - HeaderHeight); + + if (_itemGridNode.ItemsPerLine != itemsPerLine) + _itemGridNode.ItemsPerLine = itemsPerLine; _baseHeaderWidth = calculatedWidth; ApplyHeaderVisualStateAndSize();