WIP pinning and hoisting
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.Extensions;
|
|
||||||
using AetherBags.Inventory;
|
using AetherBags.Inventory;
|
||||||
using AetherBags.Nodes;
|
|
||||||
using AetherBags.Nodes.Input;
|
using AetherBags.Nodes.Input;
|
||||||
using AetherBags.Nodes.Inventory;
|
using AetherBags.Nodes.Inventory;
|
||||||
using AetherBags.Nodes.Layout;
|
using AetherBags.Nodes.Layout;
|
||||||
using Dalamud.Game.Addon.Lifecycle;
|
using Dalamud.Game.Addon.Lifecycle;
|
||||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||||
using Dalamud.Game.Gui;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
using KamiToolKit;
|
using KamiToolKit;
|
||||||
using KamiToolKit.Classes;
|
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
|
|
||||||
namespace AetherBags.Addons;
|
namespace AetherBags.Addons;
|
||||||
@@ -21,6 +17,7 @@ namespace AetherBags.Addons;
|
|||||||
public class AddonInventoryWindow : NativeAddon
|
public class AddonInventoryWindow : NativeAddon
|
||||||
{
|
{
|
||||||
private readonly InventoryCategoryHoverCoordinator _hoverCoordinator = new();
|
private readonly InventoryCategoryHoverCoordinator _hoverCoordinator = new();
|
||||||
|
private readonly InventoryCategoryPinCoordinator _pinCoordinator = new();
|
||||||
private readonly HashSet<InventoryCategoryNode> _hoverSubscribed = new();
|
private readonly HashSet<InventoryCategoryNode> _hoverSubscribed = new();
|
||||||
|
|
||||||
private InventoryNotificationNode _notificationNode = null!;
|
private InventoryNotificationNode _notificationNode = null!;
|
||||||
@@ -135,6 +132,20 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
RefreshCategoriesCore(true);
|
RefreshCategoriesCore(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateLootedCategory(IReadOnlyList<LootedItemInfo> lootedItemInfos)
|
||||||
|
{
|
||||||
|
if (!Services.ClientState.IsLoggedIn) return;
|
||||||
|
_recentlyLootedCategoryNode?.CategorizedInventory.Items.AddRange(
|
||||||
|
lootedItemInfos.Select(x => new ItemInfo
|
||||||
|
{
|
||||||
|
ItemCount = x.Quantity,
|
||||||
|
Key = uint.MaxValue - 1,
|
||||||
|
Item = x.Item,
|
||||||
|
})
|
||||||
|
.ToList());
|
||||||
|
RefreshCategoriesCore(true);
|
||||||
|
}
|
||||||
|
|
||||||
public void ManualCurrencyRefresh()
|
public void ManualCurrencyRefresh()
|
||||||
{
|
{
|
||||||
if (!Services.ClientState.IsLoggedIn) return;
|
if (!Services.ClientState.IsLoggedIn) return;
|
||||||
@@ -182,6 +193,10 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
Size = ContentSize with { Y = 120 },
|
Size = ContentSize with { Y = 120 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bool pinsChanged = _pinCoordinator.ApplyPinnedStates(_categoriesNode);
|
||||||
|
if (pinsChanged)
|
||||||
|
_hoverCoordinator.ResetAll(_categoriesNode);
|
||||||
|
|
||||||
WireHoverHandlers();
|
WireHoverHandlers();
|
||||||
|
|
||||||
if (autosize) AutoSizeWindow();
|
if (autosize) AutoSizeWindow();
|
||||||
@@ -192,6 +207,7 @@ public class AddonInventoryWindow : NativeAddon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void WireHoverHandlers()
|
private void WireHoverHandlers()
|
||||||
{
|
{
|
||||||
var nodes = _categoriesNode.Nodes;
|
var nodes = _categoriesNode.Nodes;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using AetherBags.Configuration;
|
using AetherBags.Configuration;
|
||||||
using AetherBags.Inventory;
|
using AetherBags.Inventory;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
using KamiToolKit.Premade;
|
using KamiToolKit.Premade;
|
||||||
using SeStringBuilder = Lumina.Text.SeStringBuilder;
|
|
||||||
|
|
||||||
namespace AetherBags.Addons;
|
namespace AetherBags.Addons;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Author>Zeffuro</Author>
|
<Author>Zeffuro, Pie Lover</Author>
|
||||||
<Name>AetherBags</Name>
|
<Name>AetherBags</Name>
|
||||||
<InternalName>AetherBags</InternalName>
|
<InternalName>AetherBags</InternalName>
|
||||||
<Punchline>Never think too hard about your bags again!</Punchline>
|
<Punchline>Never think too hard about your bags again!</Punchline>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class CategorySettings
|
|||||||
public class UserCategoryDefinition
|
public class UserCategoryDefinition
|
||||||
{
|
{
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
|
public bool Pinned { get; set; } = false;
|
||||||
public string Id { get; set; } = Guid.NewGuid().ToString("N");
|
public string Id { get; set; } = Guid.NewGuid().ToString("N");
|
||||||
public string Name { get; set; } = "New Category";
|
public string Name { get; set; } = "New Category";
|
||||||
public string Description { get; set; } = string.Empty;
|
public string Description { get; set; } = string.Empty;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using KamiToolKit.Classes;
|
using KamiToolKit.Classes;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
|
|
||||||
namespace AetherBags.Configuration;
|
namespace AetherBags.Configuration;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
using System.Numerics;
|
|
||||||
using KamiToolKit.Classes;
|
|
||||||
|
|
||||||
namespace AetherBags.Configuration;
|
namespace AetherBags.Configuration;
|
||||||
|
|
||||||
public class GeneralSettings
|
public class GeneralSettings
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
using System.Numerics;
|
|
||||||
using KamiToolKit.Classes;
|
|
||||||
|
|
||||||
namespace AetherBags.Configuration;
|
namespace AetherBags.Configuration;
|
||||||
|
|
||||||
public class SystemConfiguration
|
public class SystemConfiguration
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using AetherBags.Inventory;
|
using AetherBags.Inventory;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace AetherBags.Extensions;
|
namespace AetherBags.Extensions;
|
||||||
|
|
||||||
public static class LoggerExtensions
|
public static class LoggerExtensions
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Linq;
|
|
||||||
using AetherBags.Configuration;
|
using AetherBags.Configuration;
|
||||||
using AetherBags.Helpers.Import;
|
using AetherBags.Helpers.Import;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Game.ClientState.Keys;
|
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
|
|
||||||
namespace AetherBags.Helpers;
|
namespace AetherBags.Helpers;
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using AetherBags. Extensions;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
using FFXIVClientStructs.FFXIV.Component. GUI;
|
|
||||||
using ValueType = FFXIVClientStructs. FFXIV. Component.GUI.ValueType;
|
|
||||||
|
|
||||||
namespace AetherBags. Helpers;
|
namespace AetherBags. Helpers;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public static class CategoryBucketManager
|
|||||||
Name = category.Name,
|
Name = category.Name,
|
||||||
Description = category.Description,
|
Description = category.Description,
|
||||||
Color = category.Color,
|
Color = category.Color,
|
||||||
|
IsPinned = category.Pinned,
|
||||||
},
|
},
|
||||||
Items = new List<ItemInfo>(capacity: 16),
|
Items = new List<ItemInfo>(capacity: 16),
|
||||||
FilteredItems = new List<ItemInfo>(capacity: 16),
|
FilteredItems = new List<ItemInfo>(capacity: 16),
|
||||||
@@ -86,6 +87,7 @@ public static class CategoryBucketManager
|
|||||||
bucket.Category.Name = category.Name;
|
bucket.Category.Name = category.Name;
|
||||||
bucket.Category.Description = category.Description;
|
bucket.Category.Description = category.Description;
|
||||||
bucket.Category.Color = category.Color;
|
bucket.Category.Color = category.Color;
|
||||||
|
bucket.Category.IsPinned = category.Pinned;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var itemKvp in itemInfoByKey)
|
foreach (var itemKvp in itemInfoByKey)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace AetherBags.Inventory;
|
|||||||
public class CategoryInfo
|
public class CategoryInfo
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
public Vector4 Color { get; set; } = ColorHelper.GetColor(50);
|
public Vector4 Color { get; set; } = ColorHelper.GetColor(2);
|
||||||
public string Description { get; set; } = string.Empty;
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public bool IsPinned { get; set; } = false;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Lumina.Excel;
|
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
using Lumina.Text.ReadOnly;
|
using Lumina.Text.ReadOnly;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using AetherBags.Configuration;
|
using AetherBags.Configuration;
|
||||||
|
using AetherBags.Currency;
|
||||||
using Dalamud.Game.Inventory;
|
using Dalamud.Game.Inventory;
|
||||||
|
using Dalamud.Game.Inventory.InventoryEventArgTypes;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AetherBags.Currency;
|
|
||||||
using CurrencyManager = FFXIVClientStructs.FFXIV.Client.Game.CurrencyManager;
|
|
||||||
|
|
||||||
namespace AetherBags.Inventory;
|
namespace AetherBags.Inventory;
|
||||||
|
|
||||||
@@ -21,6 +21,9 @@ public static unsafe class InventoryState
|
|||||||
private static readonly List<UserCategoryDefinition> UserCategoriesSortedScratch = new(capacity: 64);
|
private static readonly List<UserCategoryDefinition> UserCategoriesSortedScratch = new(capacity: 64);
|
||||||
private static readonly List<ulong> RemoveKeysScratch = new(capacity: 256);
|
private static readonly List<ulong> RemoveKeysScratch = new(capacity: 256);
|
||||||
private static readonly HashSet<ulong> ClaimedKeys = new(capacity: 512);
|
private static readonly HashSet<ulong> ClaimedKeys = new(capacity: 512);
|
||||||
|
private static readonly List<LootedItemInfo>? LootedItems = new(capacity: 512);
|
||||||
|
|
||||||
|
public static bool TrackLootedItems = false;
|
||||||
|
|
||||||
public static bool Contains(this IReadOnlyCollection<InventoryType> inventoryTypes, GameInventoryType type)
|
public static bool Contains(this IReadOnlyCollection<InventoryType> inventoryTypes, GameInventoryType type)
|
||||||
=> inventoryTypes.Contains((InventoryType)type);
|
=> inventoryTypes.Contains((InventoryType)type);
|
||||||
@@ -135,6 +138,38 @@ public static unsafe class InventoryState
|
|||||||
public static InventoryContainer* GetInventoryContainer(InventoryType inventoryType)
|
public static InventoryContainer* GetInventoryContainer(InventoryType inventoryType)
|
||||||
=> InventoryScanner.GetInventoryContainer(inventoryType);
|
=> InventoryScanner.GetInventoryContainer(inventoryType);
|
||||||
|
|
||||||
|
internal static void OnRawItemAdded(IReadOnlyCollection<InventoryEventArgs> events)
|
||||||
|
{
|
||||||
|
if (!TrackLootedItems) return;
|
||||||
|
|
||||||
|
bool updateRequested = false;
|
||||||
|
|
||||||
|
foreach (var eventData in events)
|
||||||
|
{
|
||||||
|
if (!StandardInventories.Contains(eventData.Item.ContainerType)) continue;
|
||||||
|
|
||||||
|
if (!Services.ClientState.IsLoggedIn) return;
|
||||||
|
if (eventData is not (InventoryItemAddedArgs or InventoryItemChangedArgs)) return;
|
||||||
|
if (eventData is InventoryItemChangedArgs changedArgs && changedArgs.OldItemState.Quantity >= changedArgs.Item.Quantity) return;
|
||||||
|
|
||||||
|
var inventoryItem = (InventoryItem*)eventData.Item.Address;
|
||||||
|
var changeAmount = eventData is InventoryItemChangedArgs changed ? changed.Item.Quantity - changed.OldItemState.Quantity : eventData.Item.Quantity;
|
||||||
|
|
||||||
|
LootedItems?.Add(new LootedItemInfo(
|
||||||
|
LootedItems.Count,
|
||||||
|
*inventoryItem,
|
||||||
|
changeAmount)
|
||||||
|
);
|
||||||
|
|
||||||
|
updateRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateRequested)
|
||||||
|
{
|
||||||
|
System.AddonInventoryWindow?.UpdateLootedCategory(LootedItems ?? []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void ClearAll()
|
private static void ClearAll()
|
||||||
{
|
{
|
||||||
AggByKey.Clear();
|
AggByKey.Clear();
|
||||||
@@ -152,5 +187,6 @@ public static unsafe class InventoryState
|
|||||||
FilteredCategories.Clear();
|
FilteredCategories.Clear();
|
||||||
RemoveKeysScratch.Clear();
|
RemoveKeysScratch.Clear();
|
||||||
ClaimedKeys.Clear();
|
ClaimedKeys.Clear();
|
||||||
|
LootedItems?.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
using AetherBags.Extensions;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using Lumina.Excel;
|
using Lumina.Excel;
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
|
||||||
|
|
||||||
namespace AetherBags.Inventory;
|
namespace AetherBags.Inventory;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
|
|
||||||
|
namespace AetherBags.Inventory;
|
||||||
|
|
||||||
|
public record LootedItemInfo(int Index, InventoryItem Item, int Quantity);
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using AetherBags.Configuration;
|
using AetherBags.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace AetherBags.Inventory;
|
namespace AetherBags.Inventory;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Game.Addon.Events.EventDataTypes;
|
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
using ColorPreviewNode = AetherBags.Nodes.Color.ColorPreviewNode;
|
|
||||||
|
|
||||||
namespace AetherBags.Nodes.Color;
|
namespace AetherBags.Nodes.Color;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
|
||||||
using AetherBags.Addons;
|
using AetherBags.Addons;
|
||||||
using AetherBags.Configuration;
|
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
using KamiToolKit.Premade.Nodes;
|
using KamiToolKit.Premade.Nodes;
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace AetherBags.Nodes.Configuration.Category;
|
|||||||
public sealed class CategoryDefinitionConfigurationNode : VerticalListNode
|
public sealed class CategoryDefinitionConfigurationNode : VerticalListNode
|
||||||
{
|
{
|
||||||
private readonly CheckboxNode _enabledCheckbox;
|
private readonly CheckboxNode _enabledCheckbox;
|
||||||
|
private readonly CheckboxNode _pinnedCheckbox;
|
||||||
private readonly TextInputNode _nameInputNode;
|
private readonly TextInputNode _nameInputNode;
|
||||||
private readonly TextInputNode _descriptionInputNode;
|
private readonly TextInputNode _descriptionInputNode;
|
||||||
private readonly ColorInputRow _colorInputNode;
|
private readonly ColorInputRow _colorInputNode;
|
||||||
@@ -98,6 +99,20 @@ public sealed class CategoryDefinitionConfigurationNode : VerticalListNode
|
|||||||
};
|
};
|
||||||
AddNode(_enabledCheckbox);
|
AddNode(_enabledCheckbox);
|
||||||
|
|
||||||
|
_pinnedCheckbox = new CheckboxNode
|
||||||
|
{
|
||||||
|
Size = new Vector2(200, 20),
|
||||||
|
String = "Pinned",
|
||||||
|
IsChecked = CategoryDefinition.Pinned,
|
||||||
|
OnClick = isChecked =>
|
||||||
|
{
|
||||||
|
CategoryDefinition.Pinned = isChecked;
|
||||||
|
NotifyChanged();
|
||||||
|
NotifyCategoryPropertyChanged();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
AddNode(_pinnedCheckbox);
|
||||||
|
|
||||||
AddNode(new LabelTextNode
|
AddNode(new LabelTextNode
|
||||||
{
|
{
|
||||||
TextFlags = TextFlags.AutoAdjustNodeSize,
|
TextFlags = TextFlags.AutoAdjustNodeSize,
|
||||||
@@ -471,6 +486,7 @@ public sealed class CategoryDefinitionConfigurationNode : VerticalListNode
|
|||||||
if (! _isInitialized) return;
|
if (! _isInitialized) return;
|
||||||
|
|
||||||
_enabledCheckbox.IsChecked = CategoryDefinition.Enabled;
|
_enabledCheckbox.IsChecked = CategoryDefinition.Enabled;
|
||||||
|
_pinnedCheckbox.IsChecked = CategoryDefinition.Pinned;
|
||||||
_colorInputNode.CurrentColor = CategoryDefinition.Color;
|
_colorInputNode.CurrentColor = CategoryDefinition.Color;
|
||||||
_nameInputNode.String = CategoryDefinition.Name;
|
_nameInputNode.String = CategoryDefinition.Name;
|
||||||
_descriptionInputNode.String = CategoryDefinition.Description;
|
_descriptionInputNode.String = CategoryDefinition.Description;
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.Configuration;
|
using AetherBags.Configuration;
|
||||||
using AetherBags.Nodes.Configuration.Layout;
|
using AetherBags.Nodes.Configuration.Layout;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
|
|
||||||
namespace AetherBags.Nodes.Configuration.General;
|
namespace AetherBags.Nodes.Configuration.General;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.Configuration;
|
using AetherBags.Configuration;
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
using KamiToolKit.Classes;
|
|
||||||
|
|
||||||
namespace AetherBags.Nodes.Configuration.Layout;
|
namespace AetherBags.Nodes.Configuration.Layout;
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@ internal class LayoutConfigurationNode : TabbedVerticalListNode
|
|||||||
|
|
||||||
var compactPackingCheckboxNode = new CheckboxNode
|
var compactPackingCheckboxNode = new CheckboxNode
|
||||||
{
|
{
|
||||||
Size = Size with { Y = 18 },
|
Height = 18,
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
String = "Use Compact Packing",
|
String = "Use Compact Packing",
|
||||||
IsChecked = config.CompactPackingEnabled,
|
IsChecked = config.CompactPackingEnabled,
|
||||||
@@ -58,7 +57,7 @@ internal class LayoutConfigurationNode : TabbedVerticalListNode
|
|||||||
AddTab(1);
|
AddTab(1);
|
||||||
_preferLargestFitCheckboxNode = new CheckboxNode
|
_preferLargestFitCheckboxNode = new CheckboxNode
|
||||||
{
|
{
|
||||||
Size = Size with { Y = 18 },
|
Height = 18,
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
String = "Prefer Largest Fit",
|
String = "Prefer Largest Fit",
|
||||||
IsEnabled = config.CompactPackingEnabled,
|
IsEnabled = config.CompactPackingEnabled,
|
||||||
@@ -73,7 +72,7 @@ internal class LayoutConfigurationNode : TabbedVerticalListNode
|
|||||||
|
|
||||||
_useStableInsertCheckboxNode = new CheckboxNode
|
_useStableInsertCheckboxNode = new CheckboxNode
|
||||||
{
|
{
|
||||||
Size = Size with { Y = 18 },
|
Height = 18,
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
String = "Use Stable Insert",
|
String = "Use Stable Insert",
|
||||||
IsEnabled = config.CompactPackingEnabled,
|
IsEnabled = config.CompactPackingEnabled,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.Extensions;
|
|
||||||
using AetherBags.Interop;
|
using AetherBags.Interop;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Enums;
|
using FFXIVClientStructs.FFXIV.Client.Enums;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
@@ -9,7 +8,6 @@ using FFXIVClientStructs.FFXIV.Component.GUI;
|
|||||||
using KamiToolKit.Classes;
|
using KamiToolKit.Classes;
|
||||||
using KamiToolKit.Classes.Timelines;
|
using KamiToolKit.Classes.Timelines;
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
using Lumina.Text.ReadOnly;
|
|
||||||
|
|
||||||
namespace AetherBags.Nodes;
|
namespace AetherBags.Nodes;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.Extensions;
|
|
||||||
using AetherBags.Helpers;
|
using AetherBags.Helpers;
|
||||||
using AetherBags.Inventory;
|
using AetherBags.Inventory;
|
||||||
using AetherBags.Nodes.Layout;
|
using AetherBags.Nodes.Layout;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
using KamiToolKit.Classes;
|
using KamiToolKit.Classes;
|
||||||
using KamiToolKit.Nodes;
|
using KamiToolKit.Nodes;
|
||||||
@@ -107,6 +105,8 @@ public class InventoryCategoryNode : SimpleComponentNode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsPinnedInConfig => CategorizedInventory.Category?.IsPinned ?? false;
|
||||||
|
|
||||||
public void BeginHeaderHover()
|
public void BeginHeaderHover()
|
||||||
{
|
{
|
||||||
_hoverRefs++;
|
_hoverRefs++;
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using AetherBags.Nodes.Layout;
|
||||||
|
|
||||||
|
namespace AetherBags.Nodes.Inventory;
|
||||||
|
|
||||||
|
public sealed class InventoryCategoryPinCoordinator
|
||||||
|
{
|
||||||
|
public bool ApplyPinnedStates(WrappingGridNode<InventoryCategoryNode> grid)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
using (grid.DeferRecalculateLayout())
|
||||||
|
{
|
||||||
|
foreach (var node in grid.GetNodes<InventoryCategoryNode>())
|
||||||
|
{
|
||||||
|
bool shouldBePinned = node.IsPinnedInConfig;
|
||||||
|
|
||||||
|
bool isPinned = grid.IsPinned(node);
|
||||||
|
|
||||||
|
if (shouldBePinned)
|
||||||
|
{
|
||||||
|
if (!isPinned)
|
||||||
|
{
|
||||||
|
grid.PinNode(node);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isPinned)
|
||||||
|
{
|
||||||
|
grid.UnpinNode(node);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PrunePinnedNotInGrid(WrappingGridNode<InventoryCategoryNode> grid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
using KamiToolKit;
|
||||||
|
using KamiToolKit.Nodes;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using KamiToolKit;
|
|
||||||
using KamiToolKit.Nodes;
|
|
||||||
|
|
||||||
namespace AetherBags.Nodes.Layout;
|
namespace AetherBags.Nodes.Layout;
|
||||||
|
|
||||||
@@ -36,8 +36,18 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
private bool _lastuseStableInsert;
|
private bool _lastuseStableInsert;
|
||||||
private int _lastCompactLookahead;
|
private int _lastCompactLookahead;
|
||||||
|
|
||||||
|
private int _deferRecalcDepth;
|
||||||
|
private bool _pendingRecalc;
|
||||||
|
|
||||||
private int[] _orderScratch = Array.Empty<int>();
|
private int[] _orderScratch = Array.Empty<int>();
|
||||||
|
|
||||||
|
private T? _hoistedNode;
|
||||||
|
private readonly HashSet<T> _pinned = new(ReferenceEqualityComparer<T>.Instance);
|
||||||
|
|
||||||
|
private readonly List<NodeBase> _layoutOrder = new(capacity: 256);
|
||||||
|
private readonly List<NodeBase> _pinnedScratch = new(capacity: 64);
|
||||||
|
private readonly List<NodeBase> _normalScratch = new(capacity: 256);
|
||||||
|
|
||||||
public WrappingGridNode()
|
public WrappingGridNode()
|
||||||
{
|
{
|
||||||
_rowsView = new RowsReadOnlyView(_rows);
|
_rowsView = new RowsReadOnlyView(_rows);
|
||||||
@@ -45,13 +55,61 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
|
|
||||||
public IReadOnlyList<IReadOnlyList<NodeBase>> Rows => _rowsView;
|
public IReadOnlyList<IReadOnlyList<NodeBase>> Rows => _rowsView;
|
||||||
|
|
||||||
|
public T? HoistedNode => _hoistedNode;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool TryGetRowIndex(NodeBase node, out int rowIndex) => _rowIndex.TryGetValue(node, out rowIndex);
|
public bool TryGetRowIndex(NodeBase node, out int rowIndex) => _rowIndex.TryGetValue(node, out rowIndex);
|
||||||
|
|
||||||
|
public void SetHoistedNode(T? node)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(_hoistedNode, node))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_hoistedNode = node;
|
||||||
|
|
||||||
|
if (node is not null)
|
||||||
|
{
|
||||||
|
if (!NodeList.Contains(node))
|
||||||
|
AddNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PinNode(T node)
|
||||||
|
{
|
||||||
|
if (_pinned.Add(node))
|
||||||
|
{
|
||||||
|
RequestRecalculateLayout();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UnpinNode(T node)
|
||||||
|
{
|
||||||
|
if (_pinned.Remove(node))
|
||||||
|
{
|
||||||
|
RequestRecalculateLayout();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearPinned()
|
||||||
|
{
|
||||||
|
if (_pinned.Count == 0) return;
|
||||||
|
_pinned.Clear();
|
||||||
|
RequestRecalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPinned(T node) => _pinned.Contains(node);
|
||||||
|
|
||||||
protected override void InternalRecalculateLayout()
|
protected override void InternalRecalculateLayout()
|
||||||
{
|
{
|
||||||
int count = NodeList.Count;
|
int layoutCount = BuildLayoutOrder(out int hoistedCount, out int pinnedCount);
|
||||||
if (count == 0)
|
|
||||||
|
if (layoutCount == 0)
|
||||||
{
|
{
|
||||||
RecycleAllRows();
|
RecycleAllRows();
|
||||||
_rowIndex.Clear();
|
_rowIndex.Clear();
|
||||||
@@ -61,9 +119,20 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (System.Config.General.CompactPackingEnabled)
|
bool hasSpecials = hoistedCount != 0 || pinnedCount != 0;
|
||||||
|
bool compactEnabled = System.Config.General.CompactPackingEnabled;
|
||||||
|
|
||||||
|
if (compactEnabled)
|
||||||
{
|
{
|
||||||
if (_rows.Count != 0 && LayoutParamsMatchLast() && NodeSetMatchesExistingLayout(count))
|
if (hasSpecials)
|
||||||
|
{
|
||||||
|
FullReflowCompactSections(layoutCount, hoistedCount, pinnedCount);
|
||||||
|
_requiredHeightDirty = true;
|
||||||
|
RememberLayoutParams();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rows.Count != 0 && LayoutParamsMatchLast() && NodeSetMatchesExistingLayout(layoutCount))
|
||||||
{
|
{
|
||||||
RepositionExistingRows();
|
RepositionExistingRows();
|
||||||
_requiredHeightDirty = true;
|
_requiredHeightDirty = true;
|
||||||
@@ -71,44 +140,108 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FullReflowCompact(count);
|
FullReflowCompact(layoutCount);
|
||||||
_requiredHeightDirty = true;
|
_requiredHeightDirty = true;
|
||||||
RememberLayoutParams();
|
RememberLayoutParams();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_rows.Count != 0 && TryUpdateLayoutWithoutReflowOrTailReflow(count))
|
if (_rows.Count != 0 &&
|
||||||
|
NodeSetMatchesExistingLayout(layoutCount) &&
|
||||||
|
TryUpdateLayoutWithoutReflowOrTailReflow(layoutCount, hoistedCount, pinnedCount))
|
||||||
{
|
{
|
||||||
_requiredHeightDirty = true;
|
_requiredHeightDirty = true;
|
||||||
RememberLayoutParams();
|
RememberLayoutParams();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FullReflow(count);
|
FullReflowOrdered(layoutCount, hoistedCount, pinnedCount);
|
||||||
_requiredHeightDirty = true;
|
_requiredHeightDirty = true;
|
||||||
RememberLayoutParams();
|
RememberLayoutParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool NodeSetMatchesExistingLayout(int count)
|
private int BuildLayoutOrder(out int hoistedCount, out int pinnedCount)
|
||||||
{
|
{
|
||||||
if (_rowIndex.Count != count)
|
_layoutOrder.Clear();
|
||||||
|
_pinnedScratch.Clear();
|
||||||
|
_normalScratch.Clear();
|
||||||
|
|
||||||
|
int nodeCount = NodeList.Count;
|
||||||
|
if (nodeCount == 0)
|
||||||
|
{
|
||||||
|
_hoistedNode = null;
|
||||||
|
if (_pinned.Count != 0) _pinned.Clear();
|
||||||
|
|
||||||
|
hoistedCount = 0;
|
||||||
|
pinnedCount = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var present = new HashSet<T>(ReferenceEqualityComparer<T>.Instance);
|
||||||
|
|
||||||
|
bool hoistedPresent = false;
|
||||||
|
T? hoisted = _hoistedNode;
|
||||||
|
|
||||||
|
for (int i = 0; i < nodeCount; i++)
|
||||||
|
{
|
||||||
|
if (NodeList[i] is not T node)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
present.Add(node);
|
||||||
|
|
||||||
|
if (hoisted != null && ReferenceEquals(node, hoisted))
|
||||||
|
{
|
||||||
|
hoistedPresent = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pinned.Contains(node))
|
||||||
|
_pinnedScratch.Add(node);
|
||||||
|
else
|
||||||
|
_normalScratch.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pinned.Count != 0)
|
||||||
|
_pinned.RemoveWhere(n => !present.Contains(n));
|
||||||
|
|
||||||
|
if (hoisted != null && !hoistedPresent)
|
||||||
|
_hoistedNode = null;
|
||||||
|
|
||||||
|
if (hoistedPresent && hoisted != null)
|
||||||
|
_layoutOrder.Add(hoisted);
|
||||||
|
|
||||||
|
for (int i = 0; i < _pinnedScratch.Count; i++)
|
||||||
|
_layoutOrder.Add(_pinnedScratch[i]);
|
||||||
|
|
||||||
|
for (int i = 0; i < _normalScratch.Count; i++)
|
||||||
|
_layoutOrder.Add(_normalScratch[i]);
|
||||||
|
|
||||||
|
hoistedCount = (hoistedPresent && hoisted != null) ? 1 : 0;
|
||||||
|
pinnedCount = _pinnedScratch.Count;
|
||||||
|
return _layoutOrder.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool NodeSetMatchesExistingLayout(int layoutCount)
|
||||||
|
{
|
||||||
|
if (_rowIndex.Count != layoutCount)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < layoutCount; i++)
|
||||||
{
|
{
|
||||||
if (!_rowIndex.ContainsKey(NodeList[i]))
|
if (!_rowIndex.ContainsKey(_layoutOrder[i]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryUpdateLayoutWithoutReflowOrTailReflow(int count)
|
private bool TryUpdateLayoutWithoutReflowOrTailReflow(int layoutCount, int hoistedCount, int pinnedCount)
|
||||||
{
|
{
|
||||||
if (!LayoutParamsMatchLast())
|
if (!LayoutParamsMatchLast())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int mismatchRow = FindFirstMismatchRow(count, out int mismatchNodeIndex);
|
int mismatchRow = FindFirstMismatchRow(layoutCount, hoistedCount, pinnedCount, out int mismatchNodeIndex);
|
||||||
|
|
||||||
if (mismatchRow < 0)
|
if (mismatchRow < 0)
|
||||||
{
|
{
|
||||||
@@ -116,20 +249,22 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TailReflowFrom(mismatchRow, mismatchNodeIndex, count);
|
TailReflowFrom(mismatchRow, mismatchNodeIndex, layoutCount, hoistedCount, pinnedCount);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int FindFirstMismatchRow(int count, out int mismatchNodeIndex)
|
private int FindFirstMismatchRow(int layoutCount, int hoistedCount, int pinnedCount, out int mismatchNodeIndex)
|
||||||
{
|
{
|
||||||
float availableWidth = Width;
|
float availableWidth = Width;
|
||||||
float hSpace = HorizontalSpacing;
|
float hSpace = HorizontalSpacing;
|
||||||
float startX = FirstItemSpacing;
|
float startX = FirstItemSpacing;
|
||||||
|
|
||||||
|
int normalStart = hoistedCount + pinnedCount;
|
||||||
|
|
||||||
int rowIdx = 0;
|
int rowIdx = 0;
|
||||||
int nodeIdx = 0;
|
int nodeIdx = 0;
|
||||||
|
|
||||||
while (nodeIdx < count)
|
while (nodeIdx < layoutCount)
|
||||||
{
|
{
|
||||||
if (rowIdx >= _rows.Count)
|
if (rowIdx >= _rows.Count)
|
||||||
{
|
{
|
||||||
@@ -146,12 +281,22 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
return rowIdx;
|
return rowIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int predictedCount = 0;
|
int predictedCount;
|
||||||
|
|
||||||
|
if (hoistedCount != 0 && nodeIdx == 0)
|
||||||
|
{
|
||||||
|
predictedCount = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int sectionEnd = nodeIdx < normalStart ? normalStart : layoutCount;
|
||||||
|
|
||||||
|
predictedCount = 0;
|
||||||
float currentX = startX;
|
float currentX = startX;
|
||||||
|
|
||||||
while (nodeIdx + predictedCount < count)
|
while (nodeIdx + predictedCount < sectionEnd)
|
||||||
{
|
{
|
||||||
NodeBase node = NodeList[nodeIdx + predictedCount];
|
NodeBase node = _layoutOrder[nodeIdx + predictedCount];
|
||||||
float w = node.Width;
|
float w = node.Width;
|
||||||
|
|
||||||
if (predictedCount != 0 && (currentX + w) > availableWidth)
|
if (predictedCount != 0 && (currentX + w) > availableWidth)
|
||||||
@@ -161,6 +306,10 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
currentX += w + hSpace;
|
currentX += w + hSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (predictedCount == 0 && nodeIdx < sectionEnd)
|
||||||
|
predictedCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (predictedCount != existingRowCount)
|
if (predictedCount != existingRowCount)
|
||||||
{
|
{
|
||||||
mismatchNodeIndex = nodeIdx;
|
mismatchNodeIndex = nodeIdx;
|
||||||
@@ -169,7 +318,7 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
|
|
||||||
for (int j = 0; j < existingRowCount; j++)
|
for (int j = 0; j < existingRowCount; j++)
|
||||||
{
|
{
|
||||||
if (!ReferenceEquals(existingRow[j], NodeList[nodeIdx + j]))
|
if (!ReferenceEquals(existingRow[j], _layoutOrder[nodeIdx + j]))
|
||||||
{
|
{
|
||||||
mismatchNodeIndex = nodeIdx;
|
mismatchNodeIndex = nodeIdx;
|
||||||
return rowIdx;
|
return rowIdx;
|
||||||
@@ -193,7 +342,7 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
private void RepositionExistingRows()
|
private void RepositionExistingRows()
|
||||||
{
|
{
|
||||||
_rowIndex.Clear();
|
_rowIndex.Clear();
|
||||||
_rowIndex.EnsureCapacity(NodeList.Count);
|
_rowIndex.EnsureCapacity(_layoutOrder.Count);
|
||||||
|
|
||||||
float hSpace = HorizontalSpacing;
|
float hSpace = HorizontalSpacing;
|
||||||
float vSpace = VerticalSpacing;
|
float vSpace = VerticalSpacing;
|
||||||
@@ -228,10 +377,10 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TailReflowFrom(int startRowIndex, int startNodeIndex, int count)
|
private void TailReflowFrom(int startRowIndex, int startNodeIndex, int layoutCount, int hoistedCount, int pinnedCount)
|
||||||
{
|
{
|
||||||
_rowIndex.Clear();
|
_rowIndex.Clear();
|
||||||
_rowIndex.EnsureCapacity(count);
|
_rowIndex.EnsureCapacity(layoutCount);
|
||||||
|
|
||||||
float availableWidth = Width;
|
float availableWidth = Width;
|
||||||
float hSpace = HorizontalSpacing;
|
float hSpace = HorizontalSpacing;
|
||||||
@@ -277,109 +426,359 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
_rows.RemoveAt(i);
|
_rows.RemoveAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentRowIndex = startRowIndex;
|
int normalStart = hoistedCount + pinnedCount;
|
||||||
float xCursor = startX;
|
|
||||||
float rowHeightTail = 0f;
|
|
||||||
|
|
||||||
List<NodeBase> currentRow = RentRowList(capacityHint: 8);
|
int rowIndex = startRowIndex;
|
||||||
|
int idx = startNodeIndex;
|
||||||
|
|
||||||
for (int i = startNodeIndex; i < count; i++)
|
while (idx < layoutCount)
|
||||||
{
|
{
|
||||||
NodeBase node = NodeList[i];
|
List<NodeBase> row = RentRowList(capacityHint: 8);
|
||||||
|
|
||||||
|
float x = startX;
|
||||||
|
float rowHeight = 0f;
|
||||||
|
|
||||||
|
if (hoistedCount != 0 && idx == 0)
|
||||||
|
{
|
||||||
|
NodeBase node = _layoutOrder[0];
|
||||||
|
|
||||||
|
node.X = x;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
rowHeight = node.Height;
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIndex;
|
||||||
|
|
||||||
|
idx = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int sectionEnd = idx < normalStart ? normalStart : layoutCount;
|
||||||
|
|
||||||
|
while (idx < sectionEnd)
|
||||||
|
{
|
||||||
|
NodeBase node = _layoutOrder[idx];
|
||||||
float w = node.Width;
|
float w = node.Width;
|
||||||
|
|
||||||
if (currentRow.Count != 0 && (xCursor + w) > availableWidth)
|
if (row.Count != 0 && (x + w) > availableWidth)
|
||||||
{
|
break;
|
||||||
_rows.Add(currentRow);
|
|
||||||
currentRowIndex++;
|
|
||||||
|
|
||||||
y += rowHeightTail + vSpace;
|
node.X = x;
|
||||||
xCursor = startX;
|
|
||||||
rowHeightTail = 0f;
|
|
||||||
|
|
||||||
currentRow = RentRowList(capacityHint: 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.X = xCursor;
|
|
||||||
node.Y = y;
|
node.Y = y;
|
||||||
|
|
||||||
AdjustNode(node);
|
AdjustNode(node);
|
||||||
|
|
||||||
float h = node.Height;
|
float h = node.Height;
|
||||||
if (h > rowHeightTail) rowHeightTail = h;
|
if (h > rowHeight) rowHeight = h;
|
||||||
|
|
||||||
currentRow.Add(node);
|
row.Add(node);
|
||||||
_rowIndex[node] = currentRowIndex;
|
_rowIndex[node] = rowIndex;
|
||||||
|
|
||||||
xCursor += w + hSpace;
|
x += w + hSpace;
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentRow.Count != 0)
|
if (row.Count == 0 && idx < sectionEnd)
|
||||||
{
|
{
|
||||||
_rows.Add(currentRow);
|
NodeBase node = _layoutOrder[idx];
|
||||||
|
|
||||||
|
node.X = startX;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
rowHeight = node.Height;
|
||||||
|
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIndex;
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.Count != 0)
|
||||||
|
{
|
||||||
|
_rows.Add(row);
|
||||||
|
rowIndex++;
|
||||||
|
y += rowHeight + vSpace;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RecycleRow(currentRow);
|
RecycleRow(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FullReflow(int count)
|
private void FullReflowOrdered(int layoutCount, int hoistedCount, int pinnedCount)
|
||||||
{
|
{
|
||||||
RecycleAllRows();
|
RecycleAllRows();
|
||||||
_rowIndex.Clear();
|
_rowIndex.Clear();
|
||||||
_rowIndex.EnsureCapacity(count);
|
_rowIndex.EnsureCapacity(layoutCount);
|
||||||
|
|
||||||
float availableWidth = Width;
|
float availableWidth = Width;
|
||||||
float hSpace = HorizontalSpacing;
|
float hSpace = HorizontalSpacing;
|
||||||
float vSpace = VerticalSpacing;
|
float vSpace = VerticalSpacing;
|
||||||
float startX = FirstItemSpacing;
|
float startX = FirstItemSpacing;
|
||||||
|
|
||||||
float currentX = startX;
|
float y = TopPadding;
|
||||||
float currentY = TopPadding;
|
|
||||||
|
int normalStart = hoistedCount + pinnedCount;
|
||||||
|
|
||||||
|
int rowIdx = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
while (idx < layoutCount)
|
||||||
|
{
|
||||||
|
List<NodeBase> row = RentRowList(capacityHint: 8);
|
||||||
|
|
||||||
|
float x = startX;
|
||||||
float rowHeight = 0f;
|
float rowHeight = 0f;
|
||||||
|
|
||||||
int currentRowIndex = 0;
|
if (hoistedCount != 0 && idx == 0)
|
||||||
List<NodeBase> currentRow = RentRowList(capacityHint: 8);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
{
|
||||||
NodeBase node = NodeList[i];
|
NodeBase node = _layoutOrder[0];
|
||||||
float nodeWidth = node.Width;
|
|
||||||
|
|
||||||
if (currentRow.Count != 0 && (currentX + nodeWidth) > availableWidth)
|
node.X = x;
|
||||||
{
|
node.Y = y;
|
||||||
_rows.Add(currentRow);
|
|
||||||
currentRowIndex++;
|
|
||||||
|
|
||||||
currentY += rowHeight + vSpace;
|
|
||||||
currentX = startX;
|
|
||||||
rowHeight = 0f;
|
|
||||||
|
|
||||||
currentRow = RentRowList(capacityHint: 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.X = currentX;
|
|
||||||
node.Y = currentY;
|
|
||||||
|
|
||||||
AdjustNode(node);
|
AdjustNode(node);
|
||||||
|
|
||||||
float nodeHeight = node.Height;
|
rowHeight = node.Height;
|
||||||
if (nodeHeight > rowHeight) rowHeight = nodeHeight;
|
|
||||||
|
|
||||||
currentRow.Add(node);
|
row.Add(node);
|
||||||
_rowIndex[node] = currentRowIndex;
|
_rowIndex[node] = rowIdx;
|
||||||
|
|
||||||
currentX += nodeWidth + hSpace;
|
idx = 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (currentRow.Count != 0)
|
|
||||||
{
|
|
||||||
_rows.Add(currentRow);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RecycleRow(currentRow);
|
int sectionEnd = idx < normalStart ? normalStart : layoutCount;
|
||||||
|
|
||||||
|
while (idx < sectionEnd)
|
||||||
|
{
|
||||||
|
NodeBase node = _layoutOrder[idx];
|
||||||
|
float w = node.Width;
|
||||||
|
|
||||||
|
if (row.Count != 0 && (x + w) > availableWidth)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node.X = x;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
float h = node.Height;
|
||||||
|
if (h > rowHeight) rowHeight = h;
|
||||||
|
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIdx;
|
||||||
|
|
||||||
|
x += w + hSpace;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.Count == 0 && idx < sectionEnd)
|
||||||
|
{
|
||||||
|
NodeBase node = _layoutOrder[idx];
|
||||||
|
|
||||||
|
node.X = startX;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
rowHeight = node.Height;
|
||||||
|
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIdx;
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.Count != 0)
|
||||||
|
{
|
||||||
|
_rows.Add(row);
|
||||||
|
rowIdx++;
|
||||||
|
y += rowHeight + vSpace;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RecycleRow(row);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FullReflowCompactSections(int layoutCount, int hoistedCount, int pinnedCount)
|
||||||
|
{
|
||||||
|
RecycleAllRows();
|
||||||
|
_rowIndex.Clear();
|
||||||
|
_rowIndex.EnsureCapacity(layoutCount);
|
||||||
|
|
||||||
|
float vSpace = VerticalSpacing;
|
||||||
|
float y = TopPadding;
|
||||||
|
|
||||||
|
int rowIdx = 0;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
if (hoistedCount != 0)
|
||||||
|
{
|
||||||
|
NodeBase node = _layoutOrder[0];
|
||||||
|
List<NodeBase> row = RentRowList(capacityHint: 1);
|
||||||
|
|
||||||
|
node.X = FirstItemSpacing;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIdx;
|
||||||
|
|
||||||
|
_rows.Add(row);
|
||||||
|
|
||||||
|
y += node.Height + vSpace;
|
||||||
|
rowIdx++;
|
||||||
|
idx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pinnedStart = idx;
|
||||||
|
int pinnedEnd = pinnedStart + pinnedCount;
|
||||||
|
if (pinnedCount > 0)
|
||||||
|
{
|
||||||
|
PackSectionCompact(pinnedStart, pinnedEnd, ref y, ref rowIdx);
|
||||||
|
idx = pinnedEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < layoutCount)
|
||||||
|
{
|
||||||
|
PackSectionCompact(idx, layoutCount, ref y, ref rowIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PackSectionCompact(int startIndex, int endIndex, ref float y, ref int rowIdx)
|
||||||
|
{
|
||||||
|
int sectionCount = endIndex - startIndex;
|
||||||
|
if (sectionCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float availableWidth = Width;
|
||||||
|
float hSpace = HorizontalSpacing;
|
||||||
|
float vSpace = VerticalSpacing;
|
||||||
|
float startX = FirstItemSpacing;
|
||||||
|
|
||||||
|
EnsureOrderScratch(sectionCount);
|
||||||
|
for (int i = 0; i < sectionCount; i++)
|
||||||
|
_orderScratch[i] = i;
|
||||||
|
|
||||||
|
int lookahead = System.Config.General.CompactLookahead;
|
||||||
|
if (lookahead < 0) lookahead = 0;
|
||||||
|
|
||||||
|
int p = 0;
|
||||||
|
|
||||||
|
while (p < sectionCount)
|
||||||
|
{
|
||||||
|
List<NodeBase> row = RentRowList(capacityHint: 8);
|
||||||
|
|
||||||
|
float x = startX;
|
||||||
|
float rowHeight = 0f;
|
||||||
|
|
||||||
|
while (p < sectionCount)
|
||||||
|
{
|
||||||
|
int localIdx = _orderScratch[p];
|
||||||
|
NodeBase node = _layoutOrder[startIndex + localIdx];
|
||||||
|
float w = node.Width;
|
||||||
|
|
||||||
|
if (row.Count == 0 || (x + w) <= availableWidth)
|
||||||
|
{
|
||||||
|
node.X = x;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
float h = node.Height;
|
||||||
|
if (h > rowHeight) rowHeight = h;
|
||||||
|
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIdx;
|
||||||
|
|
||||||
|
x += w + hSpace;
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bestPos = -1;
|
||||||
|
float bestWidth = 0f;
|
||||||
|
|
||||||
|
int end = p + lookahead;
|
||||||
|
if (end >= sectionCount) end = sectionCount - 1;
|
||||||
|
|
||||||
|
for (int s = p + 1; s <= end; s++)
|
||||||
|
{
|
||||||
|
int candLocalIdx = _orderScratch[s];
|
||||||
|
NodeBase cand = _layoutOrder[startIndex + candLocalIdx];
|
||||||
|
float cw = cand.Width;
|
||||||
|
|
||||||
|
if ((x + cw) <= availableWidth)
|
||||||
|
{
|
||||||
|
if (!System.Config.General.CompactPreferLargestFit)
|
||||||
|
{
|
||||||
|
bestPos = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cw > bestWidth)
|
||||||
|
{
|
||||||
|
bestWidth = cw;
|
||||||
|
bestPos = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestPos < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (bestPos != p)
|
||||||
|
{
|
||||||
|
int chosen = _orderScratch[bestPos];
|
||||||
|
|
||||||
|
if (System.Config.General.CompactStableInsert)
|
||||||
|
{
|
||||||
|
Array.Copy(_orderScratch, p, _orderScratch, p + 1, bestPos - p);
|
||||||
|
_orderScratch[p] = chosen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_orderScratch[bestPos] = _orderScratch[p];
|
||||||
|
_orderScratch[p] = chosen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.Count == 0)
|
||||||
|
{
|
||||||
|
int localIdx = _orderScratch[p];
|
||||||
|
NodeBase node = _layoutOrder[startIndex + localIdx];
|
||||||
|
|
||||||
|
node.X = startX;
|
||||||
|
node.Y = y;
|
||||||
|
|
||||||
|
AdjustNode(node);
|
||||||
|
|
||||||
|
rowHeight = node.Height;
|
||||||
|
|
||||||
|
row.Add(node);
|
||||||
|
_rowIndex[node] = rowIdx;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rows.Add(row);
|
||||||
|
rowIdx++;
|
||||||
|
|
||||||
|
y += rowHeight + vSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +815,7 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
while (p < count)
|
while (p < count)
|
||||||
{
|
{
|
||||||
int idx = _orderScratch[p];
|
int idx = _orderScratch[p];
|
||||||
NodeBase node = NodeList[idx];
|
NodeBase node = _layoutOrder[idx];
|
||||||
float w = node.Width;
|
float w = node.Width;
|
||||||
|
|
||||||
if (row.Count == 0 || (x + w) <= availableWidth)
|
if (row.Count == 0 || (x + w) <= availableWidth)
|
||||||
@@ -446,7 +845,7 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
for (int s = p + 1; s <= end; s++)
|
for (int s = p + 1; s <= end; s++)
|
||||||
{
|
{
|
||||||
int candIdx = _orderScratch[s];
|
int candIdx = _orderScratch[s];
|
||||||
NodeBase cand = NodeList[candIdx];
|
NodeBase cand = _layoutOrder[candIdx];
|
||||||
float cw = cand.Width;
|
float cw = cand.Width;
|
||||||
|
|
||||||
if ((x + cw) <= availableWidth)
|
if ((x + cw) <= availableWidth)
|
||||||
@@ -488,8 +887,7 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
if (row.Count == 0)
|
if (row.Count == 0)
|
||||||
{
|
{
|
||||||
int idx = _orderScratch[p];
|
int idx = _orderScratch[p];
|
||||||
NodeBase node = NodeList[idx];
|
NodeBase node = _layoutOrder[idx];
|
||||||
float w = node.Width;
|
|
||||||
|
|
||||||
node.X = startX;
|
node.X = startX;
|
||||||
node.Y = y;
|
node.Y = y;
|
||||||
@@ -517,11 +915,11 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
if (!_requiredHeightDirty) return _requiredHeight;
|
if (!_requiredHeightDirty) return _requiredHeight;
|
||||||
|
|
||||||
float maxBottom = 0f;
|
float maxBottom = 0f;
|
||||||
int count = NodeList.Count;
|
int count = _layoutOrder.Count;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
NodeBase node = NodeList[i];
|
NodeBase node = _layoutOrder[i];
|
||||||
float bottom = node.Y + node.Height;
|
float bottom = node.Y + node.Height;
|
||||||
if (bottom > maxBottom) maxBottom = bottom;
|
if (bottom > maxBottom) maxBottom = bottom;
|
||||||
}
|
}
|
||||||
@@ -615,6 +1013,34 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
_orderScratch = new int[newSize];
|
_orderScratch = new int[newSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IDisposable DeferRecalculateLayout()
|
||||||
|
{
|
||||||
|
_deferRecalcDepth++;
|
||||||
|
return new RecalcDeferToken<T>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void RequestRecalculateLayout()
|
||||||
|
{
|
||||||
|
if (_deferRecalcDepth > 0)
|
||||||
|
{
|
||||||
|
_pendingRecalc = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndDefer()
|
||||||
|
{
|
||||||
|
_deferRecalcDepth--;
|
||||||
|
if (_deferRecalcDepth == 0 && _pendingRecalc)
|
||||||
|
{
|
||||||
|
_pendingRecalc = false;
|
||||||
|
RecalculateLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class RowsReadOnlyView : IReadOnlyList<IReadOnlyList<NodeBase>>
|
private sealed class RowsReadOnlyView : IReadOnlyList<IReadOnlyList<NodeBase>>
|
||||||
{
|
{
|
||||||
private readonly List<List<NodeBase>> _rows;
|
private readonly List<List<NodeBase>> _rows;
|
||||||
@@ -642,4 +1068,11 @@ public sealed class WrappingGridNode<T> : LayoutListNode where T : NodeBase
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int GetHashCode(TRef obj) => RuntimeHelpers.GetHashCode(obj);
|
public int GetHashCode(TRef obj) => RuntimeHelpers.GetHashCode(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private readonly struct RecalcDeferToken<TRef>(WrappingGridNode<TRef> owner) : IDisposable
|
||||||
|
where TRef : NodeBase
|
||||||
|
{
|
||||||
|
public void Dispose() => owner.EndDefer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
using System;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using AetherBags.AddonLifecycles;
|
using AetherBags.AddonLifecycles;
|
||||||
using AetherBags.Addons;
|
using AetherBags.Addons;
|
||||||
using AetherBags.Commands;
|
using AetherBags.Commands;
|
||||||
using AetherBags.Helpers;
|
using AetherBags.Helpers;
|
||||||
using AetherBags.Hooks;
|
using AetherBags.Hooks;
|
||||||
|
using AetherBags.Inventory;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Game.Command;
|
|
||||||
using Dalamud.Hooking;
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
|
||||||
using KamiToolKit;
|
using KamiToolKit;
|
||||||
|
|
||||||
namespace AetherBags;
|
namespace AetherBags;
|
||||||
@@ -50,6 +47,8 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
|
|
||||||
_commandHandler = new CommandHandler();
|
_commandHandler = new CommandHandler();
|
||||||
|
|
||||||
|
Services.GameInventory.InventoryChanged += InventoryState.OnRawItemAdded;
|
||||||
|
|
||||||
Services.ClientState.Login += OnLogin;
|
Services.ClientState.Login += OnLogin;
|
||||||
Services.ClientState.Logout += OnLogout;
|
Services.ClientState.Logout += OnLogout;
|
||||||
|
|
||||||
@@ -65,6 +64,8 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
Util.SaveConfig(System.Config);
|
Util.SaveConfig(System.Config);
|
||||||
|
|
||||||
|
Services.GameInventory.InventoryChanged -= InventoryState.OnRawItemAdded;
|
||||||
|
|
||||||
Services.ClientState.Login -= OnLogin;
|
Services.ClientState.Login -= OnLogin;
|
||||||
Services.ClientState.Logout -= OnLogout;
|
Services.ClientState.Logout -= OnLogout;
|
||||||
|
|
||||||
@@ -82,6 +83,7 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
private void OnLogin()
|
private void OnLogin()
|
||||||
{
|
{
|
||||||
System.Config = Util.LoadConfigOrDefault();
|
System.Config = Util.LoadConfigOrDefault();
|
||||||
|
InventoryState.TrackLootedItems = true;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
System.AddonInventoryWindow.Toggle();
|
System.AddonInventoryWindow.Toggle();
|
||||||
@@ -92,6 +94,8 @@ public unsafe class Plugin : IDalamudPlugin
|
|||||||
private void OnLogout(int type, int code)
|
private void OnLogout(int type, int code)
|
||||||
{
|
{
|
||||||
Util.SaveConfig(System.Config);
|
Util.SaveConfig(System.Config);
|
||||||
|
InventoryState.TrackLootedItems = false;
|
||||||
System.AddonInventoryWindow.Close();
|
System.AddonInventoryWindow.Close();
|
||||||
|
System.AddonConfigurationWindow.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
@@ -15,6 +14,7 @@ public class Services
|
|||||||
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; } = null!;
|
||||||
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
[PluginService] public static IFramework Framework { get; private set; } = null!;
|
||||||
[PluginService] public static IGameGui GameGui { get; private set; } = null!;
|
[PluginService] public static IGameGui GameGui { get; private set; } = null!;
|
||||||
|
[PluginService] public static IGameInventory GameInventory { get; set; } = null!;
|
||||||
[PluginService] public static IKeyState KeyState { get; private set; } = null!;
|
[PluginService] public static IKeyState KeyState { get; private set; } = null!;
|
||||||
[PluginService] public static IPluginLog Logger { get; private set; } = null!;
|
[PluginService] public static IPluginLog Logger { get; private set; } = null!;
|
||||||
[PluginService] public static INotificationManager NotificationManager { get; private set; } = null!;
|
[PluginService] public static INotificationManager NotificationManager { get; private set; } = null!;
|
||||||
|
|||||||
Reference in New Issue
Block a user