mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-22 23:47:45 +01:00
Current state.
This commit is contained in:
parent
0d4f7777f0
commit
06e1fb2a3b
33 changed files with 934 additions and 928 deletions
|
|
@ -2,23 +2,27 @@
|
|||
using Glamourer.Gui;
|
||||
using Glamourer.Services;
|
||||
using Luna;
|
||||
using Luna.Generators;
|
||||
using Newtonsoft.Json;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
public class EphemeralConfig : ISavable
|
||||
public partial class EphemeralConfig : ISavable
|
||||
{
|
||||
public int Version { get; set; } = Configuration.Constants.CurrentVersion;
|
||||
public bool IncognitoMode { get; set; } = false;
|
||||
public bool UnlockDetailMode { get; set; } = true;
|
||||
public bool ShowDesignQuickBar { get; set; } = false;
|
||||
public bool LockDesignQuickBar { get; set; } = false;
|
||||
public bool LockMainWindow { get; set; } = false;
|
||||
public MainTabType SelectedMainTab { get; set; } = MainTabType.Settings;
|
||||
public Guid SelectedDesign { get; set; } = Guid.Empty;
|
||||
public Guid SelectedQuickDesign { get; set; } = Guid.Empty;
|
||||
public int LastSeenVersion { get; set; } = GlamourerChangelog.LastChangelogVersion;
|
||||
public int Version { get; set; } = Configuration.Constants.CurrentVersion;
|
||||
|
||||
[ConfigProperty]
|
||||
private bool _incognitoMode;
|
||||
|
||||
public bool UnlockDetailMode { get; set; } = true;
|
||||
public bool ShowDesignQuickBar { get; set; } = false;
|
||||
public bool LockDesignQuickBar { get; set; } = false;
|
||||
public bool LockMainWindow { get; set; } = false;
|
||||
public MainTabType SelectedMainTab { get; set; } = MainTabType.Settings;
|
||||
public Guid SelectedDesign { get; set; } = Guid.Empty;
|
||||
public Guid SelectedQuickDesign { get; set; } = Guid.Empty;
|
||||
public int LastSeenVersion { get; set; } = GlamourerChangelog.LastChangelogVersion;
|
||||
|
||||
public float CurrentDesignSelectorWidth { get; set; } = 200f;
|
||||
public float DesignSelectorMinimumScale { get; set; } = 0.1f;
|
||||
|
|
@ -70,9 +74,9 @@ public class EphemeralConfig : ISavable
|
|||
|
||||
public void Save(StreamWriter writer)
|
||||
{
|
||||
using var jWriter = new JsonTextWriter(writer);
|
||||
using var jWriter = new JsonTextWriter(writer);
|
||||
jWriter.Formatting = Formatting.Indented;
|
||||
var serializer = new JsonSerializer { Formatting = Formatting.Indented };
|
||||
var serializer = new JsonSerializer { Formatting = Formatting.Indented };
|
||||
serializer.Serialize(jWriter, this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public partial class CustomizationDrawer
|
|||
}
|
||||
|
||||
if (hasIcon)
|
||||
Im.Tooltip.ImageOnHover(wrap!.Id, wrap.Size);
|
||||
Im.Tooltip.ImageOnHover(wrap!.Id, wrap!.Size);
|
||||
|
||||
Im.Line.Same();
|
||||
using (Im.Group())
|
||||
|
|
@ -221,7 +221,7 @@ public partial class CustomizationDrawer
|
|||
}
|
||||
|
||||
if (hasIcon)
|
||||
Im.Tooltip.ImageOnHover(wrap!.Id, wrap.Size);
|
||||
Im.Tooltip.ImageOnHover(wrap!.Id, wrap!.Size);
|
||||
if (idx % 4 is not 3)
|
||||
Im.Line.Same();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,9 +92,6 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, s
|
|||
DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignCombo);
|
||||
}
|
||||
|
||||
public bool Incognito
|
||||
=> Config.IncognitoMode;
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
DesignChanged.Unsubscribe(OnDesignChanged);
|
||||
|
|
@ -168,7 +165,7 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, s
|
|||
}
|
||||
|
||||
protected override string ToString(Tuple<IDesignStandIn, string> obj)
|
||||
=> obj.Item1.ResolveName(Incognito);
|
||||
=> obj.Item1.ResolveName(Config.IncognitoMode);
|
||||
|
||||
protected override float GetFilterWidth()
|
||||
=> InnerWidth - 2 * Im.Style.FramePadding.X;
|
||||
|
|
@ -294,7 +291,7 @@ public abstract class DesignCombo : DesignComboBase
|
|||
=> CurrentSelection?.Item1;
|
||||
|
||||
public void Draw(float width)
|
||||
=> Draw(Design, Design?.ResolveName(Incognito) ?? string.Empty, width);
|
||||
=> Draw(Design, Design?.ResolveName(Config.IncognitoMode) ?? string.Empty, width);
|
||||
}
|
||||
|
||||
public sealed class QuickDesignCombo : DesignCombo
|
||||
|
|
@ -392,11 +389,11 @@ public sealed class RandomDesignCombo(
|
|||
public bool Draw(RandomPredicate.Exact exact, float width)
|
||||
{
|
||||
var design = GetDesign(exact);
|
||||
return Draw(design, design?.ResolveName(Incognito) ?? $"Not Found [{exact.Value.Text}]", width);
|
||||
return Draw(design, design?.ResolveName(Config.IncognitoMode) ?? $"Not Found [{exact.Value.Text}]", width);
|
||||
}
|
||||
|
||||
public bool Draw(IDesignStandIn? design, float width)
|
||||
=> Draw(design, design?.ResolveName(Incognito) ?? string.Empty, width);
|
||||
=> Draw(design, design?.ResolveName(Config.IncognitoMode) ?? string.Empty, width);
|
||||
}
|
||||
|
||||
public sealed class SpecialDesignCombo(
|
||||
|
|
@ -419,7 +416,7 @@ public sealed class SpecialDesignCombo(
|
|||
{
|
||||
public void Draw(AutoDesignSet set, AutoDesign? design, int autoDesignIndex)
|
||||
{
|
||||
if (!Draw(design?.Design, design?.Design.ResolveName(Incognito), Im.ContentRegion.Available.X))
|
||||
if (!Draw(design?.Design, design?.Design.ResolveName(Config.IncognitoMode), Im.ContentRegion.Available.X))
|
||||
return;
|
||||
|
||||
if (autoDesignIndex >= 0)
|
||||
|
|
|
|||
119
Glamourer/Gui/Equipment/BaseItemCombo.cs
Normal file
119
Glamourer/Gui/Equipment/BaseItemCombo.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImSharp;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public abstract class BaseItemCombo(FavoriteManager favorites, ItemManager items) : FilterComboBase<BaseItemCombo.CacheItem>(new ItemFilter())
|
||||
{
|
||||
public abstract StringU8 Label { get; }
|
||||
|
||||
protected readonly FavoriteManager Favorites = favorites;
|
||||
protected readonly ItemManager Items = items;
|
||||
protected EquipItem CurrentItem;
|
||||
protected PrimaryId CustomSetId;
|
||||
protected SecondaryId CustomWeaponId;
|
||||
protected Variant CustomVariant;
|
||||
|
||||
public bool Draw(in EquipItem item, out EquipItem newItem, float width)
|
||||
{
|
||||
using var id = Im.Id.Push(Label);
|
||||
CurrentItem = item;
|
||||
CustomVariant = 0;
|
||||
if (Draw(StringU8.Empty, item.Name, StringU8.Empty, width, out var cache))
|
||||
{
|
||||
newItem = cache.Item;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CustomVariant.Id is not 0 && Identify(out newItem))
|
||||
return true;
|
||||
|
||||
newItem = item;
|
||||
return false;
|
||||
}
|
||||
|
||||
public readonly struct CacheItem(EquipItem item) : IDisposable
|
||||
{
|
||||
public readonly EquipItem Item = item;
|
||||
public readonly StringPair Name = new(item.Name);
|
||||
public readonly SizedStringPair Model = new($"({item.PrimaryId.Id}-{item.Variant.Id})");
|
||||
|
||||
public void Dispose()
|
||||
=> Model.Dispose();
|
||||
}
|
||||
|
||||
protected sealed class ItemFilter : PartwiseFilterBase<CacheItem>
|
||||
{
|
||||
public override bool WouldBeVisible(in CacheItem item, int globalIndex)
|
||||
=> base.WouldBeVisible(in item, globalIndex) || WouldBeVisible(item.Model.Utf16);
|
||||
|
||||
protected override string ToFilterString(in CacheItem item, int globalIndex)
|
||||
=> item.Name.Utf16;
|
||||
}
|
||||
|
||||
protected override FilterComboBaseCache<CacheItem> CreateCache()
|
||||
=> new Cache(this);
|
||||
|
||||
protected sealed class Cache(FilterComboBase<CacheItem> parent) : FilterComboBaseCache<CacheItem>(parent)
|
||||
{
|
||||
private static EquipItem _longestItem;
|
||||
|
||||
protected override void ComputeWidth()
|
||||
{
|
||||
if (!_longestItem.Valid)
|
||||
{
|
||||
var data = ((BaseItemCombo)Parent).Items.ItemData;
|
||||
_longestItem = data.AllItems(true).Concat(data.AllItems(false))
|
||||
.MaxBy(i => Im.Font.CalculateSize($"{i.Item2.Name} ({i.Item2.ModelString})").X).Item2;
|
||||
}
|
||||
|
||||
ComboWidth = Im.Font.CalculateSize($"{_longestItem.Name} ({_longestItem.Name})").X
|
||||
+ Im.Style.FrameHeight
|
||||
+ Im.Style.ItemSpacing.X * 3;
|
||||
}
|
||||
}
|
||||
|
||||
protected override float ItemHeight
|
||||
=> Im.Style.FrameHeightWithSpacing;
|
||||
|
||||
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
||||
{
|
||||
UiHelpers.DrawFavoriteStar(Favorites, item.Item);
|
||||
Im.Line.Same();
|
||||
var ret = Im.Selectable(item.Name.Utf8, selected);
|
||||
Im.Line.Same();
|
||||
using var color = ImGuiColor.Text.Push(Rgba32.Gray);
|
||||
ImEx.TextRightAligned(item.Model);
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override void EnterPressed()
|
||||
{
|
||||
if (!Im.Io.KeyControl)
|
||||
return;
|
||||
|
||||
var split = ((ItemFilter)Filter).Text.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
switch (split.Length)
|
||||
{
|
||||
case 2 when ushort.TryParse(split[0], out var setId) && byte.TryParse(split[1], out var variant):
|
||||
CustomSetId = setId;
|
||||
CustomVariant = variant;
|
||||
break;
|
||||
case 3 when ushort.TryParse(split[0], out var setId)
|
||||
&& ushort.TryParse(split[1], out var weaponId)
|
||||
&& byte.TryParse(split[2], out var variant):
|
||||
CustomSetId = setId;
|
||||
CustomWeaponId = weaponId;
|
||||
CustomVariant = variant;
|
||||
break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool Identify(out EquipItem item);
|
||||
|
||||
protected override bool IsSelected(CacheItem item, int globalIndex)
|
||||
=> item.Item.Id == CurrentItem.Id;
|
||||
}
|
||||
|
|
@ -1,66 +1,32 @@
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Addon = Lumina.Excel.Sheets.Addon;
|
||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public sealed class BonusItemCombo2(IDataManager gameData, ItemManager items, FavoriteManager favorites, BonusItemFlag slot)
|
||||
: ImSharp.FilterComboBase<BonusItemCombo2.CacheItem>(new ItemFilter())
|
||||
public sealed class BonusItemCombo(FavoriteManager favorites, ItemManager items, IDataManager gameData, BonusItemFlag slot)
|
||||
: BaseItemCombo(favorites, items)
|
||||
{
|
||||
public readonly StringU8 Label = GetLabel(gameData, slot);
|
||||
public readonly BonusItemFlag Slot = slot;
|
||||
public override StringU8 Label { get; } = GetLabel(gameData, slot);
|
||||
public readonly BonusItemFlag Slot = slot;
|
||||
|
||||
public readonly struct CacheItem(EquipItem item) : IDisposable
|
||||
protected override bool Identify(out EquipItem item)
|
||||
{
|
||||
public readonly EquipItem Item = item;
|
||||
public readonly StringPair Name = new(item.Name);
|
||||
public readonly SizedString Model = new($"({item.PrimaryId.Id}-{item.Variant.Id})");
|
||||
|
||||
public void Dispose()
|
||||
=> Model.Dispose();
|
||||
}
|
||||
|
||||
private sealed class ItemFilter : PartwiseFilterBase<CacheItem>
|
||||
{
|
||||
protected override string ToFilterString(in CacheItem item, int globalIndex)
|
||||
=> item.Name.Utf16;
|
||||
item = Items.Identify(Slot, CustomSetId, CustomVariant);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
{
|
||||
var nothing = EquipItem.BonusItemNothing(Slot);
|
||||
return items.ItemData.ByType[Slot.ToEquipType()].OrderByDescending(favorites.Contains).ThenBy(i => i.Id.Id).Prepend(nothing)
|
||||
return Items.ItemData.ByType[Slot.ToEquipType()].OrderByDescending(Favorites.Contains).ThenBy(i => i.Id.Id).Prepend(nothing)
|
||||
.Select(i => new CacheItem(i));
|
||||
}
|
||||
|
||||
protected override float ItemHeight
|
||||
=> Im.Style.TextHeightWithSpacing;
|
||||
|
||||
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
||||
{
|
||||
UiHelpers.DrawFavoriteStar(favorites, item.Item);
|
||||
Im.Line.Same();
|
||||
var ret = Im.Selectable(item.Name.Utf8, selected);
|
||||
Im.Line.Same();
|
||||
using var color = ImGuiColor.Text.Push(Rgba32.Gray);
|
||||
ImEx.TextRightAligned(item.Model);
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsSelected(CacheItem item, int globalIndex)
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
private static StringU8 GetLabel(IDataManager gameData, BonusItemFlag slot)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<Addon>()!;
|
||||
|
|
@ -74,109 +40,3 @@ public sealed class BonusItemCombo2(IDataManager gameData, ItemManager items, Fa
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BonusItemCombo : FilterComboCache<EquipItem>
|
||||
{
|
||||
private readonly FavoriteManager _favorites;
|
||||
public readonly string Label;
|
||||
private CustomItemId _currentItem;
|
||||
private float _innerWidth;
|
||||
|
||||
public PrimaryId CustomSetId { get; private set; }
|
||||
public Variant CustomVariant { get; private set; }
|
||||
|
||||
public BonusItemCombo(IDataManager gameData, ItemManager items, BonusItemFlag slot, Logger log, FavoriteManager favorites)
|
||||
: base(() => GetItems(favorites, items, slot), MouseWheelType.Control, log)
|
||||
{
|
||||
_favorites = favorites;
|
||||
Label = GetLabel(gameData, slot);
|
||||
_currentItem = 0;
|
||||
SearchByParts = true;
|
||||
}
|
||||
|
||||
protected override void DrawList(float width, float itemHeight)
|
||||
{
|
||||
base.DrawList(width, itemHeight);
|
||||
if (NewSelection != null && Items.Count > NewSelection.Value)
|
||||
CurrentSelection = Items[NewSelection.Value];
|
||||
}
|
||||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
if (CurrentSelection.Id == _currentItem)
|
||||
return currentSelected;
|
||||
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.Id == _currentItem);
|
||||
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
}
|
||||
|
||||
public bool Draw(string previewName, BonusItemId previewIdx, float width, float innerWidth)
|
||||
{
|
||||
_innerWidth = innerWidth;
|
||||
_currentItem = previewIdx;
|
||||
CustomVariant = 0;
|
||||
return Draw($"##{Label}", previewName, string.Empty, width, Im.Style.TextHeightWithSpacing);
|
||||
}
|
||||
|
||||
protected override float GetFilterWidth()
|
||||
=> _innerWidth - 2 * Im.Style.FramePadding.X;
|
||||
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
{
|
||||
var obj = Items[globalIdx];
|
||||
var name = ToString(obj);
|
||||
if (UiHelpers.DrawFavoriteStar(_favorites, obj) && CurrentSelectionIdx == globalIdx)
|
||||
{
|
||||
CurrentSelectionIdx = -1;
|
||||
_currentItem = obj.Id;
|
||||
CurrentSelection = default;
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
var ret = ImGui.Selectable(name, selected);
|
||||
Im.Line.Same();
|
||||
using var color = ImGuiColor.Text.Push(0xFF808080);
|
||||
ImGuiUtil.RightAlign($"({obj.PrimaryId.Id}-{obj.Variant.Id})");
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].PrimaryId.Id.ToString());
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
||||
private static string GetLabel(IDataManager gameData, BonusItemFlag slot)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<Addon>()!;
|
||||
|
||||
return slot switch
|
||||
{
|
||||
BonusItemFlag.Glasses => sheet.TryGetRow(16050, out var text) ? text.Text.ToString() : "Facewear",
|
||||
BonusItemFlag.UnkSlot => sheet.TryGetRow(16051, out var text) ? text.Text.ToString() : "Facewear",
|
||||
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private static List<EquipItem> GetItems(FavoriteManager favorites, ItemManager items, BonusItemFlag slot)
|
||||
{
|
||||
var nothing = EquipItem.BonusItemNothing(slot);
|
||||
return items.ItemData.ByType[slot.ToEquipType()].OrderByDescending(favorites.Contains).ThenBy(i => i.Id.Id).Prepend(nothing).ToList();
|
||||
}
|
||||
|
||||
protected override void OnClosePopup()
|
||||
{
|
||||
// If holding control while the popup closes, try to parse the input as a full pair of set id and variant, and set a custom item for that.
|
||||
if (!Im.Io.KeyControl)
|
||||
return;
|
||||
|
||||
var split = Filter.Text.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length != 2 || !ushort.TryParse(split[0], out var setId) || !byte.TryParse(split[1], out var variant))
|
||||
return;
|
||||
|
||||
CustomSetId = setId;
|
||||
CustomVariant = variant;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using Glamourer.Services;
|
|||
using Glamourer.Unlocks;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -19,7 +18,7 @@ public class EquipmentDrawer
|
|||
private readonly ItemManager _items;
|
||||
private readonly GlamourerColorCombo _stainCombo;
|
||||
private readonly DictStain _stainData;
|
||||
private readonly ItemCombo[] _itemCombo;
|
||||
private readonly EquipCombo[] _equipCombo;
|
||||
private readonly BonusItemCombo[] _bonusItemCombo;
|
||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||
private readonly TextureService _textures;
|
||||
|
|
@ -28,9 +27,6 @@ public class EquipmentDrawer
|
|||
private readonly AdvancedDyePopup _advancedDyes;
|
||||
private readonly ItemCopyService _itemCopy;
|
||||
|
||||
private float _requiredComboWidthUnscaled;
|
||||
private float _requiredComboWidth;
|
||||
|
||||
private Stain? _draggedStain;
|
||||
private EquipItemSlotCache _draggedItem;
|
||||
private EquipSlot _dragTarget;
|
||||
|
|
@ -46,18 +42,16 @@ public class EquipmentDrawer
|
|||
_itemCopy = itemCopy;
|
||||
_stainData = items.Stains;
|
||||
_stainCombo = new GlamourerColorCombo(_stainData, favorites);
|
||||
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log, favorites)).ToArray();
|
||||
_bonusItemCombo = BonusExtensions.AllFlags.Select(f => new BonusItemCombo(gameData, items, f, Glamourer.Log, favorites)).ToArray();
|
||||
_equipCombo = EquipSlotExtensions.EqdpSlots.Select(e => new EquipCombo(favorites, items, gameData, e)).ToArray();
|
||||
_bonusItemCombo = BonusExtensions.AllFlags.Select(f => new BonusItemCombo(favorites, items, gameData, f)).ToArray();
|
||||
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
|
||||
foreach (var type in FullEquipType.Values)
|
||||
{
|
||||
if (type.ToSlot() is EquipSlot.MainHand)
|
||||
_weaponCombo.TryAdd(type, new WeaponCombo(items, type, Glamourer.Log, favorites));
|
||||
else if (type.ToSlot() is EquipSlot.OffHand)
|
||||
_weaponCombo.TryAdd(type, new WeaponCombo(items, type, Glamourer.Log, favorites));
|
||||
if (type.ToSlot() is EquipSlot.MainHand or EquipSlot.OffHand)
|
||||
_weaponCombo.TryAdd(type, new WeaponCombo(favorites, items, type));
|
||||
}
|
||||
|
||||
_weaponCombo.Add(FullEquipType.Unknown, new WeaponCombo(items, FullEquipType.Unknown, Glamourer.Log, favorites));
|
||||
_weaponCombo.Add(FullEquipType.Unknown, new WeaponCombo(favorites, items, FullEquipType.Unknown));
|
||||
}
|
||||
|
||||
private Vector2 _iconSize;
|
||||
|
|
@ -66,15 +60,8 @@ public class EquipmentDrawer
|
|||
|
||||
public void Prepare()
|
||||
{
|
||||
_iconSize = new Vector2(2 * Im.Style.FrameHeight + Im.Style.ItemSpacing.Y);
|
||||
_comboLength = DefaultWidth * Im.Style.GlobalScale;
|
||||
if (_requiredComboWidthUnscaled is 0)
|
||||
_requiredComboWidthUnscaled = _items.ItemData.AllItems(true)
|
||||
.Concat(_items.ItemData.AllItems(false))
|
||||
.Max(i => Im.Font.CalculateSize($"{i.Item2.Name} ({i.Item2.ModelString})").X)
|
||||
/ Im.Style.GlobalScale;
|
||||
|
||||
_requiredComboWidth = _requiredComboWidthUnscaled * Im.Style.GlobalScale;
|
||||
_iconSize = new Vector2(2 * Im.Style.FrameHeight + Im.Style.ItemSpacing.Y);
|
||||
_comboLength = DefaultWidth * Im.Style.GlobalScale;
|
||||
_advancedMaterialColor = ColorId.AdvancedDyeActive.Value();
|
||||
_dragTarget = EquipSlot.Unknown;
|
||||
}
|
||||
|
|
@ -194,11 +181,11 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (equipDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot, equipDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot, equipDrawData.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
|
||||
if (VerifyRestrictedGear(equipDrawData))
|
||||
label += " (Restricted)";
|
||||
label += " (Restricted)"u8;
|
||||
|
||||
DrawEquipLabel(equipDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
}
|
||||
|
|
@ -216,7 +203,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (bonusDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot, bonusDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot, bonusDrawData.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
|
||||
DrawEquipLabel(bonusDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
|
|
@ -236,11 +223,11 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (mainhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand, mainhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand, mainhand.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
|
||||
if (allWeapons)
|
||||
mainhandLabel += $" ({mainhand.CurrentItem.Type.ToName()})";
|
||||
mainhandLabel = new StringU8($"{mainhandLabel} ({mainhand.CurrentItem.Type.ToName()})");
|
||||
WeaponHelpMarker(mainhand is { IsDesign: true, HasAdvancedDyes: true }, mainhandLabel);
|
||||
|
||||
if (offhand.CurrentItem.Type is FullEquipType.Unknown)
|
||||
|
|
@ -258,7 +245,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (offhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand, offhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand, offhand.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
|
||||
WeaponHelpMarker(offhand is { IsDesign: true, HasAdvancedDyes: true }, offhandLabel);
|
||||
|
|
@ -292,7 +279,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (equipDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot, equipDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(equipDrawData.Slot, equipDrawData.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
|
||||
if (VerifyRestrictedGear(equipDrawData))
|
||||
|
|
@ -316,7 +303,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (bonusDrawData.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot, bonusDrawData.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(bonusDrawData.Slot, bonusDrawData.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
|
||||
DrawEquipLabel(bonusDrawData is { IsDesign: true, HasAdvancedDyes: true }, label);
|
||||
|
|
@ -339,7 +326,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
|
||||
WeaponHelpMarker(mainhand is { IsDesign: true, HasAdvancedDyes: true }, mainhandLabel,
|
||||
allWeapons ? mainhand.CurrentItem.Type.ToName() : null);
|
||||
allWeapons ? new StringU8(mainhand.CurrentItem.Type.ToName()) : null);
|
||||
|
||||
DrawStain(mainhand, false);
|
||||
if (mainhand.DisplayApplication)
|
||||
|
|
@ -349,7 +336,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (mainhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand, mainhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(EquipSlot.MainHand, mainhand.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +366,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
else if (offhand.IsState)
|
||||
{
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand, offhand.HasAdvancedDyes ? _advancedMaterialColor : 0u);
|
||||
_advancedDyes.DrawButton(EquipSlot.OffHand, offhand.HasAdvancedDyes ? _advancedMaterialColor : ColorParameter.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -434,23 +421,20 @@ public class EquipmentDrawer
|
|||
}
|
||||
}
|
||||
|
||||
private void DrawItem(in EquipDrawData data, out string label, bool small, bool clear, bool open)
|
||||
private void DrawItem(in EquipDrawData data, out StringU8 label, bool small, bool clear, bool open)
|
||||
{
|
||||
Debug.Assert(data.Slot.IsEquipment() || data.Slot.IsAccessory(), $"Called {nameof(DrawItem)} on {data.Slot}.");
|
||||
|
||||
var combo = _itemCombo[data.Slot.ToIndex()];
|
||||
var combo = _equipCombo[data.Slot.ToIndex()];
|
||||
label = combo.Label;
|
||||
if (!data.Locked && open)
|
||||
UiHelpers.OpenCombo($"##{combo.Label}");
|
||||
|
||||
using var disabled = Im.Disabled(data.Locked);
|
||||
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.ItemId, small ? _comboLength - Im.Style.FrameHeight : _comboLength,
|
||||
_requiredComboWidth);
|
||||
var change = combo.Draw(data.CurrentItem, out var newItem, small ? _comboLength - Im.Style.FrameHeight : _comboLength);
|
||||
DrawGearDragDrop(data);
|
||||
if (change)
|
||||
data.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0)
|
||||
data.SetItem(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant));
|
||||
data.SetItem(newItem);
|
||||
_itemCopy.HandleCopyPaste(data);
|
||||
|
||||
if (ResetOrClear(data.Locked, clear, data.AllowRevert, true, data.CurrentItem, data.GameItem, ItemManager.NothingItem(data.Slot),
|
||||
|
|
@ -458,7 +442,7 @@ public class EquipmentDrawer
|
|||
data.SetItem(item);
|
||||
}
|
||||
|
||||
private void DrawBonusItem(in BonusDrawData data, out string label, bool small, bool clear, bool open)
|
||||
private void DrawBonusItem(in BonusDrawData data, out StringU8 label, bool small, bool clear, bool open)
|
||||
{
|
||||
var combo = _bonusItemCombo[data.Slot.ToIndex()];
|
||||
label = combo.Label;
|
||||
|
|
@ -466,21 +450,17 @@ public class EquipmentDrawer
|
|||
UiHelpers.OpenCombo($"##{combo.Label}");
|
||||
|
||||
using var disabled = Im.Disabled(data.Locked);
|
||||
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.Id.BonusItem,
|
||||
small ? _comboLength - Im.Style.FrameHeight : _comboLength,
|
||||
_requiredComboWidth);
|
||||
var change = combo.Draw(data.CurrentItem, out var newItem, small ? _comboLength - Im.Style.FrameHeight : _comboLength);
|
||||
if (Im.Item.Hovered() && Im.Io.KeyControl)
|
||||
{
|
||||
if (Im.Keyboard.IsPressed(Key.C))
|
||||
_itemCopy.Copy(combo.CurrentSelection);
|
||||
_itemCopy.Copy(newItem);
|
||||
else if (Im.Keyboard.IsPressed(Key.V))
|
||||
_itemCopy.Paste(data.Slot.ToEquipType(), data.SetItem);
|
||||
}
|
||||
|
||||
if (change)
|
||||
data.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0)
|
||||
data.SetItem(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant));
|
||||
data.SetItem(newItem);
|
||||
|
||||
if (ResetOrClear(data.Locked, clear, data.AllowRevert, true, data.CurrentItem, data.GameItem, EquipItem.BonusItemNothing(data.Slot),
|
||||
out var item))
|
||||
|
|
@ -563,12 +543,12 @@ public class EquipmentDrawer
|
|||
return clicked && valid;
|
||||
}
|
||||
|
||||
private void DrawMainhand(ref EquipDrawData mainhand, ref EquipDrawData offhand, out string label, bool drawAll, bool small,
|
||||
private void DrawMainhand(ref EquipDrawData mainhand, ref EquipDrawData offhand, out StringU8 label, bool drawAll, bool small,
|
||||
bool open)
|
||||
{
|
||||
if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : mainhand.CurrentItem.Type, out var combo))
|
||||
{
|
||||
label = string.Empty;
|
||||
label = StringU8.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -580,11 +560,8 @@ public class EquipmentDrawer
|
|||
{
|
||||
if (!mainhand.Locked && open)
|
||||
UiHelpers.OpenCombo($"##{label}");
|
||||
if (combo.Draw(mainhand.CurrentItem.Name, mainhand.CurrentItem.ItemId, small ? _comboLength - Im.Style.FrameHeight : _comboLength,
|
||||
_requiredComboWidth))
|
||||
changedItem = combo.CurrentSelection;
|
||||
else if (combo.CustomVariant.Id > 0 && (drawAll || ItemData.ConvertWeaponId(combo.CustomSetId) == mainhand.CurrentItem.Type))
|
||||
changedItem = _items.Identify(mainhand.Slot, combo.CustomSetId, combo.CustomWeaponId, combo.CustomVariant);
|
||||
if (combo.Draw(mainhand.CurrentItem, out var newItem, small ? _comboLength - Im.Style.FrameHeight : _comboLength))
|
||||
changedItem = newItem;
|
||||
_itemCopy.HandleCopyPaste(mainhand);
|
||||
DrawGearDragDrop(mainhand);
|
||||
|
||||
|
|
@ -610,11 +587,11 @@ public class EquipmentDrawer
|
|||
"The weapon type could not be identified, thus changing it to other weapons of that type is not possible."u8);
|
||||
}
|
||||
|
||||
private void DrawOffhand(in EquipDrawData mainhand, in EquipDrawData offhand, out string label, bool small, bool clear, bool open)
|
||||
private void DrawOffhand(in EquipDrawData mainhand, in EquipDrawData offhand, out StringU8 label, bool small, bool clear, bool open)
|
||||
{
|
||||
if (!_weaponCombo.TryGetValue(offhand.CurrentItem.Type, out var combo))
|
||||
{
|
||||
label = string.Empty;
|
||||
label = StringU8.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -624,11 +601,8 @@ public class EquipmentDrawer
|
|||
using var disabled = Im.Disabled(locked);
|
||||
if (!locked && open)
|
||||
UiHelpers.OpenCombo($"##{combo.Label}");
|
||||
if (combo.Draw(offhand.CurrentItem.Name, offhand.CurrentItem.ItemId, small ? _comboLength - Im.Style.FrameHeight : _comboLength,
|
||||
_requiredComboWidth))
|
||||
offhand.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0 && ItemData.ConvertWeaponId(combo.CustomSetId) == offhand.CurrentItem.Type)
|
||||
offhand.SetItem(_items.Identify(mainhand.Slot, combo.CustomSetId, combo.CustomWeaponId, combo.CustomVariant));
|
||||
if (combo.Draw(offhand.CurrentItem, out var newItem, small ? _comboLength - Im.Style.FrameHeight : _comboLength))
|
||||
offhand.SetItem(newItem);
|
||||
_itemCopy.HandleCopyPaste(offhand);
|
||||
DrawGearDragDrop(offhand);
|
||||
|
||||
|
|
@ -664,8 +638,9 @@ public class EquipmentDrawer
|
|||
|
||||
#endregion
|
||||
|
||||
private void WeaponHelpMarker(bool hasAdvancedDyes, string label, string? type = null)
|
||||
private void WeaponHelpMarker(bool hasAdvancedDyes, StringU8 label, StringU8? type = null)
|
||||
{
|
||||
Im.Line.SameInner();
|
||||
LunaStyle.DrawAlignedHelpMarker(
|
||||
"Changing weapons to weapons of different types can cause crashes, freezes, soft- and hard locks and cheating, "u8
|
||||
+ "thus it is only allowed to change weapons to other weapons of the same type."u8);
|
||||
|
|
@ -680,7 +655,7 @@ public class EquipmentDrawer
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
|
||||
private void DrawEquipLabel(bool hasAdvancedDyes, string label)
|
||||
private void DrawEquipLabel(bool hasAdvancedDyes, StringU8 label)
|
||||
{
|
||||
Im.Line.Same();
|
||||
using (ImGuiColor.Text.Push(_advancedMaterialColor, hasAdvancedDyes))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Glamourer.Gui.Equipment;
|
|||
public sealed class GlamourerColorCombo(DictStain stains, FavoriteManager favorites) : FilterComboColors
|
||||
{
|
||||
protected override float AdditionalSpace
|
||||
=> AwesomeIcon.Font.CalculateTextSize(LunaStyle.FavoriteIcon.Span).X + 4 * Im.Style.GlobalScale;
|
||||
=> AwesomeIcon.Font.CalculateTextSize(LunaStyle.FavoriteIcon.Span).X + 8 * Im.Style.GlobalScale;
|
||||
|
||||
protected override bool DrawItem(in Item item, int globalIndex, bool selected)
|
||||
{
|
||||
|
|
@ -17,7 +17,7 @@ public sealed class GlamourerColorCombo(DictStain stains, FavoriteManager favori
|
|||
Im.Dummy(AwesomeIcon.Font.CalculateTextSize(LunaStyle.FavoriteIcon.Span));
|
||||
else
|
||||
UiHelpers.DrawFavoriteStar(favorites, item.Id);
|
||||
Im.Line.Same(0, 4 * Im.Style.GlobalScale);
|
||||
Im.Line.Same(0, 8 * Im.Style.GlobalScale);
|
||||
|
||||
var buttonWidth = Im.ContentRegion.Available.X;
|
||||
var totalWidth = Im.ContentRegion.Maximum.X;
|
||||
|
|
|
|||
|
|
@ -1,135 +1,54 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using Lumina.Excel.Sheets;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public sealed class ItemCombo : FilterComboCache<EquipItem>
|
||||
public sealed class EquipCombo(FavoriteManager favorites, ItemManager items, IDataManager gameData, EquipSlot slot)
|
||||
: BaseItemCombo(favorites, items)
|
||||
{
|
||||
private readonly FavoriteManager _favorites;
|
||||
public readonly string Label;
|
||||
private ItemId _currentItem;
|
||||
private float _innerWidth;
|
||||
public override StringU8 Label { get; } = GetLabel(gameData, slot);
|
||||
public readonly EquipSlot Slot = slot;
|
||||
|
||||
public PrimaryId CustomSetId { get; private set; }
|
||||
public Variant CustomVariant { get; private set; }
|
||||
|
||||
public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot, Logger log, FavoriteManager favorites)
|
||||
: base(() => GetItems(favorites, items, slot), MouseWheelType.Control, log)
|
||||
protected override bool Identify(out EquipItem item)
|
||||
{
|
||||
_favorites = favorites;
|
||||
Label = GetLabel(gameData, slot);
|
||||
_currentItem = ItemManager.NothingId(slot);
|
||||
SearchByParts = true;
|
||||
item = Items.Identify(Slot, CustomSetId, CustomVariant);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void DrawList(float width, float itemHeight)
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
{
|
||||
base.DrawList(width, itemHeight);
|
||||
if (NewSelection != null && Items.Count > NewSelection.Value)
|
||||
CurrentSelection = Items[NewSelection.Value];
|
||||
var nothing = ItemManager.NothingItem(Slot);
|
||||
if (!Items.ItemData.ByType.TryGetValue(Slot.ToEquipType(), out var list))
|
||||
return [new CacheItem(nothing)];
|
||||
|
||||
var enumerable = list.AsEnumerable();
|
||||
if (Slot.IsEquipment())
|
||||
enumerable = enumerable.Append(ItemManager.SmallClothesItem(Slot));
|
||||
return enumerable.OrderByDescending(Favorites.Contains).ThenBy(i => i.Name).Prepend(nothing).Select(e => new CacheItem(e));
|
||||
}
|
||||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
if (CurrentSelection.ItemId == _currentItem)
|
||||
return currentSelected;
|
||||
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItem);
|
||||
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
}
|
||||
|
||||
public bool Draw(string previewName, ItemId previewIdx, float width, float innerWidth)
|
||||
{
|
||||
_innerWidth = innerWidth;
|
||||
_currentItem = previewIdx;
|
||||
CustomVariant = 0;
|
||||
return Draw($"##{Label}", previewName, string.Empty, width, Im.Style.TextHeightWithSpacing);
|
||||
}
|
||||
|
||||
protected override float GetFilterWidth()
|
||||
=> _innerWidth - 2 * Im.Style.FramePadding.X;
|
||||
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
{
|
||||
var obj = Items[globalIdx];
|
||||
var name = ToString(obj);
|
||||
if (UiHelpers.DrawFavoriteStar(_favorites, obj) && CurrentSelectionIdx == globalIdx)
|
||||
{
|
||||
CurrentSelectionIdx = -1;
|
||||
_currentItem = obj.ItemId;
|
||||
CurrentSelection = default;
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
var ret = ImGui.Selectable(name, selected);
|
||||
Im.Line.Same();
|
||||
using var color = ImGuiColor.Text.Push(0xFF808080);
|
||||
ImUtf8.TextRightAligned($"({obj.PrimaryId.Id}-{obj.Variant.Id})");
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || Items[globalIndex].ModelString.StartsWith(filter.Lower);
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
||||
private static string GetLabel(IDataManager gameData, EquipSlot slot)
|
||||
private static StringU8 GetLabel(IDataManager gameData, EquipSlot slot)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<Addon>();
|
||||
|
||||
return slot switch
|
||||
{
|
||||
EquipSlot.Head => sheet.TryGetRow(740, out var text) ? text.Text.ToString() : "Head",
|
||||
EquipSlot.Body => sheet.TryGetRow(741, out var text) ? text.Text.ToString() : "Body",
|
||||
EquipSlot.Hands => sheet.TryGetRow(742, out var text) ? text.Text.ToString() : "Hands",
|
||||
EquipSlot.Legs => sheet.TryGetRow(744, out var text) ? text.Text.ToString() : "Legs",
|
||||
EquipSlot.Feet => sheet.TryGetRow(745, out var text) ? text.Text.ToString() : "Feet",
|
||||
EquipSlot.Ears => sheet.TryGetRow(746, out var text) ? text.Text.ToString() : "Ears",
|
||||
EquipSlot.Neck => sheet.TryGetRow(747, out var text) ? text.Text.ToString() : "Neck",
|
||||
EquipSlot.Wrists => sheet.TryGetRow(748, out var text) ? text.Text.ToString() : "Wrists",
|
||||
EquipSlot.RFinger => sheet.TryGetRow(749, out var text) ? text.Text.ToString() : "Right Ring",
|
||||
EquipSlot.LFinger => sheet.TryGetRow(750, out var text) ? text.Text.ToString() : "Left Ring",
|
||||
_ => string.Empty,
|
||||
EquipSlot.Head => sheet.TryGetRow(740, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Head"u8),
|
||||
EquipSlot.Body => sheet.TryGetRow(741, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Body"u8),
|
||||
EquipSlot.Hands => sheet.TryGetRow(742, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Hands"u8),
|
||||
EquipSlot.Legs => sheet.TryGetRow(744, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Legs"u8),
|
||||
EquipSlot.Feet => sheet.TryGetRow(745, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Feet"u8),
|
||||
EquipSlot.Ears => sheet.TryGetRow(746, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Ears"u8),
|
||||
EquipSlot.Neck => sheet.TryGetRow(747, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Neck"u8),
|
||||
EquipSlot.Wrists => sheet.TryGetRow(748, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Wrists"u8),
|
||||
EquipSlot.RFinger => sheet.TryGetRow(749, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Right Ring"u8),
|
||||
EquipSlot.LFinger => sheet.TryGetRow(750, out var text) ? new StringU8(text.Text.Data, false) : new StringU8("Left Ring"u8),
|
||||
_ => StringU8.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private static List<EquipItem> GetItems(FavoriteManager favorites, ItemManager items, EquipSlot slot)
|
||||
{
|
||||
var nothing = ItemManager.NothingItem(slot);
|
||||
if (!items.ItemData.ByType.TryGetValue(slot.ToEquipType(), out var list))
|
||||
return [nothing];
|
||||
|
||||
var enumerable = list.AsEnumerable();
|
||||
if (slot.IsEquipment())
|
||||
enumerable = enumerable.Append(ItemManager.SmallClothesItem(slot));
|
||||
return enumerable.OrderByDescending(favorites.Contains).ThenBy(i => i.Name).Prepend(nothing).ToList();
|
||||
}
|
||||
|
||||
protected override void OnClosePopup()
|
||||
{
|
||||
// If holding control while the popup closes, try to parse the input as a full pair of set id and variant, and set a custom item for that.
|
||||
if (!Im.Io.KeyControl)
|
||||
return;
|
||||
|
||||
var split = Filter.Text.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length != 2 || !ushort.TryParse(split[0], out var setId) || !byte.TryParse(split[1], out var variant))
|
||||
return;
|
||||
|
||||
CustomSetId = setId;
|
||||
CustomVariant = variant;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,115 +1,30 @@
|
|||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
||||
public sealed class WeaponCombo(FavoriteManager favorites, ItemManager items, FullEquipType slot)
|
||||
: BaseItemCombo(favorites, items)
|
||||
{
|
||||
private readonly FavoriteManager _favorites;
|
||||
public readonly string Label;
|
||||
private ItemId _currentItem;
|
||||
private float _innerWidth;
|
||||
public override StringU8 Label { get; } = GetLabel(slot);
|
||||
public readonly FullEquipType Slot = slot;
|
||||
|
||||
public PrimaryId CustomSetId { get; private set; }
|
||||
public SecondaryId CustomWeaponId { get; private set; }
|
||||
public Variant CustomVariant { get; private set; }
|
||||
|
||||
public WeaponCombo(ItemManager items, FullEquipType type, OtterGui.Log.Logger log, FavoriteManager favorites)
|
||||
: base(() => GetWeapons(favorites, items, type), MouseWheelType.Control, log)
|
||||
protected override bool Identify(out EquipItem item)
|
||||
{
|
||||
_favorites = favorites;
|
||||
Label = GetLabel(type);
|
||||
SearchByParts = true;
|
||||
}
|
||||
|
||||
protected override void DrawList(float width, float itemHeight)
|
||||
{
|
||||
base.DrawList(width, itemHeight);
|
||||
if (NewSelection != null && Items.Count > NewSelection.Value)
|
||||
CurrentSelection = Items[NewSelection.Value];
|
||||
}
|
||||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
if (CurrentSelection.ItemId == _currentItem)
|
||||
return currentSelected;
|
||||
|
||||
CurrentSelectionIdx = Items.IndexOf(i => i.ItemId == _currentItem);
|
||||
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||
}
|
||||
|
||||
public bool Draw(string previewName, ItemId previewIdx, float width, float innerWidth)
|
||||
{
|
||||
_innerWidth = innerWidth;
|
||||
_currentItem = previewIdx;
|
||||
CustomVariant = 0;
|
||||
return Draw($"##{Label}", previewName, string.Empty, width, Im.Style.TextHeightWithSpacing);
|
||||
}
|
||||
|
||||
protected override float GetFilterWidth()
|
||||
=> _innerWidth - 2 * Im.Style.FramePadding.X;
|
||||
|
||||
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
{
|
||||
var obj = Items[globalIdx];
|
||||
var name = ToString(obj);
|
||||
if (UiHelpers.DrawFavoriteStar(_favorites, obj) && CurrentSelectionIdx == globalIdx)
|
||||
if (Slot is not FullEquipType.Unknown && ItemData.ConvertWeaponId(CustomSetId) != CurrentItem.Type)
|
||||
{
|
||||
CurrentSelectionIdx = -1;
|
||||
_currentItem = obj.ItemId;
|
||||
CurrentSelection = default;
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
var ret = ImGui.Selectable(name, selected);
|
||||
Im.Line.Same();
|
||||
using var color = ImGuiColor.Text.Push(0xFF808080);
|
||||
ImUtf8.TextRightAligned($"({obj.PrimaryId.Id}-{obj.SecondaryId.Id}-{obj.Variant.Id})");
|
||||
return ret;
|
||||
item = Items.Identify(Slot.ToSlot(), CustomSetId, CustomWeaponId, CustomVariant);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnClosePopup()
|
||||
{
|
||||
// If holding control while the popup closes, try to parse the input as a full tuple of set id, weapon id and variant, and set a custom item for that.
|
||||
if (!Im.Io.KeyControl)
|
||||
return;
|
||||
|
||||
var split = Filter.Text.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length != 3
|
||||
|| !ushort.TryParse(split[0], out var setId)
|
||||
|| !ushort.TryParse(split[1], out var weaponId)
|
||||
|| !byte.TryParse(split[2], out var variant))
|
||||
return;
|
||||
|
||||
CustomSetId = setId;
|
||||
CustomWeaponId = weaponId;
|
||||
CustomVariant = variant;
|
||||
}
|
||||
|
||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||
=> base.IsVisible(globalIndex, filter) || Items[globalIndex].ModelString.StartsWith(filter.Lower);
|
||||
|
||||
protected override string ToString(EquipItem obj)
|
||||
=> obj.Name;
|
||||
|
||||
private static string GetLabel(FullEquipType type)
|
||||
=> type.IsUnknown() ? "Mainhand" : type.ToName();
|
||||
|
||||
private static IReadOnlyList<EquipItem> GetWeapons(FavoriteManager favorites, ItemManager items, FullEquipType type)
|
||||
private static IReadOnlyList<EquipItem> GetItems(FavoriteManager favorites, ItemManager items, FullEquipType type)
|
||||
{
|
||||
if (type is FullEquipType.Unknown)
|
||||
{
|
||||
|
|
@ -131,4 +46,30 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
|
|||
|
||||
return [.. list.OrderByDescending(favorites.Contains).ThenBy(e => e.Name)];
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
{
|
||||
if (Slot is FullEquipType.Unknown)
|
||||
{
|
||||
var enumerable = Array.Empty<EquipItem>().AsEnumerable();
|
||||
foreach (var t in FullEquipType.Values.Where(e => e.ToSlot() is EquipSlot.MainHand))
|
||||
{
|
||||
if (Items.ItemData.ByType.TryGetValue(t, out var l))
|
||||
enumerable = enumerable.Concat(l);
|
||||
}
|
||||
|
||||
return enumerable.OrderByDescending(Favorites.Contains).ThenBy(e => e.Name).Select(e => new CacheItem(e));
|
||||
}
|
||||
|
||||
if (!Items.ItemData.ByType.TryGetValue(Slot, out var list))
|
||||
return [];
|
||||
|
||||
IEnumerable<EquipItem> ret = list.OrderByDescending(Favorites.Contains).ThenBy(e => e.Name);
|
||||
if (Slot.AllowsNothing())
|
||||
ret = ret.Prepend(ItemManager.NothingItem(Slot));
|
||||
return ret.Select(e => new CacheItem(e));
|
||||
}
|
||||
|
||||
private static StringU8 GetLabel(FullEquipType type)
|
||||
=> type.IsUnknown() ? new StringU8("Mainhand"u8) : new StringU8(type.ToName());
|
||||
}
|
||||
|
|
@ -45,13 +45,13 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
return true;
|
||||
}
|
||||
|
||||
public void DrawButton(EquipSlot slot, Rgba32 color)
|
||||
public void DrawButton(EquipSlot slot, ColorParameter color)
|
||||
=> DrawButton(MaterialValueIndex.FromSlot(slot), color);
|
||||
|
||||
public void DrawButton(BonusItemFlag slot, Rgba32 color)
|
||||
public void DrawButton(BonusItemFlag slot, ColorParameter color)
|
||||
=> DrawButton(MaterialValueIndex.FromSlot(slot), color);
|
||||
|
||||
private void DrawButton(MaterialValueIndex index, Rgba32 color)
|
||||
private void DrawButton(MaterialValueIndex index, ColorParameter color)
|
||||
{
|
||||
if (config.HideDesignPanel.HasFlag(DesignPanelFlag.AdvancedDyes))
|
||||
return;
|
||||
|
|
@ -62,7 +62,7 @@ public sealed unsafe class AdvancedDyePopup(
|
|||
|
||||
var (textColor, buttonColor) = isOpen
|
||||
? (ColorId.HeaderButtons.Value(), ImGuiColor.ButtonActive.Get())
|
||||
: (color, 0u);
|
||||
: (color, ColorParameter.Default);
|
||||
|
||||
using (ImStyleBorder.Frame.Push(textColor, 2 * Im.Style.GlobalScale, isOpen))
|
||||
{
|
||||
|
|
|
|||
100
Glamourer/Gui/Tabs/ActorTab/ActorFilter.cs
Normal file
100
Glamourer/Gui/Tabs/ActorTab/ActorFilter.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class ActorFilter : TextFilterBase<ActorCacheItem>, IUiService
|
||||
{
|
||||
private readonly IPlayerState _playerState;
|
||||
|
||||
private enum FilterMethod
|
||||
{
|
||||
Player,
|
||||
Owned,
|
||||
Npc,
|
||||
Retainer,
|
||||
Special,
|
||||
Homeworld,
|
||||
Text,
|
||||
Empty,
|
||||
};
|
||||
|
||||
private FilterMethod _method = FilterMethod.Empty;
|
||||
|
||||
public ActorFilter(IPlayerState playerState)
|
||||
{
|
||||
_playerState = playerState;
|
||||
FilterChanged += () =>
|
||||
{
|
||||
_method = Text switch
|
||||
{
|
||||
"" => FilterMethod.Empty,
|
||||
"<p>" or "<P>" => FilterMethod.Player,
|
||||
"<o>" or "<O>" => FilterMethod.Owned,
|
||||
"<n>" or "<N>" => FilterMethod.Npc,
|
||||
"<r>" or "<R>" => FilterMethod.Retainer,
|
||||
"<s>" or "<S>" => FilterMethod.Special,
|
||||
"<w>" or "<W>" => FilterMethod.Homeworld,
|
||||
_ => FilterMethod.Text,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
public override bool DrawFilter(ReadOnlySpan<byte> label, Vector2 availableRegion)
|
||||
{
|
||||
var ret = base.DrawFilter(label, availableRegion);
|
||||
|
||||
if (!Im.Item.Hovered())
|
||||
return ret;
|
||||
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
Im.Text("Filter for names containing the input."u8);
|
||||
Im.Dummy(new Vector2(0, Im.Style.TextHeight / 2));
|
||||
Im.Text("Special filters are:"u8);
|
||||
var color = ColorId.HeaderButtons.Value();
|
||||
Im.Text("<p>"u8, color);
|
||||
Im.Line.NoSpacing();
|
||||
Im.Text(": show only player characters."u8);
|
||||
|
||||
|
||||
Im.Text("<o>"u8, color);
|
||||
Im.Line.NoSpacing();
|
||||
Im.Text(": show only owned game objects."u8);
|
||||
|
||||
Im.Text("<n>"u8, color);
|
||||
Im.Line.NoSpacing();
|
||||
Im.Text(": show only NPCs."u8);
|
||||
|
||||
Im.Text("<r>"u8, color);
|
||||
Im.Line.NoSpacing();
|
||||
Im.Text(": show only retainers."u8);
|
||||
|
||||
Im.Text("<s>"u8, color);
|
||||
Im.Line.NoSpacing();
|
||||
Im.Text(": show only special screen characters."u8);
|
||||
|
||||
Im.Text("<w>"u8, color);
|
||||
Im.Line.NoSpacing();
|
||||
Im.Text(": show only players from your world."u8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override string ToFilterString(in ActorCacheItem item, int globalIndex)
|
||||
=> item.DisplayText.Utf16;
|
||||
|
||||
public override bool WouldBeVisible(in ActorCacheItem item, int globalIndex)
|
||||
=> _method switch
|
||||
{
|
||||
FilterMethod.Player => item.Identifier.Type is IdentifierType.Player,
|
||||
FilterMethod.Owned => item.Identifier.Type is IdentifierType.Owned,
|
||||
FilterMethod.Npc => item.Identifier.Type is IdentifierType.Npc,
|
||||
FilterMethod.Retainer => item.Identifier.Type is IdentifierType.Retainer,
|
||||
FilterMethod.Special => item.Identifier.Type is IdentifierType.Special,
|
||||
FilterMethod.Homeworld => item.Identifier.Type is IdentifierType.Player
|
||||
&& item.Identifier.HomeWorld == _playerState.HomeWorld.RowId,
|
||||
FilterMethod.Text => base.WouldBeVisible(item, globalIndex),
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Designs;
|
||||
|
|
@ -14,20 +10,16 @@ using Glamourer.Interop;
|
|||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using TextStringHandlerBuffer = OtterGui.Text.HelperObjects.TextStringHandlerBuffer;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public class ActorPanel
|
||||
public sealed class ActorPanel : IPanel
|
||||
{
|
||||
private readonly ActorSelector _selector;
|
||||
private readonly ActorSelection _selection;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly CustomizationDrawer _customizationDrawer;
|
||||
private readonly EquipmentDrawer _equipmentDrawer;
|
||||
|
|
@ -35,18 +27,12 @@ public class ActorPanel
|
|||
private readonly Configuration _config;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly DesignManager _designManager;
|
||||
private readonly ImportService _importService;
|
||||
private readonly ICondition _conditions;
|
||||
private readonly DictModelChara _modelChara;
|
||||
private readonly CustomizeParameterDrawer _parameterDrawer;
|
||||
private readonly AdvancedDyePopup _advancedDyes;
|
||||
private readonly EditorHistory _editorHistory;
|
||||
private readonly HeaderDrawer.Button[] _leftButtons;
|
||||
private readonly HeaderDrawer.Button[] _rightButtons;
|
||||
|
||||
public ActorPanel(ActorSelector selector,
|
||||
StateManager stateManager,
|
||||
public ActorPanel(StateManager stateManager,
|
||||
CustomizationDrawer customizationDrawer,
|
||||
EquipmentDrawer equipmentDrawer,
|
||||
AutoDesignApplier autoDesignApplier,
|
||||
|
|
@ -55,13 +41,11 @@ public class ActorPanel
|
|||
ActorObjectManager objects,
|
||||
DesignManager designManager,
|
||||
ImportService importService,
|
||||
ICondition conditions,
|
||||
DictModelChara modelChara,
|
||||
CustomizeParameterDrawer parameterDrawer,
|
||||
AdvancedDyePopup advancedDyes,
|
||||
EditorHistory editorHistory)
|
||||
EditorHistory editorHistory, ActorSelection selection)
|
||||
{
|
||||
_selector = selector;
|
||||
_stateManager = stateManager;
|
||||
_customizationDrawer = customizationDrawer;
|
||||
_equipmentDrawer = equipmentDrawer;
|
||||
|
|
@ -69,61 +53,40 @@ public class ActorPanel
|
|||
_config = config;
|
||||
_converter = converter;
|
||||
_objects = objects;
|
||||
_designManager = designManager;
|
||||
_importService = importService;
|
||||
_conditions = conditions;
|
||||
_modelChara = modelChara;
|
||||
_parameterDrawer = parameterDrawer;
|
||||
_advancedDyes = advancedDyes;
|
||||
_editorHistory = editorHistory;
|
||||
_leftButtons =
|
||||
[
|
||||
new SetFromClipboardButton(this),
|
||||
new ExportToClipboardButton(this),
|
||||
new SaveAsDesignButton(this),
|
||||
new UndoButton(this),
|
||||
];
|
||||
_rightButtons =
|
||||
[
|
||||
new LockedButton(this),
|
||||
new HeaderDrawer.IncognitoButton(_config),
|
||||
];
|
||||
_selection = selection;
|
||||
}
|
||||
|
||||
|
||||
private ActorIdentifier _identifier;
|
||||
private string _actorName = string.Empty;
|
||||
private Actor _actor = Actor.Null;
|
||||
private ActorData _data;
|
||||
private ActorState? _state;
|
||||
private bool _lockedRedraw;
|
||||
|
||||
private CustomizeFlag CustomizeApplicationFlags
|
||||
=> _lockedRedraw ? CustomizeFlagExtensions.AllRelevant & ~CustomizeFlagExtensions.RedrawRequired : CustomizeFlagExtensions.AllRelevant;
|
||||
=> _selection.LockedRedraw
|
||||
? CustomizeFlagExtensions.AllRelevant & ~CustomizeFlagExtensions.RedrawRequired
|
||||
: CustomizeFlagExtensions.AllRelevant;
|
||||
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "ActorPanel"u8;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var group = ImRaii.Group();
|
||||
(_identifier, _data) = _selector.Selection;
|
||||
_lockedRedraw = _identifier.Type is IdentifierType.Special || _objects.IsInLobby
|
||||
|| _conditions[ConditionFlag.OccupiedInCutSceneEvent];
|
||||
(_actorName, _actor) = GetHeaderName();
|
||||
DrawHeader();
|
||||
DrawPanel();
|
||||
|
||||
if (_state is not { IsLocked: false })
|
||||
if (_selection.State is not { IsLocked: false })
|
||||
return;
|
||||
|
||||
if (_importService.CreateDatTarget(out var dat))
|
||||
{
|
||||
_stateManager.ChangeEntireCustomize(_state!, dat.Customize, CustomizeApplicationFlags, ApplySettings.Manual);
|
||||
Glamourer.Messager.NotificationMessage($"Applied games .dat file {dat.Description} customizations to {_state.Identifier}.",
|
||||
_stateManager.ChangeEntireCustomize(_selection.State!, dat.Customize, CustomizeApplicationFlags, ApplySettings.Manual);
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Applied games .dat file {dat.Description} customizations to {_selection.State.Identifier}.",
|
||||
NotificationType.Success, false);
|
||||
}
|
||||
else if (_importService.CreateCharaTarget(out var designBase, out var name))
|
||||
{
|
||||
_stateManager.ApplyDesign(_state!, designBase, ApplySettings.Manual);
|
||||
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_state.Identifier}.", NotificationType.Success,
|
||||
_stateManager.ApplyDesign(_selection.State!, designBase, ApplySettings.Manual);
|
||||
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selection.State.Identifier}.",
|
||||
NotificationType.Success,
|
||||
false);
|
||||
}
|
||||
|
||||
|
|
@ -131,39 +94,19 @@ public class ActorPanel
|
|||
_importService.CreateCharaSource();
|
||||
}
|
||||
|
||||
private void DrawHeader()
|
||||
{
|
||||
var textColor = !_identifier.IsValid ? ImGuiColor.Text.Get() :
|
||||
_data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
|
||||
HeaderDrawer.Draw(_actorName, textColor.Color, ImGuiColor.FrameBackground.Get().Color, _leftButtons, _rightButtons);
|
||||
|
||||
SaveDesignDrawPopup();
|
||||
}
|
||||
|
||||
private (string, Actor) GetHeaderName()
|
||||
{
|
||||
if (!_identifier.IsValid)
|
||||
return ("No Selection", Actor.Null);
|
||||
|
||||
if (_data.Valid)
|
||||
return (_selector.IncognitoMode ? _identifier.Incognito(_data.Label) : _data.Label, _data.Objects[0]);
|
||||
|
||||
return (_selector.IncognitoMode ? _identifier.Incognito(null) : _identifier.ToString(), Actor.Null);
|
||||
}
|
||||
|
||||
private unsafe void DrawPanel()
|
||||
{
|
||||
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.BordersOuter | TableFlags.ScrollY, Im.ContentRegion.Available);
|
||||
if (!table || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state))
|
||||
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.ScrollY, Im.ContentRegion.Available);
|
||||
if (!table || _selection.State is null)
|
||||
return;
|
||||
|
||||
table.SetupScrollFreeze(0, 1);
|
||||
table.NextColumn();
|
||||
Im.Dummy(Vector2.Zero);
|
||||
var transformationId = _actor.IsCharacter ? _actor.AsCharacter->CharacterData.TransformationId : 0;
|
||||
var transformationId = _selection.Actor.IsCharacter ? _selection.Actor.AsCharacter->CharacterData.TransformationId : 0;
|
||||
if (transformationId is not 0)
|
||||
ImGuiUtil.DrawTextButton($"Currently transformed to Transformation {transformationId}.",
|
||||
-Vector2.UnitX, Colors.SelectedRed);
|
||||
ImEx.TextFramed($"Currently transformed to Transformation {transformationId}.", Im.ContentRegion.Available with { Y = 0 },
|
||||
Colors.SelectedRed);
|
||||
|
||||
DrawApplyToSelf();
|
||||
Im.Line.Same();
|
||||
|
|
@ -173,12 +116,12 @@ public class ActorPanel
|
|||
table.NextColumn();
|
||||
|
||||
using var disabled = Im.Disabled(transformationId is not 0);
|
||||
if (_state.ModelData.IsHuman)
|
||||
if (_selection.State.ModelData.IsHuman)
|
||||
DrawHumanPanel();
|
||||
else
|
||||
DrawMonsterPanel();
|
||||
if (_data.Objects.Count > 0)
|
||||
_advancedDyes.Draw(_data.Objects.Last(), _state);
|
||||
if (_selection.Data.Objects.Count > 0)
|
||||
_advancedDyes.Draw(_selection.Data.Objects.Last(), _selection.State);
|
||||
}
|
||||
|
||||
private void DrawHumanPanel()
|
||||
|
|
@ -194,18 +137,19 @@ public class ActorPanel
|
|||
if (_config.HideDesignPanel.HasFlag(DesignPanelFlag.Customization))
|
||||
return;
|
||||
|
||||
var header = _state!.ModelData.ModelId == 0
|
||||
? "Customization"
|
||||
: $"Customization (Model Id #{_state.ModelData.ModelId})###Customization";
|
||||
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
|
||||
using var h = Im.Tree.HeaderId(header, expand ? TreeNodeFlags.DefaultOpen : TreeNodeFlags.None);
|
||||
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
|
||||
using var h = Im.Tree.HeaderId(_selection.State!.ModelData.ModelId is 0
|
||||
? "Customization"u8
|
||||
: $"Customization (Model Id #{_selection.State.ModelData.ModelId})###Customization",
|
||||
expand ? TreeNodeFlags.DefaultOpen : TreeNodeFlags.None);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
if (_customizationDrawer.Draw(_state!.ModelData.Customize, _state.IsLocked, _lockedRedraw))
|
||||
_stateManager.ChangeEntireCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, ApplySettings.Manual);
|
||||
if (_customizationDrawer.Draw(_selection.State!.ModelData.Customize, _selection.State.IsLocked, _selection.LockedRedraw))
|
||||
_stateManager.ChangeEntireCustomize(_selection.State, _customizationDrawer.Customize, _customizationDrawer.Changed,
|
||||
ApplySettings.Manual);
|
||||
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.Wetness, _stateManager, _state));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.Wetness, _stateManager, _selection.State));
|
||||
Im.Dummy(new Vector2(Im.Style.TextHeight / 2));
|
||||
}
|
||||
|
||||
|
|
@ -217,22 +161,22 @@ public class ActorPanel
|
|||
|
||||
_equipmentDrawer.Prepare();
|
||||
|
||||
var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _state!.IsLocked);
|
||||
var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _selection.State!.IsLocked);
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var data = EquipDrawData.FromState(_stateManager, _state!, slot);
|
||||
var data = EquipDrawData.FromState(_stateManager, _selection.State!, slot);
|
||||
_equipmentDrawer.DrawEquip(data);
|
||||
if (usedAllStain)
|
||||
_stateManager.ChangeStains(_state, slot, newAllStain, ApplySettings.Manual);
|
||||
_stateManager.ChangeStains(_selection.State, slot, newAllStain, ApplySettings.Manual);
|
||||
}
|
||||
|
||||
var mainhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.MainHand);
|
||||
var offhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.OffHand);
|
||||
var mainhand = EquipDrawData.FromState(_stateManager, _selection.State, EquipSlot.MainHand);
|
||||
var offhand = EquipDrawData.FromState(_stateManager, _selection.State, EquipSlot.OffHand);
|
||||
_equipmentDrawer.DrawWeapons(mainhand, offhand, GameMain.IsInGPose());
|
||||
|
||||
foreach (var slot in BonusExtensions.AllFlags)
|
||||
{
|
||||
var data = BonusDrawData.FromState(_stateManager, _state!, slot);
|
||||
var data = BonusDrawData.FromState(_stateManager, _selection.State!, slot);
|
||||
_equipmentDrawer.DrawBonusItem(data);
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +192,7 @@ public class ActorPanel
|
|||
if (!h)
|
||||
return;
|
||||
|
||||
_parameterDrawer.Draw(_stateManager, _state!);
|
||||
_parameterDrawer.Draw(_stateManager, _selection.State!);
|
||||
}
|
||||
|
||||
private unsafe void DrawDebugData()
|
||||
|
|
@ -260,63 +204,64 @@ public class ActorPanel
|
|||
if (!h)
|
||||
return;
|
||||
|
||||
using var t = Im.Table.Begin("table"u8, 2, TableFlags.SizingFixedFit);
|
||||
if (!t)
|
||||
using var table = Im.Table.Begin("table"u8, 2, TableFlags.SizingFixedFit);
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
ImUtf8.DrawTableColumn("Object Index"u8);
|
||||
DrawCopyColumn($"{string.Join(", ", _data.Objects.Select(d => d.AsObject->ObjectIndex))}");
|
||||
ImUtf8.DrawTableColumn("Name ID"u8);
|
||||
DrawCopyColumn($"{string.Join(", ", _data.Objects.Select(d => d.AsObject->GetNameId()))}");
|
||||
ImUtf8.DrawTableColumn("Base ID"u8);
|
||||
DrawCopyColumn($"{string.Join(", ", _data.Objects.Select(d => d.AsObject->BaseId))}");
|
||||
ImUtf8.DrawTableColumn("Entity ID"u8);
|
||||
DrawCopyColumn($"{string.Join(", ", _data.Objects.Select(d => d.AsObject->EntityId))}");
|
||||
ImUtf8.DrawTableColumn("Owner ID"u8);
|
||||
DrawCopyColumn($"{string.Join(", ", _data.Objects.Select(d => d.AsObject->OwnerId))}");
|
||||
ImUtf8.DrawTableColumn("Game Object ID"u8);
|
||||
DrawCopyColumn($"{string.Join(", ", _data.Objects.Select(d => d.AsObject->GetGameObjectId().ObjectId))}");
|
||||
table.DrawColumn("Object Index"u8);
|
||||
DrawCopyColumn(table, StringU8.Join(", "u8, _selection.Data.Objects.Select(d => d.AsObject->ObjectIndex)));
|
||||
table.DrawColumn("Name ID"u8);
|
||||
DrawCopyColumn(table, StringU8.Join(", "u8, _selection.Data.Objects.Select(d => d.AsObject->GetNameId())));
|
||||
table.DrawColumn("Base ID"u8);
|
||||
DrawCopyColumn(table, StringU8.Join(", "u8, _selection.Data.Objects.Select(d => d.AsObject->BaseId)));
|
||||
table.DrawColumn("Entity ID"u8);
|
||||
DrawCopyColumn(table, StringU8.Join(", "u8, _selection.Data.Objects.Select(d => d.AsObject->EntityId)));
|
||||
table.DrawColumn("Owner ID"u8);
|
||||
DrawCopyColumn(table, StringU8.Join(", "u8, _selection.Data.Objects.Select(d => d.AsObject->OwnerId)));
|
||||
table.DrawColumn("Game Object ID"u8);
|
||||
DrawCopyColumn(table, StringU8.Join(", "u8, _selection.Data.Objects.Select(d => d.AsObject->GetGameObjectId().ObjectId)));
|
||||
return;
|
||||
|
||||
static void DrawCopyColumn(ref OtterGui.Text.HelperObjects.Utf8StringHandler<TextStringHandlerBuffer> text)
|
||||
static void DrawCopyColumn(Im.TableDisposable table, Utf8StringHandler<TextStringHandlerBuffer> text)
|
||||
{
|
||||
ImUtf8.DrawTableColumn(ref text);
|
||||
table.DrawColumn(ref text);
|
||||
if (Im.Item.RightClicked())
|
||||
ImUtf8.SetClipboardText(TextStringHandlerBuffer.Span);
|
||||
Im.Clipboard.Set(ref text);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEquipmentMetaToggles()
|
||||
{
|
||||
using (_ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.HatState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Head, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.HatState, _stateManager, _selection.State!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Head, _stateManager, _selection.State!));
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (_ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.VisorState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Body, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.VisorState, _stateManager, _selection.State!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Body, _stateManager, _selection.State!));
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (_ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.WeaponState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.OffHand, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.WeaponState, _stateManager, _selection.State!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.OffHand, _stateManager, _selection.State!));
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (_ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.EarState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(MetaIndex.EarState, _stateManager, _selection.State!));
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMonsterPanel()
|
||||
{
|
||||
var names = _modelChara[_state!.ModelData.ModelId];
|
||||
var names = _modelChara[_selection.State!.ModelData.ModelId];
|
||||
var turnHuman = Im.Button("Turn Human"u8);
|
||||
Im.Separator();
|
||||
using (Im.ListBox.Begin("##MonsterList"u8, Im.ContentRegion.Available with { Y = 10 * Im.Style.TextHeightWithSpacing }))
|
||||
|
|
@ -324,15 +269,14 @@ public class ActorPanel
|
|||
if (names.Count is 0)
|
||||
Im.Text("Unknown Monster"u8);
|
||||
else
|
||||
ImGuiClip.ClippedDraw(names, p => Im.Text($"{p.Name} ({p.Kind.ToName()} #{p.Id})"),
|
||||
Im.Style.TextHeightWithSpacing);
|
||||
Im.ListClipper.Draw(names, p => Im.Text($"{p.Name} ({p.Kind.ToName()} #{p.Id})"), Im.Style.TextHeightWithSpacing);
|
||||
}
|
||||
|
||||
Im.Separator();
|
||||
Im.Text("Customization Data"u8);
|
||||
using (Im.Font.PushMono())
|
||||
{
|
||||
foreach (var b in _state.ModelData.Customize)
|
||||
foreach (var b in _selection.State.ModelData.Customize)
|
||||
{
|
||||
using (Im.Group())
|
||||
{
|
||||
|
|
@ -353,7 +297,7 @@ public class ActorPanel
|
|||
Im.Text("Equipment Data"u8);
|
||||
using (Im.Font.PushMono())
|
||||
{
|
||||
foreach (var b in _state.ModelData.GetEquipmentBytes())
|
||||
foreach (var b in _selection.State.ModelData.GetEquipmentBytes())
|
||||
{
|
||||
using (Im.Group())
|
||||
{
|
||||
|
|
@ -371,65 +315,53 @@ public class ActorPanel
|
|||
}
|
||||
|
||||
if (turnHuman)
|
||||
_stateManager.TurnHuman(_state, StateSource.Manual);
|
||||
_stateManager.TurnHuman(_selection.State, StateSource.Manual);
|
||||
}
|
||||
|
||||
private string _newName = string.Empty;
|
||||
private DesignBase? _newDesign;
|
||||
|
||||
private void SaveDesignDrawPopup()
|
||||
{
|
||||
if (!ImGuiUtil.OpenNameField("Save as Design", ref _newName))
|
||||
return;
|
||||
|
||||
if (_newDesign != null && _newName.Length > 0)
|
||||
_designManager.CreateClone(_newDesign, _newName, true);
|
||||
_newDesign = null;
|
||||
_newName = string.Empty;
|
||||
}
|
||||
|
||||
private void RevertButtons()
|
||||
{
|
||||
if (ImGuiUtil.DrawDisabledButton("Revert to Game", Vector2.Zero, "Revert the character to its actual state in the game.",
|
||||
_state!.IsLocked))
|
||||
_stateManager.ResetState(_state!, StateSource.Manual, isFinal: true);
|
||||
if (ImEx.Button("Revert to Game"u8, Vector2.Zero, "Revert the character to its actual state in the game."u8,
|
||||
_selection.State!.IsLocked))
|
||||
_stateManager.ResetState(_selection.State!, StateSource.Manual, isFinal: true);
|
||||
|
||||
Im.Line.Same();
|
||||
|
||||
if (ImGuiUtil.DrawDisabledButton("Reapply Automation", Vector2.Zero,
|
||||
"Reapply the current automation state for the character on top of its current state..",
|
||||
!_config.EnableAutoDesigns || _state!.IsLocked))
|
||||
if (ImEx.Button("Reapply Automation"u8, Vector2.Zero,
|
||||
"Reapply the current automation state for the character on top of its current state.."u8,
|
||||
!_config.EnableAutoDesigns || _selection.State!.IsLocked))
|
||||
{
|
||||
_autoDesignApplier.ReapplyAutomation(_actor, _identifier, _state!, false, false, out var forcedRedraw);
|
||||
_stateManager.ReapplyAutomationState(_actor, forcedRedraw, false, StateSource.Manual);
|
||||
_autoDesignApplier.ReapplyAutomation(_selection.Actor, _selection.Identifier, _selection.State!, false, false,
|
||||
out var forcedRedraw);
|
||||
_stateManager.ReapplyAutomationState(_selection.Actor, forcedRedraw, false, StateSource.Manual);
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImGuiUtil.DrawDisabledButton("Revert to Automation", Vector2.Zero,
|
||||
"Try to revert the character to the state it would have using automated designs.",
|
||||
!_config.EnableAutoDesigns || _state!.IsLocked))
|
||||
if (ImEx.Button("Revert to Automation"u8, Vector2.Zero,
|
||||
"Try to revert the character to the state it would have using automated designs."u8,
|
||||
!_config.EnableAutoDesigns || _selection.State!.IsLocked))
|
||||
{
|
||||
_autoDesignApplier.ReapplyAutomation(_actor, _identifier, _state!, true, false, out var forcedRedraw);
|
||||
_stateManager.ReapplyAutomationState(_actor, forcedRedraw, true, StateSource.Manual);
|
||||
_autoDesignApplier.ReapplyAutomation(_selection.Actor, _selection.Identifier, _selection.State!, true, false, out var forcedRedraw);
|
||||
_stateManager.ReapplyAutomationState(_selection.Actor, forcedRedraw, true, StateSource.Manual);
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImGuiUtil.DrawDisabledButton("Reapply", Vector2.Zero,
|
||||
"Try to reapply the configured state if something went wrong. Should generally not be necessary.",
|
||||
_state!.IsLocked))
|
||||
_stateManager.ReapplyState(_actor, false, StateSource.Manual, true);
|
||||
if (ImEx.Button("Reapply"u8, Vector2.Zero,
|
||||
"Try to reapply the configured state if something went wrong. Should generally not be necessary."u8,
|
||||
_selection.State!.IsLocked))
|
||||
_stateManager.ReapplyState(_selection.Actor, false, StateSource.Manual, true);
|
||||
}
|
||||
|
||||
private void DrawApplyToSelf()
|
||||
{
|
||||
var (id, data) = _objects.PlayerData;
|
||||
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero,
|
||||
"Apply the current state to your own character.\nHold Control to only apply gear.\nHold Shift to only apply customizations.",
|
||||
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
|
||||
if (!ImEx.Button("Apply to Yourself"u8, Vector2.Zero,
|
||||
"Apply the current state to your own character.\nHold Control to only apply gear.\nHold Shift to only apply customizations."u8,
|
||||
!data.Valid || id == _selection.Identifier || _selection.State!.ModelData.ModelId is not 0))
|
||||
return;
|
||||
|
||||
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
|
||||
_stateManager.ApplyDesign(state, _converter.Convert(_state!, ApplicationRules.FromModifiers(_state!)),
|
||||
_stateManager.ApplyDesign(state, _converter.Convert(_selection.State!, ApplicationRules.FromModifiers(_selection.State!)),
|
||||
ApplySettings.Manual with { IsFinal = true });
|
||||
}
|
||||
|
||||
|
|
@ -438,136 +370,15 @@ public class ActorPanel
|
|||
var (id, data) = _objects.TargetData;
|
||||
var tt = id.IsValid
|
||||
? data.Valid
|
||||
? "Apply the current state to your current target.\nHold Control to only apply gear.\nHold Shift to only apply customizations."
|
||||
: "The current target can not be manipulated."
|
||||
: "No valid target selected.";
|
||||
if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt,
|
||||
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
|
||||
? "Apply the current state to your current target.\nHold Control to only apply gear.\nHold Shift to only apply customizations."u8
|
||||
: "The current target can not be manipulated."u8
|
||||
: "No valid target selected."u8;
|
||||
if (!ImEx.Button("Apply to Target"u8, Vector2.Zero, tt,
|
||||
!data.Valid || id == _selection.Identifier || _selection.State!.ModelData.ModelId is not 0))
|
||||
return;
|
||||
|
||||
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
|
||||
_stateManager.ApplyDesign(state, _converter.Convert(_state!, ApplicationRules.FromModifiers(_state!)),
|
||||
_stateManager.ApplyDesign(state, _converter.Convert(_selection.State!, ApplicationRules.FromModifiers(_selection.State!)),
|
||||
ApplySettings.Manual with { IsFinal = true });
|
||||
}
|
||||
|
||||
|
||||
private sealed class SetFromClipboardButton(ActorPanel panel)
|
||||
: HeaderDrawer.Button
|
||||
{
|
||||
protected override string Description
|
||||
=> "Try to apply a design from your clipboard.\nHold Control to only apply gear.\nHold Shift to only apply customizations.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Clipboard;
|
||||
|
||||
public override bool Visible
|
||||
=> panel._state != null;
|
||||
|
||||
protected override bool Disabled
|
||||
=> panel._state?.IsLocked ?? true;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToBool();
|
||||
var text = ImGui.GetClipboardText();
|
||||
var design = panel._converter.FromBase64(text, applyCustomize, applyGear, out _)
|
||||
?? throw new Exception("The clipboard did not contain valid data.");
|
||||
panel._stateManager.ApplyDesign(panel._state!, design, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not apply clipboard to {panel._identifier}.",
|
||||
$"Could not apply clipboard to design {panel._identifier.Incognito(null)}", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ExportToClipboardButton(ActorPanel panel) : HeaderDrawer.Button
|
||||
{
|
||||
protected override string Description
|
||||
=> "Copy the current design to your clipboard.\nHold Control to disable applying of customizations for the copied design.\nHold Shift to disable applying of gear for the copied design.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Copy;
|
||||
|
||||
public override bool Visible
|
||||
=> panel._state?.ModelData.ModelId == 0;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = panel._converter.ShareBase64(panel._state!, ApplicationRules.FromModifiers(panel._state!));
|
||||
ImGui.SetClipboardText(text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not copy {panel._identifier} data to clipboard.",
|
||||
$"Could not copy data from design {panel._identifier.Incognito(null)} to clipboard", NotificationType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SaveAsDesignButton(ActorPanel panel) : HeaderDrawer.Button
|
||||
{
|
||||
protected override string Description
|
||||
=> "Save the current state as a design.\nHold Control to disable applying of customizations for the saved design.\nHold Shift to disable applying of gear for the saved design.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Save;
|
||||
|
||||
public override bool Visible
|
||||
=> panel._state?.ModelData.ModelId == 0;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
ImGui.OpenPopup("Save as Design");
|
||||
panel._newName = panel._state!.Identifier.ToName();
|
||||
panel._newDesign = panel._converter.Convert(panel._state, ApplicationRules.FromModifiers(panel._state));
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class UndoButton(ActorPanel panel) : HeaderDrawer.Button
|
||||
{
|
||||
protected override string Description
|
||||
=> "Undo the last change.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Undo;
|
||||
|
||||
public override bool Visible
|
||||
=> panel._state != null;
|
||||
|
||||
protected override bool Disabled
|
||||
=> (panel._state?.IsLocked ?? true) || !panel._editorHistory.CanUndo(panel._state);
|
||||
|
||||
protected override void OnClick()
|
||||
=> panel._editorHistory.Undo(panel._state!);
|
||||
}
|
||||
|
||||
private sealed class LockedButton(ActorPanel panel) : HeaderDrawer.Button
|
||||
{
|
||||
protected override string Description
|
||||
=> "The current state of this actor is locked by external tools.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Lock;
|
||||
|
||||
public override bool Visible
|
||||
=> panel._state?.IsLocked ?? false;
|
||||
|
||||
protected override bool Disabled
|
||||
=> true;
|
||||
|
||||
protected override Rgba32 BorderColor
|
||||
=> ColorId.ActorUnavailable.Value();
|
||||
|
||||
protected override Rgba32 TextColor
|
||||
=> ColorId.ActorUnavailable.Value();
|
||||
|
||||
protected override void OnClick()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
64
Glamourer/Gui/Tabs/ActorTab/ActorSelection.cs
Normal file
64
Glamourer/Gui/Tabs/ActorTab/ActorSelection.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class ActorSelection(StateManager manager, ActorObjectManager objects, ICondition conditions) : IUiService
|
||||
{
|
||||
private static readonly StringU8 NoSelection = new("No Selection"u8);
|
||||
|
||||
public ActorIdentifier Identifier { get; private set; }
|
||||
public ActorState? State { get; private set; }
|
||||
public StringU8 ActorName { get; private set; } = NoSelection;
|
||||
public StringU8 IncognitoName { get; private set; } = NoSelection;
|
||||
public ActorData Data { get; private set; } = ActorData.Invalid;
|
||||
public Actor Actor { get; private set; } = Actor.Null;
|
||||
public bool LockedRedraw { get; private set; } = false;
|
||||
|
||||
public void Select(ActorIdentifier identifier, ActorData data)
|
||||
{
|
||||
Identifier = identifier.CreatePermanent();
|
||||
if (Identifier.IsValid)
|
||||
{
|
||||
ActorName = new StringU8(data.Label);
|
||||
IncognitoName = new StringU8(Identifier.Incognito(data.Label));
|
||||
State = data.Valid && manager.GetOrCreate(Identifier, data.Objects[0], out var s) ? s : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ActorName = NoSelection;
|
||||
IncognitoName = NoSelection;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (Identifier.IsValid)
|
||||
{
|
||||
if (objects.TryGetValue(Identifier, out var data))
|
||||
{
|
||||
Data = data;
|
||||
Actor = Data.Objects[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Data = ActorData.Invalid;
|
||||
Actor = Actor.Null;
|
||||
}
|
||||
|
||||
LockedRedraw = Identifier.Type is IdentifierType.Special || objects.IsInLobby || conditions[ConditionFlag.OccupiedInCutSceneEvent];
|
||||
}
|
||||
else
|
||||
{
|
||||
Data = ActorData.Invalid;
|
||||
Actor = Actor.Null;
|
||||
LockedRedraw = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,135 +1,68 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public class ActorSelector(ActorObjectManager objects, ActorManager actors, EphemeralConfig config)
|
||||
public readonly struct ActorCacheItem(ActorIdentifier identifier, ActorData data)
|
||||
{
|
||||
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
|
||||
public readonly ActorIdentifier Identifier = identifier;
|
||||
public readonly ActorData Data = data;
|
||||
public readonly StringPair DisplayText = new(data.Label);
|
||||
public readonly StringU8 IncognitoText = new(identifier.Incognito(data.Label));
|
||||
}
|
||||
|
||||
public bool IncognitoMode
|
||||
public sealed class ActorSelector(ActorSelection selection, ActorObjectManager objects, ActorFilter filter, PenumbraService penumbra, EphemeralConfig config) : IPanel
|
||||
{
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "ActorSelector"u8;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
get => config.IncognitoMode;
|
||||
set
|
||||
Im.Cursor.Y += Im.Style.FramePadding.Y;
|
||||
var cache = CacheManager.Instance.GetOrCreateCache(Im.Id.Current, () => new ActorSelectorCache(objects, filter, penumbra));
|
||||
using var clip = new Im.ListClipper(cache.Count, Im.Style.TextHeightWithSpacing);
|
||||
foreach (var actor in clip.Iterate(cache))
|
||||
{
|
||||
config.IncognitoMode = value;
|
||||
config.Save();
|
||||
Im.Cursor.X += Im.Style.FramePadding.X;
|
||||
var selected = actor.Identifier.Equals(selection.Identifier);
|
||||
if (Im.Selectable(config.IncognitoMode ? actor.IncognitoText : actor.DisplayText.Utf8, selected) && !selected)
|
||||
selection.Select(actor.Identifier, actor.Data);
|
||||
}
|
||||
}
|
||||
|
||||
private LowerString _actorFilter = LowerString.Empty;
|
||||
private Vector2 _defaultItemSpacing;
|
||||
private WorldId _world;
|
||||
private float _width;
|
||||
|
||||
public (ActorIdentifier Identifier, ActorData Data) Selection
|
||||
=> objects.TryGetValue(_identifier, out var data) ? (_identifier, data) : (_identifier, ActorData.Invalid);
|
||||
|
||||
public bool HasSelection
|
||||
=> _identifier.IsValid;
|
||||
|
||||
public void Draw(float width)
|
||||
private sealed class ActorSelectorCache : BasicFilterCache<ActorCacheItem>
|
||||
{
|
||||
_width = width;
|
||||
using var group = Im.Group();
|
||||
_defaultItemSpacing = Im.Style.ItemSpacing;
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.FrameRounding, 0);
|
||||
ImGui.SetNextItemWidth(_width);
|
||||
LowerString.InputWithHint("##actorFilter", "Filter...", ref _actorFilter, 64);
|
||||
if (ImGui.IsItemHovered())
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly PenumbraService _penumbra;
|
||||
|
||||
public ActorSelectorCache(ActorObjectManager objects, ActorFilter filter, PenumbraService penumbra)
|
||||
: base(filter)
|
||||
{
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
ImUtf8.Text("Filter for names containing the input."u8);
|
||||
Im.Dummy(new Vector2(0, Im.Style.TextHeight / 2));
|
||||
ImUtf8.Text("Special filters are:"u8);
|
||||
var color = ColorId.HeaderButtons.Value();
|
||||
Im.Text("<p>"u8, color);
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.Text(": show only player characters."u8);
|
||||
|
||||
Im.Text("<o>"u8, color);
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.Text(": show only owned game objects."u8);
|
||||
|
||||
Im.Text("<n>"u8, color);
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.Text(": show only NPCs."u8);
|
||||
|
||||
Im.Text("<r>"u8, color);
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.Text(": show only retainers."u8);
|
||||
|
||||
Im.Text("<s>"u8, color);
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.Text(": show only special screen characters."u8);
|
||||
|
||||
Im.Text("<w>"u8, color);
|
||||
ImGui.SameLine(0, 0);
|
||||
ImUtf8.Text(": show only players from your world."u8);
|
||||
_objects = objects;
|
||||
_penumbra = penumbra;
|
||||
_objects.Objects.OnUpdateRequired += OnUpdateRequired;
|
||||
_penumbra.CreatedCharacterBase += OnCreatedCharacterBase;
|
||||
}
|
||||
|
||||
DrawSelector();
|
||||
DrawSelectionButtons();
|
||||
}
|
||||
/// <summary> Update actors when models are created since visible models are required. </summary>
|
||||
private void OnCreatedCharacterBase(nint _1, Guid _2, IntPtr _3)
|
||||
=> Dirty |= IManagedCache.DirtyFlags.Custom;
|
||||
|
||||
private void DrawSelector()
|
||||
{
|
||||
using var child = ImUtf8.Child("##Selector"u8, new Vector2(_width, -Im.Style.FrameHeight), true);
|
||||
if (!child)
|
||||
return;
|
||||
/// <summary> Update actors when anything changes in the object table. </summary>
|
||||
private void OnUpdateRequired()
|
||||
=> Dirty |= IManagedCache.DirtyFlags.Custom;
|
||||
|
||||
_world = new WorldId(objects.Player.Valid ? objects.Player.HomeWorld : (ushort)0);
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
|
||||
var skips = ImGuiClip.GetNecessarySkips(Im.Style.TextHeight);
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(objects.Where(p => p.Value.Objects.Any(a => a.Model)), skips, CheckFilter,
|
||||
DrawSelectable);
|
||||
ImGuiClip.DrawEndDummy(remainder, Im.Style.TextHeight);
|
||||
}
|
||||
|
||||
private bool CheckFilter(KeyValuePair<ActorIdentifier, ActorData> pair)
|
||||
=> _actorFilter.Lower switch
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
"" => true,
|
||||
"<p>" => pair.Key.Type is IdentifierType.Player,
|
||||
"<o>" => pair.Key.Type is IdentifierType.Owned,
|
||||
"<n>" => pair.Key.Type is IdentifierType.Npc,
|
||||
"<r>" => pair.Key.Type is IdentifierType.Retainer,
|
||||
"<s>" => pair.Key.Type is IdentifierType.Special,
|
||||
"<w>" => pair.Key.Type is IdentifierType.Player && pair.Key.HomeWorld == _world,
|
||||
_ => _actorFilter.IsContained(pair.Value.Label),
|
||||
};
|
||||
base.Dispose(disposing);
|
||||
_objects.Objects.OnUpdateRequired -= OnUpdateRequired;
|
||||
_penumbra.CreatedCharacterBase -= OnCreatedCharacterBase;
|
||||
}
|
||||
|
||||
private void DrawSelectable(KeyValuePair<ActorIdentifier, ActorData> pair)
|
||||
{
|
||||
var equals = pair.Key.Equals(_identifier);
|
||||
if (ImUtf8.Selectable(IncognitoMode ? pair.Key.Incognito(pair.Value.Label) : pair.Value.Label, equals) && !equals)
|
||||
_identifier = pair.Key.CreatePermanent();
|
||||
}
|
||||
|
||||
private void DrawSelectionButtons()
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.FrameRounding, 0);
|
||||
var buttonWidth = new Vector2(_width / 2, 0);
|
||||
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.UserCircle, "Select the local player character."u8, buttonWidth, !objects.Player))
|
||||
_identifier = objects.Player.GetIdentifier(actors);
|
||||
|
||||
Im.Line.Same();
|
||||
var (id, data) = objects.TargetData;
|
||||
var tt = data.Valid ? $"Select the current target {id} in the list." :
|
||||
id.IsValid ? $"The target {id} is not in the list." : "No target selected.";
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.HandPointer, tt, buttonWidth, objects.IsInGPose || !data.Valid))
|
||||
_identifier = id;
|
||||
protected override IEnumerable<ActorCacheItem> GetItems()
|
||||
=> _objects.Where(p => p.Value.Objects.Any(a => a.Model)).Select(a => new ActorCacheItem(a.Key, a.Value));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,18 +3,35 @@ using Luna;
|
|||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class ActorTab(ActorSelector selector, ActorPanel panel) : ITab<MainTabType>
|
||||
public sealed class ActorTab : TwoPanelLayout, ITab<MainTabType>
|
||||
{
|
||||
public ReadOnlySpan<byte> Label
|
||||
=> "Actors"u8;
|
||||
private readonly ActorSelection _selection;
|
||||
|
||||
public MainTabType Identifier
|
||||
=> MainTabType.Actors;
|
||||
public ActorTab(ActorSelector selector, ActorPanel panel, ActorFilter filter, SelectPlayerButton selectPlayer,
|
||||
SelectTargetButton selectTarget, ActorsHeader header, ActorSelection selection)
|
||||
{
|
||||
_selection = selection;
|
||||
LeftPanel = selector;
|
||||
LeftHeader = new FilterHeader<ActorCacheItem>(filter, new StringU8("Filter..."u8));
|
||||
var footer = new ButtonFooter();
|
||||
footer.Buttons.AddButton(selectPlayer, 100);
|
||||
footer.Buttons.AddButton(selectTarget, 0);
|
||||
LeftFooter = footer;
|
||||
|
||||
RightHeader = header;
|
||||
RightPanel = panel;
|
||||
RightFooter = NopHeaderFooter.Instance;
|
||||
}
|
||||
|
||||
public override ReadOnlySpan<byte> Label
|
||||
=> "Actors"u8;
|
||||
|
||||
public void DrawContent()
|
||||
{
|
||||
selector.Draw(200 * Im.Style.GlobalScale);
|
||||
Im.Line.Same();
|
||||
panel.Draw();
|
||||
_selection.Update();
|
||||
Draw(TwoPanelWidth.IndeterminateRelative);
|
||||
}
|
||||
|
||||
public MainTabType Identifier
|
||||
=> MainTabType.Actors;
|
||||
}
|
||||
|
|
|
|||
38
Glamourer/Gui/Tabs/ActorTab/ActorsHeader.cs
Normal file
38
Glamourer/Gui/Tabs/ActorTab/ActorsHeader.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class ActorsHeader : SplitButtonHeader
|
||||
{
|
||||
private readonly ActorSelection _selection;
|
||||
private readonly EphemeralConfig _config;
|
||||
|
||||
public ActorsHeader(SetFromClipboardButton setFromClipboard, ExportToClipboardButton exportToClipboard, SaveAsDesignButton save,
|
||||
UndoButton undo, LockedButton locked, IncognitoButton incognito, ActorSelection selection, EphemeralConfig config)
|
||||
{
|
||||
_selection = selection;
|
||||
_config = config;
|
||||
LeftButtons.AddButton(setFromClipboard, 100);
|
||||
LeftButtons.AddButton(exportToClipboard, 90);
|
||||
LeftButtons.AddButton(save, 80);
|
||||
LeftButtons.AddButton(undo, 70);
|
||||
|
||||
RightButtons.AddButton(locked, 100);
|
||||
RightButtons.AddButton(incognito, 90);
|
||||
}
|
||||
|
||||
public override ReadOnlySpan<byte> Text
|
||||
=> _config.IncognitoMode ? _selection.IncognitoName : _selection.ActorName;
|
||||
|
||||
public override ColorParameter TextColor
|
||||
=> _selection.State is null ? ColorParameter.Default :
|
||||
_selection.Data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
|
||||
|
||||
public override void Draw(Vector2 size)
|
||||
{
|
||||
var color = ColorId.HeaderButtons.Value();
|
||||
using var _ = ImGuiColor.Text.Push(color).Push(ImGuiColor.Border, color);
|
||||
base.Draw(size with { Y = Im.Style.FrameHeight });
|
||||
}
|
||||
}
|
||||
41
Glamourer/Gui/Tabs/ActorTab/ExportToClipboardButton.cs
Normal file
41
Glamourer/Gui/Tabs/ActorTab/ExportToClipboardButton.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class ExportToClipboardButton(ActorSelection selection, DesignConverter converter) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.ToClipboardIcon;
|
||||
|
||||
public override bool IsVisible
|
||||
=> selection.State?.ModelData.ModelId is 0;
|
||||
|
||||
public override bool Enabled
|
||||
=> !(selection.State?.IsLocked ?? true);
|
||||
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(
|
||||
"Copy the current design to your clipboard.\nHold Control to disable applying of customizations for the copied design.\nHold Shift to disable applying of gear for the copied design."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = converter.ShareBase64(selection.State!, ApplicationRules.FromModifiers(selection.State!));
|
||||
ImGui.SetClipboardText(text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not copy {selection.Identifier} data to clipboard.",
|
||||
$"Could not copy data from design {selection.Identifier.Incognito(null)} to clipboard", NotificationType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Glamourer/Gui/Tabs/ActorTab/LockedButton.cs
Normal file
32
Glamourer/Gui/Tabs/ActorTab/LockedButton.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class LockedButton(ActorSelection selection) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.LockedIcon;
|
||||
|
||||
public override bool IsVisible
|
||||
=> selection.State?.IsLocked ?? false;
|
||||
|
||||
public override bool Enabled
|
||||
=> true;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("The current state of this actor is locked by external tools."u8);
|
||||
|
||||
protected override void PreDraw()
|
||||
{
|
||||
var color = ColorId.ActorAvailable.Value();
|
||||
ImGuiColor.Border.Push(color)
|
||||
.Push(ImGuiColor.Text, color);
|
||||
}
|
||||
|
||||
protected override void PostDraw()
|
||||
=> Im.ColorDisposable.PopUnsafe(2);
|
||||
}
|
||||
47
Glamourer/Gui/Tabs/ActorTab/SaveAsDesignButton.cs
Normal file
47
Glamourer/Gui/Tabs/ActorTab/SaveAsDesignButton.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class SaveAsDesignButton(ActorSelection selection, DesignConverter converter, DesignManager designManager)
|
||||
: BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.SaveIcon;
|
||||
|
||||
public override bool IsVisible
|
||||
=> selection.State?.ModelData.ModelId is 0;
|
||||
|
||||
public override bool Enabled
|
||||
=> !(selection.State?.IsLocked ?? true);
|
||||
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(
|
||||
"Save the current state as a design.\nHold Control to disable applying of customizations for the saved design.\nHold Shift to disable applying of gear for the saved design."u8);
|
||||
|
||||
private string _newName = string.Empty;
|
||||
private DesignBase? _newDesign;
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
Im.Popup.Open("Save as Design"u8);
|
||||
_newName = selection.State!.Identifier.ToName();
|
||||
_newDesign = converter.Convert(selection.State, ApplicationRules.FromModifiers(selection.State));
|
||||
}
|
||||
|
||||
protected override void PostDraw()
|
||||
{
|
||||
if (!InputPopup.Open("Save as Design"u8, _newName, out var newName, "Enter Design Name..."u8))
|
||||
return;
|
||||
|
||||
if (_newDesign is not null && newName.Length > 0)
|
||||
designManager.CreateClone(_newDesign, newName, true);
|
||||
_newDesign = null;
|
||||
_newName = string.Empty;
|
||||
}
|
||||
}
|
||||
27
Glamourer/Gui/Tabs/ActorTab/SelectPlayerButton.cs
Normal file
27
Glamourer/Gui/Tabs/ActorTab/SelectPlayerButton.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Dalamud.Interface;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class SelectPlayerButton(ActorObjectManager objects, ActorSelection selection) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> FontAwesomeIcon.UserCircle;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Select the local player character."u8);
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override bool Enabled
|
||||
=> objects.Player;
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
var (identifier, data) = objects.PlayerData;
|
||||
selection.Select(identifier, data);
|
||||
}
|
||||
}
|
||||
35
Glamourer/Gui/Tabs/ActorTab/SelectTargetButton.cs
Normal file
35
Glamourer/Gui/Tabs/ActorTab/SelectTargetButton.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
using Dalamud.Interface;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class SelectTargetButton(ActorObjectManager objects, ActorSelection selection) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> FontAwesomeIcon.HandPointer;
|
||||
|
||||
public override void DrawTooltip()
|
||||
{
|
||||
var (id, data) = objects.TargetData;
|
||||
if (data.Valid)
|
||||
Im.Text($"Select the current target {id} in the list.");
|
||||
else if (id.IsValid)
|
||||
Im.Text($"The target {id} is not in the list.");
|
||||
else
|
||||
Im.Text("No target selected."u8);
|
||||
}
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override bool Enabled
|
||||
=> objects.IsInGPose || !objects.TargetData.Data.Valid;
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
var (identifier, data) = objects.TargetData;
|
||||
selection.Select(identifier, data);
|
||||
}
|
||||
}
|
||||
44
Glamourer/Gui/Tabs/ActorTab/SetFromClipboardButton.cs
Normal file
44
Glamourer/Gui/Tabs/ActorTab/SetFromClipboardButton.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class SetFromClipboardButton(ActorSelection selection, DesignConverter converter, StateManager stateManager) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.FromClipboardIcon;
|
||||
|
||||
public override bool IsVisible
|
||||
=> selection.State is not null;
|
||||
|
||||
public override bool Enabled
|
||||
=> !(selection.State?.IsLocked ?? true);
|
||||
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Try to apply a design from your clipboard.\nHold Control to only apply gear.\nHold Shift to only apply customizations."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToBool();
|
||||
var text = ImGui.GetClipboardText();
|
||||
var design = converter.FromBase64(text, applyCustomize, applyGear, out _)
|
||||
?? throw new Exception("The clipboard did not contain valid data.");
|
||||
stateManager.ApplyDesign(selection.State!, design, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not apply clipboard to {selection.Identifier}.",
|
||||
$"Could not apply clipboard to design {selection.Identifier.Incognito(null)}", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Glamourer/Gui/Tabs/ActorTab/UndoButton.cs
Normal file
26
Glamourer/Gui/Tabs/ActorTab/UndoButton.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Glamourer.Designs.History;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.ActorTab;
|
||||
|
||||
public sealed class UndoButton(ActorSelection selection, EditorHistory editorHistory) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.UndoIcon;
|
||||
|
||||
public override bool IsVisible
|
||||
=> selection.State is not null;
|
||||
|
||||
public override bool Enabled
|
||||
=> !(selection.State?.IsLocked ?? true) && editorHistory.CanUndo(selection.State);
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Undo the last change."u8);
|
||||
|
||||
public override void OnClick()
|
||||
=> editorHistory.Undo(selection.State!);
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ public class SetPanel(
|
|||
RandomRestrictionDrawer randomDrawer)
|
||||
{
|
||||
private readonly JobGroupCombo _jobGroupCombo = new(manager, jobs, Glamourer.Log);
|
||||
private readonly HeaderDrawer.Button[] _rightButtons = [new HeaderDrawer.IncognitoButton(config)];
|
||||
private readonly HeaderDrawer.Button[] _rightButtons = []; // [new IncognitoButton(config)];
|
||||
private string? _tempName;
|
||||
private int _dragIndex = -1;
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ public class SetPanel(
|
|||
Im.Dummy(Vector2.Zero);
|
||||
|
||||
var name = _tempName ?? Selection.Name;
|
||||
var flags = selector.IncognitoMode ? InputTextFlags.ReadOnly | InputTextFlags.Password : InputTextFlags.None;
|
||||
var flags = config.Ephemeral.IncognitoMode ? InputTextFlags.ReadOnly | InputTextFlags.Password : InputTextFlags.None;
|
||||
Im.Item.SetNextWidthScaled(330);
|
||||
if (Im.Input.Text("Rename Set##Name"u8, ref name, StringU8.Empty, flags))
|
||||
_tempName = name;
|
||||
|
|
|
|||
|
|
@ -25,16 +25,6 @@ public class SetSelector : IDisposable
|
|||
public AutoDesignSet? Selection { get; private set; }
|
||||
public int SelectionIndex { get; private set; } = -1;
|
||||
|
||||
public bool IncognitoMode
|
||||
{
|
||||
get => _config.Ephemeral.IncognitoMode;
|
||||
set
|
||||
{
|
||||
_config.Ephemeral.IncognitoMode = value;
|
||||
_config.Ephemeral.Save();
|
||||
}
|
||||
}
|
||||
|
||||
private int _dragIndex = -1;
|
||||
private Action? _endAction;
|
||||
|
||||
|
|
@ -58,7 +48,7 @@ public class SetSelector : IDisposable
|
|||
=> GetSetName(Selection, SelectionIndex);
|
||||
|
||||
public string GetSetName(AutoDesignSet? set, int index)
|
||||
=> set == null ? "No Selection" : IncognitoMode ? $"Auto Design Set #{index + 1}" : set.Name;
|
||||
=> set == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? $"Auto Design Set #{index + 1}" : set.Name;
|
||||
|
||||
private void OnAutomationChange(AutomationChanged.Type type, AutoDesignSet? set, object? data)
|
||||
{
|
||||
|
|
@ -200,7 +190,7 @@ public class SetSelector : IDisposable
|
|||
DrawDragDrop(pair.Set, pair.Index);
|
||||
|
||||
var text = pair.Set.Identifiers[0].ToString();
|
||||
if (IncognitoMode)
|
||||
if (_config.Ephemeral.IncognitoMode)
|
||||
text = pair.Set.Identifiers[0].Incognito(text);
|
||||
var textSize = ImGui.CalcTextSize(text);
|
||||
var textColor = pair.Set.Identifiers.Any(_objects.ContainsKey) ? ColorId.AutomationActorAvailable : ColorId.AutomationActorUnavailable;
|
||||
|
|
|
|||
|
|
@ -32,16 +32,6 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
|
|||
private Design? _cloneDesign;
|
||||
private string _newName = string.Empty;
|
||||
|
||||
public bool IncognitoMode
|
||||
{
|
||||
get => _config.Ephemeral.IncognitoMode;
|
||||
set
|
||||
{
|
||||
_config.Ephemeral.IncognitoMode = value;
|
||||
_config.Ephemeral.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public new DesignFileSystem.Leaf? SelectedLeaf
|
||||
=> base.SelectedLeaf;
|
||||
|
||||
|
|
@ -175,7 +165,7 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
|
|||
protected override void DrawLeafName(FileSystem<Design>.Leaf leaf, in DesignState state, bool selected)
|
||||
{
|
||||
var flag = selected ? ImGuiTreeNodeFlags.Selected | LeafFlags : LeafFlags;
|
||||
var name = IncognitoMode ? leaf.Value.Incognito : leaf.Value.Name.Text;
|
||||
var name = _config.Ephemeral.IncognitoMode ? leaf.Value.Incognito : leaf.Value.Name.Text;
|
||||
using var color = ImGuiColor.Text.Push(state.Color);
|
||||
using var _ = ImUtf8.TreeNode(name, flag);
|
||||
if (_config.AllowDoubleClickToApply && ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(ImGuiMouseButton.Left))
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class DesignLinkDrawer(
|
|||
using (ImGuiColor.Text.Push(color))
|
||||
{
|
||||
Im.Cursor.FrameAlign();
|
||||
Im.Selectable(selector.IncognitoMode ? selector.Selected!.Incognito : selector.Selected!.Name.Text);
|
||||
Im.Selectable(config.Ephemeral.IncognitoMode ? selector.Selected!.Incognito : selector.Selected!.Name.Text);
|
||||
}
|
||||
|
||||
Im.Tooltip.OnHover("Current Design"u8);
|
||||
|
|
@ -133,7 +133,7 @@ public class DesignLinkDrawer(
|
|||
using (ImGuiColor.Text.Push(colorManager.GetColor(design)))
|
||||
{
|
||||
Im.Cursor.FrameAlign();
|
||||
Im.Selectable(selector.IncognitoMode ? design.Incognito : design.Name.Text);
|
||||
Im.Selectable(config.Ephemeral.IncognitoMode ? design.Incognito : design.Name.Text);
|
||||
}
|
||||
|
||||
DrawDragDrop(design, order, i);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public class DesignPanel
|
|||
_rightButtons =
|
||||
[
|
||||
new LockButton(this),
|
||||
new IncognitoButton(_config),
|
||||
//new IncognitoButton(_config),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ public class DesignPanel
|
|||
=> HeaderDrawer.Draw(SelectionName, 0, ImGuiColor.FrameBackground.Get().Color, _leftButtons, _rightButtons);
|
||||
|
||||
private string SelectionName
|
||||
=> _selector.Selected == null ? "No Selection" : _selector.IncognitoMode ? _selector.Selected.Incognito : _selector.Selected.Name.Text;
|
||||
=> _selector.Selected == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? _selector.Selected.Incognito : _selector.Selected.Name.Text;
|
||||
|
||||
private void DrawEquipment()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class MultiDesignPanel(
|
|||
Configuration config)
|
||||
{
|
||||
private readonly Button[] _leftButtons = [];
|
||||
private readonly Button[] _rightButtons = [new IncognitoButton(config)];
|
||||
private readonly Button[] _rightButtons = []; //[new IncognitoButton(config)];
|
||||
|
||||
private readonly DesignColorCombo _colorCombo = new(colors, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,39 +44,6 @@ public static class HeaderDrawer
|
|||
}
|
||||
}
|
||||
|
||||
public sealed class IncognitoButton(Configuration config) : Button
|
||||
{
|
||||
protected override string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
var hold = config.IncognitoModifier.IsActive();
|
||||
return (config.Ephemeral.IncognitoMode, hold)
|
||||
switch
|
||||
{
|
||||
(true, true) => "Toggle incognito mode off.",
|
||||
(false, true) => "Toggle incognito mode on.",
|
||||
(true, false) => $"Toggle incognito mode off.\n\nHold {config.IncognitoModifier} while clicking to toggle.",
|
||||
(false, false) => $"Toggle incognito mode on.\n\nHold {config.IncognitoModifier} while clicking to toggle.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> config.Ephemeral.IncognitoMode
|
||||
? FontAwesomeIcon.EyeSlash
|
||||
: FontAwesomeIcon.Eye;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
if (!config.IncognitoModifier.IsActive())
|
||||
return;
|
||||
|
||||
config.Ephemeral.IncognitoMode = !config.Ephemeral.IncognitoMode;
|
||||
config.Ephemeral.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Draw(string text, uint textColor, uint frameColor, Button[] leftButtons, Button[] rightButtons)
|
||||
{
|
||||
var width = Im.Style.FrameHeightWithSpacing;
|
||||
|
|
@ -110,4 +77,4 @@ public static class HeaderDrawer
|
|||
button.Draw(width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Glamourer/Gui/Tabs/IncognitoButton.cs
Normal file
29
Glamourer/Gui/Tabs/IncognitoButton.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs;
|
||||
|
||||
public sealed class IncognitoButton(Configuration config) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> config.Ephemeral.IncognitoMode
|
||||
? LunaStyle.IncognitoOn
|
||||
: LunaStyle.IncognitoOff;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
{
|
||||
var hold = config.IncognitoModifier.IsActive();
|
||||
Im.Text(config.Ephemeral.IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8);
|
||||
if (!hold)
|
||||
Im.Text($"\nHold {config.IncognitoModifier} while clicking to toggle.");
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if (config.IncognitoModifier.IsActive())
|
||||
config.Ephemeral.IncognitoMode = !config.Ephemeral.IncognitoMode;
|
||||
}
|
||||
}
|
||||
2
Luna
2
Luna
|
|
@ -1 +1 @@
|
|||
Subproject commit 6235cc8b4d0196c2545bf39834265fb4e0939b08
|
||||
Subproject commit ab620925015405133533c8811793f64082804d59
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit bdbf134934238c7af53aa8625467bd5ad580d6f6
|
||||
Subproject commit ab77b934eecc097ca1bf0d6243c8cd0dd4ffa155
|
||||
Loading…
Add table
Add a link
Reference in a new issue