Initial commit: AetherBags + KamiToolKit for FC Gitea
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using FFXIVClientStructs.Interop;
|
||||
using KamiToolKit.Premade.ListItemNodes;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public unsafe class AddonSearchAddon : BaseSearchAddon<Pointer<AtkUnitBase>, AddonListItemNode> {
|
||||
|
||||
public AddonSearchAddon() {
|
||||
SearchOptions = GetAllAddons();
|
||||
SortingOptions = [ "Visibility", "Alphabetical" ];
|
||||
ItemSpacing = 3.0f;
|
||||
}
|
||||
|
||||
protected override int Comparer(Pointer<AtkUnitBase> left, Pointer<AtkUnitBase> right, string sortingString, bool reversed) {
|
||||
if (left.Value is null || right.Value is null) return 0;
|
||||
|
||||
switch (sortingString) {
|
||||
case "Alphabetical":
|
||||
return string.CompareOrdinal(left.Value->NameString, right.Value->NameString) * (reversed ? -1 : 1);
|
||||
|
||||
case "Visibility":
|
||||
var visibilityComparison = right.Value->IsVisible.CompareTo(left.Value->IsVisible);
|
||||
if (visibilityComparison is 0) {
|
||||
visibilityComparison = string.CompareOrdinal(left.Value->NameString, right.Value->NameString);
|
||||
}
|
||||
|
||||
return visibilityComparison * (reversed ? -1 : 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override bool IsMatch(Pointer<AtkUnitBase> item, string searchString) {
|
||||
var regex = new Regex(searchString,RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
|
||||
return regex.IsMatch(item.Value->NameString);
|
||||
}
|
||||
|
||||
private static List<Pointer<AtkUnitBase>> GetAllAddons() {
|
||||
List<Pointer<AtkUnitBase>> addons = [];
|
||||
|
||||
foreach (var entry in RaptureAtkUnitManager.Instance()->AllLoadedUnitsList.Entries) {
|
||||
if (entry.Value is null) continue;
|
||||
addons.Add(entry);
|
||||
}
|
||||
|
||||
return addons;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using KamiToolKit.Nodes;
|
||||
using KamiToolKit.Premade.Widgets;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public abstract class BaseSearchAddon<T, TU> : NativeAddon where TU : ListItemNode<T>, new() {
|
||||
|
||||
private SearchWidget? searchWidget;
|
||||
private ListNode<T, TU>? listNode;
|
||||
|
||||
private TextButtonNode? cancelButton;
|
||||
private TextButtonNode? confirmButton;
|
||||
|
||||
private T? selectedOption;
|
||||
|
||||
protected override unsafe void OnSetup(AtkUnitBase* addon) {
|
||||
searchWidget = new SearchWidget {
|
||||
Size = ContentSize,
|
||||
Position = ContentStartPosition,
|
||||
SortingOptions = SortingOptions,
|
||||
OnSortOrderChanged = OnSortOrderUpdated,
|
||||
OnSearchUpdated = OnSearchUpdated,
|
||||
};
|
||||
searchWidget.AttachNode(this);
|
||||
|
||||
listNode = new ListNode<T, TU> {
|
||||
Position = new Vector2(ContentStartPosition.X, searchWidget.Y + searchWidget.Height + 8.0f),
|
||||
Size = new Vector2(ContentSize.X, ContentSize.Y - searchWidget.Height - 16.0f - 24.0f - 8.0f),
|
||||
ItemSpacing = ItemSpacing,
|
||||
OptionsList = SearchOptions,
|
||||
OnItemSelected = item => {
|
||||
selectedOption = item;
|
||||
confirmButton?.IsEnabled = true;
|
||||
},
|
||||
};
|
||||
listNode.AttachNode(this);
|
||||
|
||||
const float buttonPadding = 20.0f;
|
||||
var contentWidth = ContentSize.X - buttonPadding * 2;
|
||||
var buttonWidth = contentWidth / 3.0f;
|
||||
|
||||
cancelButton = new TextButtonNode {
|
||||
Size = new Vector2(buttonWidth, 24.0f),
|
||||
Position = new Vector2(ContentStartPosition.X, ContentStartPosition.Y + ContentSize.Y - 24.0f - 8.0f),
|
||||
String = "Cancel",
|
||||
OnClick = OnCancelClicked,
|
||||
};
|
||||
cancelButton.AttachNode(this);
|
||||
|
||||
confirmButton = new TextButtonNode {
|
||||
Size = new Vector2(buttonWidth, 24.0f),
|
||||
Position = new Vector2(ContentStartPosition.X + buttonWidth * 2 + buttonPadding * 2, ContentStartPosition.Y + ContentSize.Y - 24.0f - 8.0f),
|
||||
IsEnabled = false,
|
||||
String = "Confirm",
|
||||
OnClick = OnConfirmClicked,
|
||||
};
|
||||
confirmButton.AttachNode(this);
|
||||
|
||||
if (SortingOptions.Count > 0) {
|
||||
OnSortOrderUpdated(SortingOptions.First(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancelClicked() {
|
||||
selectedOption = default;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnConfirmClicked() {
|
||||
if (selectedOption is not null) {
|
||||
SelectionResult?.Invoke(selectedOption);
|
||||
}
|
||||
|
||||
selectedOption = default;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnSortOrderUpdated(string sortingString, bool reversed) {
|
||||
var resortedList = SearchOptions.ToList();
|
||||
resortedList.Sort((left, right) => Comparer(left, right, sortingString, reversed));
|
||||
|
||||
listNode?.OptionsList = resortedList;
|
||||
}
|
||||
|
||||
private void OnSearchUpdated(string searchString) {
|
||||
listNode?.OptionsList = SearchOptions.Where(item => IsMatch(item, searchString)).ToList();
|
||||
}
|
||||
|
||||
protected abstract int Comparer(T left, T right, string sortingString, bool reversed);
|
||||
protected abstract bool IsMatch(T item, string searchString);
|
||||
|
||||
public List<string> SortingOptions { get; init; } = [ "Alphabetical", "Id" ];
|
||||
|
||||
public List<T> SearchOptions {
|
||||
get;
|
||||
set {
|
||||
field = value;
|
||||
listNode?.OptionsList = value;
|
||||
}
|
||||
} = [];
|
||||
|
||||
public float ItemSpacing {
|
||||
get;
|
||||
set {
|
||||
field = value;
|
||||
listNode?.ItemSpacing = value;
|
||||
}
|
||||
} = 6.0f;
|
||||
|
||||
public Action<T>? SelectionResult { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using KamiToolKit.Classes;
|
||||
using KamiToolKit.Premade.ListItemNodes;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public class CurrencySearchAddon : ItemSearchAddonBase<CurrencyListItemNode> {
|
||||
public CurrencySearchAddon()
|
||||
=> SearchOptions = GetCurrencyItems().ToList();
|
||||
|
||||
private static IEnumerable<Item> GetCurrencyItems() {
|
||||
var dataManager = DalamudInterface.Instance.DataManager;
|
||||
|
||||
var obsoleteTomes = dataManager.GetExcelSheet<TomestonesItem>()
|
||||
.Where(item => item.Tomestones.RowId is 0)
|
||||
.Select(item => item.Item.Value)
|
||||
.ToHashSet(EqualityComparer<Item>.Create(
|
||||
(x, y) => x.RowId == y.RowId,
|
||||
obj => obj.RowId.GetHashCode()
|
||||
));
|
||||
|
||||
return dataManager.GetExcelSheet<Item>()
|
||||
.Where(item => item is { Name.IsEmpty: false, ItemUICategory.RowId: 100 } or { RowId: >= 1 and < 100, Name.IsEmpty: false })
|
||||
.Where(item => !obsoleteTomes.Contains(item));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using KamiToolKit.Premade.ListItemNodes;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public class ItemSearchAddon : ItemSearchAddonBase<ItemListItemNode>;
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using KamiToolKit.Nodes;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public class ItemSearchAddonBase<T> : BaseSearchAddon<Item, T> where T : ListItemNode<Item>, new() {
|
||||
protected override int Comparer(Item left, Item right, string sortingString, bool reversed) {
|
||||
var result = sortingString switch {
|
||||
"Alphabetical" => string.CompareOrdinal(left.Name.ToString(), right.Name.ToString()),
|
||||
"Id" => left.RowId.CompareTo(right.RowId),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
return reversed ? -result : result;
|
||||
}
|
||||
|
||||
protected override bool IsMatch(Item item, string searchString) {
|
||||
var isDescriptionSearch = searchString.StartsWith('$');
|
||||
|
||||
if (isDescriptionSearch) {
|
||||
searchString = searchString[1..];
|
||||
}
|
||||
|
||||
var regex = new Regex(searchString,RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
|
||||
if (regex.IsMatch(item.RowId.ToString())) return true;
|
||||
if (regex.IsMatch(item.Name.ToString())) return true;
|
||||
if (regex.IsMatch(item.Description.ToString()) && isDescriptionSearch) return true;
|
||||
if (regex.IsMatch(item.LevelEquip.ToString())) return true;
|
||||
if (regex.IsMatch(item.LevelItem.RowId.ToString())) return true;
|
||||
if (regex.IsMatch(item.ClassJobCategory.Value.Name.ToString())) return true;
|
||||
if (regex.IsMatch(item.ItemUICategory.Value.Name.ToString())) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using KamiToolKit.Classes;
|
||||
using KamiToolKit.Premade.ListItemNodes;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public class StatusSearchAddon : BaseSearchAddon<Status, StatusListItemNode> {
|
||||
public StatusSearchAddon() {
|
||||
SearchOptions = DalamudInterface.Instance.DataManager.GetExcelSheet<Status>()
|
||||
.Where(territory => territory.RowId is not 0)
|
||||
.Where(territory => !territory.Name.IsEmpty)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
protected override int Comparer(Status left, Status right, string sortingString, bool reversed){
|
||||
var result = sortingString switch {
|
||||
"Alphabetical" => string.CompareOrdinal(left.Name.ToString(), right.Name.ToString()),
|
||||
"Id" => left.RowId.CompareTo(right.RowId),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
return reversed ? -result : result;
|
||||
}
|
||||
|
||||
protected override bool IsMatch(Status item, string searchString) {
|
||||
var regex = new Regex(searchString,RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
|
||||
if (regex.IsMatch(item.RowId.ToString())) return true;
|
||||
if (regex.IsMatch(item.Name.ToString())) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Dalamud.Utility;
|
||||
using KamiToolKit.Classes;
|
||||
using KamiToolKit.Premade.ListItemNodes;
|
||||
using Lumina.Excel.Sheets;
|
||||
|
||||
namespace KamiToolKit.Premade.SearchAddons;
|
||||
|
||||
public class TerritorySearchAddon : BaseSearchAddon<TerritoryType, TerritoryTypeListItemNode> {
|
||||
public TerritorySearchAddon() {
|
||||
SearchOptions = DalamudInterface.Instance.DataManager.GetExcelSheet<TerritoryType>()
|
||||
.Where(territory => territory.RowId is not 0)
|
||||
.Where(territory => territory.LoadingImage.RowId is not 0)
|
||||
.Where(territory => !territory.PlaceName.ValueNullable?.Name.ToString().IsNullOrEmpty() ?? false)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
protected override int Comparer(TerritoryType left, TerritoryType right, string sortingString, bool reversed) {
|
||||
var result = sortingString switch {
|
||||
"Alphabetical" => string.CompareOrdinal(left.Name.ToString(), right.Name.ToString()),
|
||||
"Id" => left.RowId.CompareTo(right.RowId),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
return reversed ? -result : result;
|
||||
}
|
||||
|
||||
protected override bool IsMatch(TerritoryType item, string searchString) {
|
||||
var regex = new Regex(searchString,RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
|
||||
if (regex.IsMatch(item.RowId.ToString())) return true;
|
||||
if (regex.IsMatch(item.PlaceName.ValueNullable?.Name.ToString() ?? string.Empty)) return true;
|
||||
if (regex.IsMatch(item.ContentFinderCondition.ValueNullable?.Name.ToString() ?? string.Empty)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user