Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2025f4e0d2 | |||
| cd847a4fb7 | |||
| c9d2b9ce94 | |||
| f6d06a652d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -367,3 +367,6 @@ FodyWeavers.xsd
|
|||||||
Glamaholic/.github/
|
Glamaholic/.github/
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
/.claude
|
||||||
|
/.claude/settings.local.json
|
||||||
|
/nul
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class Commands : IDisposable {
|
internal class Commands : IDisposable {
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class Configuration : IPluginConfiguration {
|
internal class Configuration : IPluginConfiguration {
|
||||||
private const int CURRENT_VERSION = 1;
|
private const int CURRENT_VERSION = 1;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System;
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class DataCache {
|
internal class DataCache {
|
||||||
public static Lazy<ImmutableList<Item>> EquippableItems { get; } =
|
public static Lazy<ImmutableList<Item>> EquippableItems { get; } =
|
||||||
new(() => Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!
|
new(() => Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!
|
||||||
@@ -13,6 +13,11 @@ namespace Glamaholic {
|
|||||||
row.EquipSlotCategory.Value!.SoulCrystal == 0)
|
row.EquipSlotCategory.Value!.SoulCrystal == 0)
|
||||||
.ToImmutableList());
|
.ToImmutableList());
|
||||||
|
|
||||||
|
public static Lazy<ImmutableList<Glasses>> GlassesItems { get; } =
|
||||||
|
new(() => Service.DataManager.GetExcelSheet<Glasses>(ClientLanguage.English)!
|
||||||
|
.Where(row => row.Name.ByteLength > 0)
|
||||||
|
.ToImmutableList());
|
||||||
|
|
||||||
public static Lazy<ImmutableDictionary<string, byte>> StainLookup { get; } =
|
public static Lazy<ImmutableDictionary<string, byte>> StainLookup { get; } =
|
||||||
new (() =>
|
new (() =>
|
||||||
Service.DataManager.GetExcelSheet<Stain>(ClientLanguage.English)!
|
Service.DataManager.GetExcelSheet<Stain>(ClientLanguage.English)!
|
||||||
|
|||||||
60
GlamourBrowser/Interop/AT.cs
Normal file
60
GlamourBrowser/Interop/AT.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Ipc;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using HeightAdjuster.Interop.Glamourer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GlamourBrowser.Interop {
|
||||||
|
internal class AT {
|
||||||
|
|
||||||
|
private static bool Initialized { get; set; } = false;
|
||||||
|
private static bool Available { get; set; } = false;
|
||||||
|
private static ICommandManager _commandManager;
|
||||||
|
private static IChatGui _chatGui;
|
||||||
|
|
||||||
|
|
||||||
|
public static void Initialize(ICommandManager commandManager, IDalamudPluginInterface pluginInterface, IChatGui chatGui) {
|
||||||
|
if (Initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_commandManager = commandManager;
|
||||||
|
_chatGui = chatGui;
|
||||||
|
|
||||||
|
Initialized = true;
|
||||||
|
|
||||||
|
RefreshStatus(pluginInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RefreshStatus(IDalamudPluginInterface pluginInterface) {
|
||||||
|
var prev = Available;
|
||||||
|
|
||||||
|
Available = false;
|
||||||
|
|
||||||
|
foreach (var plugin in pluginInterface.InstalledPlugins) {
|
||||||
|
if (plugin.InternalName == "InventoryTools") {
|
||||||
|
Available = plugin.IsLoaded;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev == Available)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void OpenMoreInformationSub(string itemId) {
|
||||||
|
if (IsAvailable()) {
|
||||||
|
_commandManager.ProcessCommand("/moreinfo " + itemId);
|
||||||
|
} else {
|
||||||
|
_chatGui.PrintError("Allagan Tools was not detected, please install it to get more information about this item.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static bool IsAvailable() {
|
||||||
|
return Available;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,10 @@ using HeightAdjuster.Interop.Glamourer;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Glamaholic.Interop {
|
namespace GlamourBrowser.Interop {
|
||||||
internal class Glamourer {
|
internal class Glamourer {
|
||||||
private static SetItem _SetItem { get; set; } = null!;
|
private static SetItem _SetItem { get; set; } = null!;
|
||||||
|
private static SetBonusItem _SetBonusItem { get; set; } = null!;
|
||||||
private static GetState _GetState { get; set; } = null!;
|
private static GetState _GetState { get; set; } = null!;
|
||||||
private static RevertState _RevertState { get; set; } = null!;
|
private static RevertState _RevertState { get; set; } = null!;
|
||||||
|
|
||||||
@@ -64,11 +65,23 @@ namespace Glamaholic.Interop {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetBonusItem(int playerIndex, ApiBonusSlot slot, uint itemId) {
|
||||||
|
if (!IsAvailable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Service.Framework.Run(() => {
|
||||||
|
_SetBonusItem.Invoke(playerIndex, slot, itemId);
|
||||||
|
});
|
||||||
|
} catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
public static void Initialize(IDalamudPluginInterface pluginInterface) {
|
public static void Initialize(IDalamudPluginInterface pluginInterface) {
|
||||||
if (Initialized)
|
if (Initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_SetItem = new SetItem(pluginInterface);
|
_SetItem = new SetItem(pluginInterface);
|
||||||
|
_SetBonusItem = new SetBonusItem(pluginInterface);
|
||||||
_GetState = new GetState(pluginInterface);
|
_GetState = new GetState(pluginInterface);
|
||||||
_RevertState = new RevertState(pluginInterface);
|
_RevertState = new RevertState(pluginInterface);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using Dalamud.Plugin;
|
|||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
public class Plugin : IDalamudPlugin {
|
public class Plugin : IDalamudPlugin {
|
||||||
internal static string Name => "GlamourBrowser";
|
internal static string Name => "GlamourBrowser";
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ namespace Glamaholic {
|
|||||||
this.Commands = new Commands(this);
|
this.Commands = new Commands(this);
|
||||||
|
|
||||||
Interop.Glamourer.Initialize(Service.Interface);
|
Interop.Glamourer.Initialize(Service.Interface);
|
||||||
|
Interop.AT.Initialize(Service.CommandManager, Service.Interface, Service.ChatGui);
|
||||||
Service.Framework.Update += OnFrameworkUpdate;
|
Service.Framework.Update += OnFrameworkUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ namespace Glamaholic {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Interop.Glamourer.RefreshStatus(Service.Interface);
|
Interop.Glamourer.RefreshStatus(Service.Interface);
|
||||||
|
Interop.AT.RefreshStatus(Service.Interface);
|
||||||
|
|
||||||
LastInteropCheckTime = now;
|
LastInteropCheckTime = now;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Dalamud.Interface.Textures.TextureWraps;
|
using Dalamud.Interface.Textures.TextureWraps;
|
||||||
using Glamaholic.Ui;
|
using GlamourBrowser.Ui;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class PluginUi : IDisposable {
|
internal class PluginUi : IDisposable {
|
||||||
internal Plugin Plugin { get; }
|
internal Plugin Plugin { get; }
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ namespace Glamaholic {
|
|||||||
this.MainInterface.Toggle();
|
this.MainInterface.Toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IDalamudTextureWrap? GetIcon(ushort id) {
|
internal IDalamudTextureWrap? GetIcon(uint id) {
|
||||||
var icon = Service.TextureProvider.GetFromGameIcon(new Dalamud.Interface.Textures.GameIconLookup(id)).GetWrapOrDefault();
|
var icon = Service.TextureProvider.GetFromGameIcon(new Dalamud.Interface.Textures.GameIconLookup(id)).GetWrapOrDefault();
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using Dalamud.IoC;
|
|||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class Service {
|
internal class Service {
|
||||||
[PluginService] internal static IPluginLog Log { get; private set; } = null!;
|
[PluginService] internal static IPluginLog Log { get; private set; } = null!;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Glamourer.Api.Enums;
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -7,7 +7,7 @@ using System.Collections.Immutable;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Glamaholic.Ui {
|
namespace GlamourBrowser.Ui {
|
||||||
internal class MainInterface {
|
internal class MainInterface {
|
||||||
internal const int IconSize = 48;
|
internal const int IconSize = 48;
|
||||||
private const int ItemsPerRow = 5;
|
private const int ItemsPerRow = 5;
|
||||||
@@ -22,6 +22,7 @@ namespace Glamaholic.Ui {
|
|||||||
Gloves,
|
Gloves,
|
||||||
Legs,
|
Legs,
|
||||||
Feet,
|
Feet,
|
||||||
|
Glasses,
|
||||||
}
|
}
|
||||||
|
|
||||||
private PluginUi Ui { get; }
|
private PluginUi Ui { get; }
|
||||||
@@ -31,12 +32,13 @@ namespace Glamaholic.Ui {
|
|||||||
private Dictionary<ItemCategory, float> ScrollPositions { get; set; } = new();
|
private Dictionary<ItemCategory, float> ScrollPositions { get; set; } = new();
|
||||||
private Dictionary<ItemCategory, byte> SelectedStain1 { get; set; } = new();
|
private Dictionary<ItemCategory, byte> SelectedStain1 { get; set; } = new();
|
||||||
private Dictionary<ItemCategory, byte> SelectedStain2 { get; set; } = new();
|
private Dictionary<ItemCategory, byte> SelectedStain2 { get; set; } = new();
|
||||||
|
private Glasses? SelectedGlasses { get; set; } = null;
|
||||||
|
|
||||||
private bool _visible;
|
private bool _visible;
|
||||||
private string _itemFilter = string.Empty;
|
private string _itemFilter = string.Empty;
|
||||||
private ItemCategory _currentCategory = ItemCategory.Head;
|
private ItemCategory _currentCategory = ItemCategory.Head;
|
||||||
private ItemCategory _previousCategory = ItemCategory.Head;
|
private ItemCategory _previousCategory = ItemCategory.Head;
|
||||||
private string _lastFilterUsed = string.Empty;
|
private Dictionary<ItemCategory, string> _lastFilterUsed = new();
|
||||||
private string _dyeFilter = string.Empty;
|
private string _dyeFilter = string.Empty;
|
||||||
|
|
||||||
internal MainInterface(PluginUi ui) {
|
internal MainInterface(PluginUi ui) {
|
||||||
@@ -126,16 +128,26 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Item> GetFilteredItems() {
|
private List<Item> GetFilteredItems() {
|
||||||
|
// Glasses are handled separately, so return empty list if on Glasses tab
|
||||||
|
if (_currentCategory == ItemCategory.Glasses) {
|
||||||
|
return new List<Item>();
|
||||||
|
}
|
||||||
|
|
||||||
var filter = this._itemFilter.ToLowerInvariant();
|
var filter = this._itemFilter.ToLowerInvariant();
|
||||||
|
|
||||||
if (!FilteredItemsCache.ContainsKey(_currentCategory) || _lastFilterUsed != _itemFilter) {
|
// Check if we need to recalculate the filter for this category
|
||||||
|
bool needsRecalculation = !FilteredItemsCache.ContainsKey(_currentCategory) ||
|
||||||
|
!_lastFilterUsed.ContainsKey(_currentCategory) ||
|
||||||
|
_lastFilterUsed[_currentCategory] != _itemFilter;
|
||||||
|
|
||||||
|
if (needsRecalculation) {
|
||||||
var items = ItemsByCategory[_currentCategory];
|
var items = ItemsByCategory[_currentCategory];
|
||||||
var filtered = string.IsNullOrEmpty(this._itemFilter)
|
var filtered = string.IsNullOrEmpty(this._itemFilter)
|
||||||
? items.ToList()
|
? items.ToList()
|
||||||
: items.Where(item => item.Name.ExtractText().ToLowerInvariant().Contains(filter)).ToList();
|
: items.Where(item => item.Name.ExtractText().ToLowerInvariant().Contains(filter)).ToList();
|
||||||
|
|
||||||
FilteredItemsCache[_currentCategory] = filtered;
|
FilteredItemsCache[_currentCategory] = filtered;
|
||||||
_lastFilterUsed = _itemFilter;
|
_lastFilterUsed[_currentCategory] = _itemFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FilteredItemsCache[_currentCategory];
|
return FilteredItemsCache[_currentCategory];
|
||||||
@@ -230,6 +242,19 @@ namespace Glamaholic.Ui {
|
|||||||
|
|
||||||
ImGui.TextUnformatted(label);
|
ImGui.TextUnformatted(label);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(2, 2));
|
||||||
|
if (ImGui.Button($"?##info-{label}", new Vector2(20, 20))) {
|
||||||
|
if (selectedItem.HasValue) {
|
||||||
|
Interop.AT.OpenMoreInformationSub(selectedItem.Value.RowId.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered()) {
|
||||||
|
ImGui.SetTooltip("Click to see item location");
|
||||||
|
}
|
||||||
|
|
||||||
var drawCursor = ImGui.GetCursorScreenPos();
|
var drawCursor = ImGui.GetCursorScreenPos();
|
||||||
var slotSize = SelectedGearIconSize + SelectedGearPaddingSize;
|
var slotSize = SelectedGearIconSize + SelectedGearPaddingSize;
|
||||||
var borderColour = *ImGui.GetStyleColorVec4(ImGuiCol.Border);
|
var borderColour = *ImGui.GetStyleColorVec4(ImGuiCol.Border);
|
||||||
@@ -274,6 +299,7 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui.PopItemWidth();
|
ImGui.PopItemWidth();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ImGui.SetCursorPos(cursorAfter);
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
ImGui.TextUnformatted("(empty)");
|
ImGui.TextUnformatted("(empty)");
|
||||||
@@ -282,6 +308,9 @@ namespace Glamaholic.Ui {
|
|||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw glasses/bonus slot
|
||||||
|
DrawGlassesSlot();
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
|
|
||||||
@@ -294,6 +323,64 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe void DrawGlassesSlot() {
|
||||||
|
ImGui.TextUnformatted("Glasses");
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(2, 2));
|
||||||
|
if (ImGui.Button("?##info-Glasses", new Vector2(20, 20))) {
|
||||||
|
if (SelectedGlasses.HasValue) {
|
||||||
|
Interop.AT.OpenMoreInformationSub(SelectedGlasses.Value.RowId.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered()) {
|
||||||
|
ImGui.SetTooltip("Click to see item location");
|
||||||
|
}
|
||||||
|
|
||||||
|
var drawCursor = ImGui.GetCursorScreenPos();
|
||||||
|
var slotSize = SelectedGearIconSize + SelectedGearPaddingSize;
|
||||||
|
var borderColour = *ImGui.GetStyleColorVec4(ImGuiCol.Border);
|
||||||
|
|
||||||
|
ImGui.GetWindowDrawList().AddRect(
|
||||||
|
drawCursor,
|
||||||
|
drawCursor + new Vector2(slotSize),
|
||||||
|
ImGui.ColorConvertFloat4ToU32(borderColour)
|
||||||
|
);
|
||||||
|
|
||||||
|
var cursorBefore = ImGui.GetCursorPos();
|
||||||
|
ImGui.InvisibleButton("gear-slot Glasses", new Vector2(slotSize));
|
||||||
|
var cursorAfter = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) {
|
||||||
|
SelectedGlasses = null;
|
||||||
|
// Remove glasses from character (item ID 0 means remove/nothing)
|
||||||
|
Interop.Glamourer.SetBonusItem(0, ApiBonusSlot.Glasses, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedGlasses != null) {
|
||||||
|
try {
|
||||||
|
var icon = this.Ui.GetIcon((uint)SelectedGlasses.Value.Icon);
|
||||||
|
if (icon != null) {
|
||||||
|
ImGui.SetCursorPos(cursorBefore + new Vector2(SelectedGearPaddingSize / 2f));
|
||||||
|
ImGui.Image(icon.Handle, new Vector2(SelectedGearIconSize));
|
||||||
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Icon not found, skip rendering it
|
||||||
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TextUnformatted(SelectedGlasses.Value.Singular.ExtractText());
|
||||||
|
} else {
|
||||||
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
|
ImGui.TextUnformatted("(empty)");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe bool DrawDyeCombo(string id, Dictionary<ItemCategory, byte> stainDict, ItemCategory category, bool isPrimary) {
|
private unsafe bool DrawDyeCombo(string id, Dictionary<ItemCategory, byte> stainDict, ItemCategory category, bool isPrimary) {
|
||||||
var allStains = DataCache.AllStains.Value;
|
var allStains = DataCache.AllStains.Value;
|
||||||
var currentStain = stainDict[category];
|
var currentStain = stainDict[category];
|
||||||
@@ -457,6 +544,11 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply glasses if selected
|
||||||
|
if (SelectedGlasses.HasValue) {
|
||||||
|
Interop.Glamourer.SetBonusItem(playerIndex, Glamourer.Api.Enums.ApiBonusSlot.Glasses, SelectedGlasses.Value.RowId);
|
||||||
|
}
|
||||||
|
|
||||||
Service.ChatGui.Print("[Glamour Browser] Gear applied to character!");
|
Service.ChatGui.Print("[Glamour Browser] Gear applied to character!");
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Service.Log.Error(ex, "Failed to apply gear to character");
|
Service.Log.Error(ex, "Failed to apply gear to character");
|
||||||
@@ -471,6 +563,7 @@ namespace Glamaholic.Ui {
|
|||||||
DrawTabButton("Gloves", ItemCategory.Gloves);
|
DrawTabButton("Gloves", ItemCategory.Gloves);
|
||||||
DrawTabButton("Bottom", ItemCategory.Legs);
|
DrawTabButton("Bottom", ItemCategory.Legs);
|
||||||
DrawTabButton("Shoes", ItemCategory.Feet);
|
DrawTabButton("Shoes", ItemCategory.Feet);
|
||||||
|
DrawTabButton("Glasses", ItemCategory.Glasses);
|
||||||
|
|
||||||
ImGui.EndTabBar();
|
ImGui.EndTabBar();
|
||||||
}
|
}
|
||||||
@@ -494,7 +587,129 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawGlassesGrid() {
|
||||||
|
var glassesItems = DataCache.GlassesItems.Value;
|
||||||
|
var filteredGlasses = string.IsNullOrEmpty(this._itemFilter)
|
||||||
|
? glassesItems
|
||||||
|
: glassesItems.Where(item => item.Singular.ExtractText().ToLowerInvariant().Contains(this._itemFilter.ToLowerInvariant()));
|
||||||
|
|
||||||
|
var glassesList = filteredGlasses.ToList();
|
||||||
|
|
||||||
|
if (glassesList.Count == 0) {
|
||||||
|
ImGui.TextDisabled("No glasses found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset scroll if category changed
|
||||||
|
if (_currentCategory != _previousCategory) {
|
||||||
|
ImGui.SetScrollY(0);
|
||||||
|
_previousCategory = _currentCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ImGui.BeginTable("glasses grid", ItemsPerRow, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoKeepColumnsVisible)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Virtual scrolling
|
||||||
|
var scrollY = ImGui.GetScrollY();
|
||||||
|
var visibleHeight = ImGui.GetContentRegionAvail().Y;
|
||||||
|
|
||||||
|
var totalRows = (glassesList.Count + ItemsPerRow - 1) / ItemsPerRow;
|
||||||
|
var firstVisibleRow = Math.Max(0, (int)(scrollY / ItemHeight));
|
||||||
|
var lastVisibleRow = Math.Min(totalRows, firstVisibleRow + (int)((visibleHeight / ItemHeight) + 2));
|
||||||
|
|
||||||
|
if (firstVisibleRow > 0) {
|
||||||
|
ImGui.TableNextRow(ImGuiTableRowFlags.None, ItemHeight * firstVisibleRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row = firstVisibleRow; row < lastVisibleRow; row++) {
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
|
||||||
|
for (int col = 0; col < ItemsPerRow; col++) {
|
||||||
|
var itemIndex = row * ItemsPerRow + col;
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
if (itemIndex < glassesList.Count) {
|
||||||
|
this.DrawGlassesIcon(glassesList[itemIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTable();
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.TextDisabled($"Showing {glassesList.Count} glasses");
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void DrawGlassesIcon(Glasses glasses) {
|
||||||
|
var drawCursor = ImGui.GetCursorScreenPos();
|
||||||
|
var iconSize = IconSize;
|
||||||
|
var paddingSize = PaddingSize;
|
||||||
|
|
||||||
|
ImGui.BeginGroup();
|
||||||
|
|
||||||
|
var borderColour = *ImGui.GetStyleColorVec4(ImGuiCol.Border);
|
||||||
|
ImGui.GetWindowDrawList().AddRect(
|
||||||
|
drawCursor,
|
||||||
|
drawCursor + new Vector2(iconSize + paddingSize),
|
||||||
|
ImGui.ColorConvertFloat4ToU32(borderColour)
|
||||||
|
);
|
||||||
|
|
||||||
|
var cursorBefore = ImGui.GetCursorPos();
|
||||||
|
ImGui.InvisibleButton($"glasses {glasses.RowId}", new Vector2(iconSize + paddingSize));
|
||||||
|
var cursorAfter = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var icon = this.Ui.GetIcon((uint)glasses.Icon);
|
||||||
|
if (icon != null) {
|
||||||
|
ImGui.SetCursorPos(cursorBefore + new Vector2(paddingSize / 2f));
|
||||||
|
ImGui.Image(icon.Handle, new Vector2(iconSize));
|
||||||
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Icon not found, skip rendering it
|
||||||
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndGroup();
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered()) {
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.TextUnformatted($"ID: {glasses.RowId}");
|
||||||
|
ImGui.TextUnformatted($"Name: {glasses.Singular.ExtractText()}");
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) {
|
||||||
|
SelectedGlasses = glasses;
|
||||||
|
this.ApplyGlassesToCharacter(glasses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyGlassesToCharacter(Glasses glasses) {
|
||||||
|
if (Service.ObjectTable.LocalPlayer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Interop.Glamourer.IsAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int playerIndex = Service.ObjectTable.LocalPlayer.ObjectIndex;
|
||||||
|
Interop.Glamourer.SetBonusItem(playerIndex, Glamourer.Api.Enums.ApiBonusSlot.Glasses, glasses.RowId);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Service.Log.Error(ex, "Failed to apply glasses to character");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawItemGrid() {
|
private void DrawItemGrid() {
|
||||||
|
// Handle glasses separately
|
||||||
|
if (_currentCategory == ItemCategory.Glasses) {
|
||||||
|
DrawGlassesGrid();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var filteredItems = GetFilteredItems();
|
var filteredItems = GetFilteredItems();
|
||||||
|
|
||||||
if (filteredItems.Count == 0) {
|
if (filteredItems.Count == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user