mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-20 14:37:46 +01:00
.
This commit is contained in:
parent
b63b02ae5e
commit
60443f6a53
17 changed files with 970 additions and 225 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
145
Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs
Normal file
145
Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
276
Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs
Normal file
276
Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
60
Glamourer/Gui/Tabs/UnlocksTab/UnlocksTab.cs
Normal file
60
Glamourer/Gui/Tabs/UnlocksTab/UnlocksTab.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue