Some cleanup, use OtterGui.

This commit is contained in:
Ottermandias 2022-07-03 16:35:56 +02:00
parent a36d1f1935
commit 0fc8992271
40 changed files with 2686 additions and 2792 deletions

4
.gitmodules vendored Normal file
View file

@ -0,0 +1,4 @@
[submodule "OtterGui"]
path = OtterGui
url = git@github.com:Ottermandias/OtterGui.git
branch = main

View file

@ -3,8 +3,8 @@ using System.ComponentModel;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
namespace Glamourer namespace Glamourer;
{
public static class WriteExtensions public static class WriteExtensions
{ {
private static unsafe void Write(IntPtr characterPtr, EquipSlot slot, SetId? id, WeaponType? type, ushort? variant, StainId? stain) private static unsafe void Write(IntPtr characterPtr, EquipSlot slot, SetId? id, WeaponType? type, ushort? variant, StainId? stain)
@ -27,7 +27,7 @@ namespace Glamourer
void WriteEquip(int offset) void WriteEquip(int offset)
{ {
var address = (byte*) characterPtr + offset; var address = (uint*)characterPtr + offset;
if (id.HasValue) if (id.HasValue)
*(ushort*)address = (ushort)id.Value; *(ushort*)address = (ushort)id.Value;
@ -165,4 +165,3 @@ namespace Glamourer
Write(characterAddress, EquipSlot.RFinger, equip.RFinger.Set, null, equip.RFinger.Variant, null); Write(characterAddress, EquipSlot.RFinger, equip.RFinger.Set, null, equip.RFinger.Variant, null);
} }
} }
}

View file

@ -1,23 +0,0 @@
using System;
namespace Glamourer
{
[Flags]
public enum CharacterEquipMask : ushort
{
None = 0,
MainHand = 0b000000000001,
OffHand = 0b000000000010,
Head = 0b000000000100,
Body = 0b000000001000,
Hands = 0b000000010000,
Legs = 0b000000100000,
Feet = 0b000001000000,
Ears = 0b000010000000,
Neck = 0b000100000000,
Wrists = 0b001000000000,
RFinger = 0b010000000000,
LFinger = 0b100000000000,
All = 0b111111111111,
}
}

View file

@ -1,10 +1,11 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
namespace Glamourer.Customization namespace Glamourer.Customization;
{
public unsafe struct LazyCustomization public unsafe struct LazyCustomization
{ {
public CharacterCustomization* Address; public CharacterCustomization* Address;
@ -19,7 +20,6 @@ namespace Glamourer.Customization
=> Address = &data; => Address = &data;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CharacterCustomization public struct CharacterCustomization
{ {
@ -150,6 +150,9 @@ namespace Glamourer.Customization
} }
} }
public unsafe void Read(Customization* customize)
=> Read((IntPtr)customize);
public void Read(Character character) public void Read(Character character)
=> Read(character.Address + CustomizationOffset); => Read(character.Address + CustomizationOffset);
@ -300,5 +303,21 @@ namespace Glamourer.Customization
WriteBytes(ret); WriteBytes(ret);
return ret; return ret;
} }
public string HumanReadable()
{
// TODO
var sb = new StringBuilder();
sb.Append($"Race: {Race.ToName()} - {Clan.ToName()}\n");
sb.Append($"Gender: {Gender.ToName()}\n");
sb.Append($"Height: {Height}%\n");
sb.Append($"Face: #{Face}\n");
sb.Append($"Hairstyle: #{Hairstyle}\n");
sb.Append($"Haircolor: #{HairColor}");
if (HighlightsOn)
sb.Append($" with Highlights #{HighlightsColor}\n");
else
sb.Append('\n');
return sb.ToString();
} }
} }

View file

@ -1,8 +1,8 @@
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Plugin; using Dalamud.Plugin;
namespace Glamourer namespace Glamourer;
{
public class CmpFile public class CmpFile
{ {
public readonly Lumina.Data.FileResource File; public readonly Lumina.Data.FileResource File;
@ -21,4 +21,3 @@ namespace Glamourer
} }
} }
} }
}

View file

@ -5,15 +5,15 @@ using System.Reflection;
using Dalamud; using Dalamud;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Plugin; using Dalamud.Plugin;
using Glamourer.Util;
using Lumina.Data; using Lumina.Data;
using Lumina.Excel; using Lumina.Excel;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using OtterGui.Classes;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Race = Penumbra.GameData.Enums.Race; using Race = Penumbra.GameData.Enums.Race;
namespace Glamourer.Customization namespace Glamourer.Customization;
{
public partial class CustomizationOptions public partial class CustomizationOptions
{ {
internal static readonly Race[] Races = ((Race[])Enum.GetValues(typeof(Race))).Skip(1).ToArray(); internal static readonly Race[] Races = ((Race[])Enum.GetValues(typeof(Race))).Skip(1).ToArray();
@ -371,4 +371,3 @@ namespace Glamourer.Customization
_names[(int)CustomName.VeenaF] = subRace.GetRow((int)SubRace.Veena)?.Feminine.ToString() ?? SubRace.Veena.ToName(); _names[(int)CustomName.VeenaF] = subRace.GetRow((int)SubRace.Veena)?.Feminine.ToString() ?? SubRace.Veena.ToName();
} }
} }
}

View file

@ -3,11 +3,14 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Dalamud; using Dalamud;
using Dalamud.Data; using Dalamud.Data;
using Glamourer.Structs;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Item = Glamourer.Structs.Item;
using Stain = Glamourer.Structs.Stain;
namespace Glamourer;
namespace Glamourer
{
public static class GameData public static class GameData
{ {
private static Dictionary<byte, Stain>? _stains; private static Dictionary<byte, Stain>? _stains;
@ -54,17 +57,53 @@ namespace Glamourer
_itemsBySlot = new Dictionary<EquipSlot, List<Item>>() _itemsBySlot = new Dictionary<EquipSlot, List<Item>>()
{ {
[EquipSlot.Head] = new(200) { EmptySlot(EquipSlot.Head), EmptyNpc(EquipSlot.Head) }, [EquipSlot.Head] = new(200)
[EquipSlot.Body] = new(200) { EmptySlot(EquipSlot.Body), EmptyNpc(EquipSlot.Body) }, {
[EquipSlot.Hands] = new(200) { EmptySlot(EquipSlot.Hands), EmptyNpc(EquipSlot.Hands) }, EmptySlot(EquipSlot.Head),
[EquipSlot.Legs] = new(200) { EmptySlot(EquipSlot.Legs), EmptyNpc(EquipSlot.Legs) }, EmptyNpc(EquipSlot.Head),
[EquipSlot.Feet] = new(200) { EmptySlot(EquipSlot.Feet), EmptyNpc(EquipSlot.Feet) }, },
[EquipSlot.RFinger] = new(200) { EmptySlot(EquipSlot.RFinger), EmptyNpc(EquipSlot.RFinger) }, [EquipSlot.Body] = new(200)
[EquipSlot.Neck] = new(200) { EmptySlot(EquipSlot.Neck), EmptyNpc(EquipSlot.Neck) }, {
EmptySlot(EquipSlot.Body),
EmptyNpc(EquipSlot.Body),
},
[EquipSlot.Hands] = new(200)
{
EmptySlot(EquipSlot.Hands),
EmptyNpc(EquipSlot.Hands),
},
[EquipSlot.Legs] = new(200)
{
EmptySlot(EquipSlot.Legs),
EmptyNpc(EquipSlot.Legs),
},
[EquipSlot.Feet] = new(200)
{
EmptySlot(EquipSlot.Feet),
EmptyNpc(EquipSlot.Feet),
},
[EquipSlot.RFinger] = new(200)
{
EmptySlot(EquipSlot.RFinger),
EmptyNpc(EquipSlot.RFinger),
},
[EquipSlot.Neck] = new(200)
{
EmptySlot(EquipSlot.Neck),
EmptyNpc(EquipSlot.Neck),
},
[EquipSlot.MainHand] = new(1000) { EmptySlot(EquipSlot.MainHand) }, [EquipSlot.MainHand] = new(1000) { EmptySlot(EquipSlot.MainHand) },
[EquipSlot.OffHand] = new(200) { EmptySlot(EquipSlot.OffHand) }, [EquipSlot.OffHand] = new(200) { EmptySlot(EquipSlot.OffHand) },
[EquipSlot.Wrists] = new(200) { EmptySlot(EquipSlot.Wrists), EmptyNpc(EquipSlot.Wrists) }, [EquipSlot.Wrists] = new(200)
[EquipSlot.Ears] = new(200) { EmptySlot(EquipSlot.Ears), EmptyNpc(EquipSlot.Ears) }, {
EmptySlot(EquipSlot.Wrists),
EmptyNpc(EquipSlot.Wrists),
},
[EquipSlot.Ears] = new(200)
{
EmptySlot(EquipSlot.Ears),
EmptyNpc(EquipSlot.Ears),
},
}; };
foreach (var item in sheet) foreach (var item in sheet)
@ -111,7 +150,7 @@ namespace Glamourer
static bool ValidIndex(uint idx) static bool ValidIndex(uint idx)
{ {
if (idx > 0 && idx < 36) if (idx is > 0 and < 36)
return true; return true;
return idx switch return idx switch
@ -141,4 +180,3 @@ namespace Glamourer
return _jobGroups; return _jobGroups;
} }
} }
}

View file

@ -58,6 +58,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Penumbra\OtterGui\OtterGui.csproj" />
<ProjectReference Include="..\..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj" /> <ProjectReference Include="..\..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,55 +0,0 @@
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer
{
public readonly struct Item
{
private static (SetId id, WeaponType type, ushort variant) ParseModel(EquipSlot slot, ulong data)
{
if (slot == EquipSlot.MainHand || slot == EquipSlot.OffHand)
{
var id = (SetId) (data & 0xFFFF);
var type = (WeaponType) ((data >> 16) & 0xFFFF);
var variant = (ushort) ((data >> 32) & 0xFFFF);
return (id, type, variant);
}
else
{
var id = (SetId) (data & 0xFFFF);
var variant = (byte) ((data >> 16) & 0xFF);
return (id, new WeaponType(), variant);
}
}
public readonly Lumina.Excel.GeneratedSheets.Item Base;
public readonly string Name;
public readonly EquipSlot EquippableTo;
public (SetId id, WeaponType type, ushort variant) MainModel
=> ParseModel(EquippableTo, Base.ModelMain);
public bool HasSubModel
=> Base.ModelSub != 0;
public (SetId id, WeaponType type, ushort variant) SubModel
=> ParseModel(EquippableTo, Base.ModelSub);
public Item(Lumina.Excel.GeneratedSheets.Item item, string name, EquipSlot slot = EquipSlot.Unknown)
{
Base = item;
Name = name;
EquippableTo = slot == EquipSlot.Unknown ? ((EquipSlot) item.EquipSlotCategory.Row).ToSlot() : slot;
}
public static Item Nothing(EquipSlot slot)
=> new("Nothing", slot);
private Item(string name, EquipSlot slot)
{
Name = name;
Base = new Lumina.Excel.GeneratedSheets.Item();
EquippableTo = slot;
}
}
}

View file

@ -1,21 +0,0 @@
using Lumina.Excel.GeneratedSheets;
namespace Glamourer
{
public readonly struct Job
{
public readonly string Name;
public readonly string Abbreviation;
public readonly ClassJob Base;
public uint Id
=> Base.RowId;
public Job(ClassJob job)
{
Base = job;
Name = job.Name.ToString();
Abbreviation = job.Abbreviation.ToString();
}
}
}

View file

@ -1,50 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace Glamourer
{
public readonly struct JobGroup
{
public readonly string Name;
private readonly ulong _flags;
public readonly int Count;
public readonly uint Id;
public JobGroup(ClassJobCategory group, ExcelSheet<ClassJob> jobs)
{
Count = 0;
_flags = 0ul;
Id = group.RowId;
Name = group.Name.ToString();
Debug.Assert(jobs.RowCount < 64);
foreach (var job in jobs)
{
var abbr = job.Abbreviation.ToString();
if (!abbr.Any())
continue;
var prop = group.GetType().GetProperty(abbr);
Debug.Assert(prop != null);
if (!(bool) prop.GetValue(group)!)
continue;
++Count;
_flags |= 1ul << (int) job.RowId;
}
}
public bool Fits(Job job)
=> Fits(job.Id);
public bool Fits(uint jobId)
{
var flag = 1ul << (int)jobId;
return (flag & _flags) != 0;
}
}
}

View file

@ -1,50 +0,0 @@
using Penumbra.GameData.Structs;
namespace Glamourer
{
public readonly struct Stain
{
public readonly string Name;
public readonly uint RgbaColor;
private readonly uint _seColorId;
public byte R
=> (byte) (RgbaColor & 0xFF);
public byte G
=> (byte) ((RgbaColor >> 8) & 0xFF);
public byte B
=> (byte) ((RgbaColor >> 16) & 0xFF);
public byte Intensity
=> (byte) ((1 + R + G + B) / 3);
public uint SeColor
=> _seColorId & 0x00FFFFFF;
public StainId RowIndex
=> (StainId) (_seColorId >> 24);
public static uint SeColorToRgba(uint color)
=> ((color & 0xFF) << 16) | ((color >> 16) & 0xFF) | (color & 0xFF00) | 0xFF000000;
public Stain(byte index, Lumina.Excel.GeneratedSheets.Stain stain)
{
Name = stain.Name.ToString();
_seColorId = stain.Color | ((uint) index << 24);
RgbaColor = SeColorToRgba(stain.Color);
}
public static readonly Stain None = new("None");
private Stain(string name)
{
Name = name;
_seColorId = 0;
RgbaColor = 0;
}
}
}

View file

@ -0,0 +1,43 @@
using System;
using Penumbra.GameData.Enums;
namespace Glamourer.Structs;
[Flags]
public enum CharacterEquipMask : ushort
{
None = 0,
MainHand = 0b000000000001,
OffHand = 0b000000000010,
Head = 0b000000000100,
Body = 0b000000001000,
Hands = 0b000000010000,
Legs = 0b000000100000,
Feet = 0b000001000000,
Ears = 0b000010000000,
Neck = 0b000100000000,
Wrists = 0b001000000000,
RFinger = 0b010000000000,
LFinger = 0b100000000000,
All = 0b111111111111,
}
public static class CharacterEquipMaskExtensions
{
public static bool Fits(this CharacterEquipMask mask, EquipSlot slot)
=> slot switch
{
EquipSlot.Unknown => false,
EquipSlot.Head => mask.HasFlag(CharacterEquipMask.Head),
EquipSlot.Body => mask.HasFlag(CharacterEquipMask.Body),
EquipSlot.Hands => mask.HasFlag(CharacterEquipMask.Hands),
EquipSlot.Legs => mask.HasFlag(CharacterEquipMask.Legs),
EquipSlot.Feet => mask.HasFlag(CharacterEquipMask.Feet),
EquipSlot.Ears => mask.HasFlag(CharacterEquipMask.Ears),
EquipSlot.Neck => mask.HasFlag(CharacterEquipMask.Neck),
EquipSlot.Wrists => mask.HasFlag(CharacterEquipMask.Wrists),
EquipSlot.RFinger => mask.HasFlag(CharacterEquipMask.RFinger),
EquipSlot.LFinger => mask.HasFlag(CharacterEquipMask.LFinger),
_ => false,
};
}

View file

@ -0,0 +1,54 @@
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Structs;
public readonly struct Item
{
private static (SetId id, WeaponType type, ushort variant) ParseModel(EquipSlot slot, ulong data)
{
if (slot is EquipSlot.MainHand or EquipSlot.OffHand)
{
var id = (SetId)(data & 0xFFFF);
var type = (WeaponType)((data >> 16) & 0xFFFF);
var variant = (ushort)((data >> 32) & 0xFFFF);
return (id, type, variant);
}
else
{
var id = (SetId)(data & 0xFFFF);
var variant = (byte)((data >> 16) & 0xFF);
return (id, new WeaponType(), variant);
}
}
public readonly Lumina.Excel.GeneratedSheets.Item Base;
public readonly string Name;
public readonly EquipSlot EquippableTo;
public (SetId id, WeaponType type, ushort variant) MainModel
=> ParseModel(EquippableTo, Base.ModelMain);
public bool HasSubModel
=> Base.ModelSub != 0;
public (SetId id, WeaponType type, ushort variant) SubModel
=> ParseModel(EquippableTo, Base.ModelSub);
public Item(Lumina.Excel.GeneratedSheets.Item item, string name, EquipSlot slot = EquipSlot.Unknown)
{
Base = item;
Name = name;
EquippableTo = slot == EquipSlot.Unknown ? ((EquipSlot)item.EquipSlotCategory.Row).ToSlot() : slot;
}
public static Item Nothing(EquipSlot slot)
=> new("Nothing", slot);
private Item(string name, EquipSlot slot)
{
Name = name;
Base = new Lumina.Excel.GeneratedSheets.Item();
EquippableTo = slot;
}
}

View file

@ -0,0 +1,20 @@
using Lumina.Excel.GeneratedSheets;
namespace Glamourer.Structs;
public readonly struct Job
{
public readonly string Name;
public readonly string Abbreviation;
public readonly ClassJob Base;
public uint Id
=> Base.RowId;
public Job(ClassJob job)
{
Base = job;
Name = job.Name.ToString();
Abbreviation = job.Abbreviation.ToString();
}
}

View file

@ -0,0 +1,48 @@
using System.Diagnostics;
using System.Linq;
using Lumina.Excel;
using Lumina.Excel.GeneratedSheets;
namespace Glamourer.Structs;
public readonly struct JobGroup
{
public readonly string Name;
private readonly ulong _flags;
public readonly int Count;
public readonly uint Id;
public JobGroup(ClassJobCategory group, ExcelSheet<ClassJob> jobs)
{
Count = 0;
_flags = 0ul;
Id = group.RowId;
Name = group.Name.ToString();
Debug.Assert(jobs.RowCount < 64);
foreach (var job in jobs)
{
var abbr = job.Abbreviation.ToString();
if (!abbr.Any())
continue;
var prop = group.GetType().GetProperty(abbr);
Debug.Assert(prop != null);
if (!(bool)prop.GetValue(group)!)
continue;
++Count;
_flags |= 1ul << (int)job.RowId;
}
}
public bool Fits(Job job)
=> Fits(job.Id);
public bool Fits(uint jobId)
{
var flag = 1ul << (int)jobId;
return (flag & _flags) != 0;
}
}

View file

@ -0,0 +1,49 @@
using Penumbra.GameData.Structs;
namespace Glamourer.Structs;
public readonly struct Stain
{
public readonly string Name;
public readonly uint RgbaColor;
private readonly uint _seColorId;
public byte R
=> (byte)(RgbaColor & 0xFF);
public byte G
=> (byte)(RgbaColor >> 8 & 0xFF);
public byte B
=> (byte)(RgbaColor >> 16 & 0xFF);
public byte Intensity
=> (byte)((1 + R + G + B) / 3);
public uint SeColor
=> _seColorId & 0x00FFFFFF;
public StainId RowIndex
=> (StainId)(_seColorId >> 24);
public static uint SeColorToRgba(uint color)
=> (color & 0xFF) << 16 | color >> 16 & 0xFF | color & 0xFF00 | 0xFF000000;
public Stain(byte index, Lumina.Excel.GeneratedSheets.Stain stain)
{
Name = stain.Name.ToString();
_seColorId = stain.Color | (uint)index << 24;
RgbaColor = SeColorToRgba(stain.Color);
}
public static readonly Stain None = new("None");
private Stain(string name)
{
Name = name;
_seColorId = 0;
RgbaColor = 0;
}
}

View file

@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using Dalamud.Data;
using Dalamud.Plugin;
using Dalamud.Utility;
using ImGuiScene;
using Lumina.Data.Files;
namespace Glamourer.Util
{
public class IconStorage : IDisposable
{
private readonly DalamudPluginInterface _pi;
private readonly DataManager _gameData;
private readonly Dictionary<uint, TextureWrap> _icons;
public IconStorage(DalamudPluginInterface pi, DataManager gameData, int size = 0)
{
_pi = pi;
_gameData = gameData;
_icons = new Dictionary<uint, TextureWrap>(size);
}
public TextureWrap this[int id]
=> LoadIcon(id);
private TexFile? LoadIconHq(uint id)
{
var path = $"ui/icon/{id / 1000 * 1000:000000}/{id:000000}_hr1.tex";
return _gameData.GetFile<TexFile>(path);
}
public TextureWrap LoadIcon(int id)
=> LoadIcon((uint) id);
public TextureWrap LoadIcon(uint id)
{
if (_icons.TryGetValue(id, out var ret))
return ret;
var icon = LoadIconHq(id) ?? _gameData.GetIcon(id)!;
var iconData = icon.GetRgbaImageData();
ret = _pi.UiBuilder.LoadImageRaw(iconData, icon.Header.Width, icon.Header.Height, 4);
_icons[id] = ret;
return ret;
}
public void Dispose()
{
foreach (var icon in _icons.Values)
icon.Dispose();
_icons.Clear();
}
~IconStorage()
=> Dispose();
}
}

View file

@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "..\Pen
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.PlayerWatch", "..\Penumbra\Penumbra.PlayerWatch\Penumbra.PlayerWatch.csproj", "{FECEDB39-C103-4333-82A6-A422BDC51EEE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.PlayerWatch", "..\Penumbra\Penumbra.PlayerWatch\Penumbra.PlayerWatch.csproj", "{FECEDB39-C103-4333-82A6-A422BDC51EEE}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OtterGui", "..\Penumbra\OtterGui\OtterGui.csproj", "{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -75,6 +77,18 @@ Global
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x64.Build.0 = Release|Any CPU {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x64.Build.0 = Release|Any CPU
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.ActiveCfg = Release|Any CPU {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.ActiveCfg = Release|Any CPU
{FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.Build.0 = Release|Any CPU {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.Build.0 = Release|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Debug|x64.Build.0 = Debug|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Debug|x86.Build.0 = Debug|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Release|Any CPU.Build.0 = Release|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Release|x64.ActiveCfg = Release|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Release|x64.Build.0 = Release|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Release|x86.ActiveCfg = Release|Any CPU
{6A4F7788-DB91-41B6-A264-7FD9CCACD7AA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -2,6 +2,7 @@
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Logging; using Dalamud.Logging;
using Dalamud.Plugin.Ipc; using Dalamud.Plugin.Ipc;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Gui; using Glamourer.Gui;
using ImGuiNET; using ImGuiNET;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
@ -17,10 +18,14 @@ public class PenumbraAttach : IDisposable
private ICallGateSubscriber<MouseButton, ChangedItemType, uint, object>? _clickSubscriber; private ICallGateSubscriber<MouseButton, ChangedItemType, uint, object>? _clickSubscriber;
private ICallGateSubscriber<string, int, object>? _redrawSubscriberName; private ICallGateSubscriber<string, int, object>? _redrawSubscriberName;
private ICallGateSubscriber<GameObject, int, object>? _redrawSubscriberObject; private ICallGateSubscriber<GameObject, int, object>? _redrawSubscriberObject;
private ICallGateSubscriber<IntPtr, (IntPtr, string)>? _drawObjectInfo;
private ICallGateSubscriber<IntPtr, string, IntPtr, IntPtr, object?>? _creatingCharacterBase;
private readonly ICallGateSubscriber<object?> _initializedEvent; private readonly ICallGateSubscriber<object?> _initializedEvent;
private readonly ICallGateSubscriber<object?> _disposedEvent; private readonly ICallGateSubscriber<object?> _disposedEvent;
public event Action<IntPtr, IntPtr, IntPtr>? CreatingCharacterBase;
public PenumbraAttach(bool attach) public PenumbraAttach(bool attach)
{ {
_initializedEvent = Dalamud.PluginInterface.GetIpcSubscriber<object?>("Penumbra.Initialized"); _initializedEvent = Dalamud.PluginInterface.GetIpcSubscriber<object?>("Penumbra.Initialized");
@ -47,6 +52,7 @@ public class PenumbraAttach : IDisposable
_redrawSubscriberName = Dalamud.PluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName"); _redrawSubscriberName = Dalamud.PluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
_redrawSubscriberObject = Dalamud.PluginInterface.GetIpcSubscriber<GameObject, int, object>("Penumbra.RedrawObject"); _redrawSubscriberObject = Dalamud.PluginInterface.GetIpcSubscriber<GameObject, int, object>("Penumbra.RedrawObject");
_drawObjectInfo = Dalamud.PluginInterface.GetIpcSubscriber<IntPtr, (IntPtr, string)>("Penumbra.GetDrawObjectInfo");
if (!attach) if (!attach)
return; return;
@ -54,8 +60,11 @@ public class PenumbraAttach : IDisposable
_tooltipSubscriber = Dalamud.PluginInterface.GetIpcSubscriber<ChangedItemType, uint, object>("Penumbra.ChangedItemTooltip"); _tooltipSubscriber = Dalamud.PluginInterface.GetIpcSubscriber<ChangedItemType, uint, object>("Penumbra.ChangedItemTooltip");
_clickSubscriber = _clickSubscriber =
Dalamud.PluginInterface.GetIpcSubscriber<MouseButton, ChangedItemType, uint, object>("Penumbra.ChangedItemClick"); Dalamud.PluginInterface.GetIpcSubscriber<MouseButton, ChangedItemType, uint, object>("Penumbra.ChangedItemClick");
_creatingCharacterBase =
Dalamud.PluginInterface.GetIpcSubscriber<IntPtr, string, IntPtr, IntPtr, object?>("Penumbra.CreatingCharacterBase");
_tooltipSubscriber.Subscribe(PenumbraTooltip); _tooltipSubscriber.Subscribe(PenumbraTooltip);
_clickSubscriber.Subscribe(PenumbraRightClick); _clickSubscriber.Subscribe(PenumbraRightClick);
_creatingCharacterBase.Subscribe(SubscribeCharacterBase);
PluginLog.Debug("Glamourer attached to Penumbra."); PluginLog.Debug("Glamourer attached to Penumbra.");
} }
catch (Exception e) catch (Exception e)
@ -64,13 +73,19 @@ public class PenumbraAttach : IDisposable
} }
} }
private void SubscribeCharacterBase(IntPtr gameObject, string _, IntPtr customize, IntPtr equipment)
=> CreatingCharacterBase?.Invoke(gameObject, customize, equipment);
public void Unattach() public void Unattach()
{ {
_tooltipSubscriber?.Unsubscribe(PenumbraTooltip); _tooltipSubscriber?.Unsubscribe(PenumbraTooltip);
_clickSubscriber?.Unsubscribe(PenumbraRightClick); _clickSubscriber?.Unsubscribe(PenumbraRightClick);
_creatingCharacterBase?.Unsubscribe(SubscribeCharacterBase);
_tooltipSubscriber = null; _tooltipSubscriber = null;
_clickSubscriber = null; _clickSubscriber = null;
_creatingCharacterBase = null;
_redrawSubscriberName = null; _redrawSubscriberName = null;
_drawObjectInfo = null;
if (_redrawSubscriberObject != null) if (_redrawSubscriberObject != null)
{ {
PluginLog.Debug("Glamourer detached from Penumbra."); PluginLog.Debug("Glamourer detached from Penumbra.");
@ -112,6 +127,9 @@ public class PenumbraAttach : IDisposable
} }
} }
public unsafe FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* GameObjectFromDrawObject(IntPtr drawObject)
=> (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)(_drawObjectInfo?.InvokeFunc(drawObject).Item1 ?? IntPtr.Zero);
public void RedrawObject(GameObject actor, RedrawType settings, bool repeat) public void RedrawObject(GameObject actor, RedrawType settings, bool repeat)
{ {
if (_redrawSubscriberObject != null) if (_redrawSubscriberObject != null)

View file

@ -1,68 +0,0 @@
using System;
namespace Glamourer
{
[Flags]
public enum CharacterFlag : ulong
{
MainHand = 1ul << 0,
OffHand = 1ul << 1,
Head = 1ul << 2,
Body = 1ul << 3,
Hands = 1ul << 4,
Legs = 1ul << 5,
Feet = 1ul << 6,
Ears = 1ul << 7,
Neck = 1ul << 8,
Wrists = 1ul << 9,
RFinger = 1ul << 10,
LFinger = 1ul << 11,
ModelMask = (1ul << 12) - 1,
StainMainHand = MainHand << 16,
StainOffHand = OffHand << 16,
StainHead = Head << 16,
StainBody = Body << 16,
StainHands = Hands << 16,
StainLegs = Legs << 16,
StainFeet = Feet << 16,
StainEars = Ears << 16,
StainNeck = Neck << 16,
StainWrists = Wrists << 16,
StainRFinger = RFinger << 16,
StainLFinger = LFinger << 16,
StainMask = ModelMask << 16,
EquipMask = ModelMask | StainMask,
Race = 1ul << 32,
Gender = 1ul << 33,
BodyType = 1ul << 34,
Height = 1ul << 35,
Clan = 1ul << 36,
Face = 1ul << 37,
Hairstyle = 1ul << 38,
Highlights = 1ul << 39,
SkinColor = 1ul << 40,
EyeColorRight = 1ul << 41,
HairColor = 1ul << 42,
HighlightsColor = 1ul << 43,
FacialFeatures = 1ul << 44,
TattooColor = 1ul << 45,
Eyebrows = 1ul << 46,
EyeColorLeft = 1ul << 47,
EyeShape = 1ul << 48,
IrisSize = 1ul << 49,
NoseShape = 1ul << 50,
JawShape = 1ul << 51,
MouthShape = 1ul << 52,
Lipstick = 1ul << 53,
LipColor = 1ul << 54,
MuscleMass = 1ul << 55,
TailShape = 1ul << 56,
BustSize = 1ul << 57,
FacePaint = 1ul << 58,
FacePaintReversed = 1ul << 59,
FacePaintColor = 1ul << 60,
CustomizeMask = ((1ul << 61) - 1) & ~EquipMask,
}
}

View file

@ -1,27 +1,16 @@
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Game; using Dalamud.Game;
using Dalamud.Game.ClientState; using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Buddy;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Fates;
using Dalamud.Game.ClientState.JobGauge;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Party;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Game.Gui.FlyText;
using Dalamud.Game.Gui.PartyFinder;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Libc;
using Dalamud.Game.Network;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Local // ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
namespace Glamourer namespace Glamourer;
{
public class Dalamud public class Dalamud
{ {
public static void Initialize(DalamudPluginInterface pluginInterface) public static void Initialize(DalamudPluginInterface pluginInterface)
@ -30,27 +19,11 @@ namespace Glamourer
// @formatter:off // @formatter:off
[PluginService][RequiredVersion("1.0")] public static DalamudPluginInterface PluginInterface { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static DalamudPluginInterface PluginInterface { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static CommandManager Commands { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static CommandManager Commands { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static SigScanner SigScanner { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static DataManager GameData { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static DataManager GameData { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static ClientState ClientState { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static ClientState ClientState { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static ChatGui Chat { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static ChatGui Chat { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static SeStringManager SeStrings { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static ChatHandlers ChatHandlers { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static Framework Framework { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static Framework Framework { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static GameNetwork Network { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static Condition Conditions { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static KeyState Keys { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static GameGui GameGui { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static FlyTextGui FlyTexts { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static ToastGui Toasts { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static JobGauges Gauges { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static PartyFinderGui PartyFinder { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static BuddyList Buddies { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static PartyList Party { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static TargetManager Targets { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static TargetManager Targets { get; private set; } = null!;
[PluginService][RequiredVersion("1.0")] public static ObjectTable Objects { get; private set; } = null!; [PluginService][RequiredVersion("1.0")] public static ObjectTable Objects { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static FateTable Fates { get; private set; } = null!;
//[PluginService][RequiredVersion("1.0")] public static LibcFunction LibC { get; private set; } = null!;
// @formatter:on // @formatter:on
} }
}

View file

@ -5,6 +5,7 @@ using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Logging; using Dalamud.Logging;
using Glamourer.FileSystem; using Glamourer.FileSystem;
using Glamourer.Structs;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.PlayerWatch; using Penumbra.PlayerWatch;
@ -122,19 +123,19 @@ namespace Glamourer.Designs
private void OnPlayerChange(Character character) private void OnPlayerChange(Character character)
{ {
var name = character.Name.ToString(); //var name = character.Name.ToString();
if (!EnabledDesigns.TryGetValue(name, out var designs)) //if (!EnabledDesigns.TryGetValue(name, out var designs))
return; // return;
//
var design = designs.OrderBy(d => d.Jobs.Count).FirstOrDefault(d => d.Jobs.Fits(character.ClassJob.Id)); //var design = designs.OrderBy(d => d.Jobs.Count).FirstOrDefault(d => d.Jobs.Fits(character.ClassJob.Id));
if (design == null) //if (design == null)
return; // return;
//
PluginLog.Debug("Redrawing {CharacterName} with {DesignName} for job {JobGroup}.", name, design.Design.FullName(), //PluginLog.Debug("Redrawing {CharacterName} with {DesignName} for job {JobGroup}.", name, design.Design.FullName(),
design.Jobs.Name); // design.Jobs.Name);
design.Design.Data.Apply(character); //design.Design.Data.Apply(character);
Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character); //Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character);
Glamourer.Penumbra.RedrawObject(character, RedrawType.Redraw, false); //Glamourer.Penumbra.RedrawObject(character, RedrawType.Redraw, false);
} }
public void Add(string name, Design design, JobGroup group, bool enabled = false) public void Add(string name, Design design, JobGroup group, bool enabled = false)

View file

@ -1,19 +1,146 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Hooking;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Api; using Glamourer.Api;
using Glamourer.Customization; using Glamourer.Customization;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.FileSystem; using Glamourer.FileSystem;
using Glamourer.Gui; using Glamourer.Gui;
using ImGuiNET; using ImGuiNET;
using Penumbra.GameData.ByteString;
using Penumbra.GameData.Enums;
using Penumbra.PlayerWatch; using Penumbra.PlayerWatch;
namespace Glamourer namespace Glamourer;
public unsafe class FixedDesignManager : IDisposable
{ {
public delegate ulong FlagSlotForUpdateDelegate(Human* drawObject, uint slot, uint* data);
[Signature("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B DA 49 8B F0 48 8B F9 83 FA 0A",
DetourName = nameof(FlagSlotForUpdateDetour))]
public Hook<FlagSlotForUpdateDelegate>? FlagSlotForUpdateHook;
public readonly FixedDesigns FixedDesigns;
public FixedDesignManager(DesignManager designs)
{
SignatureHelper.Initialise(this);
FixedDesigns = new FixedDesigns(designs);
if (Glamourer.Config.ApplyFixedDesigns)
Enable();
}
public void Enable()
{
FlagSlotForUpdateHook?.Enable();
Glamourer.Penumbra.CreatingCharacterBase += ApplyFixedDesign;
}
public void Disable()
{
FlagSlotForUpdateHook?.Disable();
Glamourer.Penumbra.CreatingCharacterBase -= ApplyFixedDesign;
}
public void Dispose()
{
FlagSlotForUpdateHook?.Dispose();
}
private void ApplyFixedDesign(IntPtr addr, IntPtr customize, IntPtr equipData)
{
var human = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)addr;
if (human->GameObject.ObjectKind is (byte)ObjectKind.EventNpc or (byte)ObjectKind.BattleNpc or (byte)ObjectKind.Player
&& human->ModelCharaId == 0)
{
var name = new Utf8String(human->GameObject.Name).ToString();
if (FixedDesigns.EnabledDesigns.TryGetValue(name, out var designs))
{
var design = designs.OrderBy(d => d.Jobs.Count).FirstOrDefault(d => d.Jobs.Fits(human->ClassJob));
if (design != null)
{
if (design.Design.Data.WriteCustomizations)
*(CharacterCustomization*)customize = design.Design.Data.Customizations;
var data = (uint*)equipData;
for (var i = 0u; i < 10; ++i)
{
var slot = i.ToEquipSlot();
if (design.Design.Data.WriteEquipment.Fits(slot))
data[i] = slot switch
{
EquipSlot.Head => design.Design.Data.Equipment.Head.Value,
EquipSlot.Body => design.Design.Data.Equipment.Body.Value,
EquipSlot.Hands => design.Design.Data.Equipment.Hands.Value,
EquipSlot.Legs => design.Design.Data.Equipment.Legs.Value,
EquipSlot.Feet => design.Design.Data.Equipment.Feet.Value,
EquipSlot.Ears => design.Design.Data.Equipment.Ears.Value,
EquipSlot.Neck => design.Design.Data.Equipment.Neck.Value,
EquipSlot.Wrists => design.Design.Data.Equipment.Wrists.Value,
EquipSlot.RFinger => design.Design.Data.Equipment.RFinger.Value,
EquipSlot.LFinger => design.Design.Data.Equipment.LFinger.Value,
_ => 0,
};
}
}
}
}
}
private ulong FlagSlotForUpdateDetour(Human* drawObject, uint slotIdx, uint* data)
{
ulong ret;
var slot = slotIdx.ToEquipSlot();
try
{
if (slot != EquipSlot.Unknown)
{
var gameObject =
(FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)Glamourer.Penumbra.GameObjectFromDrawObject((IntPtr)drawObject);
if (gameObject != null)
{
var name = new Utf8String(gameObject->GameObject.Name).ToString();
if (FixedDesigns.EnabledDesigns.TryGetValue(name, out var designs))
{
var design = designs.OrderBy(d => d.Jobs.Count).FirstOrDefault(d => d.Jobs.Fits(gameObject->ClassJob));
if (design != null && design.Design.Data.WriteEquipment.Fits(slot))
*data = slot switch
{
EquipSlot.Head => design.Design.Data.Equipment.Head.Value,
EquipSlot.Body => design.Design.Data.Equipment.Body.Value,
EquipSlot.Hands => design.Design.Data.Equipment.Hands.Value,
EquipSlot.Legs => design.Design.Data.Equipment.Legs.Value,
EquipSlot.Feet => design.Design.Data.Equipment.Feet.Value,
EquipSlot.Ears => design.Design.Data.Equipment.Ears.Value,
EquipSlot.Neck => design.Design.Data.Equipment.Neck.Value,
EquipSlot.Wrists => design.Design.Data.Equipment.Wrists.Value,
EquipSlot.RFinger => design.Design.Data.Equipment.RFinger.Value,
EquipSlot.LFinger => design.Design.Data.Equipment.LFinger.Value,
_ => 0,
};
}
}
}
}
finally
{
ret = FlagSlotForUpdateHook!.Original(drawObject, slotIdx, data);
}
return ret;
}
}
public class Glamourer : IDalamudPlugin public class Glamourer : IDalamudPlugin
{ {
private const string HelpString = "[Copy|Apply|Save],[Name or PlaceHolder],<Name for Save>"; private const string HelpString = "[Copy|Apply|Save],[Name or PlaceHolder],<Name for Save>";
@ -24,9 +151,10 @@ namespace Glamourer
public static GlamourerConfig Config = null!; public static GlamourerConfig Config = null!;
public static IPlayerWatcher PlayerWatcher = null!; public static IPlayerWatcher PlayerWatcher = null!;
public static ICustomizationManager Customization = null!; public static ICustomizationManager Customization = null!;
public static FixedDesignManager FixedDesignManager = null!;
private readonly Interface _interface; private readonly Interface _interface;
public readonly DesignManager Designs; public readonly DesignManager Designs;
public readonly FixedDesigns FixedDesigns;
public static RevertableDesigns RevertableDesigns = new(); public static RevertableDesigns RevertableDesigns = new();
public readonly GlamourerIpc GlamourerIpc; public readonly GlamourerIpc GlamourerIpc;
@ -44,11 +172,10 @@ namespace Glamourer
Penumbra = new PenumbraAttach(Config.AttachToPenumbra); Penumbra = new PenumbraAttach(Config.AttachToPenumbra);
PlayerWatcher = PlayerWatchFactory.Create(Dalamud.Framework, Dalamud.ClientState, Dalamud.Objects); PlayerWatcher = PlayerWatchFactory.Create(Dalamud.Framework, Dalamud.ClientState, Dalamud.Objects);
GlamourerIpc = new GlamourerIpc(Dalamud.ClientState, Dalamud.Objects, Dalamud.PluginInterface); GlamourerIpc = new GlamourerIpc(Dalamud.ClientState, Dalamud.Objects, Dalamud.PluginInterface);
FixedDesignManager = new FixedDesignManager(Designs);
if (!Config.ApplyFixedDesigns) if (!Config.ApplyFixedDesigns)
PlayerWatcher.Disable(); PlayerWatcher.Disable();
FixedDesigns = new FixedDesigns(Designs);
Dalamud.Commands.AddHandler("/glamourer", new CommandInfo(OnGlamourer) Dalamud.Commands.AddHandler("/glamourer", new CommandInfo(OnGlamourer)
{ {
HelpMessage = "Open or close the Glamourer window.", HelpMessage = "Open or close the Glamourer window.",
@ -199,7 +326,7 @@ namespace Glamourer
public void Dispose() public void Dispose()
{ {
FixedDesigns.Dispose(); FixedDesignManager.Dispose();
Penumbra.Dispose(); Penumbra.Dispose();
PlayerWatcher.Dispose(); PlayerWatcher.Dispose();
_interface.Dispose(); _interface.Dispose();
@ -208,4 +335,3 @@ namespace Glamourer
Dalamud.Commands.RemoveHandler("/glamourer"); Dalamud.Commands.RemoveHandler("/glamourer");
} }
} }
}

View file

@ -48,6 +48,10 @@
<ItemGroup> <ItemGroup>
<Reference Include="Dalamud"> <Reference Include="Dalamud">
<HintPath>$(appdata)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath> <HintPath>$(appdata)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="FFXIVClientStructs">
<HintPath>$(appdata)\XIVLauncher\addon\Hooks\dev\FFXIVClientStructs.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="ImGui.NET"> <Reference Include="ImGui.NET">

View file

@ -4,8 +4,8 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
namespace Glamourer.Gui namespace Glamourer.Gui;
{
public class ComboWithFilter<T> public class ComboWithFilter<T>
{ {
private readonly string _label; private readonly string _label;
@ -205,4 +205,3 @@ namespace Glamourer.Gui
return ret; return ret;
} }
} }
}

View file

@ -1,14 +0,0 @@
using System.Linq;
using ImGuiNET;
namespace Glamourer.Gui
{
public static partial class ImGuiCustom
{
public static void HoverTooltip(string text)
{
if (text.Any() && ImGui.IsItemHovered())
ImGui.SetTooltip(text);
}
}
}

View file

@ -1,155 +0,0 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using ImGuiNET;
namespace Glamourer.Gui
{
public sealed class ImGuiRaii : IDisposable
{
private int _colorStack;
private int _fontStack;
private int _styleStack;
private float _indentation;
private Stack<Action>? _onDispose;
public static ImGuiRaii NewGroup()
=> new ImGuiRaii().Group();
public ImGuiRaii Group()
=> Begin(ImGui.BeginGroup, ImGui.EndGroup);
public static ImGuiRaii NewTooltip()
=> new ImGuiRaii().Tooltip();
public ImGuiRaii Tooltip()
=> Begin(ImGui.BeginTooltip, ImGui.EndTooltip);
public ImGuiRaii PushColor(ImGuiCol which, uint color)
{
ImGui.PushStyleColor(which, color);
++_colorStack;
return this;
}
public ImGuiRaii PushColor(ImGuiCol which, Vector4 color)
{
ImGui.PushStyleColor(which, color);
++_colorStack;
return this;
}
public ImGuiRaii PopColors(int n = 1)
{
var actualN = Math.Min(n, _colorStack);
if (actualN > 0)
{
ImGui.PopStyleColor(actualN);
_colorStack -= actualN;
}
return this;
}
public ImGuiRaii PushStyle(ImGuiStyleVar style, Vector2 value)
{
ImGui.PushStyleVar(style, value);
++_styleStack;
return this;
}
public ImGuiRaii PushStyle(ImGuiStyleVar style, float value)
{
ImGui.PushStyleVar(style, value);
++_styleStack;
return this;
}
public ImGuiRaii PopStyles(int n = 1)
{
var actualN = Math.Min(n, _styleStack);
if (actualN > 0)
{
ImGui.PopStyleVar(actualN);
_styleStack -= actualN;
}
return this;
}
public ImGuiRaii PushFont(ImFontPtr font)
{
ImGui.PushFont(font);
++_fontStack;
return this;
}
public ImGuiRaii PopFonts(int n = 1)
{
var actualN = Math.Min(n, _fontStack);
while (actualN-- > 0)
{
ImGui.PopFont();
--_fontStack;
}
return this;
}
public ImGuiRaii Indent(float width)
{
if (width != 0)
{
ImGui.Indent(width);
_indentation += width;
}
return this;
}
public ImGuiRaii Unindent(float width)
=> Indent(-width);
public bool Begin(Func<bool> begin, Action end)
{
if (begin())
{
_onDispose ??= new Stack<Action>();
_onDispose.Push(end);
return true;
}
return false;
}
public ImGuiRaii Begin(Action begin, Action end)
{
begin();
_onDispose ??= new Stack<Action>();
_onDispose.Push(end);
return this;
}
public void End(int n = 1)
{
var actualN = Math.Min(n, _onDispose?.Count ?? 0);
while (actualN-- > 0)
_onDispose!.Pop()();
}
public void Dispose()
{
Unindent(_indentation);
PopColors(_colorStack);
PopStyles(_styleStack);
PopFonts(_fontStack);
if (_onDispose != null)
{
End(_onDispose.Count);
_onDispose = null;
}
}
}
}

View file

@ -7,11 +7,12 @@ using Dalamud.Game.ClientState.Objects.Types;
using Glamourer.Designs; using Glamourer.Designs;
using ImGuiNET; using ImGuiNET;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using OtterGui.Raii;
using Penumbra.GameData; using Penumbra.GameData;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
namespace Glamourer.Gui namespace Glamourer.Gui;
{
internal partial class Interface : IDisposable internal partial class Interface : IDisposable
{ {
public const float SelectorWidth = 200; public const float SelectorWidth = 200;
@ -82,8 +83,8 @@ namespace Glamourer.Gui
try try
{ {
using var raii = new ImGuiRaii(); using var tabBar = ImRaii.TabBar("##tabBar");
if (!raii.Begin(() => ImGui.BeginTabBar("##tabBar"), ImGui.EndTabBar)) if (!tabBar)
return; return;
_inGPose = Dalamud.Objects[GPoseObjectId] != null; _inGPose = Dalamud.Objects[GPoseObjectId] != null;
@ -107,4 +108,3 @@ namespace Glamourer.Gui
} }
} }
} }
}

View file

@ -11,11 +11,13 @@ using Glamourer.Customization;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.FileSystem; using Glamourer.FileSystem;
using ImGuiNET; using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.PlayerWatch; using Penumbra.PlayerWatch;
namespace Glamourer.Gui namespace Glamourer.Gui;
{
internal partial class Interface internal partial class Interface
{ {
private readonly CharacterSave _currentSave = new(); private readonly CharacterSave _currentSave = new();
@ -31,13 +33,12 @@ namespace Glamourer.Gui
{ {
var color = _player == null ? RedHeaderColor : GreenHeaderColor; var color = _player == null ? RedHeaderColor : GreenHeaderColor;
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg); var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
using var raii = new ImGuiRaii() using var c = ImRaii.PushColor(ImGuiCol.Text, color)
.PushColor(ImGuiCol.Text, color) .Push(ImGuiCol.Button, buttonColor)
.PushColor(ImGuiCol.Button, buttonColor) .Push(ImGuiCol.ButtonHovered, buttonColor)
.PushColor(ImGuiCol.ButtonHovered, buttonColor) .Push(ImGuiCol.ButtonActive, buttonColor);
.PushColor(ImGuiCol.ButtonActive, buttonColor) using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) .Push(ImGuiStyleVar.FrameRounding, 0);
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
ImGui.Button($"{_currentLabel}##playerHeader", -Vector2.UnitX * 0.0001f); ImGui.Button($"{_currentLabel}##playerHeader", -Vector2.UnitX * 0.0001f);
} }
@ -47,7 +48,7 @@ namespace Glamourer.Gui
if (ImGui.Button(FontAwesomeIcon.Clipboard.ToIconString())) if (ImGui.Button(FontAwesomeIcon.Clipboard.ToIconString()))
ImGui.SetClipboardText(save.ToBase64()); ImGui.SetClipboardText(save.ToBase64());
ImGui.PopFont(); ImGui.PopFont();
ImGuiCustom.HoverTooltip("Copy customization code to clipboard."); ImGuiUtil.HoverTooltip("Copy customization code to clipboard.");
} }
private static void ConditionalApply(CharacterSave save, Character player) private static void ConditionalApply(CharacterSave save, Character player)
@ -88,7 +89,8 @@ namespace Glamourer.Gui
ImGui.PushFont(UiBuilder.IconFont); ImGui.PushFont(UiBuilder.IconFont);
var applyButton = ImGui.Button(FontAwesomeIcon.Paste.ToIconString()) && _player != null; var applyButton = ImGui.Button(FontAwesomeIcon.Paste.ToIconString()) && _player != null;
ImGui.PopFont(); ImGui.PopFont();
ImGuiCustom.HoverTooltip("Apply customization code from clipboard.\nHold Shift to apply only customizations.\nHold Control to apply only equipment."); ImGuiUtil.HoverTooltip(
"Apply customization code from clipboard.\nHold Shift to apply only customizations.\nHold Control to apply only equipment.");
if (!applyButton) if (!applyButton)
return false; return false;
@ -98,6 +100,7 @@ namespace Glamourer.Gui
var text = ImGui.GetClipboardText(); var text = ImGui.GetClipboardText();
if (!text.Any()) if (!text.Any())
return false; return false;
var save = CharacterSave.FromString(text); var save = CharacterSave.FromString(text);
ConditionalApply(save, _player!); ConditionalApply(save, _player!);
} }
@ -117,7 +120,7 @@ namespace Glamourer.Gui
OpenDesignNamePopup(DesignNameUse.SaveCurrent); OpenDesignNamePopup(DesignNameUse.SaveCurrent);
ImGui.PopFont(); ImGui.PopFont();
ImGuiCustom.HoverTooltip("Save the current design.\nHold Shift to save only customizations.\nHold Control to save only equipment."); ImGuiUtil.HoverTooltip("Save the current design.\nHold Shift to save only customizations.\nHold Control to save only equipment.");
DrawDesignNamePopup(DesignNameUse.SaveCurrent); DrawDesignNamePopup(DesignNameUse.SaveCurrent);
} }
@ -178,7 +181,7 @@ namespace Glamourer.Gui
private void DrawRevertButton() private void DrawRevertButton()
{ {
if (!DrawDisableButton("Revert", _player == null)) if (!ImGuiUtil.DrawDisabledButton("Revert", Vector2.Zero, string.Empty, _player == null))
return; return;
Glamourer.RevertableDesigns.Revert(_player!); Glamourer.RevertableDesigns.Revert(_player!);
@ -227,8 +230,8 @@ namespace Glamourer.Gui
} }
var currentModel = _player!.ModelType(); var currentModel = _player!.ModelType();
using var raii = new ImGuiRaii(); using var combo = ImRaii.Combo("Model Id", currentModel.ToString());
if (!raii.Begin(() => ImGui.BeginCombo("Model Id", currentModel.ToString()), ImGui.EndCombo)) if (!combo)
return; return;
foreach (var (id, _) in _models.Skip(1)) foreach (var (id, _) in _models.Skip(1))
@ -291,20 +294,15 @@ namespace Glamourer.Gui
private void DrawActorPanel() private void DrawActorPanel()
{ {
using var raii = ImGuiRaii.NewGroup(); using var group = ImRaii.Group();
DrawPlayerHeader(); DrawPlayerHeader();
if (!ImGui.BeginChild("##playerData", -Vector2.One, true)) using var child = ImRaii.Child("##playerData", -Vector2.One, true);
{ if (!child)
ImGui.EndChild();
return; return;
}
if (_player == null || _player.ModelType() == 0) if (_player == null || _player.ModelType() == 0)
DrawPlayerPanel(); DrawPlayerPanel();
else else
DrawMonsterPanel(); DrawMonsterPanel();
ImGui.EndChild();
}
} }
} }

View file

@ -7,6 +7,8 @@ using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Logging; using Dalamud.Logging;
using ImGuiNET; using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.PlayerWatch; using Penumbra.PlayerWatch;
namespace Glamourer.Gui; namespace Glamourer.Gui;
@ -27,9 +29,8 @@ internal partial class Interface
private void DrawPlayerFilter() private void DrawPlayerFilter()
{ {
using var raii = new ImGuiRaii() using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) .Push(ImGuiStyleVar.FrameRounding, 0);
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
ImGui.SetNextItemWidth(SelectorWidth * ImGui.GetIO().FontGlobalScale); ImGui.SetNextItemWidth(SelectorWidth * ImGui.GetIO().FontGlobalScale);
if (ImGui.InputTextWithHint("##playerFilter", "Filter Players...", ref _playerFilter, 32)) if (ImGui.InputTextWithHint("##playerFilter", "Filter Players...", ref _playerFilter, 32))
_playerFilterLower = _playerFilter.ToLowerInvariant(); _playerFilterLower = _playerFilter.ToLowerInvariant();
@ -115,23 +116,22 @@ internal partial class Interface
private void DrawSelectionButtons() private void DrawSelectionButtons()
{ {
using var raii = new ImGuiRaii() using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) .Push(ImGuiStyleVar.FrameRounding, 0);
.PushStyle(ImGuiStyleVar.FrameRounding, 0) using var font = ImRaii.PushFont(UiBuilder.IconFont);
.PushFont(UiBuilder.IconFont);
Character? select = null; Character? select = null;
var buttonWidth = Vector2.UnitX * SelectorWidth / 2; var buttonWidth = Vector2.UnitX * SelectorWidth / 2;
if (ImGui.Button(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth)) if (ImGui.Button(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth))
select = Dalamud.ClientState.LocalPlayer; select = Dalamud.ClientState.LocalPlayer;
raii.PopFonts(); font.Pop();
ImGuiCustom.HoverTooltip("Select the local player character."); ImGuiUtil.HoverTooltip("Select the local player character.");
ImGui.SameLine(); ImGui.SameLine();
raii.PushFont(UiBuilder.IconFont); font.Push(UiBuilder.IconFont);
if (_inGPose) if (_inGPose)
{ {
raii.PushStyle(ImGuiStyleVar.Alpha, 0.5f); style.Push(ImGuiStyleVar.Alpha, 0.5f);
ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth); ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth);
raii.PopStyles(); style.Pop();
} }
else else
{ {
@ -139,8 +139,8 @@ internal partial class Interface
select = CharacterFactory.Convert(Dalamud.Targets.Target); select = CharacterFactory.Convert(Dalamud.Targets.Target);
} }
raii.PopFonts(); font.Pop();
ImGuiCustom.HoverTooltip("Select the current target, if it is in the list."); ImGuiUtil.HoverTooltip("Select the current target, if it is in the list.");
if (select == null) if (select == null)
return; return;
@ -196,7 +196,7 @@ internal partial class Interface
} }
using (var _ = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)) using (var _ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
{ {
ImGui.EndChild(); ImGui.EndChild();
} }
@ -207,14 +207,14 @@ internal partial class Interface
private void DrawPlayerTab() private void DrawPlayerTab()
{ {
using var raii = new ImGuiRaii(); using var tab = ImRaii.TabItem("Current Players");
_player = null; _player = null;
if (!raii.Begin(() => ImGui.BeginTabItem("Current Players"), ImGui.EndTabItem)) if (!tab)
return; return;
DrawPlayerSelector(); DrawPlayerSelector();
if (!_currentLabel.Any()) if (_currentLabel.Length == 0)
return; return;
ImGui.SameLine(); ImGui.SameLine();

View file

@ -1,6 +1,8 @@
using System; using System;
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
namespace Glamourer.Gui namespace Glamourer.Gui
{ {
@ -11,7 +13,7 @@ namespace Glamourer.Gui
if (DrawCheckMark(label, value, setter)) if (DrawCheckMark(label, value, setter))
Glamourer.Config.Save(); Glamourer.Config.Save();
ImGuiCustom.HoverTooltip(tooltip); ImGuiUtil.HoverTooltip(tooltip);
} }
private static void ChangeAndSave<T>(T value, T currentValue, Action<T> setter) where T : IEquatable<T> private static void ChangeAndSave<T>(T value, T currentValue, Action<T> setter) where T : IEquatable<T>
@ -33,19 +35,19 @@ namespace Glamourer.Gui
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button($"Default##{name}")) if (ImGui.Button($"Default##{name}"))
ChangeAndSave(defaultValue, value, setter); ChangeAndSave(defaultValue, value, setter);
ImGuiCustom.HoverTooltip( ImGuiUtil.HoverTooltip(
$"Reset to default: #{defaultValue & 0xFF:X2}{(defaultValue >> 8) & 0xFF:X2}{(defaultValue >> 16) & 0xFF:X2}{defaultValue >> 24:X2}"); $"Reset to default: #{defaultValue & 0xFF:X2}{(defaultValue >> 8) & 0xFF:X2}{(defaultValue >> 16) & 0xFF:X2}{defaultValue >> 24:X2}");
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text(name); ImGui.Text(name);
ImGuiCustom.HoverTooltip(tooltip); ImGuiUtil.HoverTooltip(tooltip);
} }
private void DrawRestorePenumbraButton() private static void DrawRestorePenumbraButton()
{ {
const string buttonLabel = "Re-Register Penumbra"; const string buttonLabel = "Re-Register Penumbra";
if (!Glamourer.Config.AttachToPenumbra) if (!Glamourer.Config.AttachToPenumbra)
{ {
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.Alpha, 0.5f); using var style = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f);
ImGui.Button(buttonLabel); ImGui.Button(buttonLabel);
return; return;
} }
@ -53,14 +55,14 @@ namespace Glamourer.Gui
if (ImGui.Button(buttonLabel)) if (ImGui.Button(buttonLabel))
Glamourer.Penumbra.Reattach(true); Glamourer.Penumbra.Reattach(true);
ImGuiCustom.HoverTooltip( ImGuiUtil.HoverTooltip(
"If Penumbra did not register the functions for some reason, pressing this button might help restore functionality."); "If Penumbra did not register the functions for some reason, pressing this button might help restore functionality.");
} }
private void DrawConfigTab() private static void DrawConfigTab()
{ {
using var raii = new ImGuiRaii(); using var tab = ImRaii.TabItem("Config");
if (!raii.Begin(() => ImGui.BeginTabItem("Config"), ImGui.EndTabItem)) if (!tab)
return; return;
var cfg = Glamourer.Config; var cfg = Glamourer.Config;

View file

@ -5,6 +5,8 @@ using Dalamud.Interface;
using Dalamud.Logging; using Dalamud.Logging;
using Glamourer.Customization; using Glamourer.Customization;
using ImGuiNET; using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
namespace Glamourer.Gui namespace Glamourer.Gui
@ -14,13 +16,14 @@ namespace Glamourer.Gui
private static bool DrawColorPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value) private static bool DrawColorPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value)
{ {
value = default; value = default;
if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize)) using var popup = ImRaii.Popup(label, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return false; return false;
var ret = false; var ret = false;
var count = set.Count(id); var count = set.Count(id);
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.FrameRounding, 0); .Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < count; ++i) for (var i = 0; i < count; ++i)
{ {
var custom = set.Data(id, i); var custom = set.Data(id, i);
@ -35,7 +38,6 @@ namespace Glamourer.Gui
ImGui.SameLine(); ImGui.SameLine();
} }
ImGui.EndPopup();
return ret; return ret;
} }
@ -58,7 +60,7 @@ namespace Glamourer.Gui
ret = true; ret = true;
} }
ImGuiCustom.HoverTooltip($"Input Range: [{minValue}, {maxValue}]"); ImGuiUtil.HoverTooltip($"Input Range: [{minValue}, {maxValue}]");
return ret; return ret;
} }
@ -92,7 +94,7 @@ namespace Glamourer.Gui
ImGui.SameLine(); ImGui.SameLine();
using (var _ = ImGuiRaii.NewGroup()) using (var _ = ImRaii.Group())
{ {
if (InputInt($"##text_{id}", ref current, 1, count)) if (InputInt($"##text_{id}", ref current, 1, count))
{ {
@ -102,7 +104,7 @@ namespace Glamourer.Gui
ImGui.Text(label); ImGui.Text(label);
ImGuiCustom.HoverTooltip(tooltip); ImGuiUtil.HoverTooltip(tooltip);
} }
if (!DrawColorPickerPopup(popupName, set, id, out var newCustom)) if (!DrawColorPickerPopup(popupName, set, id, out var newCustom))
@ -117,7 +119,7 @@ namespace Glamourer.Gui
private bool DrawListSelector(string label, string tooltip, ref CharacterCustomization customization, CustomizationId id, private bool DrawListSelector(string label, string tooltip, ref CharacterCustomization customization, CustomizationId id,
CustomizationSet set) CustomizationSet set)
{ {
using var bigGroup = ImGuiRaii.NewGroup(); using var bigGroup = ImRaii.Group();
var ret = false; var ret = false;
int current = customization[id]; int current = customization[id];
var count = set.Count(id); var count = set.Count(id);
@ -146,7 +148,7 @@ namespace Glamourer.Gui
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text(label); ImGui.Text(label);
ImGuiCustom.HoverTooltip(tooltip); ImGuiUtil.HoverTooltip(tooltip);
return ret; return ret;
} }
@ -157,10 +159,10 @@ namespace Glamourer.Gui
private bool DrawMultiSelector(ref CharacterCustomization customization, CustomizationSet set) private bool DrawMultiSelector(ref CharacterCustomization customization, CustomizationSet set)
{ {
using var bigGroup = ImGuiRaii.NewGroup(); using var bigGroup = ImRaii.Group();
var ret = false; var ret = false;
var count = set.Count(CustomizationId.FacialFeaturesTattoos); var count = set.Count(CustomizationId.FacialFeaturesTattoos);
using (var _ = ImGuiRaii.NewGroup()) using (var _ = ImRaii.Group())
{ {
var face = customization.Face; var face = customization.Face;
if (set.Faces.Count < face) if (set.Faces.Count < face)
@ -180,11 +182,7 @@ namespace Glamourer.Gui
customization.FacialFeature(i, !enabled); customization.FacialFeature(i, !enabled);
} }
if (ImGui.IsItemHovered()) ImGuiUtil.HoverIconTooltip(icon, _iconSize);
{
using var tt = ImGuiRaii.NewTooltip();
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
}
if (i % 4 != 3) if (i % 4 != 3)
ImGui.SameLine(); ImGui.SameLine();
@ -192,7 +190,7 @@ namespace Glamourer.Gui
} }
ImGui.SameLine(); ImGui.SameLine();
using var group = ImGuiRaii.NewGroup(); using var group = ImRaii.Group();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() + 3 * ImGui.GetStyle().ItemSpacing.Y / 2); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() + 3 * ImGui.GetStyle().ItemSpacing.Y / 2);
int value = customization[CustomizationId.FacialFeaturesTattoos]; int value = customization[CustomizationId.FacialFeaturesTattoos];
if (InputInt($"##{CustomizationId.FacialFeaturesTattoos}", ref value, 1, 256)) if (InputInt($"##{CustomizationId.FacialFeaturesTattoos}", ref value, 1, 256))
@ -201,7 +199,7 @@ namespace Glamourer.Gui
ret = true; ret = true;
} }
ImGui.Text(set.Option(CustomizationId.FacialFeaturesTattoos)); ImGui.TextUnformatted(set.Option(CustomizationId.FacialFeaturesTattoos));
return ret; return ret;
} }
@ -210,13 +208,14 @@ namespace Glamourer.Gui
private bool DrawIconPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value) private bool DrawIconPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value)
{ {
value = default; value = default;
if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize)) using var popup = ImRaii.Popup(label, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return false; return false;
var ret = false; var ret = false;
var count = set.Count(id); var count = set.Count(id);
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.FrameRounding, 0); .Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < count; ++i) for (var i = 0; i < count; ++i)
{ {
var custom = set.Data(id, i); var custom = set.Data(id, i);
@ -229,11 +228,7 @@ namespace Glamourer.Gui
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
if (ImGui.IsItemHovered()) ImGuiUtil.HoverIconTooltip(icon, _iconSize);
{
using var tt = ImGuiRaii.NewTooltip();
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
}
var text = custom.Value.ToString(); var text = custom.Value.ToString();
var textWidth = ImGui.CalcTextSize(text).X; var textWidth = ImGui.CalcTextSize(text).X;
@ -244,14 +239,13 @@ namespace Glamourer.Gui
ImGui.SameLine(); ImGui.SameLine();
} }
ImGui.EndPopup();
return ret; return ret;
} }
private bool DrawIconSelector(string label, string tooltip, ref CharacterCustomization customization, CustomizationId id, private bool DrawIconSelector(string label, string tooltip, ref CharacterCustomization customization, CustomizationId id,
CustomizationSet set) CustomizationSet set)
{ {
using var bigGroup = ImGuiRaii.NewGroup(); using var bigGroup = ImRaii.Group();
var ret = false; var ret = false;
var count = set.Count(id); var count = set.Count(id);
@ -268,14 +262,10 @@ namespace Glamourer.Gui
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize)) if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
ImGui.OpenPopup(popupName); ImGui.OpenPopup(popupName);
if (ImGui.IsItemHovered()) ImGuiUtil.HoverIconTooltip(icon, _iconSize);
{
using var tt = ImGuiRaii.NewTooltip();
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
}
ImGui.SameLine(); ImGui.SameLine();
using var group = ImGuiRaii.NewGroup(); using var group = ImRaii.Group();
if (InputInt($"##text_{id}", ref current, 1, count)) if (InputInt($"##text_{id}", ref current, 1, count))
{ {
customization[id] = set.Data(id, current).Value; customization[id] = set.Data(id, current).Value;
@ -288,8 +278,8 @@ namespace Glamourer.Gui
ret = true; ret = true;
} }
ImGui.Text($"{label} ({custom.Value.Value})"); ImGui.TextUnformatted($"{label} ({custom.Value.Value})");
ImGuiCustom.HoverTooltip(tooltip); ImGuiUtil.HoverTooltip(tooltip);
return ret; return ret;
} }
@ -298,7 +288,7 @@ namespace Glamourer.Gui
private bool DrawPercentageSelector(string label, string tooltip, ref CharacterCustomization customization, CustomizationId id, private bool DrawPercentageSelector(string label, string tooltip, ref CharacterCustomization customization, CustomizationId id,
CustomizationSet set) CustomizationSet set)
{ {
using var bigGroup = ImGuiRaii.NewGroup(); using var bigGroup = ImRaii.Group();
var ret = false; var ret = false;
int value = customization[id]; int value = customization[id];
var count = set.Count(id); var count = set.Count(id);
@ -318,15 +308,15 @@ namespace Glamourer.Gui
} }
ImGui.SameLine(); ImGui.SameLine();
ImGui.Text(label); ImGui.TextUnformatted(label);
ImGuiCustom.HoverTooltip(tooltip); ImGuiUtil.HoverTooltip(tooltip);
return ret; return ret;
} }
private bool DrawRaceSelector(ref CharacterCustomization customization) private bool DrawRaceSelector(ref CharacterCustomization customization)
{ {
using var group = ImGuiRaii.NewGroup(); using var group = ImRaii.Group();
var ret = false; var ret = false;
ImGui.SetNextItemWidth(_raceSelectorWidth); ImGui.SetNextItemWidth(_raceSelectorWidth);
if (ImGui.BeginCombo("##subRaceCombo", ClanName(customization.Clan, customization.Gender))) if (ImGui.BeginCombo("##subRaceCombo", ClanName(customization.Clan, customization.Gender)))
@ -343,7 +333,7 @@ namespace Glamourer.Gui
ImGui.EndCombo(); ImGui.EndCombo();
} }
ImGui.Text( ImGui.TextUnformatted(
$"{Glamourer.Customization.GetName(CustomName.Gender)} & {Glamourer.Customization.GetName(CustomName.Clan)}"); $"{Glamourer.Customization.GetName(CustomName.Gender)} & {Glamourer.Customization.GetName(CustomName.Clan)}");
return ret; return ret;
@ -352,7 +342,7 @@ namespace Glamourer.Gui
private bool DrawGenderSelector(ref CharacterCustomization customization) private bool DrawGenderSelector(ref CharacterCustomization customization)
{ {
var ret = false; var ret = false;
ImGui.PushFont(UiBuilder.IconFont); using var font = ImRaii.PushFont(UiBuilder.IconFont);
var icon = customization.Gender == Gender.Male ? FontAwesomeIcon.Mars : FontAwesomeIcon.Venus; var icon = customization.Gender == Gender.Male ? FontAwesomeIcon.Mars : FontAwesomeIcon.Venus;
var restricted = false; var restricted = false;
if (customization.Race == Race.Hrothgar) if (customization.Race == Race.Hrothgar)
@ -370,7 +360,6 @@ namespace Glamourer.Gui
if (restricted) if (restricted)
ImGui.PopStyleVar(); ImGui.PopStyleVar();
ImGui.PopFont();
return ret; return ret;
} }

View file

@ -6,9 +6,11 @@ using Dalamud.Logging;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.FileSystem; using Glamourer.FileSystem;
using ImGuiNET; using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
namespace Glamourer.Gui;
namespace Glamourer.Gui
{
internal partial class Interface internal partial class Interface
{ {
private int _totalObject; private int _totalObject;
@ -44,7 +46,7 @@ namespace Glamourer.Gui
if (_selection!.Data.WriteProtected) if (_selection!.Data.WriteProtected)
ImGui.PopStyleVar(); ImGui.PopStyleVar();
ImGuiCustom.HoverTooltip("Overwrite with customization code from clipboard."); ImGuiUtil.HoverTooltip("Overwrite with customization code from clipboard.");
if (_selection!.Data.WriteProtected || !applyButton) if (_selection!.Data.WriteProtected || !applyButton)
return; return;
@ -70,7 +72,7 @@ namespace Glamourer.Gui
if (ImGui.Button(FontAwesomeIcon.FolderPlus.ToIconString(), Vector2.UnitX * SelectorWidth / 5)) if (ImGui.Button(FontAwesomeIcon.FolderPlus.ToIconString(), Vector2.UnitX * SelectorWidth / 5))
OpenDesignNamePopup(DesignNameUse.NewFolder); OpenDesignNamePopup(DesignNameUse.NewFolder);
ImGui.PopFont(); ImGui.PopFont();
ImGuiCustom.HoverTooltip("Create a new, empty Folder."); ImGuiUtil.HoverTooltip("Create a new, empty Folder.");
DrawDesignNamePopup(DesignNameUse.NewFolder); DrawDesignNamePopup(DesignNameUse.NewFolder);
} }
@ -81,7 +83,7 @@ namespace Glamourer.Gui
if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), Vector2.UnitX * SelectorWidth / 5)) if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), Vector2.UnitX * SelectorWidth / 5))
OpenDesignNamePopup(DesignNameUse.NewDesign); OpenDesignNamePopup(DesignNameUse.NewDesign);
ImGui.PopFont(); ImGui.PopFont();
ImGuiCustom.HoverTooltip("Create a new, empty Design."); ImGuiUtil.HoverTooltip("Create a new, empty Design.");
DrawDesignNamePopup(DesignNameUse.NewDesign); DrawDesignNamePopup(DesignNameUse.NewDesign);
} }
@ -92,7 +94,7 @@ namespace Glamourer.Gui
if (ImGui.Button(FontAwesomeIcon.Paste.ToIconString(), Vector2.UnitX * SelectorWidth / 5)) if (ImGui.Button(FontAwesomeIcon.Paste.ToIconString(), Vector2.UnitX * SelectorWidth / 5))
OpenDesignNamePopup(DesignNameUse.FromClipboard); OpenDesignNamePopup(DesignNameUse.FromClipboard);
ImGui.PopFont(); ImGui.PopFont();
ImGuiCustom.HoverTooltip("Create a new design from the customization string in your clipboard."); ImGuiUtil.HoverTooltip("Create a new design from the customization string in your clipboard.");
DrawDesignNamePopup(DesignNameUse.FromClipboard); DrawDesignNamePopup(DesignNameUse.FromClipboard);
} }
@ -112,7 +114,7 @@ namespace Glamourer.Gui
ImGui.PopFont(); ImGui.PopFont();
if (style) if (style)
ImGui.PopStyleVar(); ImGui.PopStyleVar();
ImGuiCustom.HoverTooltip("Delete the currently selected Design."); ImGuiUtil.HoverTooltip("Delete the currently selected Design.");
} }
private void DrawDuplicateDesignButton() private void DrawDuplicateDesignButton()
@ -125,16 +127,16 @@ namespace Glamourer.Gui
ImGui.PopFont(); ImGui.PopFont();
if (_selection == null) if (_selection == null)
ImGui.PopStyleVar(); ImGui.PopStyleVar();
ImGuiCustom.HoverTooltip("Clone the currently selected Design.\nHold Shift to only clone the customizations.\nHold Control to only clone the equipment."); ImGuiUtil.HoverTooltip(
"Clone the currently selected Design.\nHold Shift to only clone the customizations.\nHold Control to only clone the equipment.");
DrawDesignNamePopup(DesignNameUse.DuplicateDesign); DrawDesignNamePopup(DesignNameUse.DuplicateDesign);
} }
private void DrawDesignSelectorButtons() private void DrawDesignSelectorButtons()
{ {
using var raii = new ImGuiRaii() using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) .Push(ImGuiStyleVar.FrameRounding, 0f);
.PushStyle(ImGuiStyleVar.FrameRounding, 0f);
DrawNewFolderButton(); DrawNewFolderButton();
ImGui.SameLine(); ImGui.SameLine();
@ -200,9 +202,9 @@ namespace Glamourer.Gui
private void DrawSaves() private void DrawSaves()
{ {
using var raii = new ImGuiRaii(); using var style = ImRaii.PushStyle(ImGuiStyleVar.IndentSpacing, 12.5f * ImGui.GetIO().FontGlobalScale);
raii.PushStyle(ImGuiStyleVar.IndentSpacing, 12.5f * ImGui.GetIO().FontGlobalScale); using var tab = ImRaii.TabItem("Designs");
_inDesignMode = raii.Begin(() => ImGui.BeginTabItem("Designs"), ImGui.EndTabItem); _inDesignMode = tab.Success;
if (!_inDesignMode) if (!_inDesignMode)
return; return;
@ -279,7 +281,7 @@ namespace Glamourer.Gui
{ {
if (ImGui.MenuItem("Delete") && ImGui.GetIO().KeyCtrl && ImGui.GetIO().KeyShift) if (ImGui.MenuItem("Delete") && ImGui.GetIO().KeyCtrl && ImGui.GetIO().KeyShift)
_designs.DeleteAllChildren(child, false); _designs.DeleteAllChildren(child, false);
ImGuiCustom.HoverTooltip("Hold Control and Shift to delete."); ImGuiUtil.HoverTooltip("Hold Control and Shift to delete.");
RenameChildInput(child); RenameChildInput(child);
@ -342,19 +344,18 @@ namespace Glamourer.Gui
++_totalObject; ++_totalObject;
var color = GetDesignColor(d.Data); var color = GetDesignColor(d.Data);
using var raii = new ImGuiRaii() using var c = ImRaii.PushColor(ImGuiCol.Text, color);
.PushColor(ImGuiCol.Text, color);
var selected = ImGui.Selectable($"{child.Name}##{_totalObject}", ReferenceEquals(child, _selection)); var selected = ImGui.Selectable($"{child.Name}##{_totalObject}", ReferenceEquals(child, _selection));
raii.PopColors(); c.Pop();
DrawOrnaments(child); DrawOrnaments(child);
if (Glamourer.Config.ShowLocks && d.Data.WriteProtected) if (Glamourer.Config.ShowLocks && d.Data.WriteProtected)
{ {
ImGui.SameLine(); ImGui.SameLine();
raii.PushFont(UiBuilder.IconFont) using var font = ImRaii.PushFont(UiBuilder.IconFont);
.PushColor(ImGuiCol.Text, color); c.Push(ImGuiCol.Text, color);
ImGui.Text(FontAwesomeIcon.Lock.ToIconString()); ImGui.TextUnformatted(FontAwesomeIcon.Lock.ToIconString());
} }
if (selected) if (selected)
@ -371,4 +372,3 @@ namespace Glamourer.Gui
ContextMenu(child); ContextMenu(child);
} }
} }
}

View file

@ -1,6 +1,7 @@
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
using Lumina.Text; using Lumina.Text;
using OtterGui;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
@ -20,7 +21,7 @@ namespace Glamourer.Gui
var change = stainCombo.Draw(string.Empty, out var newStain) && !newStain.RowIndex.Equals(stainIdx); var change = stainCombo.Draw(string.Empty, out var newStain) && !newStain.RowIndex.Equals(stainIdx);
if (!change && (byte) stainIdx != 0) if (!change && (byte) stainIdx != 0)
{ {
ImGuiCustom.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{ {
change = true; change = true;
@ -46,7 +47,7 @@ namespace Glamourer.Gui
var change = equipCombo.Draw(currentName, out var newItem, _itemComboWidth) && newItem.Base.RowId != item.RowId; var change = equipCombo.Draw(currentName, out var newItem, _itemComboWidth) && newItem.Base.RowId != item.RowId;
if (!change && !ReferenceEquals(item, SmallClothes)) if (!change && !ReferenceEquals(item, SmallClothes))
{ {
ImGuiCustom.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{ {
change = true; change = true;

View file

@ -6,9 +6,10 @@ using Dalamud.Interface;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.FileSystem; using Glamourer.FileSystem;
using ImGuiNET; using ImGuiNET;
using OtterGui.Raii;
namespace Glamourer.Gui;
namespace Glamourer.Gui
{
internal partial class Interface internal partial class Interface
{ {
private const string FixDragDropLabel = "##FixDragDrop"; private const string FixDragDropLabel = "##FixDragDrop";
@ -25,44 +26,45 @@ namespace Glamourer.Gui
private void DrawFixedDesignsTab() private void DrawFixedDesignsTab()
{ {
_newFixDesignGroup ??= _plugin.FixedDesigns.JobGroups[1]; _newFixDesignGroup ??= Glamourer.FixedDesignManager.FixedDesigns.JobGroups[1];
using var raii = new ImGuiRaii(); using var tabItem = ImRaii.TabItem("Fixed Designs");
if (!raii.Begin(() => ImGui.BeginTabItem("Fixed Designs"), ImGui.EndTabItem)) if (!tabItem)
{ {
_fullPathCache = null; _fullPathCache = null;
_newFixDesign = null; _newFixDesign = null;
_newFixDesignPath = string.Empty; _newFixDesignPath = string.Empty;
_newFixDesignGroup = _plugin.FixedDesigns.JobGroups[1]; _newFixDesignGroup = Glamourer.FixedDesignManager.FixedDesigns.JobGroups[1];
return; return;
} }
_fullPathCache ??= _plugin.FixedDesigns.Data.Select(d => d.Design.FullName()).ToList(); _fullPathCache ??= Glamourer.FixedDesignManager.FixedDesigns.Data.Select(d => d.Design.FullName()).ToList();
raii.Begin(() => ImGui.BeginTable("##FixedTable", 4), ImGui.EndTable);
using var table = ImRaii.Table("##FixedTable", 4);
var buttonWidth = 23.5f * ImGuiHelpers.GlobalScale; var buttonWidth = 23.5f * ImGuiHelpers.GlobalScale;
ImGui.TableSetupColumn("##DeleteColumn", ImGuiTableColumnFlags.WidthFixed, 2 * buttonWidth); ImGui.TableSetupColumn("##DeleteColumn", ImGuiTableColumnFlags.WidthFixed, 2 * buttonWidth);
ImGui.TableSetupColumn("Character", ImGuiTableColumnFlags.WidthFixed, 200 * ImGuiHelpers.GlobalScale); ImGui.TableSetupColumn("Character", ImGuiTableColumnFlags.WidthFixed, 200 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Jobs", ImGuiTableColumnFlags.WidthFixed, 175 * ImGuiHelpers.GlobalScale); ImGui.TableSetupColumn("Jobs", ImGuiTableColumnFlags.WidthFixed, 175 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthStretch); ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
var xPos = 0f; var xPos = 0f;
using var style = new ImRaii.Style();
using var font = new ImRaii.Font();
for (var i = 0; i < _fullPathCache.Count; ++i) for (var i = 0; i < _fullPathCache.Count; ++i)
{ {
var path = _fullPathCache[i]; var path = _fullPathCache[i];
var name = _plugin.FixedDesigns.Data[i]; var name = Glamourer.FixedDesignManager.FixedDesigns.Data[i];
ImGui.TableNextRow(); ImGui.TableNextRow();
ImGui.TableNextColumn(); ImGui.TableNextColumn();
raii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2); style.Push(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2);
raii.PushFont(UiBuilder.IconFont); font.Push(UiBuilder.IconFont);
if (ImGui.Button($"{FontAwesomeIcon.Trash.ToIconChar()}##{i}")) if (ImGui.Button($"{FontAwesomeIcon.Trash.ToIconChar()}##{i}"))
{ {
_fullPathCache.RemoveAt(i--); _fullPathCache.RemoveAt(i--);
_plugin.FixedDesigns.Remove(name); Glamourer.FixedDesignManager.FixedDesigns.Remove(name);
continue; continue;
} }
@ -70,15 +72,15 @@ namespace Glamourer.Gui
ImGui.SameLine(); ImGui.SameLine();
xPos = ImGui.GetCursorPosX(); xPos = ImGui.GetCursorPosX();
if (ImGui.Checkbox($"##Enabled{i}", ref tmp)) if (ImGui.Checkbox($"##Enabled{i}", ref tmp))
if (tmp && _plugin.FixedDesigns.EnableDesign(name) if (tmp && Glamourer.FixedDesignManager.FixedDesigns.EnableDesign(name)
|| !tmp && _plugin.FixedDesigns.DisableDesign(name)) || !tmp && Glamourer.FixedDesignManager.FixedDesigns.DisableDesign(name))
{ {
Glamourer.Config.FixedDesigns[i].Enabled = tmp; Glamourer.Config.FixedDesigns[i].Enabled = tmp;
Glamourer.Config.Save(); Glamourer.Config.Save();
} }
raii.PopStyles(); style.Pop();
raii.PopFonts(); font.Pop();
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Selectable($"{name.Name}##Fix{i}"); ImGui.Selectable($"{name.Name}##Fix{i}");
if (ImGui.BeginDragDropSource()) if (ImGui.BeginDragDropSource())
@ -88,67 +90,68 @@ namespace Glamourer.Gui
ImGui.Text($"Dragging {name.Name} ({path})..."); ImGui.Text($"Dragging {name.Name} ({path})...");
ImGui.EndDragDropSource(); ImGui.EndDragDropSource();
} }
if (ImGui.BeginDragDropTarget()) if (ImGui.BeginDragDropTarget())
{ {
if (IsDropping() && _fixDragDropIdx >= 0) if (IsDropping() && _fixDragDropIdx >= 0)
{ {
var d = _plugin.FixedDesigns.Data[_fixDragDropIdx]; var d = Glamourer.FixedDesignManager.FixedDesigns.Data[_fixDragDropIdx];
_plugin.FixedDesigns.Move(d, i); Glamourer.FixedDesignManager.FixedDesigns.Move(d, i);
var p = _fullPathCache[_fixDragDropIdx]; var p = _fullPathCache[_fixDragDropIdx];
_fullPathCache.RemoveAt(_fixDragDropIdx); _fullPathCache.RemoveAt(_fixDragDropIdx);
_fullPathCache.Insert(i, p); _fullPathCache.Insert(i, p);
_fixDragDropIdx = -1; _fixDragDropIdx = -1;
} }
ImGui.EndDragDropTarget(); ImGui.EndDragDropTarget();
} }
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(_plugin.FixedDesigns.Data[i].Jobs.Name); ImGui.Text(Glamourer.FixedDesignManager.FixedDesigns.Data[i].Jobs.Name);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Text(path); ImGui.Text(path);
} }
ImGui.TableNextRow(); ImGui.TableNextRow();
ImGui.TableNextColumn(); ImGui.TableNextColumn();
raii.PushFont(UiBuilder.IconFont); font.Push(UiBuilder.IconFont);
ImGui.SetCursorPosX(xPos); ImGui.SetCursorPosX(xPos);
if (_newFixDesign == null || _newFixCharacterName == string.Empty) if (_newFixDesign == null || _newFixCharacterName == string.Empty)
{ {
raii.PushStyle(ImGuiStyleVar.Alpha, 0.5f); style.Push(ImGuiStyleVar.Alpha, 0.5f);
ImGui.Button($"{FontAwesomeIcon.Plus.ToIconChar()}##NewFix"); ImGui.Button($"{FontAwesomeIcon.Plus.ToIconChar()}##NewFix");
raii.PopStyles(); style.Pop();
} }
else if (ImGui.Button($"{FontAwesomeIcon.Plus.ToIconChar()}##NewFix")) else if (ImGui.Button($"{FontAwesomeIcon.Plus.ToIconChar()}##NewFix"))
{ {
_fullPathCache.Add(_newFixDesignPath); _fullPathCache.Add(_newFixDesignPath);
_plugin.FixedDesigns.Add(_newFixCharacterName, _newFixDesign, _newFixDesignGroup.Value, false); Glamourer.FixedDesignManager.FixedDesigns.Add(_newFixCharacterName, _newFixDesign, _newFixDesignGroup.Value, false);
_newFixCharacterName = string.Empty; _newFixCharacterName = string.Empty;
_newFixDesignPath = string.Empty; _newFixDesignPath = string.Empty;
_newFixDesign = null; _newFixDesign = null;
_newFixDesignGroup = _plugin.FixedDesigns.JobGroups[1]; _newFixDesignGroup = Glamourer.FixedDesignManager.FixedDesigns.JobGroups[1];
} }
raii.PopFonts(); font.Pop();
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
ImGui.InputTextWithHint("##NewFix", "Enter new Character", ref _newFixCharacterName, 32); ImGui.InputTextWithHint("##NewFix", "Enter new Character", ref _newFixCharacterName, 32);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
if (raii.Begin(() => ImGui.BeginCombo("##NewFixDesignGroup", _newFixDesignGroup.Value.Name), ImGui.EndCombo)) using var combo = ImRaii.Combo("##NewFixDesignGroup", _newFixDesignGroup.Value.Name);
{ if (combo)
foreach (var (id, group) in _plugin.FixedDesigns.JobGroups) foreach (var (id, group) in Glamourer.FixedDesignManager.FixedDesigns.JobGroups)
{ {
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
if (ImGui.Selectable($"{group.Name}##NewFixDesignGroup", group.Name == _newFixDesignGroup.Value.Name)) if (ImGui.Selectable($"{group.Name}##NewFixDesignGroup", group.Name == _newFixDesignGroup.Value.Name))
_newFixDesignGroup = group; _newFixDesignGroup = group;
} }
raii.End();
}
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1); ImGui.SetNextItemWidth(-1);
if (!raii.Begin(() => ImGui.BeginCombo("##NewFixPath", _newFixDesignPath), ImGui.EndCombo)) using var combo2 = ImRaii.Combo("##NewFixPath", _newFixDesignPath);
if (!combo2)
return; return;
foreach (var design in _plugin.Designs.FileSystem.Root.AllLeaves(SortMode.Lexicographical).Cast<Design>()) foreach (var design in _plugin.Designs.FileSystem.Root.AllLeaves(SortMode.Lexicographical).Cast<Design>())
@ -163,4 +166,3 @@ namespace Glamourer.Gui
} }
} }
} }
}

View file

@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using Dalamud.Logging; using Dalamud.Logging;
using Glamourer.Customization; using Glamourer.Customization;
using Glamourer.Structs;
using ImGuiNET; using ImGuiNET;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;

View file

@ -4,6 +4,7 @@ using System.Reflection;
using ImGuiNET; using ImGuiNET;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Glamourer.Structs;
namespace Glamourer.Gui namespace Glamourer.Gui
{ {

View file

@ -2,8 +2,8 @@
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using ImGuiNET; using ImGuiNET;
namespace Glamourer.Gui namespace Glamourer.Gui;
{
internal partial class Interface internal partial class Interface
{ {
private static bool DrawCheckMark(string label, bool value, Action<bool> setter) private static bool DrawCheckMark(string label, bool value, Action<bool> setter)
@ -18,17 +18,6 @@ namespace Glamourer.Gui
return false; return false;
} }
private static bool DrawDisableButton(string label, bool disabled)
{
if (!disabled)
return ImGui.Button(label);
using var raii = new ImGuiRaii();
raii.PushStyle(ImGuiStyleVar.Alpha, 0.5f);
ImGui.Button(label);
return false;
}
private static bool DrawMiscellaneous(CharacterSave save, Character? player) private static bool DrawMiscellaneous(CharacterSave save, Character? player)
{ {
var ret = false; var ret = false;
@ -72,4 +61,3 @@ namespace Glamourer.Gui
return ret; return ret;
} }
} }
}

View file

@ -2,9 +2,10 @@
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using ImGuiNET; using ImGuiNET;
using OtterGui.Raii;
namespace Glamourer.Gui;
namespace Glamourer.Gui
{
internal partial class Interface internal partial class Interface
{ {
private string? _currentRevertableName; private string? _currentRevertableName;
@ -31,7 +32,7 @@ namespace Glamourer.Gui
} }
} }
using (var _ = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)) using (var _ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
{ {
ImGui.EndChild(); ImGui.EndChild();
} }
@ -42,16 +43,15 @@ namespace Glamourer.Gui
private void DrawRevertablePanel() private void DrawRevertablePanel()
{ {
using var group = ImGuiRaii.NewGroup(); using var group = ImRaii.Group();
{ {
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg); var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
using var raii = new ImGuiRaii() using var color = ImRaii.PushColor(ImGuiCol.Text, GreenHeaderColor)
.PushColor(ImGuiCol.Text, GreenHeaderColor) .Push(ImGuiCol.Button, buttonColor)
.PushColor(ImGuiCol.Button, buttonColor) .Push(ImGuiCol.ButtonHovered, buttonColor)
.PushColor(ImGuiCol.ButtonHovered, buttonColor) .Push(ImGuiCol.ButtonActive, buttonColor);
.PushColor(ImGuiCol.ButtonActive, buttonColor) using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) .Push(ImGuiStyleVar.FrameRounding, 0);
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
ImGui.Button($"{_currentRevertableName}##playerHeader", -Vector2.UnitX * 0.0001f); ImGui.Button($"{_currentRevertableName}##playerHeader", -Vector2.UnitX * 0.0001f);
} }
@ -72,8 +72,8 @@ namespace Glamourer.Gui
[Conditional("DEBUG")] [Conditional("DEBUG")]
private void DrawRevertablesTab() private void DrawRevertablesTab()
{ {
using var raii = new ImGuiRaii(); using var tabItem = ImRaii.TabItem("Revertables");
if (!raii.Begin(() => ImGui.BeginTabItem("Revertables"), ImGui.EndTabItem)) if (!tabItem)
return; return;
DrawRevertablesSelector(); DrawRevertablesSelector();
@ -85,4 +85,3 @@ namespace Glamourer.Gui
DrawRevertablePanel(); DrawRevertablePanel();
} }
} }
}