This commit is contained in:
Ottermandias 2023-07-02 15:34:27 +02:00
parent b63b02ae5e
commit 60443f6a53
17 changed files with 970 additions and 225 deletions

View file

@ -6,6 +6,7 @@ using Glamourer.Gui.Tabs;
using Glamourer.Gui.Tabs.ActorTab;
using Glamourer.Gui.Tabs.AutomationTab;
using Glamourer.Gui.Tabs.DesignTab;
using Glamourer.Gui.Tabs.UnlocksTab;
using ImGuiNET;
using OtterGui.Custom;
using OtterGui.Widgets;
@ -22,6 +23,7 @@ public class MainWindow : Window
Actors = 2,
Designs = 3,
Automation = 4,
Unlocks = 5,
}
private readonly Configuration _config;
@ -32,11 +34,12 @@ public class MainWindow : Window
public readonly DebugTab Debug;
public readonly DesignTab Designs;
public readonly AutomationTab Automation;
public readonly UnlocksTab Unlocks;
public TabType SelectTab = TabType.None;
public MainWindow(DalamudPluginInterface pi, Configuration config, SettingsTab settings, ActorTab actors, DesignTab designs,
DebugTab debugTab, AutomationTab automation)
DebugTab debugTab, AutomationTab automation, UnlocksTab unlocks)
: base(GetLabel())
{
pi.UiBuilder.DisableGposeUiHide = true;
@ -50,6 +53,7 @@ public class MainWindow : Window
Designs = designs;
Automation = automation;
Debug = debugTab;
Unlocks = unlocks;
_config = config;
_tabs = new ITab[]
{
@ -57,6 +61,7 @@ public class MainWindow : Window
actors,
designs,
automation,
unlocks,
debugTab,
};
@ -81,6 +86,7 @@ public class MainWindow : Window
TabType.Actors => Actors.Label,
TabType.Designs => Designs.Label,
TabType.Automation => Automation.Label,
TabType.Unlocks => Unlocks.Label,
_ => ReadOnlySpan<byte>.Empty,
};
@ -91,6 +97,7 @@ public class MainWindow : Window
if (label == Designs.Label) return TabType.Designs;
if (label == Settings.Label) return TabType.Settings;
if (label == Automation.Label) return TabType.Automation;
if (label == Unlocks.Label) return TabType.Unlocks;
if (label == Debug.Label) return TabType.Debug;
// @formatter:on
return TabType.None;

View file

@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Glamourer.Events;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.Services;
using Glamourer.State;
using Glamourer.Structs;
using ImGuiNET;
using OtterGui.Raii;
using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
@ -45,10 +48,115 @@ public class PenumbraChangedItemTooltip : IDisposable
_penumbra.Click -= OnPenumbraClick;
}
public bool Player()
=> _objects.Player.Valid;
public bool Player([NotNullWhen(true)] out ActorState? player)
{
var (identifier, data) = _objects.PlayerData;
if (!data.Valid || !_stateManager.GetOrCreate(identifier, data.Objects[0], out player))
{
player = null;
return false;
}
return true;
}
public void CreateTooltip(EquipItem item, string prefix, bool openTooltip)
{
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)
{
case EquipSlot.MainHand when !CanApplyWeapon(EquipSlot.MainHand, item):
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
break;
case EquipSlot.RFinger:
using (var tt = !openTooltip ? null : ImRaii.Tooltip())
{
ImGui.TextUnformatted($"{prefix}Right-Click to apply to current actor (Right Finger).");
ImGui.TextUnformatted($"{prefix}Shift + Right-Click to apply to current actor (Left Finger).");
if (last.Valid)
ImGui.TextUnformatted(
$"{prefix}Control + Right-Click to re-apply {last.Name} to current actor (Right Finger).");
var last2 = _lastItems[EquipSlot.LFinger.ToIndex()];
if (last2.Valid)
ImGui.TextUnformatted(
$"{prefix}Shift + Control + Right-Click to re-apply {last.Name} to current actor (Left Finger).");
}
break;
default:
using (var tt = !openTooltip ? null : ImRaii.Tooltip())
{
ImGui.TextUnformatted($"{prefix}Right-Click to apply to current actor.");
if (last.Valid)
ImGui.TextUnformatted($"{prefix}Control + Right-Click to re-apply {last.Name} to current actor.");
}
break;
}
}
public void ApplyItem(ActorState state, EquipItem item)
{
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)
{
case EquipSlot.MainHand when !CanApplyWeapon(EquipSlot.MainHand, item):
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
break;
case EquipSlot.RFinger:
switch (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift)
{
case (false, false):
Glamourer.Log.Information($"Applying {item.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, item, state);
_stateManager.ChangeItem(state, EquipSlot.RFinger, item, StateChanged.Source.Manual);
break;
case (false, true):
Glamourer.Log.Information($"Applying {item.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, item, state);
_stateManager.ChangeItem(state, EquipSlot.LFinger, item, StateChanged.Source.Manual);
break;
case (true, false) when last.Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, default, state);
_stateManager.ChangeItem(state, EquipSlot.RFinger, last, StateChanged.Source.Manual);
break;
case (true, true) when _lastItems[EquipSlot.LFinger.ToIndex()].Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, default, state);
_stateManager.ChangeItem(state, EquipSlot.LFinger, last, StateChanged.Source.Manual);
break;
}
return;
default:
if (ImGui.GetIO().KeyCtrl && last.Valid)
{
Glamourer.Log.Information($"Re-Applying {last.Name} to {slot.ToName()}.");
SetLastItem(slot, default, state);
_stateManager.ChangeItem(state, slot, last, StateChanged.Source.Manual);
}
else
{
Glamourer.Log.Information($"Applying {item.Name} to {slot.ToName()}.");
SetLastItem(slot, item, state);
_stateManager.ChangeItem(state, slot, item, StateChanged.Source.Manual);
}
return;
}
}
private void OnPenumbraTooltip(ChangedItemType type, uint id)
{
LastTooltip = DateTime.UtcNow;
if (!_objects.Player.Valid)
if (!Player())
return;
switch (type)
@ -57,33 +165,7 @@ public class PenumbraChangedItemTooltip : IDisposable
if (!_items.ItemService.AwaitedService.TryGetValue(id, out var item))
return;
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)
{
case EquipSlot.MainHand when !CanApplyWeapon(EquipSlot.MainHand, item):
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
break;
case EquipSlot.RFinger:
ImGui.TextUnformatted("[Glamourer] Right-Click to apply to current actor (Right Finger).");
ImGui.TextUnformatted("[Glamourer] Shift + Right-Click to apply to current actor (Left Finger).");
if (last.Valid)
ImGui.TextUnformatted(
$"[Glamourer] Control + Right-Click to re-apply {last.Name} to current actor (Right Finger).");
var last2 = _lastItems[EquipSlot.LFinger.ToIndex()];
if (last2.Valid)
ImGui.TextUnformatted(
$"[Glamourer] Shift + Control + Right-Click to re-apply {last.Name} to current actor (Left Finger).");
break;
default:
ImGui.TextUnformatted("[Glamourer] Right-Click to apply to current actor.");
if (last.Valid)
ImGui.TextUnformatted($"[Glamourer] Control + Right-Click to re-apply {last.Name} to current actor.");
break;
}
CreateTooltip(item, "[Glamourer] ", false);
return;
}
}
@ -107,60 +189,13 @@ public class PenumbraChangedItemTooltip : IDisposable
if (button is not MouseButton.Right)
return;
var (identifier, data) = _objects.PlayerData;
if (!data.Valid)
return;
if (!_stateManager.GetOrCreate(identifier, data.Objects[0], out var state))
if (!Player(out var state))
return;
if (!_items.ItemService.AwaitedService.TryGetValue(id, out var item))
return;
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)
{
case EquipSlot.MainHand when !CanApplyWeapon(EquipSlot.MainHand, item):
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
break;
case EquipSlot.RFinger:
switch (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift)
{
case (false, false):
Glamourer.Log.Information($"Applying {item.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, item, state);
break;
case (false, true):
Glamourer.Log.Information($"Applying {item.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, item, state);
break;
case (true, false) when last.Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, default, state);
break;
case (true, true) when _lastItems[EquipSlot.LFinger.ToIndex()].Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, default, state);
break;
}
return;
default:
if (ImGui.GetIO().KeyCtrl && last.Valid)
{
Glamourer.Log.Information($"Re-Applying {last.Name} to {slot.ToName()}.");
SetLastItem(slot, default, state);
}
else
{
Glamourer.Log.Information($"Applying {item.Name} to {slot.ToName()}.");
SetLastItem(slot, item, state);
}
return;
}
ApplyItem(state, item);
return;
}
}

View file

@ -42,7 +42,7 @@ public unsafe class DebugTab : ITab
private readonly ObjectTable _objects;
private readonly ObjectManager _objectManager;
private readonly GlamourerIpc _ipc;
private readonly PhrasingService _phrasing;
private readonly CodeService _code;
private readonly ItemManager _items;
private readonly ActorService _actors;
@ -69,7 +69,7 @@ public unsafe class DebugTab : ITab
ActorService actors, ItemManager items, CustomizationService customization, ObjectManager objectManager,
DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config,
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
AutoDesignManager autoDesignManager, JobService jobs, PhrasingService phrasing, CustomizeUnlockManager customizeUnlocks,
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
ItemUnlockManager itemUnlocks)
{
_changeCustomizeService = changeCustomizeService;
@ -92,7 +92,7 @@ public unsafe class DebugTab : ITab
_pluginInterface = pluginInterface;
_autoDesignManager = autoDesignManager;
_jobs = jobs;
_phrasing = phrasing;
_code = code;
_customizeUnlocks = customizeUnlocks;
_itemUnlocks = itemUnlocks;
}
@ -1190,8 +1190,6 @@ public unsafe class DebugTab : ITab
if (!ImGui.CollapsingHeader("Auto Designs"))
return;
DrawPhrasingService();
foreach (var (set, idx) in _autoDesignManager.WithIndex())
{
using var id = ImRaii.PushId(idx);
@ -1223,24 +1221,6 @@ public unsafe class DebugTab : ITab
}
}
private void DrawPhrasingService()
{
using var tree = ImRaii.TreeNode("Phrasing");
if (!tree)
return;
using var table = ImRaii.Table("phrasing", 3, ImGuiTableFlags.SizingFixedFit);
if (!table)
return;
ImGuiUtil.DrawTableColumn("Phrasing 1");
ImGuiUtil.DrawTableColumn(_config.Phrasing1);
ImGuiUtil.DrawTableColumn(_phrasing.Phrasing1.ToString());
ImGuiUtil.DrawTableColumn("Phrasing 2");
ImGuiUtil.DrawTableColumn(_config.Phrasing2);
ImGuiUtil.DrawTableColumn(_phrasing.Phrasing2.ToString());
}
#endregion
#region Unlocks
@ -1279,7 +1259,7 @@ public unsafe class DebugTab : ITab
ImGuiUtil.DrawTableColumn(t.Value.Data.ToString());
ImGuiUtil.DrawTableColumn(t.Value.Name);
ImGuiUtil.DrawTableColumn(_customizeUnlocks.IsUnlocked(t.Key, out var time)
? time == DateTimeOffset.MaxValue
? time == DateTimeOffset.MinValue
? "Always"
: time.LocalDateTime.ToString("g")
: "Never");
@ -1325,7 +1305,7 @@ public unsafe class DebugTab : ITab
}
ImGuiUtil.DrawTableColumn(_itemUnlocks.IsUnlocked(t.Key, out var time)
? time == DateTimeOffset.MaxValue
? time == DateTimeOffset.MinValue
? "Always"
: time.LocalDateTime.ToString("g")
: "Never");
@ -1372,7 +1352,7 @@ public unsafe class DebugTab : ITab
}
ImGuiUtil.DrawTableColumn(_itemUnlocks.IsUnlocked(t.Key, out var time)
? time == DateTimeOffset.MaxValue
? time == DateTimeOffset.MinValue
? "Always"
: time.LocalDateTime.ToString("g")
: "Never");

View file

@ -1,4 +1,5 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using Dalamud.Interface;
using Glamourer.Gui.Tabs.DesignTab;
@ -17,24 +18,24 @@ public class SettingsTab : ITab
private readonly Configuration _config;
private readonly DesignFileSystemSelector _selector;
private readonly StateListener _stateListener;
private readonly PhrasingService _phrasingService;
private readonly CodeService _codeService;
private readonly PenumbraAutoRedraw _autoRedraw;
public SettingsTab(Configuration config, DesignFileSystemSelector selector, StateListener stateListener,
PhrasingService phrasingService, PenumbraAutoRedraw autoRedraw)
CodeService codeService, PenumbraAutoRedraw autoRedraw)
{
_config = config;
_selector = selector;
_stateListener = stateListener;
_phrasingService = phrasingService;
_autoRedraw = autoRedraw;
_config = config;
_selector = selector;
_stateListener = stateListener;
_codeService = codeService;
_autoRedraw = autoRedraw;
}
public ReadOnlySpan<byte> Label
=> "Settings"u8;
private string? _tmpPhrasing1 = null;
private string? _tmpPhrasing2 = null;
private string _currentCode = string.Empty;
public void DrawContent()
{
@ -62,27 +63,46 @@ public class SettingsTab : ITab
Checkbox("Debug Mode", "Show the debug tab. Only useful for debugging or advanced use.", _config.DebugMode, v => _config.DebugMode = v);
DrawColorSettings();
_tmpPhrasing1 ??= _config.Phrasing1;
ImGui.InputText("Phrasing 1", ref _tmpPhrasing1, 512);
if (ImGui.IsItemDeactivatedAfterEdit())
{
_phrasingService.SetPhrasing1(_tmpPhrasing1);
_tmpPhrasing1 = null;
}
_tmpPhrasing2 ??= _config.Phrasing2;
ImGui.InputText("Phrasing 2", ref _tmpPhrasing2, 512);
if (ImGui.IsItemDeactivatedAfterEdit())
{
_phrasingService.SetPhrasing2(_tmpPhrasing2);
_tmpPhrasing2 = null;
}
DrawCodes();
MainWindow.DrawSupportButtons();
}
private void DrawCodes()
{
if (!ImGui.CollapsingHeader("Codes"))
return;
using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, _currentCode.Length > 0))
{
var color = _codeService.CheckCode(_currentCode) != null ? ColorId.ActorAvailable : ColorId.ActorUnavailable;
using var c = ImRaii.PushColor(ImGuiCol.Border, color.Value(), _currentCode.Length > 0);
if (ImGui.InputTextWithHint("##Code", "Enter Code...", ref _currentCode, 512, ImGuiInputTextFlags.EnterReturnsTrue))
{
if (_codeService.AddCode(_currentCode))
_currentCode = string.Empty;
}
}
if (_config.Codes.Count <= 0)
return;
for (var i = 0; i < _config.Codes.Count; ++i)
{
var (code, state) = _config.Codes[i];
var action = _codeService.CheckCode(code);
if (action == null)
continue;
if (ImGui.Checkbox(code, ref state))
{
action(state);
_config.Codes[i] = (code, state);
_config.Save();
}
}
}
/// <summary> Draw the entire Color subsection. </summary>
private void DrawColorSettings()
{

View file

@ -0,0 +1,145 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Customization;
using Glamourer.Services;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
namespace Glamourer.Gui.Tabs.UnlocksTab;
public class UnlockOverview
{
private readonly ItemManager _items;
private readonly ItemUnlockManager _itemUnlocks;
private readonly CustomizationService _customizations;
private readonly CustomizeUnlockManager _customizeUnlocks;
private readonly PenumbraChangedItemTooltip _tooltip;
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip)
{
_items = items;
_customizations = customizations;
_itemUnlocks = itemUnlocks;
_customizeUnlocks = customizeUnlocks;
_tooltip = tooltip;
}
public void Draw()
{
using var color = ImRaii.PushColor(ImGuiCol.Border, ImGui.GetColorU32(ImGuiCol.TableBorderStrong));
using var child = ImRaii.Child("Panel", -Vector2.One, true);
if (!child)
return;
var iconSize = ImGuiHelpers.ScaledVector2(32);
foreach (var type in Enum.GetValues<FullEquipType>())
DrawEquipTypeHeader(iconSize, type);
iconSize = ImGuiHelpers.ScaledVector2(64);
foreach (var gender in _customizations.AwaitedService.Genders)
{
foreach (var clan in _customizations.AwaitedService.Clans)
DrawCustomizationHeader(iconSize, clan, gender);
}
}
private void DrawCustomizationHeader(Vector2 iconSize, SubRace subRace, Gender gender)
{
var set = _customizations.AwaitedService.GetList(subRace, gender);
if (set.HairStyles.Count == 0 && set.FacePaints.Count == 0)
return;
if (!ImGui.CollapsingHeader($"Unlockable {subRace.ToName()} {gender.ToName()} Customizations"))
return;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
foreach (var customization in set.HairStyles.Concat(set.FacePaints))
{
if (!_customizeUnlocks.Unlockable.TryGetValue(customization, out var unlockData))
continue;
var unlocked = _customizeUnlocks.IsUnlocked(customization, out var time);
var icon = _customizations.AwaitedService.GetIcon(customization.IconId);
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint);
if (ImGui.IsItemHovered())
{
using var tt = ImRaii.Tooltip();
var size = new Vector2(icon.Width, icon.Height);
if (size.X >= iconSize.X && size.Y >= iconSize.Y)
ImGui.Image(icon.ImGuiHandle, size);
ImGui.TextUnformatted(unlockData.Name);
ImGui.TextUnformatted($"{customization.Index.ToDefaultName()} {customization.Value.Value}");
ImGui.TextUnformatted(unlocked ? $"Unlocked on {time:g}" : "Not unlocked.");
}
ImGui.SameLine();
if (ImGui.GetContentRegionAvail().X < iconSize.X)
ImGui.NewLine();
}
if (ImGui.GetCursorPosX() != 0)
ImGui.NewLine();
}
private void DrawEquipTypeHeader(Vector2 iconSize, FullEquipType type)
{
if (type.IsOffhandType() || !_items.ItemService.AwaitedService.TryGetValue(type, out var items) || items.Count == 0)
return;
if (!ImGui.CollapsingHeader($"{type.ToName()}s"))
return;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(2 * ImGuiHelpers.GlobalScale));
foreach (var item in items)
{
if (!ImGui.IsItemVisible())
{ }
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
var icon = _customizations.AwaitedService.GetIcon(item.IconId);
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint);
if (ImGui.IsItemClicked())
{
// TODO link
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _tooltip.Player(out var state))
_tooltip.ApplyItem(state, item);
if (ImGui.IsItemHovered())
{
using var tt = ImRaii.Tooltip();
var size = new Vector2(icon.Width, icon.Height);
if (size.X >= iconSize.X && size.Y >= iconSize.Y)
ImGui.Image(icon.ImGuiHandle, size);
ImGui.TextUnformatted(item.Name);
var slot = item.Type.ToSlot();
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
if (item.Type.Offhand().IsOffhandType())
ImGui.TextUnformatted(
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.Id, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
else
ImGui.TextUnformatted(slot is EquipSlot.MainHand ? $"{item.Weapon()}" : $"{item.Armor()}");
ImGui.TextUnformatted(
unlocked ? time == DateTimeOffset.MinValue ? "Always Unlocked" : $"Unlocked on {time:g}" : "Not Unlocked.");
_tooltip.CreateTooltip(item, string.Empty, false);
}
ImGui.SameLine();
if (ImGui.GetContentRegionAvail().X < iconSize.X)
ImGui.NewLine();
}
if (ImGui.GetCursorPosX() != 0)
ImGui.NewLine();
}
}

View file

@ -0,0 +1,276 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Interface;
using Glamourer.Services;
using Glamourer.Structs;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Table;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Tabs.UnlocksTab;
public class UnlockTable : Table<EquipItem>
{
public UnlockTable(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip)
: base("ItemUnlockTable", new ItemList(items),
new NameColumn(customizations, tooltip) { Label = "Item Name..." },
new SlotColumn() { Label = "Equip Slot" },
new TypeColumn() { Label = "Item Type..." },
new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" },
new ItemIdColumn() { Label = "Item Id..." },
new ModelDataColumn(items) { Label = "Model Data..." })
{
Sortable = true;
Flags |= ImGuiTableFlags.Hideable;
}
private sealed class NameColumn : ColumnString<EquipItem>
{
private readonly CustomizationService _customizations;
private readonly PenumbraChangedItemTooltip _tooltip;
public override float Width
=> 400 * ImGuiHelpers.GlobalScale;
public NameColumn(CustomizationService customizations, PenumbraChangedItemTooltip tooltip)
{
_customizations = customizations;
_tooltip = tooltip;
Flags |= ImGuiTableColumnFlags.NoHide | ImGuiTableColumnFlags.NoReorder;
}
public override string ToName(EquipItem item)
=> item.Name;
public override void DrawColumn(EquipItem item, int _)
{
var icon = _customizations.AwaitedService.GetIcon(item.IconId);
ImGui.Image(icon.ImGuiHandle, new Vector2(ImGui.GetFrameHeight()));
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
if (ImGui.Selectable(item.Name))
{
// TODO link
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _tooltip.Player(out var state))
_tooltip.ApplyItem(state, item);
if (ImGui.IsItemHovered() && _tooltip.Player())
_tooltip.CreateTooltip(item, string.Empty, true);
}
}
private sealed class TypeColumn : ColumnString<EquipItem>
{
public override float Width
=> ImGui.CalcTextSize(FullEquipType.CrossPeinHammer.ToName()).X;
public override string ToName(EquipItem item)
=> item.Type.ToName();
public override void DrawColumn(EquipItem item, int _)
{
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(item.Type.ToName());
}
public override int Compare(EquipItem lhs, EquipItem rhs)
=> lhs.Type.CompareTo(rhs.Type);
}
private sealed class SlotColumn : ColumnFlags<EquipFlag, EquipItem>
{
public override float Width
=> ImGui.CalcTextSize("Equip Slotmm").X;
private EquipFlag _filterValue;
public SlotColumn()
{
AllFlags = Values.Aggregate((a, b) => a | b);
_filterValue = AllFlags;
}
public override void DrawColumn(EquipItem item, int idx)
{
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(ToString(item.Type.ToSlot()));
}
public override EquipFlag FilterValue
=> _filterValue;
protected override IReadOnlyList<EquipFlag> Values
=> new[]
{
EquipFlag.Mainhand,
EquipFlag.Offhand,
EquipFlag.Head,
EquipFlag.Body,
EquipFlag.Hands,
EquipFlag.Legs,
EquipFlag.Feet,
EquipFlag.Ears,
EquipFlag.Neck,
EquipFlag.Wrist,
EquipFlag.RFinger,
};
protected override string[] Names
=> new[]
{
ToString(EquipSlot.MainHand),
ToString(EquipSlot.OffHand),
ToString(EquipSlot.Head),
ToString(EquipSlot.Body),
ToString(EquipSlot.Hands),
ToString(EquipSlot.Legs),
ToString(EquipSlot.Feet),
ToString(EquipSlot.Ears),
ToString(EquipSlot.Neck),
ToString(EquipSlot.Wrists),
ToString(EquipSlot.RFinger),
};
protected override void SetValue(EquipFlag value, bool enable)
=> _filterValue = enable ? _filterValue | value : _filterValue & ~value;
public override int Compare(EquipItem lhs, EquipItem rhs)
=> lhs.Type.ToSlot().CompareTo(rhs.Type.ToSlot());
public override bool FilterFunc(EquipItem item)
=> _filterValue.HasFlag(item.Type.ToSlot().ToFlag());
private static string ToString(EquipSlot slot)
=> slot switch
{
EquipSlot.MainHand => "Mainhand",
EquipSlot.OffHand => "Offhand",
EquipSlot.Head => "Head",
EquipSlot.Body => "Body",
EquipSlot.Hands => "Hands",
EquipSlot.Legs => "Legs",
EquipSlot.Feet => "Feet",
EquipSlot.Ears => "Ears",
EquipSlot.Neck => "Neck",
EquipSlot.Wrists => "Wrists",
EquipSlot.RFinger => "Finger",
_ => string.Empty,
};
}
private sealed class UnlockDateColumn : Column<EquipItem>
{
private readonly ItemUnlockManager _unlocks;
public override float Width
=> 110 * ImGuiHelpers.GlobalScale;
public UnlockDateColumn(ItemUnlockManager unlocks)
=> _unlocks = unlocks;
public override void DrawColumn(EquipItem item, int idx)
{
if (!_unlocks.IsUnlocked(item.Id, out var time))
return;
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(time == DateTimeOffset.MinValue ? "Always" : time.ToString("g"));
}
public override int Compare(EquipItem lhs, EquipItem rhs)
{
var unlockedLhs = _unlocks.IsUnlocked(lhs.Id, out var timeLhs);
var unlockedRhs = _unlocks.IsUnlocked(lhs.Id, out var timeRhs);
var c1 = unlockedLhs.CompareTo(unlockedRhs);
return c1 != 0 ? c1 : timeLhs.CompareTo(timeRhs);
}
}
private sealed class ItemIdColumn : ColumnString<EquipItem>
{
public override float Width
=> 70 * ImGuiHelpers.GlobalScale;
public override int Compare(EquipItem lhs, EquipItem rhs)
=> lhs.Id.CompareTo(rhs.Id);
public override string ToName(EquipItem item)
=> item.Id.ToString();
public override void DrawColumn(EquipItem item, int _)
{
ImGui.AlignTextToFramePadding();
ImGuiUtil.RightAlign(item.Id.ToString());
}
}
private sealed class ModelDataColumn : ColumnString<EquipItem>
{
private readonly ItemManager _items;
public override float Width
=> 100 * ImGuiHelpers.GlobalScale;
public ModelDataColumn(ItemManager items)
=> _items = items;
public override void DrawColumn(EquipItem item, int _)
{
ImGui.AlignTextToFramePadding();
ImGuiUtil.RightAlign(item.ModelString);
if (ImGui.IsItemHovered()
&& item.Type.Offhand().IsOffhandType()
&& _items.ItemService.AwaitedService.TryGetValue(item.Id, false, out var offhand))
{
using var tt = ImRaii.Tooltip();
ImGui.TextUnformatted("Offhand: " + offhand.ModelString);
}
}
public override int Compare(EquipItem lhs, EquipItem rhs)
=> lhs.Weapon().Value.CompareTo(rhs.Weapon().Value);
public override bool FilterFunc(EquipItem item)
{
if (FilterValue.Length == 0)
return true;
if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase))
return true;
if (item.Type.Offhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.Id, false, out var offhand))
return FilterRegex?.IsMatch(offhand.ModelString)
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);
return false;
}
}
private sealed class ItemList : IReadOnlyCollection<EquipItem>
{
private readonly ItemManager _items;
public ItemList(ItemManager items)
=> _items = items;
public IEnumerator<EquipItem> GetEnumerator()
=> _items.ItemService.AwaitedService.AllItems(true).Select(i => i.Item2).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
public int Count
=> _items.ItemService.AwaitedService.TotalItemCount(true);
}
}

View file

@ -0,0 +1,60 @@
using System;
using System.Numerics;
using Dalamud.Interface;
using ImGuiNET;
using OtterGui.Raii;
using OtterGui;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.UnlocksTab;
public class UnlocksTab : ITab
{
private readonly Configuration _config;
private readonly UnlockOverview _overview;
private readonly UnlockTable _table;
public UnlocksTab(Configuration config, UnlockOverview overview, UnlockTable table)
{
_config = config;
_overview = overview;
_table = table;
}
private bool DetailMode
{
get => _config.UnlockDetailMode;
set
{
_config.UnlockDetailMode = value;
_config.Save();
}
}
public ReadOnlySpan<byte> Label
=> "Unlocks"u8;
public void DrawContent()
{
DrawTypeSelection();
if (DetailMode)
_table.Draw(ImGui.GetFrameHeightWithSpacing());
else
_overview.Draw();
}
private void DrawTypeSelection()
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
var buttonSize = new Vector2(ImGui.GetContentRegionAvail().X / 2, ImGui.GetFrameHeight());
if (ImGuiUtil.DrawDisabledButton("Overview Mode", buttonSize, "Show tinted icons of sets of unlocks.", !DetailMode))
DetailMode = false;
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton("Detailed Mode", buttonSize, "Show all unlockable data as a combined filterable and sortable table.",
DetailMode))
DetailMode = true;
}
}