Update KTK, Swap Dropdowns to EnumDropdowns

This commit is contained in:
Zeffuro
2026-01-23 14:49:33 +01:00
parent 0fee7d0954
commit 26b3de8a1d
14 changed files with 141 additions and 77 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
using KamiToolKit.Premade.GenericSearchListItemNodes;
using KamiToolKit.Premade.GenericListItemNodes;
namespace AetherBags.Addons;
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Numerics;
using System.Text.Json.Serialization;
using KamiToolKit.Classes;
@@ -84,6 +85,9 @@ public enum ToggleFilterState
public enum PluginFilterMode
{
[Description("Create New Categories")]
Categorize = 0,
[Description("Apply Highlight Only")]
Highlight = 1,
}
@@ -1,3 +1,5 @@
using System.ComponentModel;
namespace AetherBags.Configuration;
public class GeneralSettings
@@ -21,12 +23,18 @@ public class GeneralSettings
public enum InventoryStackMode : byte
{
[Description("Split Stacks (Game Default)")]
NaturalStacks = 0,
[Description("Merge Stacks (By Item ID)")]
AggregateByItemId = 1,
}
public enum SearchMode : byte
{
[Description("Filter (Hide non-matches)")]
Filter = 0,
[Description("Highlight (Dim non-matches)")]
Highlight = 1,
}
+52
View File
@@ -0,0 +1,52 @@
using System;
using System.ComponentModel;
using System.Numerics;
using System.Runtime.CompilerServices;
using Dalamud.Utility;
namespace KamiToolKit.Extensions;
internal static class EnumExtensions {
extension(Enum enumValue) {
public string Description => enumValue.GetDescription();
private string GetDescription() {
var attribute = enumValue.GetAttribute<DescriptionAttribute>();
return attribute?.Description ?? enumValue.ToString();
}
}
extension<T>(ref T flagValue) where T : unmanaged, Enum {
public void SetFlags(params T[] flags) {
foreach (var flag in flags) {
flagValue.SetFlag(flag, true);
}
}
public void ClearFlags(params T[] flags) {
foreach (var flag in flags) {
flagValue.SetFlag(flag, false);
}
}
private unsafe void SetFlag(T flag, bool enable) {
switch (sizeof(T)) {
case 1: flagValue.SetFlag<T, byte>(flag, enable); break;
case 2: flagValue.SetFlag<T, ushort>(flag, enable); break;
case 4: flagValue.SetFlag<T, uint>(flag, enable); break;
case 8: flagValue.SetFlag<T, ulong>(flag, enable); break;
default: throw new NotSupportedException("Unsupported enum size");
}
}
private void SetFlag<TUnderlying>(T flag, bool enable) where TUnderlying : unmanaged, IBinaryInteger<TUnderlying> {
ref var value = ref Unsafe.As<T, TUnderlying>(ref flagValue);
var mask = Unsafe.As<T, TUnderlying>(ref flag);
if (enable)
value |= mask;
else
value &= ~mask;
}
}
}
@@ -80,24 +80,21 @@ public sealed class CategoryGeneralConfigurationNode : TabbedVerticalListNode
bool bisBuddyReady = System.IPC.BisBuddy?.IsReady ?? false;
LabeledDropdownNode? bbModeDropdown = new LabeledDropdownNode
LabeledDropdownNode<PluginFilterMode>? bbModeDropdown = new LabeledDropdownNode<PluginFilterMode>
{
Size = new Vector2(300, 20),
Size = new Vector2(500, 20),
LabelText = "Filter Display Mode",
LabelTextFlags = TextFlags.AutoAdjustNodeSize,
IsEnabled = config.BisBuddyEnabled && bisBuddyReady,
Options = Enum.GetNames(typeof(PluginFilterMode)).ToList(),
SelectedOption = config.BisBuddyMode.ToString(),
Options = Enum.GetValues<PluginFilterMode>().ToList(),
SelectedOption = config.BisBuddyMode,
OnOptionSelected = selected =>
{
if (Enum.TryParse<PluginFilterMode>(selected, out var parsed))
{
config.BisBuddyMode = parsed;
if (parsed == PluginFilterMode.Categorize)
HighlightState.ClearFilter(HighlightSource.AllaganTools);
config.BisBuddyMode = selected;
if (selected == PluginFilterMode.Categorize)
HighlightState.ClearFilter(HighlightSource.AllaganTools);
RefreshInventory();
}
RefreshInventory();
}
};
@@ -121,24 +118,23 @@ public sealed class CategoryGeneralConfigurationNode : TabbedVerticalListNode
bool allaganReady = System.IPC.AllaganTools?.IsReady ?? false;
LabeledDropdownNode? atModeDropdown = new LabeledDropdownNode
LabeledDropdownNode<PluginFilterMode>? atModeDropdown = new LabeledDropdownNode<PluginFilterMode>
{
Size = new Vector2(300, 20),
Size = new Vector2(500, 20),
LabelText = "Filter Display Mode",
LabelTextFlags = TextFlags.AutoAdjustNodeSize,
IsEnabled = config.AllaganToolsCategoriesEnabled && allaganReady,
Options = Enum.GetNames(typeof(PluginFilterMode)).ToList(),
SelectedOption = config.AllaganToolsFilterMode.ToString(),
Options = Enum.GetValues<PluginFilterMode>().ToList(),
SelectedOption = config.AllaganToolsFilterMode,
OnOptionSelected = selected =>
{
if (Enum.TryParse<PluginFilterMode>(selected, out var parsed))
config.AllaganToolsFilterMode = selected;
if (selected == PluginFilterMode.Categorize)
{
config.AllaganToolsFilterMode = parsed;
if (parsed == PluginFilterMode.Categorize)
HighlightState.ClearFilter(HighlightSource.AllaganTools);
RefreshInventory();
HighlightState.ClearFilter(HighlightSource.AllaganTools);
}
RefreshInventory();
}
};
@@ -3,6 +3,7 @@ using System.Numerics;
using AetherBags.Configuration;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Nodes;
using Lumina.Text.ReadOnly;
namespace AetherBags.Nodes.Configuration.Category;
@@ -14,9 +15,9 @@ public sealed class RangeFilterRow : VerticalListNode
public Action<bool, int, int>? OnFilterChanged { get; set; }
public required string Label
public required ReadOnlySeString Label
{
get => _enabledCheckbox.String.Replace(" Filter", "");
get => _enabledCheckbox.String.ExtractText().Replace(" Filter", "");
init => _enabledCheckbox.String = $"{value} Filter";
}
@@ -113,9 +114,9 @@ public sealed class RangeFilterRowUint : VerticalListNode
public Action<bool, uint, uint>? OnFilterChanged { get; set; }
public required string Label
public required ReadOnlySeString Label
{
get => _enabledCheckbox.String.Replace(" Filter", "");
get => _enabledCheckbox.String.ExtractText().Replace(" Filter", "");
init => _enabledCheckbox.String = $"{value} Filter";
}
@@ -4,6 +4,7 @@ using System.Numerics;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Classes;
using KamiToolKit.Nodes;
using Lumina.Text.ReadOnly;
namespace AetherBags.Nodes.Configuration.Category;
@@ -16,12 +17,11 @@ public sealed class StringListEditorNode : VerticalListNode
private readonly LabelTextNode _headerLabel;
private readonly VerticalListNode _itemsContainer;
private readonly HorizontalListNode _addRow;
private readonly TextInputNode _addInput;
public Action? OnChanged { get; set; }
public required string Label
public required ReadOnlySeString Label
{
get => _headerLabel.String;
init => _headerLabel.String = value;
@@ -49,7 +49,7 @@ public sealed class StringListEditorNode : VerticalListNode
};
AddNode(_itemsContainer);
_addRow = new HorizontalListNode
var addRow = new HorizontalListNode
{
Size = new Vector2(LabelWidth + 40f, RowHeight),
ItemSpacing = 4.0f,
@@ -61,7 +61,7 @@ public sealed class StringListEditorNode : VerticalListNode
PlaceholderString = "Add new...",
OnInputComplete = _ => AddCurrentValue(),
};
_addRow.AddNode(_addInput);
addRow.AddNode(_addInput);
var addButton = new TextButtonNode
{
@@ -69,9 +69,9 @@ public sealed class StringListEditorNode : VerticalListNode
String = "Add",
OnClick = AddCurrentValue,
};
_addRow.AddNode(addButton);
addRow.AddNode(addButton);
AddNode(_addRow);
AddNode(addRow);
}
public void SetList(List<string> newList)
@@ -82,7 +82,7 @@ public sealed class StringListEditorNode : VerticalListNode
private void AddCurrentValue()
{
var value = _addInput.String;
var value = _addInput.String.ExtractText();
if (!string.IsNullOrWhiteSpace(value) && !_list.Contains(value))
{
_list.Add(value);
@@ -4,6 +4,7 @@ using System.Numerics;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Classes;
using KamiToolKit.Nodes;
using Lumina.Text.ReadOnly;
namespace AetherBags.Nodes.Configuration.Category;
@@ -16,13 +17,12 @@ public sealed class UintListEditorNode : VerticalListNode
private readonly LabelTextNode _headerLabel;
private readonly VerticalListNode _itemsContainer;
private readonly HorizontalListNode _addRow;
private readonly NumericInputNode _addInput;
public Func<uint, string>? LabelResolver { get; init; }
public Action? OnChanged { get; set; }
public required string Label
public required ReadOnlySeString Label
{
get => _headerLabel.String;
init => _headerLabel.String = value;
@@ -50,7 +50,7 @@ public sealed class UintListEditorNode : VerticalListNode
};
AddNode(_itemsContainer);
_addRow = new HorizontalListNode
var addRow = new HorizontalListNode
{
Size = new Vector2(LabelWidth + 40f, RowHeight),
ItemSpacing = 4.0f,
@@ -63,7 +63,7 @@ public sealed class UintListEditorNode : VerticalListNode
Max = int.MaxValue,
Value = 0,
};
_addRow.AddNode(_addInput);
addRow.AddNode(_addInput);
var addButton = new TextButtonNode
{
@@ -71,9 +71,9 @@ public sealed class UintListEditorNode : VerticalListNode
String = "Add",
OnClick = AddCurrentValue,
};
_addRow.AddNode(addButton);
addRow.AddNode(addButton);
AddNode(_addRow);
AddNode(addRow);
}
public void SetList(List<uint> newList)
@@ -14,7 +14,7 @@ internal sealed class FunctionalConfigurationNode : TabbedVerticalListNode
private readonly CheckboxNode _hideDefaultBagsCheckboxNode;
private readonly CheckboxNode _hideSaddlebagsCheckboxNode;
private readonly CheckboxNode _hideRetainerbagsCheckboxNode;
private readonly LabeledDropdownNode _stackDropDown;
private readonly LabeledDropdownNode<InventoryStackMode> _stackDropDown;
public FunctionalConfigurationNode()
{
@@ -139,39 +139,33 @@ internal sealed class FunctionalConfigurationNode : TabbedVerticalListNode
Height = 6
});
var searchModeDropDown = new LabeledDropdownNode
var searchModeDropDown = new LabeledDropdownNode<SearchMode>
{
Size = new Vector2(300, 20),
Size = new Vector2(500, 20),
LabelText = "Search Mode",
LabelTextFlags = TextFlags.AutoAdjustNodeSize,
Options = Enum.GetNames(typeof(SearchMode)).ToList(),
SelectedOption = config.SearchMode.ToString(),
Options = Enum.GetValues<SearchMode>().ToList(),
SelectedOption = config.SearchMode,
OnOptionSelected = selected =>
{
if (Enum.TryParse<SearchMode>(selected, out var parsed))
{
config.SearchMode = parsed;
InventoryOrchestrator.RefreshAll(updateMaps: false);
}
config.SearchMode = selected;
InventoryOrchestrator.RefreshAll(updateMaps: false);
}
};
AddNode(searchModeDropDown);
_stackDropDown = new LabeledDropdownNode
_stackDropDown = new LabeledDropdownNode<InventoryStackMode>
{
Size = new Vector2(300, 20),
Size = new Vector2(500, 20),
IsEnabled = true,
LabelText = "Stack Mode",
LabelTextFlags = TextFlags.AutoAdjustNodeSize,
Options = Enum.GetNames(typeof(InventoryStackMode)).ToList(),
SelectedOption = config.StackMode.ToString(),
Options = Enum.GetValues<InventoryStackMode>().ToList(),
SelectedOption = config.StackMode,
OnOptionSelected = selected =>
{
if (Enum.TryParse<InventoryStackMode>(selected, out var parsed))
{
config.StackMode = parsed;
InventoryOrchestrator.RefreshAll(updateMaps: true);
}
config.StackMode = selected;
InventoryOrchestrator.RefreshAll(updateMaps: true);
}
};
AddNode(_stackDropDown);
+20 -12
View File
@@ -2,13 +2,14 @@ using System;
using System.Collections.Generic;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Nodes;
using Lumina.Text.ReadOnly;
namespace AetherBags.Nodes.Input;
public class LabeledDropdownNode : SimpleComponentNode {
public class LabeledDropdownNode<T> : SimpleComponentNode where T : Enum {
private readonly GridNode _gridNode;
private readonly TextNode _labelNode;
private readonly TextDropDownNode _dropDownNode;
private readonly EnumDropDownNode<T> _dropDownNode;
public LabeledDropdownNode() {
_gridNode = new GridNode {
@@ -17,12 +18,12 @@ public class LabeledDropdownNode : SimpleComponentNode {
_gridNode.AttachNode(this);
_labelNode = new LabelTextNode {
String = String.Empty,
String = string.Empty,
};
_labelNode.AttachNode(_gridNode[0, 0]);
_dropDownNode = new TextDropDownNode {
Options = new List<string>(),
_dropDownNode = new EnumDropDownNode<T> {
Options = new List<T>(),
};
_dropDownNode.AttachNode(_gridNode[1, 0]);
}
@@ -36,25 +37,32 @@ public class LabeledDropdownNode : SimpleComponentNode {
_dropDownNode.Size = _gridNode[1, 0].Size;
}
public required string LabelText
public required ReadOnlySeString LabelText
{
get => _labelNode.String;
set => _labelNode.String = value;
}
public Action<string>? OnOptionSelected
public Action<T>? OnOptionSelected
{
get => _dropDownNode.OnOptionSelected;
set => _dropDownNode.OnOptionSelected = value;
}
public string? SelectedOption
public T? SelectedOption
{
get => _dropDownNode.SelectedOption;
set => _dropDownNode.SelectedOption = value;
get => _dropDownNode.OptionListNode.SelectedOption;
set
{
_dropDownNode.OptionListNode.SelectedOption = value;
if (value != null)
{
_dropDownNode.LabelNode.String = value.Description;
}
}
}
public required List<string> Options
public required List<T> Options
{
get => _dropDownNode.Options!;
set => _dropDownNode.Options = value;
@@ -65,4 +73,4 @@ public class LabeledDropdownNode : SimpleComponentNode {
get => _labelNode.TextFlags;
set => _labelNode.TextFlags = value;
}
}
}
@@ -49,7 +49,7 @@ public class TextInputWithButtonNode : SimpleComponentNode {
}
public ReadOnlySeString SearchString {
get => _textInputNode.SeString;
set => _textInputNode.SeString = value;
get => _textInputNode.String;
set => _textInputNode.String = value;
}
}
@@ -5,7 +5,7 @@ using AetherBags.Nodes.Currency;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Classes;
using KamiToolKit.Nodes;
using Lumina.Text.ReadOnly;
using static AetherBags.Inventory.State.InventoryStateBase;
namespace AetherBags.Nodes.Inventory;
@@ -60,7 +60,7 @@ public sealed class InventoryFooterNode : SimpleComponentNode
});
}
public string SlotAmountText
public ReadOnlySeString SlotAmountText
{
get => _slotAmountTextNode.String;
set => _slotAmountTextNode.String = value;
@@ -74,8 +74,8 @@ public sealed class InventoryNotificationNode : SimpleComponentNode
{
field = value;
titleTextNode.SeString = value.Title;
messageTextNode.SeString = value.Message;
titleTextNode.String = value.Title;
messageTextNode.String = value.Message;
if (value.Title.IsEmpty && value.Message.IsEmpty)
{
@@ -1,6 +1,7 @@
using System. Numerics;
using FFXIVClientStructs.FFXIV.Component.GUI;
using KamiToolKit.Nodes;
using Lumina.Text.ReadOnly;
namespace AetherBags.Nodes.Inventory;
@@ -23,7 +24,7 @@ public class SaddleBagFooterNode : SimpleComponentNode
_slotCounterNode.AttachNode(this);
}
public string SlotAmountText
public ReadOnlySeString SlotAmountText
{
get => _slotCounterNode.String;
set => _slotCounterNode.String = $"Slots: {value}";