This commit is contained in:
Ottermandias 2023-07-03 16:39:52 +02:00
parent 60443f6a53
commit 5c003d8cd4
14 changed files with 566 additions and 198 deletions

View file

@ -2,22 +2,32 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using Dalamud.Interface;
using Glamourer.Automation;
using Glamourer.Customization;
using Glamourer.Designs;
using Glamourer.Interop;
using Glamourer.Services;
using Glamourer.Structs;
using Glamourer.Unlocks;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
using Penumbra.GameData.Enums;
using Action = System.Action;
namespace Glamourer.Gui.Tabs.AutomationTab;
public class SetPanel
{
private readonly AutoDesignManager _manager;
private readonly SetSelector _selector;
private readonly AutoDesignManager _manager;
private readonly SetSelector _selector;
private readonly ItemUnlockManager _itemUnlocks;
private readonly CustomizeUnlockManager _customizeUnlocks;
private readonly CustomizationService _customizations;
private readonly DesignCombo _designCombo;
private readonly JobGroupCombo _jobGroupCombo;
@ -27,12 +37,16 @@ public class SetPanel
private Action? _endAction;
public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs)
public SetPanel(SetSelector selector, AutoDesignManager manager, DesignManager designs, JobService jobs, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, CustomizationService customizations)
{
_selector = selector;
_manager = manager;
_designCombo = new DesignCombo(_manager, designs);
_jobGroupCombo = new JobGroupCombo(manager, jobs);
_selector = selector;
_manager = manager;
_itemUnlocks = itemUnlocks;
_customizeUnlocks = customizeUnlocks;
_customizations = customizations;
_designCombo = new DesignCombo(_manager, designs);
_jobGroupCombo = new JobGroupCombo(manager, jobs);
}
private AutoDesignSet Selection
@ -92,7 +106,7 @@ public class SetPanel
private void DrawDesignTable()
{
using var table = ImRaii.Table("SetTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY);
using var table = ImRaii.Table("SetTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY);
if (!table)
return;
@ -101,6 +115,7 @@ public class SetPanel
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, 5 * ImGui.GetFrameHeight() + 4 * 2 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Job Restrictions", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Warnings", ImGuiTableColumnFlags.WidthFixed, 4 * ImGui.GetFrameHeight() + 3 * 2 * ImGuiHelpers.GlobalScale);
ImGui.TableHeadersRow();
foreach (var (design, idx) in Selection.Designs.WithIndex())
@ -120,6 +135,8 @@ public class SetPanel
DrawApplicationTypeBoxes(Selection, design, idx);
ImGui.TableNextColumn();
_jobGroupCombo.Draw(Selection, design, idx);
ImGui.TableNextColumn();
DrawWarnings(design, idx);
}
ImGui.TableNextColumn();
@ -135,6 +152,79 @@ public class SetPanel
_endAction = null;
}
private void DrawWarnings(AutoDesign design, int idx)
{
var size = new Vector2(ImGui.GetFrameHeight());
size.X += ImGuiHelpers.GlobalScale;
var (equipFlags, customizeFlags, _, _, _, _) = design.ApplyWhat();
equipFlags &= design.Design.ApplyEquip;
customizeFlags &= design.Design.ApplyCustomize;
var sb = new StringBuilder();
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
{
var flag = slot.ToFlag();
if (!equipFlags.HasFlag(flag))
continue;
var item = design.Design.DesignData.Item(slot);
if (!_itemUnlocks.IsUnlocked(item.Id, out _))
sb.AppendLine($"{item.Name} in {slot.ToName()} slot is not unlocked but should be applied.");
}
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(2 * ImGuiHelpers.GlobalScale, 0));
static void DrawWarning(StringBuilder sb, uint color, Vector2 size, string suffix, string good)
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
if (sb.Length > 0)
{
sb.Append(suffix);
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
{
ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color);
}
ImGuiUtil.HoverTooltip(sb.ToString());
}
else
{
ImGuiUtil.DrawTextButton(string.Empty, size, 0);
ImGuiUtil.HoverTooltip(good);
}
}
DrawWarning(sb, 0xA03030F0, size, "\nThese items will be skipped when applied automatically. To change this, see",
"All equipment to be applied is unlocked."); // TODO
sb.Clear();
var sb2 = new StringBuilder();
var customize = design.Design.DesignData.Customize;
var set = _customizations.AwaitedService.GetList(customize.Clan, customize.Gender);
foreach (var type in CustomizationExtensions.All)
{
var flag = type.ToFlag();
if (!customizeFlags.HasFlag(flag))
continue;
if (flag.RequiresRedraw())
sb.AppendLine($"{type.ToDefaultName()} Customization can not be changed automatically."); // TODO
else if (type is CustomizeIndex.Hairstyle or CustomizeIndex.FacePaint
&& set.DataByValue(type, customize[type], out var data, customize.Face) >= 0
&& !_customizeUnlocks.IsUnlocked(data!.Value, out _))
sb2.AppendLine(
$"{type.ToDefaultName()} Customization {_customizeUnlocks.Unlockable[data.Value].Name} is not unlocked but should be applied.");
}
ImGui.SameLine();
DrawWarning(sb2, 0xA03030F0, size, "\nThese customizations will be skipped when applied automatically. To change this, see",
"All customizations to be applied are unlocked."); // TODO
ImGui.SameLine();
DrawWarning(sb, 0xA030F0F0, size, "\nThese customizations will be skipped when applied automatically.",
"No customizations unable to be applied automatically are set to be applied."); // TODO
}
private void DrawDragDrop(AutoDesignSet set, int index)
{
const string dragDropLabel = "DesignDragDrop";

View file

@ -6,8 +6,11 @@ using Glamourer.Customization;
using Glamourer.Services;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Tabs.UnlocksTab;
@ -18,55 +21,110 @@ public class UnlockOverview
private readonly CustomizationService _customizations;
private readonly CustomizeUnlockManager _customizeUnlocks;
private readonly PenumbraChangedItemTooltip _tooltip;
private readonly TextureCache _textureCache;
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
private FullEquipType _selected1 = FullEquipType.Unknown;
private SubRace _selected2 = SubRace.Unknown;
private Gender _selected3 = Gender.Unknown;
private void DrawSelector()
{
using var child = ImRaii.Child("Selector", new Vector2(200 * ImGuiHelpers.GlobalScale, -1), true);
if (!child)
return;
foreach (var type in Enum.GetValues<FullEquipType>())
{
if (type.IsOffhandType() || !_items.ItemService.AwaitedService.TryGetValue(type, out var items) || items.Count == 0)
continue;
if (ImGui.Selectable(type.ToName(), _selected1 == type))
{
ClearIcons(_selected1);
_selected1 = type;
_selected2 = SubRace.Unknown;
_selected3 = Gender.Unknown;
}
}
foreach (var clan in _customizations.AwaitedService.Clans)
{
foreach (var gender in _customizations.AwaitedService.Genders)
{
if (_customizations.AwaitedService.GetList(clan, gender).HairStyles.Count == 0)
continue;
if (ImGui.Selectable($"{(gender is Gender.Male ? '♂' : '♀')} {clan.ToShortName()} Hair & Paint",
_selected2 == clan && _selected3 == gender))
{
ClearIcons(_selected1);
_selected1 = FullEquipType.Unknown;
_selected2 = clan;
_selected3 = gender;
}
}
}
}
private void ClearIcons(FullEquipType type)
{
if (!_items.ItemService.AwaitedService.TryGetValue(type, out var items))
return;
foreach (var item in items)
_customizations.AwaitedService.RemoveIcon(item.IconId);
}
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip)
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureCache textureCache)
{
_items = items;
_customizations = customizations;
_itemUnlocks = itemUnlocks;
_customizeUnlocks = customizeUnlocks;
_tooltip = tooltip;
_textureCache = textureCache;
}
public void Draw()
{
using var color = ImRaii.PushColor(ImGuiCol.Border, ImGui.GetColorU32(ImGuiCol.TableBorderStrong));
DrawSelector();
ImGui.SameLine();
DrawPanel();
}
private void DrawPanel()
{
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);
}
if (_selected1 is not FullEquipType.Unknown)
DrawItems();
else if (_selected2 is not SubRace.Unknown && _selected3 is not Gender.Unknown)
DrawCustomizations();
}
private void DrawCustomizationHeader(Vector2 iconSize, SubRace subRace, Gender gender)
private void DrawCustomizations()
{
var set = _customizations.AwaitedService.GetList(subRace, gender);
if (set.HairStyles.Count == 0 && set.FacePaints.Count == 0)
return;
var set = _customizations.AwaitedService.GetList(_selected2, _selected3);
if (!ImGui.CollapsingHeader($"Unlockable {subRace.ToName()} {gender.ToName()} Customizations"))
return;
var spacing = IconSpacing;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
var iconSize = ImGuiHelpers.ScaledVector2(128);
var iconsPerRow = IconsPerRow(iconSize.X, spacing.X);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
foreach (var customization in set.HairStyles.Concat(set.FacePaints))
var counter = 0;
foreach (var customize in set.HairStyles.Concat(set.FacePaints))
{
if (!_customizeUnlocks.Unlockable.TryGetValue(customization, out var unlockData))
if (!_customizeUnlocks.Unlockable.TryGetValue(customize, out var unlockData))
continue;
var unlocked = _customizeUnlocks.IsUnlocked(customization, out var time);
var icon = _customizations.AwaitedService.GetIcon(customization.IconId);
var unlocked = _customizeUnlocks.IsUnlocked(customize, out var time);
var icon = _customizations.AwaitedService.GetIcon(customize.IconId);
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint);
if (ImGui.IsItemHovered())
@ -76,37 +134,44 @@ public class UnlockOverview
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($"{customize.Index.ToDefaultName()} {customize.Value.Value}");
ImGui.TextUnformatted(unlocked ? $"Unlocked on {time:g}" : "Not unlocked.");
}
ImGui.SameLine();
if (ImGui.GetContentRegionAvail().X < iconSize.X)
ImGui.NewLine();
if (counter != iconsPerRow - 1)
{
ImGui.SameLine();
++counter;
}
else
{
counter = 0;
}
}
if (ImGui.GetCursorPosX() != 0)
ImGui.NewLine();
}
private void DrawEquipTypeHeader(Vector2 iconSize, FullEquipType type)
private void DrawItems()
{
if (type.IsOffhandType() || !_items.ItemService.AwaitedService.TryGetValue(type, out var items) || items.Count == 0)
if (!_items.ItemService.AwaitedService.TryGetValue(_selected1, out var items))
return;
if (!ImGui.CollapsingHeader($"{type.ToName()}s"))
return;
var spacing = IconSpacing;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
var iconSize = ImGuiHelpers.ScaledVector2(64);
var iconsPerRow = IconsPerRow(iconSize.X, spacing.X);
var numRows = (items.Count + iconsPerRow - 1) / iconsPerRow;
var numVisibleRows = (int)(Math.Ceiling(ImGui.GetContentRegionAvail().Y / (iconSize.Y + spacing.Y)) + 0.5f);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(2 * ImGuiHelpers.GlobalScale));
foreach (var item in items)
void DrawItem(EquipItem item)
{
if (!ImGui.IsItemVisible())
{ }
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
var iconHandle = _textureCache.LoadIcon(item.IconId);
if (!iconHandle.HasValue)
return;
var unlocked = _itemUnlocks.IsUnlocked(item.Id, out var time);
var icon = _customizations.AwaitedService.GetIcon(item.IconId);
var (icon, size) = iconHandle.Value.Value;
ImGui.Image(icon.ImGuiHandle, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint);
ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One, unlocked ? Vector4.One : UnavailableTint);
if (ImGui.IsItemClicked())
{
// TODO link
@ -117,10 +182,9 @@ public class UnlockOverview
if (ImGui.IsItemHovered())
{
using var tt = ImRaii.Tooltip();
var size = new Vector2(icon.Width, icon.Height);
using var tt = ImRaii.Tooltip();
if (size.X >= iconSize.X && size.Y >= iconSize.Y)
ImGui.Image(icon.ImGuiHandle, size);
ImGui.Image(icon, size);
ImGui.TextUnformatted(item.Name);
var slot = item.Type.ToSlot();
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
@ -133,13 +197,35 @@ public class UnlockOverview
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();
var skips = ImGuiClip.GetNecessarySkips(iconSize.Y + spacing.Y);
var end = Math.Min(numVisibleRows * iconsPerRow + skips * iconsPerRow, items.Count);
var counter = 0;
for (var idx = skips * iconsPerRow; idx < end; ++idx)
{
DrawItem(items[idx]);
if (counter != iconsPerRow - 1)
{
ImGui.SameLine();
++counter;
}
else
{
counter = 0;
}
}
if (ImGui.GetCursorPosX() != 0)
ImGui.NewLine();
var remainder = numRows - numVisibleRows - skips;
if (remainder > 0)
ImGuiClip.DrawEndDummy(remainder, iconSize.Y + spacing.Y);
}
private static Vector2 IconSpacing
=> ImGuiHelpers.ScaledVector2(2);
private static int IconsPerRow(float iconWidth, float iconSpacing)
=> (int)(ImGui.GetContentRegionAvail().X / (iconWidth + iconSpacing));
}

View file

@ -3,13 +3,14 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Interface;
using Glamourer.Events;
using Glamourer.Services;
using Glamourer.Structs;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Table;
using Penumbra.GameData.Enums;
@ -17,35 +18,43 @@ using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Tabs.UnlocksTab;
public class UnlockTable : Table<EquipItem>
public class UnlockTable : Table<EquipItem>, IDisposable
{
public UnlockTable(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip)
private readonly ObjectUnlocked _event;
public UnlockTable(ItemManager items, TextureCache cache, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event)
: 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..." })
new NameColumn(cache, 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..." })
{
_event = @event;
Sortable = true;
Flags |= ImGuiTableFlags.Hideable;
_event.Subscribe(OnObjectUnlock, ObjectUnlocked.Priority.UnlockTable);
cache.Logger = Glamourer.Log;
}
public void Dispose()
=> _event.Unsubscribe(OnObjectUnlock);
private sealed class NameColumn : ColumnString<EquipItem>
{
private readonly CustomizationService _customizations;
private readonly TextureCache _textures;
private readonly PenumbraChangedItemTooltip _tooltip;
public override float Width
=> 400 * ImGuiHelpers.GlobalScale;
public NameColumn(CustomizationService customizations, PenumbraChangedItemTooltip tooltip)
public NameColumn(TextureCache textures, PenumbraChangedItemTooltip tooltip)
{
_customizations = customizations;
_tooltip = tooltip;
Flags |= ImGuiTableColumnFlags.NoHide | ImGuiTableColumnFlags.NoReorder;
_textures = textures;
_tooltip = tooltip;
Flags |= ImGuiTableColumnFlags.NoHide | ImGuiTableColumnFlags.NoReorder;
}
public override string ToName(EquipItem item)
@ -53,8 +62,11 @@ public class UnlockTable : Table<EquipItem>
public override void DrawColumn(EquipItem item, int _)
{
var icon = _customizations.AwaitedService.GetIcon(item.IconId);
ImGui.Image(icon.ImGuiHandle, new Vector2(ImGui.GetFrameHeight()));
var iconHandle = _textures.LoadIcon(item.IconId);
if (iconHandle.HasValue)
ImGuiUtil.HoverIcon(iconHandle.Value, new Vector2(ImGui.GetFrameHeight()));
else
ImGui.Dummy(new Vector2(ImGui.GetFrameHeight()));
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
if (ImGui.Selectable(item.Name))
@ -191,7 +203,7 @@ public class UnlockTable : Table<EquipItem>
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 unlockedRhs = _unlocks.IsUnlocked(rhs.Id, out var timeRhs);
var c1 = unlockedLhs.CompareTo(unlockedRhs);
return c1 != 0 ? c1 : timeLhs.CompareTo(timeRhs);
}
@ -273,4 +285,10 @@ public class UnlockTable : Table<EquipItem>
public int Count
=> _items.ItemService.AwaitedService.TotalItemCount(true);
}
private void OnObjectUnlock(ObjectUnlocked.Type _1, uint _2, DateTimeOffset _3)
{
FilterDirty = true;
SortDirty = true;
}
}