diff --git a/Luna b/Luna index 1ffa8c5d..ec5cc052 160000 --- a/Luna +++ b/Luna @@ -1 +1 @@ -Subproject commit 1ffa8c5de118f94b609f7d6352e3b63de463398c +Subproject commit ec5cc05211c5083f276e32816d8c3eb8c09d04b4 diff --git a/Penumbra.GameData b/Penumbra.GameData index 3a9406bc..182cca56 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 3a9406bc634228cc0815ddb6fe5e20419cafb864 +Subproject commit 182cca56a49411430233d73d7a8a6bb3d983f8f0 diff --git a/Penumbra/Mods/FeatureChecker.cs b/Penumbra/Mods/FeatureChecker.cs index fc3ae522..c97a860c 100644 --- a/Penumbra/Mods/FeatureChecker.cs +++ b/Penumbra/Mods/FeatureChecker.cs @@ -54,8 +54,8 @@ public static class FeatureChecker const int numButtons = 5; var innerSpacing = ImGui.GetStyle().ItemInnerSpacing; var size = new Vector2((width - (numButtons - 1) * innerSpacing.X) / numButtons, 0); - var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg); - var textColor = ImGui.GetColorU32(ImGuiCol.TextDisabled); + var buttonColor = Im.Style[ImGuiColor.FrameBackground]; + var textColor = Im.Style[ImGuiColor.TextDisabled]; using (var style = ImStyleBorder.Frame.Push(ColorId.FolderLine.Value(), 0) .Push(ImStyleDouble.ItemSpacing, innerSpacing) .Push(ImGuiColor.Button, buttonColor) diff --git a/Penumbra/Mods/Manager/ModFileSystem.cs b/Penumbra/Mods/Manager/ModFileSystem.cs index 02aa9dc3..7cbd611d 100644 --- a/Penumbra/Mods/Manager/ModFileSystem.cs +++ b/Penumbra/Mods/Manager/ModFileSystem.cs @@ -7,6 +7,103 @@ using FileSystemChangeType = OtterGui.Filesystem.FileSystemChangeType; namespace Penumbra.Mods.Manager; +//public sealed class ModFileSystem2 : BaseFileSystem +//{ +// private readonly Configuration _config; +// private readonly SaveService _saveService; +// public ModFileSystem2(FileSystemChanged @event, DataNodePathChange dataChangeEvent, Configuration config, SaveService saveService, IComparer>? comparer = null) +// : base(@event, dataChangeEvent, comparer) +// { +// _config = config; +// _saveService = saveService; +// } +// +// public void Dispose() +// { +// _communicator.ModPathChanged.Unsubscribe(OnModPathChange); +// _communicator.ModDiscoveryFinished.Unsubscribe(Reload); +// _communicator.ModDataChanged.Unsubscribe(OnModDataChange); +// } +// +// // Save the filesystem on every filesystem change except full reloading. +// private void OnChange(FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3) +// { +// if (type != FileSystemChangeType.Reload) +// _saveService.DelaySave(this); +// } +// +// // Update sort order when defaulted mod names change. +// private void OnModDataChange(in ModDataChanged.Arguments arguments) +// { +// if (!arguments.Type.HasFlag(ModDataChangeType.Name) || arguments.OldName == null || !TryGetValue(arguments.Mod, out var leaf)) +// return; +// +// var old = Extensions.FixName(arguments.OldName); +// if (old == leaf.Name || Extensions.IsDuplicateName(leaf.Name, out var baseName, out _) && baseName == old) +// RenameWithDuplicates(leaf, arguments.Mod.Name); +// } +// +// // Update the filesystem if a mod has been added or removed. +// // Save it, if the mod directory has been moved, since this will change the save format. +// private void OnModPathChange(in ModPathChanged.Arguments arguments) +// { +// switch (arguments.Type) +// { +// case ModPathChangeType.Added: +// var parent = Root; +// if (_config.DefaultImportFolder.Length != 0) +// try +// { +// parent = FindOrCreateAllFolders(_config.DefaultImportFolder); +// } +// catch (Exception e) +// { +// Penumbra.Messager.NotificationMessage(e, +// $"Could not move newly imported mod {arguments.Mod.Name} to default import folder {_config.DefaultImportFolder}.", +// NotificationType.Warning); +// } +// +// CreateDuplicateLeaf(parent, arguments.Mod.Name, arguments.Mod); +// break; +// case ModPathChangeType.Deleted: +// if (arguments.Mod.Node is not null) +// Delete(arguments.Mod.Node); +// break; +// case ModPathChangeType.Moved: +// _saveService.DelaySave(this); +// break; +// case ModPathChangeType.Reloaded: +// // Nothing +// break; +// } +// } +// +// public struct ImportDate : ISortMode +// { +// public ReadOnlySpan Name +// => "Import Date (Older First)"u8; +// +// public ReadOnlySpan Description +// => "In each folder, sort all subfolders lexicographically, then sort all leaves using their import date."u8; +// +// public IEnumerable GetChildren(IFileSystemFolder f) +// => f.GetSubFolders().Cast().Concat(f.GetLeaves().OfType>().OrderBy(l => l.Value.ImportDate)); +// } +// +// public struct InverseImportDate : ISortMode +// { +// public ReadOnlySpan Name +// => "Import Date (Newer First)"u8; +// +// public ReadOnlySpan Description +// => "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse import date."u8; +// +// public IEnumerable GetChildren(IFileSystemFolder f) +// => f.GetSubFolders().Cast().Concat(f.GetLeaves().OfType>().OrderByDescending(l => l.Value.ImportDate)); +// } +// +//} + public sealed class ModFileSystem : FileSystem, IDisposable, ISavable, IService { private readonly ModManager _modManager; diff --git a/Penumbra/Mods/Mod.cs b/Penumbra/Mods/Mod.cs index 0ef87b85..7bdcba0d 100644 --- a/Penumbra/Mods/Mod.cs +++ b/Penumbra/Mods/Mod.cs @@ -20,7 +20,7 @@ public enum FeatureFlags : ulong Invalid = 1ul << 62, } -public sealed class Mod : IMod +public sealed class Mod : IMod, IFileSystemValue { public static readonly TemporaryMod ForcedFiles = new() { @@ -69,6 +69,7 @@ public sealed class Mod : IMod // Local Data + public string FullPath { get; set; } = string.Empty; public long ImportDate { get; internal set; } = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds(); public IReadOnlyList LocalTags { get; internal set; } = []; public string Note { get; internal set; } = string.Empty; @@ -130,14 +131,15 @@ public sealed class Mod : IMod } // Cache + public IFileSystemData? Node { get; set; } public readonly SortedList ChangedItems = new(); public string LowerChangedItemsString { get; internal set; } = string.Empty; public string AllTagsLower { get; internal set; } = string.Empty; - public int TotalFileCount { get; internal set; } - public int TotalSwapCount { get; internal set; } - public int TotalManipulations { get; internal set; } - public ushort LastChangedItemsUpdate { get; internal set; } - public bool HasOptions { get; internal set; } + public int TotalFileCount { get; internal set; } + public int TotalSwapCount { get; internal set; } + public int TotalManipulations { get; internal set; } + public ushort LastChangedItemsUpdate { get; internal set; } + public bool HasOptions { get; internal set; } } diff --git a/Penumbra/Mods/ModLocalData.cs b/Penumbra/Mods/ModLocalData.cs index 9657c31b..b4cc9405 100644 --- a/Penumbra/Mods/ModLocalData.cs +++ b/Penumbra/Mods/ModLocalData.cs @@ -1,131 +1,139 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Penumbra.GameData.Structs; -using Penumbra.Mods.Manager; -using Penumbra.Services; - -namespace Penumbra.Mods; - -public readonly struct ModLocalData(Mod mod) : ISavable -{ - public const int FileVersion = 3; - - public string ToFilePath(FilenameService fileNames) - => fileNames.LocalDataFile(mod); - - public void Save(StreamWriter writer) - { - var jObject = new JObject - { - { nameof(FileVersion), JToken.FromObject(FileVersion) }, - { nameof(Mod.ImportDate), JToken.FromObject(mod.ImportDate) }, - { nameof(Mod.LocalTags), JToken.FromObject(mod.LocalTags) }, - { nameof(Mod.Note), JToken.FromObject(mod.Note) }, - { nameof(Mod.Favorite), JToken.FromObject(mod.Favorite) }, - { nameof(Mod.PreferredChangedItems), JToken.FromObject(mod.PreferredChangedItems) }, - }; - using var jWriter = new JsonTextWriter(writer); - jWriter.Formatting = Formatting.Indented; - jObject.WriteTo(jWriter); - } - - public static ModDataChangeType Load(ModDataEditor editor, Mod mod) - { - var dataFile = editor.SaveService.FileNames.LocalDataFile(mod); - - var importDate = 0L; - var localTags = Enumerable.Empty(); - var favorite = false; - var note = string.Empty; - - HashSet preferredChangedItems = []; - - var save = true; - if (File.Exists(dataFile)) - try - { - var text = File.ReadAllText(dataFile); - var json = JObject.Parse(text); - - importDate = json[nameof(Mod.ImportDate)]?.Value() ?? importDate; - favorite = json[nameof(Mod.Favorite)]?.Value() ?? favorite; - note = json[nameof(Mod.Note)]?.Value() ?? note; - localTags = (json[nameof(Mod.LocalTags)] as JArray)?.Values().OfType() ?? localTags; - preferredChangedItems = (json[nameof(Mod.PreferredChangedItems)] as JArray)?.Values().Select(i => (CustomItemId) i).ToHashSet() ?? mod.DefaultPreferredItems; - save = false; - } - catch (Exception e) - { - Penumbra.Log.Error($"Could not load local mod data:\n{e}"); - } - else - { - preferredChangedItems = mod.DefaultPreferredItems; - } - - if (importDate == 0) - importDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - - ModDataChangeType changes = 0; - if (mod.ImportDate != importDate) - { - mod.ImportDate = importDate; - changes |= ModDataChangeType.ImportDate; - } - - changes |= UpdateTags(mod, null, localTags); - - if (mod.Favorite != favorite) - { - mod.Favorite = favorite; - changes |= ModDataChangeType.Favorite; - } - - if (mod.Note != note) - { - mod.Note = note; - changes |= ModDataChangeType.Note; - } - - if (!preferredChangedItems.SetEquals(mod.PreferredChangedItems)) - { - mod.PreferredChangedItems = preferredChangedItems; - changes |= ModDataChangeType.PreferredChangedItems; - } - - if (save) - editor.SaveService.QueueSave(new ModLocalData(mod)); - - return changes; - } - - internal static ModDataChangeType UpdateTags(Mod mod, IEnumerable? newModTags, IEnumerable? newLocalTags) - { - if (newModTags == null && newLocalTags == null) - return 0; - - ModDataChangeType type = 0; - if (newModTags != null) - { - var modTags = newModTags.Where(t => t.Length > 0).Distinct().ToArray(); - if (!modTags.SequenceEqual(mod.ModTags)) - { - newLocalTags ??= mod.LocalTags; - mod.ModTags = modTags; - type |= ModDataChangeType.ModTags; - } - } - - if (newLocalTags != null) - { - var localTags = newLocalTags!.Where(t => t.Length > 0 && !mod.ModTags.Contains(t)).Distinct().ToArray(); - if (!localTags.SequenceEqual(mod.LocalTags)) - { - mod.LocalTags = localTags; - type |= ModDataChangeType.LocalTags; - } - } - - return type; - } -} +using Luna; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Penumbra.GameData.Structs; +using Penumbra.Mods.Manager; +using Penumbra.Services; + +namespace Penumbra.Mods; + +public readonly struct ModLocalData(Mod mod) : ISavable +{ + public const int FileVersion = 3; + + public string ToFilePath(FilenameService fileNames) + => fileNames.LocalDataFile(mod); + + public void Save(StreamWriter writer) + { + var jObject = new JObject + { + { nameof(FileVersion), JToken.FromObject(FileVersion) }, + { nameof(Mod.ImportDate), JToken.FromObject(mod.ImportDate) }, + { nameof(Mod.LocalTags), JToken.FromObject(mod.LocalTags) }, + { nameof(Mod.Note), JToken.FromObject(mod.Note) }, + { nameof(Mod.Favorite), JToken.FromObject(mod.Favorite) }, + { nameof(Mod.PreferredChangedItems), JToken.FromObject(mod.PreferredChangedItems) }, + }; + + if (mod.FullPath.Length > 0) + { + var baseName = mod.FullPath.GetBaseName(mod.Name, out var folder); + jObject[nameof(Mod.FullPath)] = folder.Length > 0 ? $"{folder}/{baseName}" : baseName.ToString(); + } + + using var jWriter = new JsonTextWriter(writer); + jWriter.Formatting = Formatting.Indented; + jObject.WriteTo(jWriter); + } + + public static ModDataChangeType Load(ModDataEditor editor, Mod mod) + { + var dataFile = editor.SaveService.FileNames.LocalDataFile(mod); + + var importDate = 0L; + var localTags = Enumerable.Empty(); + var favorite = false; + var note = string.Empty; + + HashSet preferredChangedItems = []; + + var save = true; + if (File.Exists(dataFile)) + try + { + var text = File.ReadAllText(dataFile); + var json = JObject.Parse(text); + + importDate = json[nameof(Mod.ImportDate)]?.Value() ?? importDate; + favorite = json[nameof(Mod.Favorite)]?.Value() ?? favorite; + note = json[nameof(Mod.Note)]?.Value() ?? note; + localTags = (json[nameof(Mod.LocalTags)] as JArray)?.Values().OfType() ?? localTags; + preferredChangedItems = + (json[nameof(Mod.PreferredChangedItems)] as JArray)?.Values().Select(i => (CustomItemId)i).ToHashSet() + ?? mod.DefaultPreferredItems; + save = false; + } + catch (Exception e) + { + Penumbra.Log.Error($"Could not load local mod data:\n{e}"); + } + else + preferredChangedItems = mod.DefaultPreferredItems; + + if (importDate == 0) + importDate = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + + ModDataChangeType changes = 0; + if (mod.ImportDate != importDate) + { + mod.ImportDate = importDate; + changes |= ModDataChangeType.ImportDate; + } + + changes |= UpdateTags(mod, null, localTags); + + if (mod.Favorite != favorite) + { + mod.Favorite = favorite; + changes |= ModDataChangeType.Favorite; + } + + if (mod.Note != note) + { + mod.Note = note; + changes |= ModDataChangeType.Note; + } + + if (!preferredChangedItems.SetEquals(mod.PreferredChangedItems)) + { + mod.PreferredChangedItems = preferredChangedItems; + changes |= ModDataChangeType.PreferredChangedItems; + } + + if (save) + editor.SaveService.QueueSave(new ModLocalData(mod)); + + return changes; + } + + internal static ModDataChangeType UpdateTags(Mod mod, IEnumerable? newModTags, IEnumerable? newLocalTags) + { + if (newModTags == null && newLocalTags == null) + return 0; + + ModDataChangeType type = 0; + if (newModTags != null) + { + var modTags = newModTags.Where(t => t.Length > 0).Distinct().ToArray(); + if (!modTags.SequenceEqual(mod.ModTags)) + { + newLocalTags ??= mod.LocalTags; + mod.ModTags = modTags; + type |= ModDataChangeType.ModTags; + } + } + + if (newLocalTags != null) + { + var localTags = newLocalTags!.Where(t => t.Length > 0 && !mod.ModTags.Contains(t)).Distinct().ToArray(); + if (!localTags.SequenceEqual(mod.LocalTags)) + { + mod.LocalTags = localTags; + type |= ModDataChangeType.LocalTags; + } + } + + return type; + } +} diff --git a/Penumbra/Services/StaticServiceManager.cs b/Penumbra/Services/StaticServiceManager.cs index 113a8e21..30adf17b 100644 --- a/Penumbra/Services/StaticServiceManager.cs +++ b/Penumbra/Services/StaticServiceManager.cs @@ -22,7 +22,7 @@ public static class StaticServiceManager { public static ServiceManager CreateProvider(Penumbra penumbra, IDalamudPluginInterface pi, Logger log) { - var services = new ServiceManager(log) + var services = new ServiceManager(log, Logger.GlobalPluginName) .AddDalamudServices(pi) .AddExistingService(log) .AddExistingService(penumbra); diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs index e6940fff..c00e6fc4 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.ColorTable.cs @@ -44,7 +44,7 @@ public partial class MtrlTab for (var j = 0; j < 8; ++j) { var pairIndex = i + j; - using (ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), pairIndex == _colorTableSelectedPair)) + using (ImGuiColor.Button.Push(Im.Style[ImGuiColor.ButtonActive], pairIndex == _colorTableSelectedPair)) { if (ImUtf8.Button($"#{pairIndex + 1}".PadLeft(3 + spacePadding), new Vector2(buttonWidth, ImGui.GetFrameHeightWithSpacing() + frameHeight))) @@ -101,6 +101,7 @@ public partial class MtrlTab { retA |= DrawRowHeader(rowAIdx, disabled); } + columns.Next(); using (ImUtf8.PushId("RowHeaderB"u8)) { @@ -232,8 +233,8 @@ public partial class MtrlTab /// Padding styles do not seem to apply to this component. It is recommended to prepend two spaces. private static void DrawHeader(ReadOnlySpan label) { - var headerColor = ImGui.GetColorU32(ImGuiCol.Header); - using var _ = ImRaii.PushColor(ImGuiCol.HeaderHovered, headerColor).Push(ImGuiCol.HeaderActive, headerColor); + var headerColor = Im.Style[ImGuiColor.Header]; + using var _ = ImGuiColor.HeaderHovered.Push(headerColor).Push(ImGuiColor.HeaderActive, headerColor); ImUtf8.CollapsingHeader(label, ImGuiTreeNodeFlags.Leaf); } diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs index b0e7cd63..fc0b3611 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.CommonColorTable.cs @@ -308,7 +308,7 @@ public partial class MtrlTab var style = ImGui.GetStyle(); var frameRounding = style.FrameRounding; var frameThickness = style.FrameBorderSize; - var borderColor = ImGui.GetColorU32(ImGuiCol.Border); + var borderColor = ImGuiColor.Border.Get(); var drawList = ImGui.GetWindowDrawList(); if (topColor == bottomColor) { @@ -328,7 +328,7 @@ public partial class MtrlTab bottomColor, frameRounding, ImDrawFlags.RoundCornersBottomLeft | ImDrawFlags.RoundCornersBottomRight); } - drawList.AddRect(rcMin, rcMax, borderColor, frameRounding, ImDrawFlags.RoundCornersDefault, frameThickness); + drawList.AddRect(rcMin, rcMax, borderColor.Color, frameRounding, ImDrawFlags.RoundCornersDefault, frameThickness); } private static bool CtColorPicker(ReadOnlySpan label, ReadOnlySpan description, HalfColor current, Action setter, diff --git a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs index 3257c840..1c0fdf54 100644 --- a/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs +++ b/Penumbra/UI/AdvancedWindow/Materials/MtrlTab.LivePreview.cs @@ -24,16 +24,15 @@ public partial class MtrlTab if (disabled) return; - if (ImUtf8.Button("Reload live preview"u8)) + if (Im.Button("Reload live preview"u8)) BindToMaterialInstances(); if (_materialPreviewers.Count != 0 || _colorTablePreviewers.Count != 0) return; Im.Line.Same(); - using var c = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder); - ImUtf8.Text( - "The current material has not been found on your character. Please check the Import from Screen tab for more information."u8); + Im.Text("The current material has not been found on your character. Please check the Import from Screen tab for more information."u8, + Colors.RegexWarningBorder); } private unsafe void BindToMaterialInstances() @@ -292,7 +291,7 @@ public partial class MtrlTab { var level = (MathF.Sin(time * 2.0f * MathF.PI) + 2.0f) / 3.0f / 255.0f; var baseColor = colorId.Value(); - var color = level * new Vector3(baseColor & 0xFF, (baseColor >> 8) & 0xFF, (baseColor >> 16) & 0xFF); + var color = level * new Vector3(baseColor.R, baseColor.G, baseColor.B); var halfColor = (HalfColor)(color * color); row.DiffuseColor = halfColor; diff --git a/Penumbra/UI/AdvancedWindow/Meta/AtrMetaDrawer.cs b/Penumbra/UI/AdvancedWindow/Meta/AtrMetaDrawer.cs index 9dc2a4d4..c0e2efb0 100644 --- a/Penumbra/UI/AdvancedWindow/Meta/AtrMetaDrawer.cs +++ b/Penumbra/UI/AdvancedWindow/Meta/AtrMetaDrawer.cs @@ -1,273 +1,274 @@ -using Dalamud.Interface; -using Dalamud.Bindings.ImGui; -using Newtonsoft.Json.Linq; -using OtterGui.Raii; -using OtterGui.Text; -using Penumbra.Collections.Cache; -using Penumbra.GameData.Enums; -using Penumbra.GameData.Structs; -using Penumbra.Meta; -using Penumbra.Meta.Files; -using Penumbra.Meta.Manipulations; -using Penumbra.Mods.Editor; -using Penumbra.UI.Classes; - -namespace Penumbra.UI.AdvancedWindow.Meta; - -public sealed class AtrMetaDrawer(ModMetaEditor editor, MetaFileManager metaFiles) - : MetaDrawer(editor, metaFiles), Luna.IService -{ - public override ReadOnlySpan Label - => "Attributes(ATR)###ATR"u8; - - private ShapeAttributeString _buffer = ShapeAttributeString.TryRead("atrx_"u8, out var s) ? s : ShapeAttributeString.Empty; - private bool _identifierValid; - - public override int NumColumns - => 7; - - public override float ColumnHeight - => ImUtf8.FrameHeightSpacing; - - protected override void Initialize() - { - Identifier = new AtrIdentifier(HumanSlot.Unknown, null, ShapeAttributeString.Empty, GenderRace.Unknown); - Entry = AtrEntry.True; - } - - protected override void DrawNew() - { - ImGui.TableNextColumn(); - CopyToClipboardButton("Copy all current ATR manipulations to clipboard."u8, - new Lazy(() => MetaDictionary.SerializeTo([], Editor.Atr))); - - ImGui.TableNextColumn(); - var canAdd = !Editor.Contains(Identifier) && _identifierValid; - var tt = canAdd - ? "Stage this edit."u8 - : _identifierValid - ? "This entry does not contain a valid attribute."u8 - : "This entry is already edited."u8; - if (ImUtf8.IconButton(FontAwesomeIcon.Plus, tt, disabled: !canAdd)) - Editor.Changes |= Editor.TryAdd(Identifier, AtrEntry.False); - - DrawIdentifierInput(ref Identifier); - DrawEntry(ref Entry, true); - } - - protected override void DrawEntry(AtrIdentifier identifier, AtrEntry entry) - { - DrawMetaButtons(identifier, entry); - DrawIdentifier(identifier); - - if (DrawEntry(ref entry, false)) - Editor.Changes |= Editor.Update(identifier, entry); - } - - protected override IEnumerable<(AtrIdentifier, AtrEntry)> Enumerate() - => Editor.Atr - .OrderBy(kvp => kvp.Key.Attribute) - .ThenBy(kvp => kvp.Key.Slot) - .ThenBy(kvp => kvp.Key.Id) - .Select(kvp => (kvp.Key, kvp.Value)); - - protected override int Count - => Editor.Atr.Count; - - private bool DrawIdentifierInput(ref AtrIdentifier identifier) - { - ImGui.TableNextColumn(); - var changes = DrawHumanSlot(ref identifier); - - ImGui.TableNextColumn(); - changes |= DrawGenderRaceConditionInput(ref identifier); - - ImGui.TableNextColumn(); - changes |= DrawPrimaryId(ref identifier); - - ImGui.TableNextColumn(); - changes |= DrawAttributeKeyInput(ref identifier, ref _buffer, ref _identifierValid); - return changes; - } - - private static void DrawIdentifier(AtrIdentifier identifier) - { - ImGui.TableNextColumn(); - - ImUtf8.TextFramed(ShpMetaDrawer.SlotName(identifier.Slot), FrameColor); - ImUtf8.HoverTooltip("Model Slot"u8); - - ImGui.TableNextColumn(); - if (identifier.GenderRaceCondition is not GenderRace.Unknown) - { - ImUtf8.TextFramed($"{identifier.GenderRaceCondition.ToName()} ({identifier.GenderRaceCondition.ToRaceCode()})", FrameColor); - ImUtf8.HoverTooltip("Gender & Race Code for this attribute to be set."); - } - else - { - ImUtf8.TextFramed("Any Gender & Race"u8, FrameColor); - } - - ImGui.TableNextColumn(); - if (identifier.Id.HasValue) - ImUtf8.TextFramed($"{identifier.Id.Value.Id}", FrameColor); - else - ImUtf8.TextFramed("All IDs"u8, FrameColor); - ImUtf8.HoverTooltip("Primary ID"u8); - - ImGui.TableNextColumn(); - ImUtf8.TextFramed(identifier.Attribute.AsSpan, FrameColor); - } - - private static bool DrawEntry(ref AtrEntry entry, bool disabled) - { - using var dis = ImRaii.Disabled(disabled); - ImGui.TableNextColumn(); - var value = entry.Value; - var changes = ImUtf8.Checkbox("##atrEntry"u8, ref value); - if (changes) - entry = new AtrEntry(value); - ImUtf8.HoverTooltip("Whether to enable or disable this attribute for the selected items."); - return changes; - } - - public static bool DrawPrimaryId(ref AtrIdentifier identifier, float unscaledWidth = 100) - { - var allSlots = identifier.Slot is HumanSlot.Unknown; - var all = !identifier.Id.HasValue; - var ret = false; - using (ImRaii.Disabled(allSlots)) - { - if (ImUtf8.Checkbox("##atrAll"u8, ref all)) - { - identifier = identifier with { Id = all ? null : 0 }; - ret = true; - } - } - - ImUtf8.HoverTooltip(allSlots - ? "When using all slots, you also need to use all IDs."u8 - : "Enable this attribute for all model IDs."u8); - - ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); - if (all) - { - using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.05f, 0.5f)); - ImUtf8.TextFramed("All IDs"u8, ImGui.GetColorU32(ImGuiCol.FrameBg, all || allSlots ? ImGui.GetStyle().DisabledAlpha : 1f), - new Vector2(unscaledWidth, 0), ImGui.GetColorU32(ImGuiCol.TextDisabled)); - } - else - { - var max = identifier.Slot.ToSpecificEnum() is BodySlot ? byte.MaxValue : ExpandedEqpGmpBase.Count - 1; - if (IdInput("##atrPrimaryId"u8, unscaledWidth, identifier.Id.GetValueOrDefault(0).Id, out var setId, 0, max, false)) - { - identifier = identifier with { Id = setId }; - ret = true; - } - } - - ImUtf8.HoverTooltip("Primary ID - You can usually find this as the 'e####' part of an item path or similar for customizations."u8); - - return ret; - } - - public bool DrawHumanSlot(ref AtrIdentifier identifier, float unscaledWidth = 150) - { - var ret = false; - ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); - using (var combo = ImUtf8.Combo("##atrSlot"u8, ShpMetaDrawer.SlotName(identifier.Slot))) - { - if (combo) - foreach (var slot in ShpMetaDrawer.AvailableSlots) - { - if (!ImUtf8.Selectable(ShpMetaDrawer.SlotName(slot), slot == identifier.Slot) || slot == identifier.Slot) - continue; - - ret = true; - if (slot is HumanSlot.Unknown) - { - identifier = identifier with - { - Id = null, - Slot = slot, - }; - } - else - { - identifier = identifier with - { - Id = identifier.Id.HasValue - ? (PrimaryId)Math.Clamp(identifier.Id.Value.Id, 0, - slot.ToSpecificEnum() is BodySlot ? byte.MaxValue : ExpandedEqpGmpBase.Count - 1) - : null, - Slot = slot, - }; - ret = true; - } - } - } - - ImUtf8.HoverTooltip("Model Slot"u8); - return ret; - } - - private static bool DrawGenderRaceConditionInput(ref AtrIdentifier identifier, float unscaledWidth = 250) - { - var ret = false; - ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); - - using (var combo = ImUtf8.Combo("##shpGenderRace"u8, - identifier.GenderRaceCondition is GenderRace.Unknown - ? "Any Gender & Race" - : $"{identifier.GenderRaceCondition.ToName()} ({identifier.GenderRaceCondition.ToRaceCode()})")) - { - if (combo) - { - if (ImUtf8.Selectable("Any Gender & Race"u8, identifier.GenderRaceCondition is GenderRace.Unknown) - && identifier.GenderRaceCondition is not GenderRace.Unknown) - { - identifier = identifier with { GenderRaceCondition = GenderRace.Unknown }; - ret = true; - } - - foreach (var gr in ShapeAttributeHashSet.GenderRaceValues.Skip(1)) - { - if (ImUtf8.Selectable($"{gr.ToName()} ({gr.ToRaceCode()})", identifier.GenderRaceCondition == gr) - && identifier.GenderRaceCondition != gr) - { - identifier = identifier with { GenderRaceCondition = gr }; - ret = true; - } - } - } - } - - ImUtf8.HoverTooltip( - "Only activate this attribute for this gender & race code."u8); - - return ret; - } - - public static unsafe bool DrawAttributeKeyInput(ref AtrIdentifier identifier, ref ShapeAttributeString buffer, ref bool valid, - float unscaledWidth = 150) - { - var ret = false; - var ptr = Unsafe.AsPointer(ref buffer); - var span = new Span(ptr, ShapeAttributeString.MaxLength + 1); - using (new ImRaii.ColorStyle().Push(ImGuiCol.Border, Colors.RegexWarningBorder, !valid).Push(ImGuiStyleVar.FrameBorderSize, 1f, !valid)) - { - ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); - if (ImUtf8.InputText("##atrAttribute"u8, span, out int newLength, "Attribute..."u8)) - { - buffer.ForceLength((byte)newLength); - valid = buffer.ValidateCustomAttributeString(); - if (valid) - identifier = identifier with { Attribute = buffer }; - ret = true; - } - } - - ImUtf8.HoverTooltip("Supported attribute need to have the format `atrx_*` and a maximum length of 30 characters."u8); - return ret; - } -} +using Dalamud.Interface; +using Dalamud.Bindings.ImGui; +using ImSharp; +using Newtonsoft.Json.Linq; +using OtterGui.Raii; +using OtterGui.Text; +using Penumbra.Collections.Cache; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; +using Penumbra.Meta; +using Penumbra.Meta.Files; +using Penumbra.Meta.Manipulations; +using Penumbra.Mods.Editor; +using Penumbra.UI.Classes; + +namespace Penumbra.UI.AdvancedWindow.Meta; + +public sealed class AtrMetaDrawer(ModMetaEditor editor, MetaFileManager metaFiles) + : MetaDrawer(editor, metaFiles), Luna.IService +{ + public override ReadOnlySpan Label + => "Attributes(ATR)###ATR"u8; + + private ShapeAttributeString _buffer = ShapeAttributeString.TryRead("atrx_"u8, out var s) ? s : ShapeAttributeString.Empty; + private bool _identifierValid; + + public override int NumColumns + => 7; + + public override float ColumnHeight + => ImUtf8.FrameHeightSpacing; + + protected override void Initialize() + { + Identifier = new AtrIdentifier(HumanSlot.Unknown, null, ShapeAttributeString.Empty, GenderRace.Unknown); + Entry = AtrEntry.True; + } + + protected override void DrawNew() + { + ImGui.TableNextColumn(); + CopyToClipboardButton("Copy all current ATR manipulations to clipboard."u8, + new Lazy(() => MetaDictionary.SerializeTo([], Editor.Atr))); + + ImGui.TableNextColumn(); + var canAdd = !Editor.Contains(Identifier) && _identifierValid; + var tt = canAdd + ? "Stage this edit."u8 + : _identifierValid + ? "This entry does not contain a valid attribute."u8 + : "This entry is already edited."u8; + if (ImUtf8.IconButton(FontAwesomeIcon.Plus, tt, disabled: !canAdd)) + Editor.Changes |= Editor.TryAdd(Identifier, AtrEntry.False); + + DrawIdentifierInput(ref Identifier); + DrawEntry(ref Entry, true); + } + + protected override void DrawEntry(AtrIdentifier identifier, AtrEntry entry) + { + DrawMetaButtons(identifier, entry); + DrawIdentifier(identifier); + + if (DrawEntry(ref entry, false)) + Editor.Changes |= Editor.Update(identifier, entry); + } + + protected override IEnumerable<(AtrIdentifier, AtrEntry)> Enumerate() + => Editor.Atr + .OrderBy(kvp => kvp.Key.Attribute) + .ThenBy(kvp => kvp.Key.Slot) + .ThenBy(kvp => kvp.Key.Id) + .Select(kvp => (kvp.Key, kvp.Value)); + + protected override int Count + => Editor.Atr.Count; + + private bool DrawIdentifierInput(ref AtrIdentifier identifier) + { + ImGui.TableNextColumn(); + var changes = DrawHumanSlot(ref identifier); + + ImGui.TableNextColumn(); + changes |= DrawGenderRaceConditionInput(ref identifier); + + ImGui.TableNextColumn(); + changes |= DrawPrimaryId(ref identifier); + + ImGui.TableNextColumn(); + changes |= DrawAttributeKeyInput(ref identifier, ref _buffer, ref _identifierValid); + return changes; + } + + private static void DrawIdentifier(AtrIdentifier identifier) + { + ImGui.TableNextColumn(); + + ImUtf8.TextFramed(ShpMetaDrawer.SlotName(identifier.Slot), FrameColor); + ImUtf8.HoverTooltip("Model Slot"u8); + + ImGui.TableNextColumn(); + if (identifier.GenderRaceCondition is not GenderRace.Unknown) + { + ImUtf8.TextFramed($"{identifier.GenderRaceCondition.ToName()} ({identifier.GenderRaceCondition.ToRaceCode()})", FrameColor); + ImUtf8.HoverTooltip("Gender & Race Code for this attribute to be set."); + } + else + { + ImUtf8.TextFramed("Any Gender & Race"u8, FrameColor); + } + + ImGui.TableNextColumn(); + if (identifier.Id.HasValue) + ImUtf8.TextFramed($"{identifier.Id.Value.Id}", FrameColor); + else + ImUtf8.TextFramed("All IDs"u8, FrameColor); + ImUtf8.HoverTooltip("Primary ID"u8); + + ImGui.TableNextColumn(); + ImUtf8.TextFramed(identifier.Attribute.AsSpan, FrameColor); + } + + private static bool DrawEntry(ref AtrEntry entry, bool disabled) + { + using var dis = ImRaii.Disabled(disabled); + ImGui.TableNextColumn(); + var value = entry.Value; + var changes = ImUtf8.Checkbox("##atrEntry"u8, ref value); + if (changes) + entry = new AtrEntry(value); + ImUtf8.HoverTooltip("Whether to enable or disable this attribute for the selected items."); + return changes; + } + + public static bool DrawPrimaryId(ref AtrIdentifier identifier, float unscaledWidth = 100) + { + var allSlots = identifier.Slot is HumanSlot.Unknown; + var all = !identifier.Id.HasValue; + var ret = false; + using (ImRaii.Disabled(allSlots)) + { + if (ImUtf8.Checkbox("##atrAll"u8, ref all)) + { + identifier = identifier with { Id = all ? null : 0 }; + ret = true; + } + } + + ImUtf8.HoverTooltip(allSlots + ? "When using all slots, you also need to use all IDs."u8 + : "Enable this attribute for all model IDs."u8); + + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + if (all) + { + using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.05f, 0.5f)); + ImUtf8.TextFramed("All IDs"u8, ImGuiColor.FrameBackground.Get(all || allSlots ? ImGui.GetStyle().DisabledAlpha : 1f).Color, + new Vector2(unscaledWidth, 0), ImGuiColor.TextDisabled.Get().Color); + } + else + { + var max = identifier.Slot.ToSpecificEnum() is BodySlot ? byte.MaxValue : ExpandedEqpGmpBase.Count - 1; + if (IdInput("##atrPrimaryId"u8, unscaledWidth, identifier.Id.GetValueOrDefault(0).Id, out var setId, 0, max, false)) + { + identifier = identifier with { Id = setId }; + ret = true; + } + } + + ImUtf8.HoverTooltip("Primary ID - You can usually find this as the 'e####' part of an item path or similar for customizations."u8); + + return ret; + } + + public bool DrawHumanSlot(ref AtrIdentifier identifier, float unscaledWidth = 150) + { + var ret = false; + ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); + using (var combo = ImUtf8.Combo("##atrSlot"u8, ShpMetaDrawer.SlotName(identifier.Slot))) + { + if (combo) + foreach (var slot in ShpMetaDrawer.AvailableSlots) + { + if (!ImUtf8.Selectable(ShpMetaDrawer.SlotName(slot), slot == identifier.Slot) || slot == identifier.Slot) + continue; + + ret = true; + if (slot is HumanSlot.Unknown) + { + identifier = identifier with + { + Id = null, + Slot = slot, + }; + } + else + { + identifier = identifier with + { + Id = identifier.Id.HasValue + ? (PrimaryId)Math.Clamp(identifier.Id.Value.Id, 0, + slot.ToSpecificEnum() is BodySlot ? byte.MaxValue : ExpandedEqpGmpBase.Count - 1) + : null, + Slot = slot, + }; + ret = true; + } + } + } + + ImUtf8.HoverTooltip("Model Slot"u8); + return ret; + } + + private static bool DrawGenderRaceConditionInput(ref AtrIdentifier identifier, float unscaledWidth = 250) + { + var ret = false; + ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); + + using (var combo = ImUtf8.Combo("##shpGenderRace"u8, + identifier.GenderRaceCondition is GenderRace.Unknown + ? "Any Gender & Race" + : $"{identifier.GenderRaceCondition.ToName()} ({identifier.GenderRaceCondition.ToRaceCode()})")) + { + if (combo) + { + if (ImUtf8.Selectable("Any Gender & Race"u8, identifier.GenderRaceCondition is GenderRace.Unknown) + && identifier.GenderRaceCondition is not GenderRace.Unknown) + { + identifier = identifier with { GenderRaceCondition = GenderRace.Unknown }; + ret = true; + } + + foreach (var gr in ShapeAttributeHashSet.GenderRaceValues.Skip(1)) + { + if (ImUtf8.Selectable($"{gr.ToName()} ({gr.ToRaceCode()})", identifier.GenderRaceCondition == gr) + && identifier.GenderRaceCondition != gr) + { + identifier = identifier with { GenderRaceCondition = gr }; + ret = true; + } + } + } + } + + ImUtf8.HoverTooltip( + "Only activate this attribute for this gender & race code."u8); + + return ret; + } + + public static unsafe bool DrawAttributeKeyInput(ref AtrIdentifier identifier, ref ShapeAttributeString buffer, ref bool valid, + float unscaledWidth = 150) + { + var ret = false; + var ptr = Unsafe.AsPointer(ref buffer); + var span = new Span(ptr, ShapeAttributeString.MaxLength + 1); + using (ImStyleBorder.Frame.Push(Colors.RegexWarningBorder, Im.Style.GlobalScale, !valid)) + { + ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); + if (ImUtf8.InputText("##atrAttribute"u8, span, out int newLength, "Attribute..."u8)) + { + buffer.ForceLength((byte)newLength); + valid = buffer.ValidateCustomAttributeString(); + if (valid) + identifier = identifier with { Attribute = buffer }; + ret = true; + } + } + + ImUtf8.HoverTooltip("Supported attribute need to have the format `atrx_*` and a maximum length of 30 characters."u8); + return ret; + } +} diff --git a/Penumbra/UI/AdvancedWindow/Meta/MetaDrawer.cs b/Penumbra/UI/AdvancedWindow/Meta/MetaDrawer.cs index f608a194..4a6b1331 100644 --- a/Penumbra/UI/AdvancedWindow/Meta/MetaDrawer.cs +++ b/Penumbra/UI/AdvancedWindow/Meta/MetaDrawer.cs @@ -1,165 +1,163 @@ -using Dalamud.Interface; -using Dalamud.Bindings.ImGui; -using Newtonsoft.Json.Linq; -using OtterGui; -using OtterGui.Raii; -using OtterGui.Text; -using Penumbra.Api.Api; -using Penumbra.Meta; -using Penumbra.Meta.Manipulations; -using Penumbra.Mods.Editor; -using Penumbra.UI.Classes; - -namespace Penumbra.UI.AdvancedWindow.Meta; - -public interface IMetaDrawer -{ - public ReadOnlySpan Label { get; } - public int NumColumns { get; } - public float ColumnHeight { get; } - public void Draw(); -} - -public abstract class MetaDrawer(ModMetaEditor editor, MetaFileManager metaFiles) : IMetaDrawer - where TIdentifier : unmanaged, IMetaIdentifier - where TEntry : unmanaged -{ - protected const uint FrameColor = 0; - - protected readonly ModMetaEditor Editor = editor; - protected readonly MetaFileManager MetaFiles = metaFiles; - protected TIdentifier Identifier; - protected TEntry Entry; - private bool _initialized; - - public void Draw() - { - if (!_initialized) - { - Initialize(); - _initialized = true; - } - - using var id = ImUtf8.PushId((int)Identifier.Type); - DrawNew(); - - var height = ColumnHeight; - var skips = ImGuiClip.GetNecessarySkipsAtPos(height, ImGui.GetCursorPosY(), Count); - if (skips < Count) - { - var remainder = ImGuiClip.ClippedTableDraw(Enumerate(), skips, DrawLine, Count); - if (remainder > 0) - ImGuiClip.DrawEndDummy(remainder, height); - } - - void DrawLine((TIdentifier Identifier, TEntry Value) pair) - => DrawEntry(pair.Identifier, pair.Value); - } - - public abstract ReadOnlySpan Label { get; } - public abstract int NumColumns { get; } - - public virtual float ColumnHeight - => ImUtf8.FrameHeightSpacing; - - protected abstract void DrawNew(); - protected abstract void Initialize(); - protected abstract void DrawEntry(TIdentifier identifier, TEntry entry); - - protected abstract IEnumerable<(TIdentifier, TEntry)> Enumerate(); - protected abstract int Count { get; } - - - /// - /// A number input for ids with an optional max id of given width. - /// Returns true if newId changed against currentId. - /// - protected static bool IdInput(ReadOnlySpan label, float unscaledWidth, ushort currentId, out ushort newId, int minId, int maxId, - bool border) - { - int tmp = currentId; - ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); - using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, UiHelpers.Scale, border); - using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder, border); - if (ImUtf8.InputScalar(label, ref tmp)) - tmp = Math.Clamp(tmp, minId, maxId); - - newId = (ushort)tmp; - return newId != currentId; - } - - /// - /// A dragging int input of given width that compares against a default value, shows a tooltip and clamps against min and max. - /// Returns true if newValue changed against currentValue. - /// - protected static bool DragInput(ReadOnlySpan label, ReadOnlySpan tooltip, float width, T currentValue, T defaultValue, - out T newValue, T minValue, T maxValue, float speed, bool addDefault) where T : unmanaged, INumber - { - newValue = currentValue; - using var color = ImRaii.PushColor(ImGuiCol.FrameBg, - defaultValue > currentValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(), - defaultValue != currentValue); - ImGui.SetNextItemWidth(width); - if (ImUtf8.DragScalar(label, ref newValue, minValue, maxValue, speed)) - newValue = newValue <= minValue ? minValue : newValue >= maxValue ? maxValue : newValue; - - if (addDefault) - ImUtf8.HoverTooltip($"{tooltip}\nDefault Value: {defaultValue}"); - else - ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip); - - return newValue != currentValue; - } - - /// - /// A checkmark that compares against a default value and shows a tooltip. - /// Returns true if newValue is changed against currentValue. - /// - protected static bool Checkmark(ReadOnlySpan label, ReadOnlySpan tooltip, bool currentValue, bool defaultValue, - out bool newValue) - { - using var color = ImRaii.PushColor(ImGuiCol.FrameBg, - defaultValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(), - defaultValue != currentValue); - newValue = currentValue; - ImUtf8.Checkbox(label, ref newValue); - ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip); - return newValue != currentValue; - } - - /// - /// A checkmark that compares against a default value and shows a tooltip. - /// Returns true if newValue is changed against currentValue. - /// - protected static bool Checkmark(ReadOnlySpan label, ReadOnlySpan tooltip, bool currentValue, bool defaultValue, - out bool newValue) - { - using var color = ImRaii.PushColor(ImGuiCol.FrameBg, - defaultValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(), - defaultValue != currentValue); - newValue = currentValue; - ImUtf8.Checkbox(label, ref newValue); - ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip); - return newValue != currentValue; - } - - protected void DrawMetaButtons(TIdentifier identifier, TEntry entry) - { - ImGui.TableNextColumn(); - CopyToClipboardButton("Copy this manipulation to clipboard."u8, new Lazy(() => new JArray { MetaDictionary.Serialize(identifier, entry)! })); - - ImGui.TableNextColumn(); - if (ImUtf8.IconButton(FontAwesomeIcon.Trash, "Delete this meta manipulation."u8)) - Editor.Changes |= Editor.Remove(identifier); - } - - protected void CopyToClipboardButton(ReadOnlySpan tooltip, Lazy manipulations) - { - if (!ImUtf8.IconButton(FontAwesomeIcon.Clipboard, tooltip)) - return; - - var text = Functions.ToCompressedBase64(manipulations.Value, 0); - if (text.Length > 0) - ImGui.SetClipboardText(text); - } -} +using Dalamud.Interface; +using Dalamud.Bindings.ImGui; +using ImSharp; +using Newtonsoft.Json.Linq; +using OtterGui; +using OtterGui.Raii; +using OtterGui.Text; +using Penumbra.Api.Api; +using Penumbra.Meta; +using Penumbra.Meta.Manipulations; +using Penumbra.Mods.Editor; +using Penumbra.UI.Classes; + +namespace Penumbra.UI.AdvancedWindow.Meta; + +public interface IMetaDrawer +{ + public ReadOnlySpan Label { get; } + public int NumColumns { get; } + public float ColumnHeight { get; } + public void Draw(); +} + +public abstract class MetaDrawer(ModMetaEditor editor, MetaFileManager metaFiles) : IMetaDrawer + where TIdentifier : unmanaged, IMetaIdentifier + where TEntry : unmanaged +{ + protected const uint FrameColor = 0; + + protected readonly ModMetaEditor Editor = editor; + protected readonly MetaFileManager MetaFiles = metaFiles; + protected TIdentifier Identifier; + protected TEntry Entry; + private bool _initialized; + + public void Draw() + { + if (!_initialized) + { + Initialize(); + _initialized = true; + } + + using var id = ImUtf8.PushId((int)Identifier.Type); + DrawNew(); + + var height = ColumnHeight; + var skips = ImGuiClip.GetNecessarySkipsAtPos(height, ImGui.GetCursorPosY(), Count); + if (skips < Count) + { + var remainder = ImGuiClip.ClippedTableDraw(Enumerate(), skips, DrawLine, Count); + if (remainder > 0) + ImGuiClip.DrawEndDummy(remainder, height); + } + + void DrawLine((TIdentifier Identifier, TEntry Value) pair) + => DrawEntry(pair.Identifier, pair.Value); + } + + public abstract ReadOnlySpan Label { get; } + public abstract int NumColumns { get; } + + public virtual float ColumnHeight + => ImUtf8.FrameHeightSpacing; + + protected abstract void DrawNew(); + protected abstract void Initialize(); + protected abstract void DrawEntry(TIdentifier identifier, TEntry entry); + + protected abstract IEnumerable<(TIdentifier, TEntry)> Enumerate(); + protected abstract int Count { get; } + + + /// + /// A number input for ids with an optional max id of given width. + /// Returns true if newId changed against currentId. + /// + protected static bool IdInput(ReadOnlySpan label, float unscaledWidth, ushort currentId, out ushort newId, int minId, int maxId, + bool border) + { + int tmp = currentId; + ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); + using var style = ImStyleBorder.Frame.Push(Colors.RegexWarningBorder, Im.Style.GlobalScale, border); + if (ImUtf8.InputScalar(label, ref tmp)) + tmp = Math.Clamp(tmp, minId, maxId); + + newId = (ushort)tmp; + return newId != currentId; + } + + /// + /// A dragging int input of given width that compares against a default value, shows a tooltip and clamps against min and max. + /// Returns true if newValue changed against currentValue. + /// + protected static bool DragInput(ReadOnlySpan label, ReadOnlySpan tooltip, float width, T currentValue, T defaultValue, + out T newValue, T minValue, T maxValue, float speed, bool addDefault) where T : unmanaged, INumber + { + newValue = currentValue; + var c = defaultValue > currentValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(); + using var color = ImGuiColor.FrameBackground.Push(c, defaultValue != currentValue); + ImGui.SetNextItemWidth(width); + if (ImUtf8.DragScalar(label, ref newValue, minValue, maxValue, speed)) + newValue = newValue <= minValue ? minValue : newValue >= maxValue ? maxValue : newValue; + + if (addDefault) + ImUtf8.HoverTooltip($"{tooltip}\nDefault Value: {defaultValue}"); + else + ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip); + + return newValue != currentValue; + } + + /// + /// A checkmark that compares against a default value and shows a tooltip. + /// Returns true if newValue is changed against currentValue. + /// + protected static bool Checkmark(ReadOnlySpan label, ReadOnlySpan tooltip, bool currentValue, bool defaultValue, + out bool newValue) + { + var c = defaultValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(); + using var color = ImGuiColor.FrameBackground.Push(c, defaultValue != currentValue); + newValue = currentValue; + ImUtf8.Checkbox(label, ref newValue); + ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip); + return newValue != currentValue; + } + + /// + /// A checkmark that compares against a default value and shows a tooltip. + /// Returns true if newValue is changed against currentValue. + /// + protected static bool Checkmark(ReadOnlySpan label, ReadOnlySpan tooltip, bool currentValue, bool defaultValue, + out bool newValue) + { + var c = defaultValue != currentValue ? ColorId.DecreasedMetaValue.Value() : ColorId.IncreasedMetaValue.Value(); + using var color = ImGuiColor.FrameBackground.Push(c, defaultValue != currentValue); + newValue = currentValue; + ImUtf8.Checkbox(label, ref newValue); + ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, tooltip); + return newValue != currentValue; + } + + protected void DrawMetaButtons(TIdentifier identifier, TEntry entry) + { + ImGui.TableNextColumn(); + CopyToClipboardButton("Copy this manipulation to clipboard."u8, + new Lazy(() => new JArray { MetaDictionary.Serialize(identifier, entry)! })); + + ImGui.TableNextColumn(); + if (ImUtf8.IconButton(FontAwesomeIcon.Trash, "Delete this meta manipulation."u8)) + Editor.Changes |= Editor.Remove(identifier); + } + + protected void CopyToClipboardButton(ReadOnlySpan tooltip, Lazy manipulations) + { + if (!ImUtf8.IconButton(FontAwesomeIcon.Clipboard, tooltip)) + return; + + var text = Functions.ToCompressedBase64(manipulations.Value, 0); + if (text.Length > 0) + ImGui.SetClipboardText(text); + } +} diff --git a/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs b/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs index 2cf43e71..6a761340 100644 --- a/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs +++ b/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs @@ -1,5 +1,6 @@ using Dalamud.Interface; using Dalamud.Bindings.ImGui; +using ImSharp; using Newtonsoft.Json.Linq; using OtterGui.Raii; using OtterGui.Text; @@ -161,8 +162,8 @@ public sealed class ShpMetaDrawer(ModMetaEditor editor, MetaFileManager metaFile if (all) { using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.05f, 0.5f)); - ImUtf8.TextFramed("All IDs"u8, ImGui.GetColorU32(ImGuiCol.FrameBg, all || allSlots ? ImGui.GetStyle().DisabledAlpha : 1f), - new Vector2(unscaledWidth, 0), ImGui.GetColorU32(ImGuiCol.TextDisabled)); + ImUtf8.TextFramed("All IDs"u8, ImGuiColor.FrameBackground.Get(all || allSlots ? ImGui.GetStyle().DisabledAlpha : 1f).Color, + new Vector2(unscaledWidth, 0), ImGuiColor.TextDisabled.Get().Color); } else { @@ -232,7 +233,7 @@ public sealed class ShpMetaDrawer(ModMetaEditor editor, MetaFileManager metaFile var ret = false; var ptr = Unsafe.AsPointer(ref buffer); var span = new Span(ptr, ShapeAttributeString.MaxLength + 1); - using (new ImRaii.ColorStyle().Push(ImGuiCol.Border, Colors.RegexWarningBorder, !valid).Push(ImGuiStyleVar.FrameBorderSize, 1f, !valid)) + using (ImStyleBorder.Frame.Push(Colors.RegexWarningBorder, Im.Style.GlobalScale, !valid)) { ImGui.SetNextItemWidth(unscaledWidth * ImUtf8.GlobalScale); if (ImUtf8.InputText("##shpShape"u8, span, out int newLength, "Shape Key..."u8)) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Deformers.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Deformers.cs index 3c729157..1031fb66 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Deformers.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Deformers.cs @@ -53,7 +53,7 @@ public partial class ModEditWindow continue; using var id = ImUtf8.PushId(index); - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), deformer.RacialDeformer.IsEmpty); + using var color = ImGuiColor.Text.Push(Im.Style[ImGuiColor.TextDisabled], deformer.RacialDeformer.IsEmpty); if (ImUtf8.Selectable(name, deformer.GenderRace == _pbdData.SelectedRaceCode)) { _pbdData.SelectedRaceCode = deformer.GenderRace; @@ -61,7 +61,7 @@ public partial class ModEditWindow } Im.Line.Same(); - color.Push(ImGuiCol.Text, metaColor); + color.Push(ImGuiColor.Text, metaColor); ImUtf8.TextRightAligned(raceCode); } } @@ -142,7 +142,7 @@ public partial class ModEditWindow var ret = false; ImUtf8.TextFrameAligned("Copy the values of the bone "u8); ImGui.SameLine(0, 0); - using (ImRaii.PushColor(ImGuiCol.Text, ColorId.NewMod.Value())) + using (ImGuiColor.Text.Push(ColorId.NewMod.Value())) { ImUtf8.TextFrameAligned(_pbdData.SelectedBone); } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs index 2d8dd366..f8ba7f67 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Files.cs @@ -182,7 +182,7 @@ public partial class ModEditWindow var selected = _selectedFiles.Contains(registry); var color = registry.SubModUsage.Count == 0 ? ColorId.ConflictingMod : registry.CurrentUsage == registry.SubModUsage.Count ? ColorId.NewMod : ColorId.InheritedMod; - using (ImRaii.PushColor(ImGuiCol.Text, color.Value())) + using (ImGuiColor.Text.Push(color.Value())) { if (Im.Selectable(registry.RelPath.Path.Span, selected)) { @@ -290,9 +290,9 @@ public partial class ModEditWindow { Im.Line.Same(); ImGui.SetCursorPosX(pos); - using (ImRaii.PushFont(UiBuilder.IconFont)) - { - ImGuiUtil.TextColored(0xFF00B0B0, FontAwesomeIcon.ExclamationCircle.ToIconString()); + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + ImGuiUtil.TextColored(0xFF00B0B0, FontAwesomeIcon.ExclamationCircle.ToIconString()); } ImUtf8.HoverTooltip("The game path and the file do not have the same extension."u8); @@ -333,9 +333,9 @@ public partial class ModEditWindow { Im.Line.Same(); ImGui.SetCursorPosX(pos); - using (ImRaii.PushFont(UiBuilder.IconFont)) - { - ImGuiUtil.TextColored(0xFF00B0B0, FontAwesomeIcon.ExclamationCircle.ToIconString()); + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + ImGuiUtil.TextColored(0xFF00B0B0, FontAwesomeIcon.ExclamationCircle.ToIconString()); } ImUtf8.HoverTooltip("The game path and the file do not have the same extension."u8); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs index 59dc3579..8fa2fe18 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs @@ -143,7 +143,7 @@ public partial class ModEditWindow var text = $"{otherOptionData.TotalCount} Edits in other Options"; var size = ImGui.CalcTextSize(text).X; ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - size, oldPos + ImGui.GetStyle().FramePadding.Y)); - ImGuiUtil.TextColored(ColorId.RedundantAssignment.Value() | 0xFF000000, text); + Im.Text(text, ColorId.RedundantAssignment.Value().FullAlpha()); if (ImGui.IsItemHovered()) { using var tt = ImUtf8.Tooltip(); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index 55f749d8..0bd5d93a 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -275,9 +275,9 @@ public partial class ModEditWindow if (tab.GamePaths!.Count == 1) { using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f)); - using var color = ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.FrameBg)) - .Push(ImGuiCol.ButtonHovered, ImGui.GetColorU32(ImGuiCol.FrameBgHovered)) - .Push(ImGuiCol.ButtonActive, ImGui.GetColorU32(ImGuiCol.FrameBgActive)); + using var color = ImGuiColor.Button.Push(Im.Style[ImGuiColor.FrameBackground]) + .Push(ImGuiColor.ButtonHovered, Im.Style[ImGuiColor.FrameBackgroundHovered]) + .Push(ImGuiColor.ButtonActive, Im.Style[ImGuiColor.FrameBackgroundActive]); using var group = ImRaii.Group(); ImGui.Button(preview, new Vector2(buttonWidth, 0)); ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); @@ -310,7 +310,7 @@ public partial class ModEditWindow var width = ImGui.CalcTextSize(text).X + framePadding.X * 2; // Draw the link button. We set the background colour to transparent to mimic the look of a link. - using var color = ImRaii.PushColor(ImGuiCol.Button, 0x00000000); + using var color = ImGuiColor.Button.Push(Vector4.Zero); SupportButton.Link(Penumbra.Messager, text, address, width, ""u8); // Draw an underline for the text. diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs index e617969f..573a0cf2 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs @@ -368,7 +368,7 @@ public partial class ModEditWindow var ret = ImUtf8.CollapsingHeader(label); ImGui.GetWindowDrawList() - .AddText(UiBuilder.DefaultFont, UiBuilder.DefaultFont.FontSize, pos, ImGui.GetColorU32(ImGuiCol.Text), "Layout"); + .AddText(UiBuilder.DefaultFont, UiBuilder.DefaultFont.FontSize, pos, ImGuiColor.Text.Get().Color, "Layout"); return ret; } @@ -403,7 +403,7 @@ public partial class ModEditWindow ImGui.TableSetupColumn("w", ImGuiTableColumnFlags.WidthFixed, 250 * UiHelpers.Scale); ImGui.TableHeadersRow(); - var textColorStart = ImGui.GetColorU32(ImGuiCol.Text); + var textColorStart = ImGuiColor.Text.Get().Color; var ret = false; for (var i = 0; i < tab.Matrix.GetLength(0); ++i) @@ -424,7 +424,7 @@ public partial class ModEditWindow var deletable = !disabled && idx >= 0; using (ImRaii.PushFont(UiBuilder.MonoFont, tooltip.Length > 0)) { - using (ImRaii.PushColor(ImGuiCol.Text, color)) + using (ImGuiColor.Text.Push(color)) { ImGui.TableNextColumn(); ImUtf8.Selectable(name); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs index ca2e0d3d..c3f9fbf1 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs @@ -49,7 +49,7 @@ public partial class ModEditWindow return; using var id = ImRaii.PushId(label); - ImGuiUtil.DrawTextButton(label, new Vector2(-1, 0), ImGui.GetColorU32(ImGuiCol.FrameBg)); + ImEx.TextFramed(label, new Vector2(-1, 0), ImGuiColor.FrameBackground.Get()); ImGui.NewLine(); using (ImRaii.Disabled(!_center.SaveTask.IsCompleted)) @@ -206,7 +206,7 @@ public partial class ModEditWindow case TaskStatus.Faulted: { ImGui.TextUnformatted("Could not save file:"); - using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF0000FF); + using var color = ImGuiColor.Text.Push(new Vector4(1, 0, 0, 1)); ImGuiUtil.TextWrapped(_center.SaveTask.Exception?.ToString() ?? "Unknown Error"); break; } diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs index c14443da..cbea9f40 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs @@ -205,7 +205,7 @@ public partial class ModEditWindow : Window, IDisposable, Luna.IUiService var offsetX = ImGui.GetContentRegionAvail().X / 2 - radius; var offsetY = ImGui.GetContentRegionAvail().Y / 2 - radius; ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(offsetX, offsetY)); - ImUtf8.Spinner("##spinner"u8, radius, thickness, ImGui.GetColorU32(ImGuiCol.Text)); + ImEx.Spinner("##spinner"u8, radius, thickness, ImGuiColor.Text.Get()); return; } @@ -501,7 +501,7 @@ public partial class ModEditWindow : Window, IDisposable, Luna.IUiService { Im.Line.Same(); ImGuiUtil.DrawTextButton($"There are {otherSwaps} file swaps configured in other options.", Vector2.Zero, - ColorId.RedundantAssignment.Value()); + ColorId.RedundantAssignment.Value().Color); } using var child = ImRaii.Child("##swaps", -Vector2.One, true); diff --git a/Penumbra/UI/AdvancedWindow/ModMergeTab.cs b/Penumbra/UI/AdvancedWindow/ModMergeTab.cs index ba99053c..5d959c51 100644 --- a/Penumbra/UI/AdvancedWindow/ModMergeTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModMergeTab.cs @@ -82,7 +82,7 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService var color = group != null || modMerger.OptionGroupName.Length == 0 && modMerger.OptionName.Length == 0 ? Colors.PressEnterWarningBg : Colors.DiscordColor; - using var c = ImRaii.PushColor(ImGuiCol.Border, color); + using var c = ImGuiColor.Border.Push(color); ImGui.SetNextItemWidth(buttonWidth); ImGui.InputTextWithHint("##optionGroupInput", "Target Option Group", ref modMerger.OptionGroupName, 64); ImGuiUtil.HoverTooltip( @@ -96,7 +96,7 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService : group == null || group.Options.Any(o => o.Name == modMerger.OptionName) ? Colors.PressEnterWarningBg : Colors.DiscordColor; - c.Push(ImGuiCol.Border, color); + c.Push(ImGuiColor.Border, color); ImGui.SetNextItemWidth(buttonWidth); ImGui.InputTextWithHint("##optionInput", "Target Option Name", ref modMerger.OptionName, 64); ImGuiUtil.HoverTooltip( @@ -249,7 +249,7 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService ImGui.Separator(); ImGui.Dummy(Vector2.One); - using var color = ImRaii.PushColor(ImGuiCol.Text, Colors.TutorialBorder); + using var color = ImGuiColor.Text.Push(Colors.TutorialBorder); foreach (var warning in modMerger.Warnings.SkipLast(1)) { ImGuiUtil.TextWrapped(warning); @@ -266,7 +266,7 @@ public class ModMergeTab(ModMerger modMerger) : Luna.IUiService ImGui.Separator(); ImGui.Dummy(Vector2.One); - using var color = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder); + using var color = ImGuiColor.Text.Push(Colors.RegexWarningBorder); ImGuiUtil.TextWrapped(modMerger.Error.ToString()); } } diff --git a/Penumbra/UI/AdvancedWindow/OptionSelectCombo.cs b/Penumbra/UI/AdvancedWindow/OptionSelectCombo.cs index c9996a1e..adb38d75 100644 --- a/Penumbra/UI/AdvancedWindow/OptionSelectCombo.cs +++ b/Penumbra/UI/AdvancedWindow/OptionSelectCombo.cs @@ -1,9 +1,10 @@ using Dalamud.Bindings.ImGui; -using OtterGui.Raii; +using ImSharp; using OtterGui.Text; using OtterGui.Widgets; using Penumbra.Mods.Editor; using Penumbra.UI.Classes; +using MouseWheelType = OtterGui.Widgets.MouseWheelType; namespace Penumbra.UI.AdvancedWindow; @@ -11,12 +12,12 @@ public sealed class OptionSelectCombo(ModEditor editor, ModEditWindow window) : FilterComboCache<(string FullName, (int Group, int Data) Index)>( () => window.Mod!.AllDataContainers.Select(c => (c.GetFullName(), c.GetDataIndices())).ToList(), MouseWheelType.Control, Penumbra.Log) { - private ImRaii.ColorStyle _border; + private readonly Im.ColorStyleDisposable _border = new(); protected override void DrawCombo(string label, string preview, string tooltip, int currentSelected, float previewWidth, float itemHeight, ImGuiComboFlags flags) { - _border = ImRaii.PushFrameBorder(ImUtf8.GlobalScale, ColorId.FolderLine.Value()); + _border.PushBorder(ImStyleBorder.Frame, ColorId.FolderLine.Value()); base.DrawCombo(label, preview, tooltip, currentSelected, previewWidth, itemHeight, flags); _border.Dispose(); } diff --git a/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs b/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs index 2dc14086..33ecddc1 100644 --- a/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs +++ b/Penumbra/UI/AdvancedWindow/ResourceTreeViewer.cs @@ -70,7 +70,7 @@ public class ResourceTreeViewer( else if (_task.Exception != null) { ImGui.NewLine(); - using var color = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder); + using var color = ImGuiColor.Text.Push(Colors.RegexWarningBorder); ImGui.TextUnformatted($"Error during calculation of character list:\n\n{_task.Exception}"); } else if (_task.IsCompletedSuccessfully) @@ -82,7 +82,7 @@ public class ResourceTreeViewer( if (!_categoryFilter.HasFlag(category) || !tree.Name.Contains(_nameFilter, StringComparison.OrdinalIgnoreCase)) continue; - using (var c = ImRaii.PushColor(ImGuiCol.Text, CategoryColor(category).Value())) + using (ImGuiColor.Text.Push(CategoryColor(category).Value())) { var isOpen = ImGui.CollapsingHeader($"{(incognito.IncognitoMode ? tree.AnonymizedName : tree.Name)}###{index}", index == 0 ? ImGuiTreeNodeFlags.DefaultOpen : 0); @@ -164,7 +164,7 @@ public class ResourceTreeViewer( if (!gameData.HasModifiedGameDataFiles) return; - using var style = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudOrange); + using var style = ImGuiColor.Text.Push(ImGuiColors.DalamudOrange); ImUtf8.TextWrapped( "Dalamud is reporting your FFXIV installation has modified game files. Any mods installed through TexTools will produce this message."u8); @@ -189,18 +189,18 @@ public class ResourceTreeViewer( var checkPadding = 10 * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.X; ImGui.SameLine(0, checkPadding); - using (var id = ImRaii.PushId("TreeCategoryFilter")) - { - var categoryFilter = (uint)_categoryFilter; - foreach (var category in Enum.GetValues()) - { - using var c = ImRaii.PushColor(ImGuiCol.CheckMark, CategoryColor(category).Value()); - ImGui.CheckboxFlags($"##{category}", ref categoryFilter, (uint)category); - ImGuiUtil.HoverTooltip(CategoryFilterDescription(category)); - ImGui.SameLine(0.0f, checkSpacing); - } - - _categoryFilter = (TreeCategory)categoryFilter; + using (ImRaii.PushId("TreeCategoryFilter")) + { + var categoryFilter = (uint)_categoryFilter; + foreach (var category in Enum.GetValues()) + { + using var c = ImGuiColor.CheckMark.Push(CategoryColor(category).Value()); + ImGui.CheckboxFlags($"##{category}", ref categoryFilter, (uint)category); + ImGuiUtil.HoverTooltip(CategoryFilterDescription(category)); + ImGui.SameLine(0.0f, checkSpacing); + } + + _categoryFilter = (TreeCategory)categoryFilter; } ImGui.SameLine(0, checkPadding); @@ -257,7 +257,7 @@ public class ResourceTreeViewer( if (visibility == NodeVisibility.Hidden) continue; - using var mutedColor = ImRaii.PushColor(ImGuiCol.Text, ImGuiUtil.HalfTransparentText(), resourceNode.Internal); + using var mutedColor = ImGuiColor.Text.Push(ImGuiUtil.HalfTransparentText(), resourceNode.Internal); var filterIcon = resourceNode.IconFlag != 0 ? resourceNode.IconFlag : parentFilterIconFlag; @@ -335,7 +335,7 @@ public class ResourceTreeViewer( var modName = $"[{(hasMod ? mod!.Name : resourceNode.ModName)}]"; var textPos = ImGui.GetCursorPosX() + ImUtf8.CalcTextSize(modName).X + ImGui.GetStyle().ItemInnerSpacing.X; using var group = ImUtf8.Group(); - using (var color = ImRaii.PushColor(ImGuiCol.Text, (hasMod ? ColorId.NewMod : ColorId.DisabledMod).Value())) + using (ImGuiColor.Text.Push((hasMod ? ColorId.NewMod : ColorId.DisabledMod).Value())) { ImUtf8.Selectable(modName, false, ImGuiSelectableFlags.AllowItemOverlap, new Vector2(ImGui.GetContentRegionAvail().X, frameHeight)); diff --git a/Penumbra/UI/ChangedItemDrawer.cs b/Penumbra/UI/ChangedItemDrawer.cs index 0776954f..7a897f39 100644 --- a/Penumbra/UI/ChangedItemDrawer.cs +++ b/Penumbra/UI/ChangedItemDrawer.cs @@ -144,7 +144,7 @@ public class ChangedItemDrawer : IDisposable, IUiService Im.Line.Same(); using var color = ImGuiColor.Text.Push(ColorId.ItemId.Value()); - Im.Cursor.Y += height - Im.Style.TextHeight / 2; + Im.Cursor.Y += (height - Im.Style.TextHeight) / 2; ImEx.TextRightAligned(additionalData, Im.Style.ItemInnerSpacing.X); } @@ -156,7 +156,7 @@ public class ChangedItemDrawer : IDisposable, IUiService Im.Line.Same(); using var color = ImGuiColor.Text.Push(ColorId.ItemId.Value()); - Im.Cursor.Y += height - Im.Style.TextHeight / 2; + Im.Cursor.Y += (height - Im.Style.TextHeight) / 2; ImEx.TextRightAligned(text, Im.Style.ItemInnerSpacing.X); } diff --git a/Penumbra/UI/Classes/MigrationSectionDrawer.cs b/Penumbra/UI/Classes/MigrationSectionDrawer.cs index dc8b8cc0..dd42e393 100644 --- a/Penumbra/UI/Classes/MigrationSectionDrawer.cs +++ b/Penumbra/UI/Classes/MigrationSectionDrawer.cs @@ -136,7 +136,7 @@ public class MigrationSectionDrawer(MigrationManager migrationManager, Configura return; Im.Line.Same(); - ImUtf8.Spinner("Spinner"u8, ImGui.GetTextLineHeight() / 2, 2, ImGui.GetColorU32(ImGuiCol.Text)); + ImEx.Spinner("Spinner"u8, ImGui.GetTextLineHeight() / 2, 2, ImGuiColor.Text.Get()); } private void DrawCancelButton(MigrationManager.TaskType task, ReadOnlySpan tooltip) diff --git a/Penumbra/UI/CollectionTab/CollectionPanel.cs b/Penumbra/UI/CollectionTab/CollectionPanel.cs index df0a46be..9f8b8c44 100644 --- a/Penumbra/UI/CollectionTab/CollectionPanel.cs +++ b/Penumbra/UI/CollectionTab/CollectionPanel.cs @@ -283,7 +283,7 @@ public sealed class CollectionPanel( if (!context) return; - using (var color = ImRaii.PushColor(ImGuiCol.Text, Colors.DiscordColor)) + using (var color = ImGuiColor.Text.Push(Colors.DiscordColor)) { if (ImGui.MenuItem("Use no mods.")) _active.SetCollection(ModCollection.Empty, type, _active.Individuals.GetGroup(identifier)); @@ -291,7 +291,7 @@ public sealed class CollectionPanel( if (collection != null && type.CanBeRemoved()) { - using var color = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder); + using var color = ImGuiColor.Text.Push(Colors.RegexWarningBorder); if (ImGui.MenuItem("Remove this assignment.")) _active.SetCollection(null, type, _active.Individuals.GetGroup(identifier)); } @@ -303,15 +303,15 @@ public sealed class CollectionPanel( } } - private bool DrawButton(string text, CollectionType type, Vector2 width, uint borderColor, ActorIdentifier id, char suffix, + private bool DrawButton(string text, CollectionType type, Vector2 width, Rgba32 borderColor, ActorIdentifier id, char suffix, ModCollection? collection = null) { using var group = ImRaii.Group(); var invalid = type == CollectionType.Individual && !id.IsValid; var redundancy = _active.RedundancyCheck(type, id); collection ??= _active.ByType(type, id); - using var color = ImRaii.PushColor(ImGuiCol.Button, - collection == null + using var color = ImGuiColor.Button.Push( + collection is null ? ColorId.NoAssignment.Value() : redundancy.Length > 0 ? ColorId.RedundantAssignment.Value() @@ -319,8 +319,8 @@ public sealed class CollectionPanel( ? ColorId.SelectedCollection.Value() : collection == ModCollection.Empty ? ColorId.NoModsAssignment.Value() - : ImGui.GetColorU32(ImGuiCol.Button), !invalid) - .Push(ImGuiCol.Border, borderColor == 0 ? ImGui.GetColorU32(ImGuiCol.TextDisabled) : borderColor); + : ImGuiColor.Button.Get(), !invalid) + .Push(ImGuiColor.Border, borderColor == 0 ? ImGuiColor.TextDisabled.Get().Color : borderColor); using var disabled = ImRaii.Disabled(invalid); var button = ImGui.Button(text, width) || ImGui.IsItemClicked(ImGuiMouseButton.Right); var hovered = redundancy.Length > 0 && ImGui.IsItemHovered(); @@ -332,7 +332,7 @@ public sealed class CollectionPanel( var name = Name(collection); var size = ImGui.CalcTextSize(name); var textPos = ImGui.GetItemRectMax() - size - ImGui.GetStyle().FramePadding; - ImGui.GetWindowDrawList().AddText(textPos, ImGui.GetColorU32(ImGuiCol.Text), name); + ImGui.GetWindowDrawList().AddText(textPos, ImGuiColor.Text.Get().Color, name); DrawContext(button, collection, type, id, text, suffix); } @@ -484,7 +484,7 @@ public sealed class CollectionPanel( private void DrawCollectionName(ModCollection collection) { ImGui.Dummy(Vector2.One); - using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.MetaInfoText); + using var color = ImGuiColor.Border.Push(Colors.MetaInfoText); using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * UiHelpers.Scale); using var f = _nameFont.Push(); var name = Name(collection); @@ -574,7 +574,7 @@ public sealed class CollectionPanel( using var f = _nameFont.Push(); using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale); - using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.MetaInfoText); + using var color = ImGuiColor.Border.Push(Colors.MetaInfoText); ImGuiUtil.DrawTextButton(Name(collection.Inheritance.DirectlyInheritedBy[0]), Vector2.Zero, 0); var constOffset = (ImGui.GetStyle().FramePadding.X + ImGuiHelpers.GlobalScale) * 2 + ImGui.GetStyle().ItemSpacing.X diff --git a/Penumbra/UI/CollectionTab/CollectionSelector.cs b/Penumbra/UI/CollectionTab/CollectionSelector.cs index c5709dd6..1fa79e34 100644 --- a/Penumbra/UI/CollectionTab/CollectionSelector.cs +++ b/Penumbra/UI/CollectionTab/CollectionSelector.cs @@ -1,4 +1,5 @@ using Dalamud.Bindings.ImGui; +using ImSharp; using OtterGui; using OtterGui.Raii; using Penumbra.Collections; @@ -75,7 +76,7 @@ public sealed class CollectionSelector : ItemSelector, IDisposabl protected override bool OnDraw(int idx) { - using var color = ImRaii.PushColor(ImGuiCol.Header, ColorId.SelectedCollection.Value()); + using var color = ImGuiColor.Header.Push(ColorId.SelectedCollection.Value()); var ret = ImGui.Selectable(Name(Items[idx]), idx == CurrentIdx); using var source = ImRaii.DragDropSource(); diff --git a/Penumbra/UI/CollectionTab/InheritanceUi.cs b/Penumbra/UI/CollectionTab/InheritanceUi.cs index ff90c806..3fd1fe89 100644 --- a/Penumbra/UI/CollectionTab/InheritanceUi.cs +++ b/Penumbra/UI/CollectionTab/InheritanceUi.cs @@ -24,7 +24,7 @@ public class InheritanceUi(CollectionManager collectionManager, IncognitoService { using var id = ImRaii.PushId("##Inheritance"); ImGuiUtil.DrawColoredText(($"The {TutorialService.SelectedCollection} ", 0), - (Name(_active.Current), ColorId.SelectedCollection.Value() | 0xFF000000), (" inherits from:", 0)); + (Name(_active.Current), ColorId.SelectedCollection.Value().FullAlpha().Color), (" inherits from:", 0)); ImGui.Dummy(Vector2.One); DrawCurrentCollectionInheritance(); @@ -111,7 +111,7 @@ public class InheritanceUi(CollectionManager collectionManager, IncognitoService foreach (var inheritance in collection.Inheritance.FlatHierarchy.Skip(1)) { // Draw the child, already seen collections are colored as conflicts. - using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.HandledConflictMod.Value(), + using var color = ImGuiColor.Text.Push(ColorId.HandledConflictMod.Value(), _seenInheritedCollections.Contains(inheritance)); _seenInheritedCollections.Add(inheritance); @@ -138,7 +138,7 @@ public class InheritanceUi(CollectionManager collectionManager, IncognitoService /// Draw a single primary inherited collection. private void DrawInheritance(ModCollection collection) { - using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.HandledConflictMod.Value(), + using var color = ImGuiColor.Text.Push(ColorId.HandledConflictMod.Value(), _seenInheritedCollections.Contains(collection)); _seenInheritedCollections.Add(collection); using var tree = ImRaii.TreeNode($"{Name(collection)}###{collection.Identity.Name}", ImGuiTreeNodeFlags.NoTreePushOnOpen); @@ -172,10 +172,10 @@ public class InheritanceUi(CollectionManager collectionManager, IncognitoService private void DrawInheritanceTrashButton() { var size = UiHelpers.IconButtonSize with { Y = ImGui.GetTextLineHeightWithSpacing() * InheritedCollectionHeight }; - var buttonColor = ImGui.GetColorU32(ImGuiCol.Button); + var buttonColor = Im.Style[ImGuiColor.Button]; // Prevent hovering from highlighting the button. - using var color = ImRaii.PushColor(ImGuiCol.ButtonActive, buttonColor) - .Push(ImGuiCol.ButtonHovered, buttonColor); + using var color = ImGuiColor.ButtonActive.Push(buttonColor) + .Push(ImGuiColor.ButtonHovered, buttonColor); ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, "Drag primary inheritance here to remove it from the list.", false, true); diff --git a/Penumbra/UI/ConfigWindow.cs b/Penumbra/UI/ConfigWindow.cs index a625b033..f2d018c4 100644 --- a/Penumbra/UI/ConfigWindow.cs +++ b/Penumbra/UI/ConfigWindow.cs @@ -140,7 +140,7 @@ public sealed class ConfigWindow : Window, Luna.IUiService private void DrawProblemWindow(string text) { - using var color = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder); + using var color = ImGuiColor.Text.Push(Colors.RegexWarningBorder); ImGui.NewLine(); ImGui.NewLine(); ImUtf8.TextWrapped(text); diff --git a/Penumbra/UI/ModsTab/Groups/ImcModGroupEditDrawer.cs b/Penumbra/UI/ModsTab/Groups/ImcModGroupEditDrawer.cs index 70165996..c542295a 100644 --- a/Penumbra/UI/ModsTab/Groups/ImcModGroupEditDrawer.cs +++ b/Penumbra/UI/ModsTab/Groups/ImcModGroupEditDrawer.cs @@ -23,7 +23,7 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr var changes = false; var width = editor.AvailableWidth.X - 3 * ImUtf8.ItemInnerSpacing.X - ImUtf8.ItemSpacing.X - ImUtf8.CalcTextSize("All Variants"u8).X - ImUtf8.CalcTextSize("Only Attributes"u8).X - 2 * ImUtf8.FrameHeight; - ImUtf8.TextFramed(identifier.ToString(), 0, new Vector2(width, 0), borderColor: ImGui.GetColorU32(ImGuiCol.Border)); + ImEx.TextFramed(identifier.ToString(), new Vector2(width, 0), Rgba32.Transparent); ImUtf8.SameLineInner(); var allVariants = group.AllVariants; @@ -175,7 +175,7 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr protected override void RenderSymbol(bool value, Vector2 position, float size) { if (value) - SymbolHelpers.RenderCross(ImGui.GetWindowDrawList(), position, ImGui.GetColorU32(ImGuiCol.CheckMark), size); + SymbolHelpers.RenderCross(ImGui.GetWindowDrawList(), position, ImGuiColor.CheckMark.Get().Color, size); } protected override bool NextValue(bool value) diff --git a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs index 12dd4f90..f256e15f 100644 --- a/Penumbra/UI/ModsTab/ModFileSystemSelector.cs +++ b/Penumbra/UI/ModsTab/ModFileSystemSelector.cs @@ -836,7 +836,7 @@ public sealed class ModFileSystemSelector : FileSystemSelector Data = []; - public bool AnyExpandable { get; private set; } - - public record struct Container - { - public IIdentifiedObjectData Data; - public ByteString Text; - public ByteString ModelData; - public uint Id; - public int Children; - public ChangedItemIconFlag Icon; - public bool Expandable; - public bool Expanded; - public bool Child; - - public static Container Single(string text, IIdentifiedObjectData data) - => new() - { - Child = false, - Text = ByteString.FromStringUnsafe(data.ToName(text), false), - ModelData = ByteString.FromStringUnsafe(data.AdditionalData, false), - Icon = data.GetIcon().ToFlag(), - Expandable = false, - Expanded = false, - Data = data, - Id = 0, - Children = 0, - }; - - public static Container Parent(string text, IIdentifiedObjectData data, uint id, int children, bool expanded) - => new() - { - Child = false, - Text = ByteString.FromStringUnsafe(data.ToName(text), false), - ModelData = ByteString.FromStringUnsafe(data.AdditionalData, false), - Icon = data.GetIcon().ToFlag(), - Expandable = true, - Expanded = expanded, - Data = data, - Id = id, - Children = children, - }; - - public static Container Indent(string text, IIdentifiedObjectData data) - => new() - { - Child = true, - Text = ByteString.FromStringUnsafe(data.ToName(text), false), - ModelData = ByteString.FromStringUnsafe(data.AdditionalData, false), - Icon = data.GetIcon().ToFlag(), - Expandable = false, - Expanded = false, - Data = data, - Id = 0, - Children = 0, - }; - } - - public void Reset() - => _reset = true; - - public void Update(Mod? mod, ChangedItemDrawer drawer, ChangedItemIconFlag filter, ChangedItemMode mode) - { - if (mod == _lastSelected - && _lastSelected!.LastChangedItemsUpdate == _lastUpdate - && _filter == filter - && !_reset - && _lastMode == mode) - return; - - _reset = false; - Data.Clear(); - AnyExpandable = false; - _lastSelected = mod; - _filter = filter; - _lastMode = mode; - if (_lastSelected == null) - return; - - _lastUpdate = _lastSelected.LastChangedItemsUpdate; - - if (mode is ChangedItemMode.Alphabetical) - { - foreach (var (s, i) in _lastSelected.ChangedItems) - { - if (drawer.FilterChangedItem(s, i, string.Empty)) - Data.Add(Container.Single(s, i)); - } - - return; - } - - var tmp = new Dictionary<(PrimaryId, FullEquipType), List>(); - var defaultExpansion = _lastMode is ChangedItemMode.GroupedExpanded; - foreach (var (s, i) in _lastSelected.ChangedItems) - { - if (i is not IdentifiedItem item) - continue; - - if (!drawer.FilterChangedItem(s, item, string.Empty)) - continue; - - if (tmp.TryGetValue((item.Item.PrimaryId, item.Item.Type), out var p)) - p.Add(item); - else - tmp[(item.Item.PrimaryId, item.Item.Type)] = [item]; - } - - foreach (var list in tmp.Values) - { - list.Sort((i1, i2) => - { - // reversed - var preferred = _lastSelected.PreferredChangedItems.Contains(i2.Item.Id) - .CompareTo(_lastSelected.PreferredChangedItems.Contains(i1.Item.Id)); - if (preferred != 0) - return preferred; - - // reversed - var count = i2.Count.CompareTo(i1.Count); - if (count != 0) - return count; - - return string.Compare(i1.Item.Name, i2.Item.Name, StringComparison.Ordinal); - }); - } - - var sortedTmp = tmp.Values.OrderBy(s => s[0].Item.Name).ToArray(); - - var sortedTmpIdx = 0; - foreach (var (s, i) in _lastSelected.ChangedItems) - { - if (i is IdentifiedItem) - continue; - - if (!drawer.FilterChangedItem(s, i, string.Empty)) - continue; - - while (sortedTmpIdx < sortedTmp.Length - && string.Compare(sortedTmp[sortedTmpIdx][0].Item.Name, s, StringComparison.Ordinal) <= 0) - AddList(sortedTmp[sortedTmpIdx++]); - - Data.Add(Container.Single(s, i)); - } - - for (; sortedTmpIdx < sortedTmp.Length; ++sortedTmpIdx) - AddList(sortedTmp[sortedTmpIdx]); - return; - - void AddList(List list) - { - var mainItem = list[0]; - if (list.Count == 1) - { - Data.Add(Container.Single(mainItem.Item.Name, mainItem)); - } - else - { - var id = ImUtf8.GetId($"{mainItem.Item.PrimaryId}{(int)mainItem.Item.Type}"); - var expanded = ImGui.GetStateStorage().GetBool(id, defaultExpansion); - Data.Add(Container.Parent(mainItem.Item.Name, mainItem, id, list.Count - 1, expanded)); - AnyExpandable = true; - if (!expanded) - return; - - foreach (var item in list.Skip(1)) - Data.Add(Container.Indent(item.Item.Name, item)); - } - } - } - } - - public ReadOnlySpan Label - => "Changed Items"u8; - - public bool IsVisible - => selector.Selected!.ChangedItems.Count > 0; - - private ImGuiStoragePtr _stateStorage; - - private Vector2 _buttonSize; - private uint _starColor; - - public void DrawContent() - { - if (cacheService.Cache(_cacheId, () => (new ChangedItemsCache(), "ModPanelChangedItemsCache")) is not { } cache) - return; - - drawer.DrawTypeFilter(); - - _stateStorage = ImGui.GetStateStorage(); - cache.Update(selector.Selected, drawer, config.Ephemeral.ChangedItemFilter, config.ChangedItemDisplay); - ImGui.Separator(); - _buttonSize = new Vector2(ImGui.GetStyle().ItemSpacing.Y + ImGui.GetFrameHeight()); - using var style = ImRaii.PushStyle(ImGuiStyleVar.CellPadding, Vector2.Zero) - .Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero) - .Push(ImGuiStyleVar.FramePadding, Vector2.Zero) - .Push(ImGuiStyleVar.SelectableTextAlign, new Vector2(0.01f, 0.5f)); - using var color = ImRaii.PushColor(ImGuiCol.Button, 0); - - using var table = ImUtf8.Table("##changedItems"u8, cache.AnyExpandable ? 2 : 1, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, - new Vector2(ImGui.GetContentRegionAvail().X, -1)); - if (!table) - return; - - _starColor = ColorId.ChangedItemPreferenceStar.Value(); - if (cache.AnyExpandable) - { - ImUtf8.TableSetupColumn("##exp"u8, ImGuiTableColumnFlags.WidthFixed, _buttonSize.Y); - ImUtf8.TableSetupColumn("##text"u8, ImGuiTableColumnFlags.WidthStretch); - ImGuiClip.ClippedDraw(cache.Data, DrawContainerExpandable, _buttonSize.Y); - } - else - { - ImGuiClip.ClippedDraw(cache.Data, DrawContainer, _buttonSize.Y); - } - } - - private void DrawContainerExpandable(ChangedItemsCache.Container obj, int idx) - { - using var id = ImUtf8.PushId(idx); - ImGui.TableNextColumn(); - if (obj.Expandable) - { - if (ImUtf8.IconButton(obj.Expanded ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight, - obj.Expanded ? "Hide the other items using the same model." : - obj.Children > 1 ? $"Show {obj.Children} other items using the same model." : - "Show one other item using the same model.", - _buttonSize)) - { - _stateStorage.SetBool(obj.Id, !obj.Expanded); - if (cacheService.TryGetCache(_cacheId, out var cache)) - cache.Reset(); - } - } - else if (obj is { Child: true, Data: IdentifiedItem item }) - { - DrawPreferredButton(item, idx); - } - else - { - ImGui.Dummy(_buttonSize); - } - - DrawBaseContainer(obj, idx); - } - - private void DrawContainer(ChangedItemsCache.Container obj, int idx) - { - using var id = ImUtf8.PushId(idx); - DrawBaseContainer(obj, idx); - } - - private void DrawPreferredButton(IdentifiedItem item, int idx) - { - if (ImUtf8.IconButton(FontAwesomeIcon.Star, "Prefer displaying this item instead of the current primary item.\n\nRight-click for more options."u8, _buttonSize, - false, _starColor)) - dataEditor.AddPreferredItem(selector.Selected!, item.Item.Id, false, true); - using var context = ImUtf8.PopupContextItem("StarContext"u8); - if (!context) - return; - - if (cacheService.TryGetCache(_cacheId, out var cache)) - for (--idx; idx >= 0; --idx) - { - if (!cache.Data[idx].Expanded) - continue; - - if (cache.Data[idx].Data is IdentifiedItem it) - { - if (selector.Selected!.PreferredChangedItems.Contains(it.Item.Id) - && ImUtf8.MenuItem("Remove Parent from Local Preferred Items"u8)) - dataEditor.RemovePreferredItem(selector.Selected!, it.Item.Id, false); - if (selector.Selected!.DefaultPreferredItems.Contains(it.Item.Id) - && ImUtf8.MenuItem("Remove Parent from Default Preferred Items"u8)) - dataEditor.RemovePreferredItem(selector.Selected!, it.Item.Id, true); - } - - break; - } - - var enabled = !selector.Selected!.DefaultPreferredItems.Contains(item.Item.Id); - if (enabled) - { - if (ImUtf8.MenuItem("Add to Local and Default Preferred Changed Items"u8)) - dataEditor.AddPreferredItem(selector.Selected!, item.Item.Id, true, true); - } - else - { - if (ImUtf8.MenuItem("Remove from Default Preferred Changed Items"u8)) - dataEditor.RemovePreferredItem(selector.Selected!, item.Item.Id, true); - } - - if (ImUtf8.MenuItem("Reset Local Preferred Items to Default"u8)) - dataEditor.ResetPreferredItems(selector.Selected!); - - if (ImUtf8.MenuItem("Clear Local and Default Preferred Items not Changed by the Mod"u8)) - dataEditor.ClearInvalidPreferredItems(selector.Selected!); - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void DrawBaseContainer(in ChangedItemsCache.Container obj, int _) - { - ImGui.TableNextColumn(); - using var indent = ImRaii.PushIndent(1, obj.Child); - drawer.DrawCategoryIcon(obj.Icon, _buttonSize.Y); - ImGui.SameLine(0, 0); - var clicked = ImUtf8.Selectable(obj.Text.Span, false, ImGuiSelectableFlags.None, _buttonSize with { X = 0 }); - drawer.ChangedItemHandling(obj.Data, clicked); - ChangedItemDrawer.DrawModelData(obj.ModelData.Span, _buttonSize.Y); - } -} +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Utility.Raii; +using ImSharp; +using Luna; +using OtterGui; +using OtterGui.Services; +using OtterGui.Text; +using OtterGui.Widgets; +using Penumbra.GameData.Data; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; +using Penumbra.Mods; +using Penumbra.Mods.Manager; +using Penumbra.String; +using Penumbra.UI.Classes; + +namespace Penumbra.UI.ModsTab; + +public class ModPanelChangedItemsTab( + ModFileSystemSelector selector, + ChangedItemDrawer drawer, + ImGuiCacheService cacheService, + Configuration config, + ModDataEditor dataEditor) + : ITab, Luna.IUiService +{ + private readonly ImGuiCacheService.CacheId _cacheId = cacheService.GetNewId(); + + private class ChangedItemsCache + { + private Mod? _lastSelected; + private ushort _lastUpdate; + private ChangedItemIconFlag _filter = ChangedItemFlagExtensions.DefaultFlags; + private ChangedItemMode _lastMode; + private bool _reset; + public readonly List Data = []; + public bool AnyExpandable { get; private set; } + + public record struct Container + { + public IIdentifiedObjectData Data; + public ByteString Text; + public ByteString ModelData; + public uint Id; + public int Children; + public ChangedItemIconFlag Icon; + public bool Expandable; + public bool Expanded; + public bool Child; + + public static Container Single(string text, IIdentifiedObjectData data) + => new() + { + Child = false, + Text = ByteString.FromStringUnsafe(data.ToName(text), false), + ModelData = ByteString.FromStringUnsafe(data.AdditionalData, false), + Icon = data.GetIcon().ToFlag(), + Expandable = false, + Expanded = false, + Data = data, + Id = 0, + Children = 0, + }; + + public static Container Parent(string text, IIdentifiedObjectData data, uint id, int children, bool expanded) + => new() + { + Child = false, + Text = ByteString.FromStringUnsafe(data.ToName(text), false), + ModelData = ByteString.FromStringUnsafe(data.AdditionalData, false), + Icon = data.GetIcon().ToFlag(), + Expandable = true, + Expanded = expanded, + Data = data, + Id = id, + Children = children, + }; + + public static Container Indent(string text, IIdentifiedObjectData data) + => new() + { + Child = true, + Text = ByteString.FromStringUnsafe(data.ToName(text), false), + ModelData = ByteString.FromStringUnsafe(data.AdditionalData, false), + Icon = data.GetIcon().ToFlag(), + Expandable = false, + Expanded = false, + Data = data, + Id = 0, + Children = 0, + }; + } + + public void Reset() + => _reset = true; + + public void Update(Mod? mod, ChangedItemDrawer drawer, ChangedItemIconFlag filter, ChangedItemMode mode) + { + if (mod == _lastSelected + && _lastSelected!.LastChangedItemsUpdate == _lastUpdate + && _filter == filter + && !_reset + && _lastMode == mode) + return; + + _reset = false; + Data.Clear(); + AnyExpandable = false; + _lastSelected = mod; + _filter = filter; + _lastMode = mode; + if (_lastSelected == null) + return; + + _lastUpdate = _lastSelected.LastChangedItemsUpdate; + + if (mode is ChangedItemMode.Alphabetical) + { + foreach (var (s, i) in _lastSelected.ChangedItems) + { + if (drawer.FilterChangedItem(s, i, string.Empty)) + Data.Add(Container.Single(s, i)); + } + + return; + } + + var tmp = new Dictionary<(PrimaryId, FullEquipType), List>(); + var defaultExpansion = _lastMode is ChangedItemMode.GroupedExpanded; + foreach (var (s, i) in _lastSelected.ChangedItems) + { + if (i is not IdentifiedItem item) + continue; + + if (!drawer.FilterChangedItem(s, item, string.Empty)) + continue; + + if (tmp.TryGetValue((item.Item.PrimaryId, item.Item.Type), out var p)) + p.Add(item); + else + tmp[(item.Item.PrimaryId, item.Item.Type)] = [item]; + } + + foreach (var list in tmp.Values) + { + list.Sort((i1, i2) => + { + // reversed + var preferred = _lastSelected.PreferredChangedItems.Contains(i2.Item.Id) + .CompareTo(_lastSelected.PreferredChangedItems.Contains(i1.Item.Id)); + if (preferred != 0) + return preferred; + + // reversed + var count = i2.Count.CompareTo(i1.Count); + if (count != 0) + return count; + + return string.Compare(i1.Item.Name, i2.Item.Name, StringComparison.Ordinal); + }); + } + + var sortedTmp = tmp.Values.OrderBy(s => s[0].Item.Name).ToArray(); + + var sortedTmpIdx = 0; + foreach (var (s, i) in _lastSelected.ChangedItems) + { + if (i is IdentifiedItem) + continue; + + if (!drawer.FilterChangedItem(s, i, string.Empty)) + continue; + + while (sortedTmpIdx < sortedTmp.Length + && string.Compare(sortedTmp[sortedTmpIdx][0].Item.Name, s, StringComparison.Ordinal) <= 0) + AddList(sortedTmp[sortedTmpIdx++]); + + Data.Add(Container.Single(s, i)); + } + + for (; sortedTmpIdx < sortedTmp.Length; ++sortedTmpIdx) + AddList(sortedTmp[sortedTmpIdx]); + return; + + void AddList(List list) + { + var mainItem = list[0]; + if (list.Count == 1) + { + Data.Add(Container.Single(mainItem.Item.Name, mainItem)); + } + else + { + var id = ImUtf8.GetId($"{mainItem.Item.PrimaryId}{(int)mainItem.Item.Type}"); + var expanded = ImGui.GetStateStorage().GetBool(id, defaultExpansion); + Data.Add(Container.Parent(mainItem.Item.Name, mainItem, id, list.Count - 1, expanded)); + AnyExpandable = true; + if (!expanded) + return; + + foreach (var item in list.Skip(1)) + Data.Add(Container.Indent(item.Item.Name, item)); + } + } + } + } + + public ReadOnlySpan Label + => "Changed Items"u8; + + public bool IsVisible + => selector.Selected!.ChangedItems.Count > 0; + + private ImGuiStoragePtr _stateStorage; + + private Vector2 _buttonSize; + private Rgba32 _starColor; + + public void DrawContent() + { + if (cacheService.Cache(_cacheId, () => (new ChangedItemsCache(), "ModPanelChangedItemsCache")) is not { } cache) + return; + + drawer.DrawTypeFilter(); + + _stateStorage = ImGui.GetStateStorage(); + cache.Update(selector.Selected, drawer, config.Ephemeral.ChangedItemFilter, config.ChangedItemDisplay); + ImGui.Separator(); + _buttonSize = new Vector2(ImGui.GetStyle().ItemSpacing.Y + ImGui.GetFrameHeight()); + using var style = ImRaii.PushStyle(ImGuiStyleVar.CellPadding, Vector2.Zero) + .Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .Push(ImGuiStyleVar.FramePadding, Vector2.Zero) + .Push(ImGuiStyleVar.SelectableTextAlign, new Vector2(0.01f, 0.5f)); + using var color = ImGuiColor.Button.Push(Rgba32.Transparent) + .Push(ImGuiColor.ButtonActive, Rgba32.Transparent) + .Push(ImGuiColor.ButtonHovered, Rgba32.Transparent); + + using var table = ImUtf8.Table("##changedItems"u8, cache.AnyExpandable ? 2 : 1, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, + new Vector2(ImGui.GetContentRegionAvail().X, -1)); + if (!table) + return; + + _starColor = ColorId.ChangedItemPreferenceStar.Value(); + if (cache.AnyExpandable) + { + ImUtf8.TableSetupColumn("##exp"u8, ImGuiTableColumnFlags.WidthFixed, _buttonSize.Y); + ImUtf8.TableSetupColumn("##text"u8, ImGuiTableColumnFlags.WidthStretch); + ImGuiClip.ClippedDraw(cache.Data, DrawContainerExpandable, _buttonSize.Y); + } + else + { + ImGuiClip.ClippedDraw(cache.Data, DrawContainer, _buttonSize.Y); + } + } + + private void DrawContainerExpandable(ChangedItemsCache.Container obj, int idx) + { + using var id = ImUtf8.PushId(idx); + ImGui.TableNextColumn(); + if (obj.Expandable) + { + if (ImUtf8.IconButton(obj.Expanded ? FontAwesomeIcon.CaretDown : FontAwesomeIcon.CaretRight, + obj.Expanded ? "Hide the other items using the same model." : + obj.Children > 1 ? $"Show {obj.Children} other items using the same model." : + "Show one other item using the same model.", + _buttonSize)) + { + _stateStorage.SetBool(obj.Id, !obj.Expanded); + if (cacheService.TryGetCache(_cacheId, out var cache)) + cache.Reset(); + } + } + else if (obj is { Child: true, Data: IdentifiedItem item }) + { + DrawPreferredButton(item, idx); + } + else + { + ImGui.Dummy(_buttonSize); + } + + DrawBaseContainer(obj, idx); + } + + private void DrawContainer(ChangedItemsCache.Container obj, int idx) + { + using var id = ImUtf8.PushId(idx); + DrawBaseContainer(obj, idx); + } + + private void DrawPreferredButton(IdentifiedItem item, int idx) + { + var textColor = Im.Mouse.IsHoveringRectangle(Rectangle.FromSize(Im.Cursor.ScreenPosition, _buttonSize)) + ? LunaStyle.FavoriteColor + : _starColor; + + if (ImEx.Icon.Button(LunaStyle.FavoriteIcon, + "Prefer displaying this item instead of the current primary item.\n\nRight-click for more options."u8, + textColor: textColor, size: _buttonSize)) + dataEditor.AddPreferredItem(selector.Selected!, item.Item.Id, false, true); + using var context = ImUtf8.PopupContextItem("StarContext"u8); + if (!context) + return; + + if (cacheService.TryGetCache(_cacheId, out var cache)) + for (--idx; idx >= 0; --idx) + { + if (!cache.Data[idx].Expanded) + continue; + + if (cache.Data[idx].Data is IdentifiedItem it) + { + if (selector.Selected!.PreferredChangedItems.Contains(it.Item.Id) + && ImUtf8.MenuItem("Remove Parent from Local Preferred Items"u8)) + dataEditor.RemovePreferredItem(selector.Selected!, it.Item.Id, false); + if (selector.Selected!.DefaultPreferredItems.Contains(it.Item.Id) + && ImUtf8.MenuItem("Remove Parent from Default Preferred Items"u8)) + dataEditor.RemovePreferredItem(selector.Selected!, it.Item.Id, true); + } + + break; + } + + var enabled = !selector.Selected!.DefaultPreferredItems.Contains(item.Item.Id); + if (enabled) + { + if (ImUtf8.MenuItem("Add to Local and Default Preferred Changed Items"u8)) + dataEditor.AddPreferredItem(selector.Selected!, item.Item.Id, true, true); + } + else + { + if (ImUtf8.MenuItem("Remove from Default Preferred Changed Items"u8)) + dataEditor.RemovePreferredItem(selector.Selected!, item.Item.Id, true); + } + + if (ImUtf8.MenuItem("Reset Local Preferred Items to Default"u8)) + dataEditor.ResetPreferredItems(selector.Selected!); + + if (ImUtf8.MenuItem("Clear Local and Default Preferred Items not Changed by the Mod"u8)) + dataEditor.ClearInvalidPreferredItems(selector.Selected!); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void DrawBaseContainer(in ChangedItemsCache.Container obj, int _) + { + ImGui.TableNextColumn(); + using var indent = ImRaii.PushIndent(1, obj.Child); + drawer.DrawCategoryIcon(obj.Icon, _buttonSize.Y); + ImGui.SameLine(0, 0); + var clicked = ImUtf8.Selectable(obj.Text.Span, false, ImGuiSelectableFlags.None, _buttonSize with { X = 0 }); + drawer.ChangedItemHandling(obj.Data, clicked); + ChangedItemDrawer.DrawModelData(obj.ModelData.Span, _buttonSize.Y); + } +} diff --git a/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs b/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs index b6f8f56c..6ab54a01 100644 --- a/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelConflictsTab.cs @@ -1,206 +1,205 @@ -using Dalamud.Interface; -using Dalamud.Interface.Utility; -using Dalamud.Bindings.ImGui; -using ImSharp; -using OtterGui; -using OtterGui.Raii; -using OtterGui.Text; -using OtterGui.Widgets; -using Penumbra.Collections.Cache; -using Penumbra.Collections.Manager; -using Penumbra.Meta.Manipulations; -using Penumbra.Mods; -using Penumbra.Mods.Editor; -using Penumbra.Mods.Settings; -using Penumbra.String.Classes; -using Penumbra.UI.Classes; - -namespace Penumbra.UI.ModsTab; - -public class ModPanelConflictsTab(CollectionManager collectionManager, ModFileSystemSelector selector) : ITab, Luna.IUiService -{ - private int? _currentPriority; - - public ReadOnlySpan Label - => "Conflicts"u8; - - public bool IsVisible - => collectionManager.Active.Current.Conflicts(selector.Selected!).Any(c => !GetPriority(c).IsHidden); - - private readonly ConditionalWeakTable _expandedMods = []; - - private ModPriority GetPriority(ModConflicts conflicts) - { - if (conflicts.Mod2.Index < 0) - return conflicts.Mod2.Priority; - - return collectionManager.Active.Current.GetActualSettings(conflicts.Mod2.Index).Settings?.Priority ?? ModPriority.Default; - } - - public void DrawContent() - { - using var table = ImRaii.Table("conflicts", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, ImGui.GetContentRegionAvail()); - if (!table) - return; - - var buttonSize = new Vector2(ImGui.GetFrameHeight()); - var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }; - var priorityRowWidth = ImGui.CalcTextSize("Priority").X + 20 * ImGuiHelpers.GlobalScale + 2 * buttonSize.X; - var priorityWidth = priorityRowWidth - 2 * (buttonSize.X + spacing.X); - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); - ImGui.TableSetupColumn("Conflicting Mod", ImGuiTableColumnFlags.WidthStretch); - ImGui.TableSetupColumn("Priority", ImGuiTableColumnFlags.WidthFixed, priorityRowWidth); - ImGui.TableSetupColumn("Files", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Files").X + spacing.X); - - ImGui.TableSetupScrollFreeze(2, 2); - ImGui.TableHeadersRow(); - DrawCurrentRow(priorityWidth); - - // Can not be null because otherwise the tab bar is never drawn. - var mod = selector.Selected!; - foreach (var (index, conflict) in collectionManager.Active.Current.Conflicts(mod).Where(c => !c.Mod2.Priority.IsHidden) - .OrderByDescending(GetPriority) - .ThenBy(c => c.Mod2.Name, StringComparer.OrdinalIgnoreCase).Index()) - { - using var id = ImRaii.PushId(index); - DrawConflictRow(conflict, priorityWidth, buttonSize); - } - } - - private void DrawCurrentRow(float priorityWidth) - { - ImGui.TableNextColumn(); - using var c = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderLine.Value()); - ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted(selector.Selected!.Name); - ImGui.TableNextColumn(); - var actualSettings = collectionManager.Active.Current.GetActualSettings(selector.Selected!.Index).Settings!; - var priority = actualSettings.Priority.Value; - // TODO - using (ImRaii.Disabled(actualSettings is TemporaryModSettings)) - { - ImGui.SetNextItemWidth(priorityWidth); - if (ImGui.InputInt("##priority", ref priority, 0, 0, flags: ImGuiInputTextFlags.EnterReturnsTrue)) - _currentPriority = priority; - - if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue) - { - if (_currentPriority != actualSettings.Priority.Value) - collectionManager.Editor.SetModPriority(collectionManager.Active.Current, selector.Selected!, - new ModPriority(_currentPriority.Value)); - - _currentPriority = null; - } - else if (ImGui.IsItemDeactivated()) - { - _currentPriority = null; - } - } - - ImGui.TableNextColumn(); - } - - private void DrawConflictSelectable(ModConflicts conflict) - { - ImGui.AlignTextToFramePadding(); - if (ImGui.Selectable(conflict.Mod2.Name) && conflict.Mod2 is Mod otherMod) - selector.SelectByValue(otherMod); - var hovered = ImGui.IsItemHovered(); - var rightClicked = ImGui.IsItemClicked(ImGuiMouseButton.Right); - if (conflict.Mod2 is Mod otherMod2) - { - if (hovered) - ImGui.SetTooltip("Click to jump to mod, Control + Right-Click to disable mod."); - if (rightClicked && ImGui.GetIO().KeyCtrl) - collectionManager.Editor.SetModState(collectionManager.Active.Current, otherMod2, false); - } - } - - private bool DrawExpandedFiles(ModConflicts conflict) - { - if (!_expandedMods.TryGetValue(conflict.Mod2, out _)) - return false; - - using var indent = ImRaii.PushIndent(30f); - foreach (var data in conflict.Conflicts) - { - _ = data switch - { - Utf8GamePath p => ImUtf8.Selectable(p.Path.Span, false), - IMetaIdentifier m => ImUtf8.Selectable(m.ToString(), false), - _ => false, - }; - } - - return true; - } - - private void DrawConflictRow(ModConflicts conflict, float priorityWidth, Vector2 buttonSize) - { - ImGui.TableNextColumn(); - DrawConflictSelectable(conflict); - var expanded = DrawExpandedFiles(conflict); - ImGui.TableNextColumn(); - var conflictPriority = DrawPriorityInput(conflict, priorityWidth); - Im.Line.Same(); - var selectedPriority = collectionManager.Active.Current.GetActualSettings(selector.Selected!.Index).Settings!.Priority.Value; - DrawPriorityButtons(conflict.Mod2 as Mod, conflictPriority, selectedPriority, buttonSize); - ImGui.TableNextColumn(); - DrawExpandButton(conflict.Mod2, expanded, buttonSize); - } - - private void DrawExpandButton(IMod mod, bool expanded, Vector2 buttonSize) - { - var (icon, tt) = expanded - ? (FontAwesomeIcon.CaretUp.ToIconString(), "Hide the conflicting files for this mod.") - : (FontAwesomeIcon.CaretDown.ToIconString(), "Show the conflicting files for this mod."); - if (ImGuiUtil.DrawDisabledButton(icon, buttonSize, tt, false, true)) - { - if (expanded) - _expandedMods.Remove(mod); - else - _expandedMods.Add(mod, new object()); - } - } - - private int DrawPriorityInput(ModConflicts conflict, float priorityWidth) - { - using var color = ImRaii.PushColor(ImGuiCol.Text, - conflict.HasPriority ? ColorId.HandledConflictMod.Value() : ColorId.ConflictingMod.Value()); - using var disabled = ImRaii.Disabled(conflict.Mod2.Index < 0); - var priority = _currentPriority ?? GetPriority(conflict).Value; - - ImGui.SetNextItemWidth(priorityWidth); - if (ImGui.InputInt("##priority", ref priority, 0, 0, flags: ImGuiInputTextFlags.EnterReturnsTrue)) - _currentPriority = priority; - - if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue) - { - if (_currentPriority != GetPriority(conflict).Value) - collectionManager.Editor.SetModPriority(collectionManager.Active.Current, (Mod)conflict.Mod2, - new ModPriority(_currentPriority.Value)); - - _currentPriority = null; - } - else if (ImGui.IsItemDeactivated()) - { - _currentPriority = null; - } - - return priority; - } - - private void DrawPriorityButtons(Mod? conflict, int conflictPriority, int selectedPriority, Vector2 buttonSize) - { - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.SortNumericUpAlt.ToIconString(), buttonSize, - $"Set the priority of the currently selected mod to this mods priority plus one. ({selectedPriority} -> {conflictPriority + 1})", - selectedPriority > conflictPriority, true)) - collectionManager.Editor.SetModPriority(collectionManager.Active.Current, selector.Selected!, - new ModPriority(conflictPriority + 1)); - Im.Line.Same(); - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.SortNumericDownAlt.ToIconString(), buttonSize, - $"Set the priority of this mod to the currently selected mods priority minus one. ({conflictPriority} -> {selectedPriority - 1})", - selectedPriority > conflictPriority || conflict == null, true)) - collectionManager.Editor.SetModPriority(collectionManager.Active.Current, conflict!, new ModPriority(selectedPriority - 1)); - } -} +using Dalamud.Interface; +using Dalamud.Interface.Utility; +using Dalamud.Bindings.ImGui; +using ImSharp; +using OtterGui; +using OtterGui.Raii; +using OtterGui.Text; +using OtterGui.Widgets; +using Penumbra.Collections.Cache; +using Penumbra.Collections.Manager; +using Penumbra.Meta.Manipulations; +using Penumbra.Mods; +using Penumbra.Mods.Editor; +using Penumbra.Mods.Settings; +using Penumbra.String.Classes; +using Penumbra.UI.Classes; + +namespace Penumbra.UI.ModsTab; + +public class ModPanelConflictsTab(CollectionManager collectionManager, ModFileSystemSelector selector) : ITab, Luna.IUiService +{ + private int? _currentPriority; + + public ReadOnlySpan Label + => "Conflicts"u8; + + public bool IsVisible + => collectionManager.Active.Current.Conflicts(selector.Selected!).Any(c => !GetPriority(c).IsHidden); + + private readonly ConditionalWeakTable _expandedMods = []; + + private ModPriority GetPriority(ModConflicts conflicts) + { + if (conflicts.Mod2.Index < 0) + return conflicts.Mod2.Priority; + + return collectionManager.Active.Current.GetActualSettings(conflicts.Mod2.Index).Settings?.Priority ?? ModPriority.Default; + } + + public void DrawContent() + { + using var table = ImRaii.Table("conflicts", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY, ImGui.GetContentRegionAvail()); + if (!table) + return; + + var buttonSize = new Vector2(ImGui.GetFrameHeight()); + var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }; + var priorityRowWidth = ImGui.CalcTextSize("Priority").X + 20 * ImGuiHelpers.GlobalScale + 2 * buttonSize.X; + var priorityWidth = priorityRowWidth - 2 * (buttonSize.X + spacing.X); + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); + ImGui.TableSetupColumn("Conflicting Mod", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Priority", ImGuiTableColumnFlags.WidthFixed, priorityRowWidth); + ImGui.TableSetupColumn("Files", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Files").X + spacing.X); + + ImGui.TableSetupScrollFreeze(2, 2); + ImGui.TableHeadersRow(); + DrawCurrentRow(priorityWidth); + + // Can not be null because otherwise the tab bar is never drawn. + var mod = selector.Selected!; + foreach (var (index, conflict) in collectionManager.Active.Current.Conflicts(mod).Where(c => !c.Mod2.Priority.IsHidden) + .OrderByDescending(GetPriority) + .ThenBy(c => c.Mod2.Name, StringComparer.OrdinalIgnoreCase).Index()) + { + using var id = ImRaii.PushId(index); + DrawConflictRow(conflict, priorityWidth, buttonSize); + } + } + + private void DrawCurrentRow(float priorityWidth) + { + ImGui.TableNextColumn(); + using var c = ImGuiColor.Text.Push(ColorId.FolderLine.Value()); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted(selector.Selected!.Name); + ImGui.TableNextColumn(); + var actualSettings = collectionManager.Active.Current.GetActualSettings(selector.Selected!.Index).Settings!; + var priority = actualSettings.Priority.Value; + // TODO + using (ImRaii.Disabled(actualSettings is TemporaryModSettings)) + { + ImGui.SetNextItemWidth(priorityWidth); + if (ImGui.InputInt("##priority", ref priority, 0, 0, flags: ImGuiInputTextFlags.EnterReturnsTrue)) + _currentPriority = priority; + + if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue) + { + if (_currentPriority != actualSettings.Priority.Value) + collectionManager.Editor.SetModPriority(collectionManager.Active.Current, selector.Selected!, + new ModPriority(_currentPriority.Value)); + + _currentPriority = null; + } + else if (ImGui.IsItemDeactivated()) + { + _currentPriority = null; + } + } + + ImGui.TableNextColumn(); + } + + private void DrawConflictSelectable(ModConflicts conflict) + { + ImGui.AlignTextToFramePadding(); + if (ImGui.Selectable(conflict.Mod2.Name) && conflict.Mod2 is Mod otherMod) + selector.SelectByValue(otherMod); + var hovered = ImGui.IsItemHovered(); + var rightClicked = ImGui.IsItemClicked(ImGuiMouseButton.Right); + if (conflict.Mod2 is Mod otherMod2) + { + if (hovered) + ImGui.SetTooltip("Click to jump to mod, Control + Right-Click to disable mod."); + if (rightClicked && ImGui.GetIO().KeyCtrl) + collectionManager.Editor.SetModState(collectionManager.Active.Current, otherMod2, false); + } + } + + private bool DrawExpandedFiles(ModConflicts conflict) + { + if (!_expandedMods.TryGetValue(conflict.Mod2, out _)) + return false; + + using var indent = ImRaii.PushIndent(30f); + foreach (var data in conflict.Conflicts) + { + _ = data switch + { + Utf8GamePath p => ImUtf8.Selectable(p.Path.Span, false), + IMetaIdentifier m => ImUtf8.Selectable(m.ToString(), false), + _ => false, + }; + } + + return true; + } + + private void DrawConflictRow(ModConflicts conflict, float priorityWidth, Vector2 buttonSize) + { + ImGui.TableNextColumn(); + DrawConflictSelectable(conflict); + var expanded = DrawExpandedFiles(conflict); + ImGui.TableNextColumn(); + var conflictPriority = DrawPriorityInput(conflict, priorityWidth); + Im.Line.Same(); + var selectedPriority = collectionManager.Active.Current.GetActualSettings(selector.Selected!.Index).Settings!.Priority.Value; + DrawPriorityButtons(conflict.Mod2 as Mod, conflictPriority, selectedPriority, buttonSize); + ImGui.TableNextColumn(); + DrawExpandButton(conflict.Mod2, expanded, buttonSize); + } + + private void DrawExpandButton(IMod mod, bool expanded, Vector2 buttonSize) + { + var (icon, tt) = expanded + ? (FontAwesomeIcon.CaretUp.ToIconString(), "Hide the conflicting files for this mod.") + : (FontAwesomeIcon.CaretDown.ToIconString(), "Show the conflicting files for this mod."); + if (ImGuiUtil.DrawDisabledButton(icon, buttonSize, tt, false, true)) + { + if (expanded) + _expandedMods.Remove(mod); + else + _expandedMods.Add(mod, new object()); + } + } + + private int DrawPriorityInput(ModConflicts conflict, float priorityWidth) + { + using var color = ImGuiColor.Text.Push(conflict.HasPriority ? ColorId.HandledConflictMod.Value() : ColorId.ConflictingMod.Value()); + using var disabled = ImRaii.Disabled(conflict.Mod2.Index < 0); + var priority = _currentPriority ?? GetPriority(conflict).Value; + + ImGui.SetNextItemWidth(priorityWidth); + if (ImGui.InputInt("##priority", ref priority, 0, 0, flags: ImGuiInputTextFlags.EnterReturnsTrue)) + _currentPriority = priority; + + if (ImGui.IsItemDeactivatedAfterEdit() && _currentPriority.HasValue) + { + if (_currentPriority != GetPriority(conflict).Value) + collectionManager.Editor.SetModPriority(collectionManager.Active.Current, (Mod)conflict.Mod2, + new ModPriority(_currentPriority.Value)); + + _currentPriority = null; + } + else if (ImGui.IsItemDeactivated()) + { + _currentPriority = null; + } + + return priority; + } + + private void DrawPriorityButtons(Mod? conflict, int conflictPriority, int selectedPriority, Vector2 buttonSize) + { + if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.SortNumericUpAlt.ToIconString(), buttonSize, + $"Set the priority of the currently selected mod to this mods priority plus one. ({selectedPriority} -> {conflictPriority + 1})", + selectedPriority > conflictPriority, true)) + collectionManager.Editor.SetModPriority(collectionManager.Active.Current, selector.Selected!, + new ModPriority(conflictPriority + 1)); + Im.Line.Same(); + if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.SortNumericDownAlt.ToIconString(), buttonSize, + $"Set the priority of this mod to the currently selected mods priority minus one. ({conflictPriority} -> {selectedPriority - 1})", + selectedPriority > conflictPriority || conflict == null, true)) + collectionManager.Editor.SetModPriority(collectionManager.Active.Current, conflict!, new ModPriority(selectedPriority - 1)); + } +} diff --git a/Penumbra/UI/ModsTab/ModPanelEditTab.cs b/Penumbra/UI/ModsTab/ModPanelEditTab.cs index 82960361..07ff516f 100644 --- a/Penumbra/UI/ModsTab/ModPanelEditTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelEditTab.cs @@ -208,8 +208,8 @@ public class ModPanelEditTab( private void DrawImportDate() { - ImUtf8.TextFramed($"{DateTimeOffset.FromUnixTimeMilliseconds(_mod.ImportDate).ToLocalTime():yyyy/MM/dd HH:mm}", - ImGui.GetColorU32(ImGuiCol.FrameBg, 0.5f), new Vector2(UiHelpers.InputTextMinusButton3, 0)); + ImEx.TextFramed($"{DateTimeOffset.FromUnixTimeMilliseconds(_mod.ImportDate).ToLocalTime():yyyy/MM/dd HH:mm}", + new Vector2(UiHelpers.InputTextMinusButton3, 0), ImGuiColor.FrameBackground.Get(0.5f)); ImGui.SameLine(0, 3 * ImUtf8.GlobalScale); var canRefresh = config.DeleteModModifier.IsActive(); diff --git a/Penumbra/UI/ModsTab/ModPanelHeader.cs b/Penumbra/UI/ModsTab/ModPanelHeader.cs index 45a14178..b1d4d9e5 100644 --- a/Penumbra/UI/ModsTab/ModPanelHeader.cs +++ b/Penumbra/UI/ModsTab/ModPanelHeader.cs @@ -149,8 +149,7 @@ public class ModPanelHeader : IDisposable ImGui.SetCursorPosX(offset); } - using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.MetaInfoText); - using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * UiHelpers.Scale); + using var style = ImStyleBorder.Frame.Push(Colors.MetaInfoText, 2 * Im.Style.GlobalScale); using var f = _nameFont.Push(); ImGuiUtil.DrawTextButton(_modName, Vector2.Zero, 0); _nameWidth = ImGui.GetItemRectSize().X; diff --git a/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs b/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs index 0b309032..209b0996 100644 --- a/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs +++ b/Penumbra/UI/ModsTab/ModPanelSettingsTab.cs @@ -92,7 +92,7 @@ public class ModPanelSettingsTab( if (!_inherited) return; - using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg); + using var color = ImGuiColor.Button.Push(Colors.PressEnterWarningBg); var width = new Vector2(ImGui.GetContentRegionAvail().X, 0); if (ImUtf8.ButtonEx($"These settings are inherited from {selection.Collection.Identity.Name}.", width, _locked)) { diff --git a/Penumbra/UI/ModsTab/ModPanelTabBar.cs b/Penumbra/UI/ModsTab/ModPanelTabBar.cs index 81c0ff89..2b9cba6e 100644 --- a/Penumbra/UI/ModsTab/ModPanelTabBar.cs +++ b/Penumbra/UI/ModsTab/ModPanelTabBar.cs @@ -1,158 +1,158 @@ -using Dalamud.Bindings.ImGui; -using Dalamud.Interface; -using OtterGui; -using OtterGui.Raii; -using OtterGui.Widgets; -using Penumbra.Mods; -using Penumbra.Mods.Manager; -using Penumbra.UI.AdvancedWindow; - -namespace Penumbra.UI.ModsTab; - -public class ModPanelTabBar : Luna.IUiService -{ - private enum ModPanelTabType - { - Description, - Settings, - ChangedItems, - Conflicts, - Collections, - Edit, - }; - - public readonly ModPanelSettingsTab Settings; - public readonly ModPanelDescriptionTab Description; - public readonly ModPanelCollectionsTab Collections; - public readonly ModPanelConflictsTab Conflicts; - public readonly ModPanelChangedItemsTab ChangedItems; - public readonly ModPanelEditTab Edit; - private readonly ModEditWindow _modEditWindow; - private readonly ModManager _modManager; - private readonly TutorialService _tutorial; - - public readonly ITab[] Tabs; - private ModPanelTabType _preferredTab = ModPanelTabType.Settings; - private Mod? _lastMod; - - public ModPanelTabBar(ModEditWindow modEditWindow, ModPanelSettingsTab settings, ModPanelDescriptionTab description, - ModPanelConflictsTab conflicts, ModPanelChangedItemsTab changedItems, ModPanelEditTab edit, ModManager modManager, - TutorialService tutorial, ModPanelCollectionsTab collections) - { - _modEditWindow = modEditWindow; - Settings = settings; - Description = description; - Conflicts = conflicts; - ChangedItems = changedItems; - Edit = edit; - _modManager = modManager; - _tutorial = tutorial; - Collections = collections; - - Tabs = - [ - Settings, - Description, - Conflicts, - ChangedItems, - Collections, - Edit, - ]; - } - - public void Draw(Mod mod) - { - var tabBarHeight = ImGui.GetCursorPosY(); - if (_lastMod != mod) - { - _lastMod = mod; - TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ToLabel(_preferredTab), out _, () => DrawAdvancedEditingButton(mod), Tabs); - } - else - { - TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ReadOnlySpan.Empty, out var label, () => DrawAdvancedEditingButton(mod), - Tabs); - _preferredTab = ToType(label); - } - - DrawFavoriteButton(mod, tabBarHeight); - } - - private ReadOnlySpan ToLabel(ModPanelTabType type) - => type switch - { - ModPanelTabType.Description => Description.Label, - ModPanelTabType.Settings => Settings.Label, - ModPanelTabType.ChangedItems => ChangedItems.Label, - ModPanelTabType.Conflicts => Conflicts.Label, - ModPanelTabType.Collections => Collections.Label, - ModPanelTabType.Edit => Edit.Label, - _ => ReadOnlySpan.Empty, - }; - - private ModPanelTabType ToType(ReadOnlySpan label) - { - if (label == Description.Label) - return ModPanelTabType.Description; - if (label == Settings.Label) - return ModPanelTabType.Settings; - if (label == ChangedItems.Label) - return ModPanelTabType.ChangedItems; - if (label == Conflicts.Label) - return ModPanelTabType.Conflicts; - if (label == Collections.Label) - return ModPanelTabType.Collections; - if (label == Edit.Label) - return ModPanelTabType.Edit; - - return 0; - } - - private void DrawAdvancedEditingButton(Mod mod) - { - if (ImGui.TabItemButton("Advanced Editing", ImGuiTabItemFlags.Trailing | ImGuiTabItemFlags.NoTooltip)) - { - _modEditWindow.ChangeMod(mod); - _modEditWindow.ChangeOption(mod.Default); - _modEditWindow.IsOpen = true; - } - - ImGuiUtil.HoverTooltip( - "Clicking this will open a new window in which you can\nedit the following things per option for this mod:\n\n" - + "\t\t- file redirections\n" - + "\t\t- file swaps\n" - + "\t\t- metadata manipulations\n" - + "\t\t- model materials\n" - + "\t\t- duplicates\n" - + "\t\t- textures"); - } - - private void DrawFavoriteButton(Mod mod, float height) - { - using (var font = ImRaii.PushFont(UiBuilder.IconFont)) - { - var size = ImGui.CalcTextSize(FontAwesomeIcon.Star.ToIconString()) + ImGui.GetStyle().FramePadding * 2; - var newPos = new Vector2(ImGui.GetWindowWidth() - size.X - ImGui.GetStyle().ItemSpacing.X, height); - if (ImGui.GetScrollMaxX() > 0) - newPos.X += ImGui.GetScrollX(); - - var rectUpper = ImGui.GetWindowPos() + newPos; - var color = ImGui.IsMouseHoveringRect(rectUpper, rectUpper + size) ? ImGui.GetColorU32(ImGuiCol.Text) : - mod.Favorite ? 0xFF00FFFF : ImGui.GetColorU32(ImGuiCol.TextDisabled); - using var c = ImRaii.PushColor(ImGuiCol.Text, color) - .Push(ImGuiCol.Button, 0) - .Push(ImGuiCol.ButtonHovered, 0) - .Push(ImGuiCol.ButtonActive, 0); - - ImGui.SetCursorPos(newPos); - if (ImGui.Button(FontAwesomeIcon.Star.ToIconString())) - _modManager.DataEditor.ChangeModFavorite(mod, !mod.Favorite); - } - - var hovered = ImGui.IsItemHovered(); - _tutorial.OpenTutorial(BasicTutorialSteps.Favorites); - - if (hovered) - ImGui.SetTooltip("Favorite"); - } -} +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using ImSharp; +using Luna; +using OtterGui; +using OtterGui.Raii; +using OtterGui.Widgets; +using Penumbra.Mods; +using Penumbra.Mods.Manager; +using Penumbra.UI.AdvancedWindow; +using ImGuiColor = ImSharp.ImGuiColor; + +namespace Penumbra.UI.ModsTab; + +public class ModPanelTabBar : IUiService +{ + private enum ModPanelTabType + { + Description, + Settings, + ChangedItems, + Conflicts, + Collections, + Edit, + }; + + public readonly ModPanelSettingsTab Settings; + public readonly ModPanelDescriptionTab Description; + public readonly ModPanelCollectionsTab Collections; + public readonly ModPanelConflictsTab Conflicts; + public readonly ModPanelChangedItemsTab ChangedItems; + public readonly ModPanelEditTab Edit; + private readonly ModEditWindow _modEditWindow; + private readonly ModManager _modManager; + private readonly TutorialService _tutorial; + + public readonly ITab[] Tabs; + private ModPanelTabType _preferredTab = ModPanelTabType.Settings; + private Mod? _lastMod; + + public ModPanelTabBar(ModEditWindow modEditWindow, ModPanelSettingsTab settings, ModPanelDescriptionTab description, + ModPanelConflictsTab conflicts, ModPanelChangedItemsTab changedItems, ModPanelEditTab edit, ModManager modManager, + TutorialService tutorial, ModPanelCollectionsTab collections) + { + _modEditWindow = modEditWindow; + Settings = settings; + Description = description; + Conflicts = conflicts; + ChangedItems = changedItems; + Edit = edit; + _modManager = modManager; + _tutorial = tutorial; + Collections = collections; + + Tabs = + [ + Settings, + Description, + Conflicts, + ChangedItems, + Collections, + Edit, + ]; + } + + public void Draw(Mod mod) + { + var tabBarHeight = ImGui.GetCursorPosY(); + if (_lastMod != mod) + { + _lastMod = mod; + TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ToLabel(_preferredTab), out _, () => DrawAdvancedEditingButton(mod), Tabs); + } + else + { + TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ReadOnlySpan.Empty, out var label, () => DrawAdvancedEditingButton(mod), + Tabs); + _preferredTab = ToType(label); + } + + DrawFavoriteButton(mod, tabBarHeight); + } + + private ReadOnlySpan ToLabel(ModPanelTabType type) + => type switch + { + ModPanelTabType.Description => Description.Label, + ModPanelTabType.Settings => Settings.Label, + ModPanelTabType.ChangedItems => ChangedItems.Label, + ModPanelTabType.Conflicts => Conflicts.Label, + ModPanelTabType.Collections => Collections.Label, + ModPanelTabType.Edit => Edit.Label, + _ => ReadOnlySpan.Empty, + }; + + private ModPanelTabType ToType(ReadOnlySpan label) + { + if (label == Description.Label) + return ModPanelTabType.Description; + if (label == Settings.Label) + return ModPanelTabType.Settings; + if (label == ChangedItems.Label) + return ModPanelTabType.ChangedItems; + if (label == Conflicts.Label) + return ModPanelTabType.Conflicts; + if (label == Collections.Label) + return ModPanelTabType.Collections; + if (label == Edit.Label) + return ModPanelTabType.Edit; + + return 0; + } + + private void DrawAdvancedEditingButton(Mod mod) + { + if (ImGui.TabItemButton("Advanced Editing", ImGuiTabItemFlags.Trailing | ImGuiTabItemFlags.NoTooltip)) + { + _modEditWindow.ChangeMod(mod); + _modEditWindow.ChangeOption(mod.Default); + _modEditWindow.IsOpen = true; + } + + ImGuiUtil.HoverTooltip( + "Clicking this will open a new window in which you can\nedit the following things per option for this mod:\n\n" + + "\t\t- file redirections\n" + + "\t\t- file swaps\n" + + "\t\t- metadata manipulations\n" + + "\t\t- model materials\n" + + "\t\t- duplicates\n" + + "\t\t- textures"); + } + + private void DrawFavoriteButton(Mod mod, float height) + { + var size = ImEx.Icon.CalculateSize(LunaStyle.FavoriteIcon) + ImGui.GetStyle().FramePadding * 2; + var newPos = new Vector2(ImGui.GetWindowWidth() - size.X - ImGui.GetStyle().ItemSpacing.X, height); + if (ImGui.GetScrollMaxX() > 0) + newPos.X += ImGui.GetScrollX(); + + var rectUpper = ImGui.GetWindowPos() + newPos; + var color = ImGui.IsMouseHoveringRect(rectUpper, rectUpper + size) ? Im.Style[ImGuiColor.Text] : + mod.Favorite ? LunaStyle.FavoriteColor : Im.Style[ImGuiColor.TextDisabled]; + using var c = ImGuiColor.Text.Push(color) + .Push(ImGuiColor.Button, Vector4.Zero) + .Push(ImGuiColor.ButtonHovered, Vector4.Zero) + .Push(ImGuiColor.ButtonActive, Vector4.Zero); + + ImGui.SetCursorPos(newPos); + if (ImEx.Icon.Button(LunaStyle.FavoriteIcon)) + _modManager.DataEditor.ChangeModFavorite(mod, !mod.Favorite); + + var hovered = ImGui.IsItemHovered(); + _tutorial.OpenTutorial(BasicTutorialSteps.Favorites); + + if (hovered) + ImGui.SetTooltip("Favorite"); + } +} diff --git a/Penumbra/UI/PredefinedTagManager.cs b/Penumbra/UI/PredefinedTagManager.cs index f76855b1..738d3b86 100644 --- a/Penumbra/UI/PredefinedTagManager.cs +++ b/Penumbra/UI/PredefinedTagManager.cs @@ -21,8 +21,8 @@ public sealed class PredefinedTagManager : ISavable, IReadOnlyList, ISer private readonly SaveService _saveService; private bool _isListOpen; - private uint _enabledColor; - private uint _disabledColor; + private Rgba32 _enabledColor; + private Rgba32 _disabledColor; private readonly SortedList _predefinedTags = []; diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs index 1289612d..3cc974c2 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs @@ -1,5 +1,6 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; +using ImSharp; using Luna; using OtterGui; using OtterGui.Raii; @@ -336,17 +337,13 @@ internal sealed class ResourceWatcherTable : Table $"Successfully loaded ({(byte)item.LoadState})."), LoadState.FailedSubResource => (FontAwesomeIcon.ExclamationCircle, ColorId.DecreasedMetaValue.Value(), $"Dependencies failed to load ({(byte)item.LoadState})."), - <= LoadState.Constructed => (FontAwesomeIcon.QuestionCircle, ColorId.UndefinedMod.Value(), $"Not yet loaded ({(byte)item.LoadState})."), + <= LoadState.Constructed => (FontAwesomeIcon.QuestionCircle, ColorId.UndefinedMod.Value(), + $"Not yet loaded ({(byte)item.LoadState})."), < LoadState.Success => (FontAwesomeIcon.Clock, ColorId.FolderLine.Value(), $"Loading asynchronously ({(byte)item.LoadState})."), > LoadState.Success => (FontAwesomeIcon.Times, ColorId.DecreasedMetaValue.Value(), $"Failed to load ({(byte)item.LoadState})."), }; - using (var font = ImRaii.PushFont(UiBuilder.IconFont)) - { - using var c = ImRaii.PushColor(ImGuiCol.Text, color); - ImGui.TextUnformatted(icon.ToIconString()); - } - + ImEx.Icon.Draw(icon.Icon(), color); ImGuiUtil.HoverTooltip(tt); } diff --git a/Penumbra/UI/Tabs/CollectionsTab.cs b/Penumbra/UI/Tabs/CollectionsTab.cs index 029e3be6..0a2f8bc6 100644 --- a/Penumbra/UI/Tabs/CollectionsTab.cs +++ b/Penumbra/UI/Tabs/CollectionsTab.cs @@ -86,29 +86,30 @@ public sealed class CollectionsTab : IDisposable, ITab, Luna.IUiService using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 0).Push(ImGuiStyleVar.ItemSpacing, Vector2.Zero); var buttonSize = new Vector2((ImGui.GetContentRegionAvail().X - withSpacing) / 4f, ImGui.GetFrameHeight()); - using var _ = ImRaii.Group(); - using var color = ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.TabActive), Mode is PanelMode.SimpleAssignment); + using var _ = ImRaii.Group(); + var tabSelectedColor = Im.Style[ImGuiColor.TabSelected]; + using var color = ImGuiColor.Button.Push(tabSelectedColor, Mode is PanelMode.SimpleAssignment); if (ImGui.Button("Simple Assignments", buttonSize)) Mode = PanelMode.SimpleAssignment; color.Pop(); _tutorial.OpenTutorial(BasicTutorialSteps.SimpleAssignments); Im.Line.Same(); - color.Push(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.TabActive), Mode is PanelMode.IndividualAssignment); + color.Push(ImGuiColor.Button, tabSelectedColor, Mode is PanelMode.IndividualAssignment); if (ImGui.Button("Individual Assignments", buttonSize)) Mode = PanelMode.IndividualAssignment; color.Pop(); _tutorial.OpenTutorial(BasicTutorialSteps.IndividualAssignments); Im.Line.Same(); - color.Push(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.TabActive), Mode is PanelMode.GroupAssignment); + color.Push(ImGuiColor.Button, tabSelectedColor, Mode is PanelMode.GroupAssignment); if (ImGui.Button("Group Assignments", buttonSize)) Mode = PanelMode.GroupAssignment; color.Pop(); _tutorial.OpenTutorial(BasicTutorialSteps.GroupAssignments); Im.Line.Same(); - color.Push(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.TabActive), Mode is PanelMode.Details); + color.Push(ImGuiColor.Button, tabSelectedColor, Mode is PanelMode.Details); if (ImGui.Button("Collection Details", buttonSize)) Mode = PanelMode.Details; color.Pop(); diff --git a/Penumbra/UI/Tabs/Debug/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs index 51d67fb2..9fdb3a9b 100644 --- a/Penumbra/UI/Tabs/Debug/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -31,7 +31,6 @@ using Penumbra.Mods.Manager; using Penumbra.Services; using Penumbra.String; using Penumbra.UI.Classes; -using static OtterGui.Raii.ImRaii; using CharacterBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase; using ImGuiClip = OtterGui.ImGuiClip; using Penumbra.Api.IpcTester; @@ -68,7 +67,7 @@ public class Diagnostics(ServiceManager provider) : IUiService } } -public class DebugTab : Window, ITab, IUiService +public class DebugTab : Window, ITab { private readonly Configuration _config; private readonly CollectionManager _collectionManager; @@ -180,7 +179,7 @@ public class DebugTab : Window, ITab, IUiService public void DrawContent() { - using var child = Child("##DebugTab", -Vector2.One); + using var child = Im.Child.Begin("##DebugTab"u8, -Vector2.One); if (!child) return; @@ -218,9 +217,9 @@ public class DebugTab : Window, ITab, IUiService { if (collection.HasCache) { - using var color = PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value()); + using var color = ImGuiColor.Text.Push(ColorId.FolderExpanded.Value()); using var node = - TreeNode($"{collection.Identity.Name} (Change Counter {collection.Counters.Change})###{collection.Identity.Name}"); + Im.Tree.Node($"{collection.Identity.Name} (Change Counter {collection.Counters.Change})###{collection.Identity.Name}"); if (!node) continue; @@ -272,24 +271,24 @@ public class DebugTab : Window, ITab, IUiService if (modNode) foreach (var (mod, paths, manips) in collection._cache!.ModData.Data.OrderBy(t => t.Item1.Name)) { - using var id = mod is TemporaryMod t ? PushId(t.Priority.Value) : PushId(((Mod)mod).ModPath.Name); - using var node2 = TreeNode(mod.Name); + using var id = mod is TemporaryMod t ? Im.Id.Push(t.Priority.Value) : Im.Id.Push(((Mod)mod).ModPath.Name); + using var node2 = Im.Tree.Node(mod.Name); if (!node2) continue; foreach (var path in paths) - TreeNode(path.ToString(), ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + Im.Tree.Node(path.Path.Span, TreeNodeFlags.Bullet | TreeNodeFlags.Leaf).Dispose(); foreach (var manip in manips) - TreeNode(manip.ToString(), ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + Im.Tree.Node($"{manip}", TreeNodeFlags.Bullet | TreeNodeFlags.Leaf).Dispose(); } } else { - using var color = PushColor(ImGuiCol.Text, ColorId.UndefinedMod.Value()); - TreeNode($"{collection.Identity.Name} (Change Counter {collection.Counters.Change})", - ImGuiTreeNodeFlags.Bullet | ImGuiTreeNodeFlags.Leaf).Dispose(); + using var color = ImGuiColor.Text.Push(ColorId.UndefinedMod.Value()); + Im.Tree.Node($"{collection.Identity.Name} (Change Counter {collection.Counters.Change})", + TreeNodeFlags.Bullet | TreeNodeFlags.Leaf).Dispose(); } } } @@ -308,7 +307,7 @@ public class DebugTab : Window, ITab, IUiService _config.Ephemeral.Save(); } - using (var table = Table("##DebugGeneralTable", 2, ImGuiTableFlags.SizingFixedFit)) + using (var table = Im.Table.Begin("##DebugGeneralTable"u8, 2, TableFlags.SizingFixedFit)) { if (table) { @@ -329,11 +328,11 @@ public class DebugTab : Window, ITab, IUiService var issues = _modManager.Index().Count(p => p.Index != p.Item.Index); - using (var tree = TreeNode($"Mods ({issues} Issues)###Mods")) + using (var tree = Im.Tree.Node($"Mods ({issues} Issues)###Mods")) { if (tree) { - using var table = Table("##DebugModsTable", 3, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("##DebugModsTable"u8, 3, TableFlags.SizingFixedFit); if (table) { var lastIndex = -1; @@ -350,11 +349,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var tree = TreeNode("Mod Import")) + using (var tree = Im.Tree.Node("Mod Import"u8)) { if (tree) { - using var table = Table("##DebugModImport", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("##DebugModImport"u8, 2, TableFlags.SizingFixedFit); if (table) { var importing = _modImporter.IsImporting(out var importer); @@ -384,11 +383,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var tree = TreeNode("Framework")) + using (var tree = Im.Tree.Node("Framework"u8)) { if (tree) { - using var table = Table("##DebugFramework", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("##DebugFramework"u8, 2, TableFlags.SizingFixedFit); if (table) { foreach (var important in _framework.Important) @@ -406,11 +405,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var tree = TreeNode($"Texture Manager {_textureManager.Tasks.Count}###Texture Manager")) + using (var tree = Im.Tree.Node($"Texture Manager {_textureManager.Tasks.Count}###Texture Manager")) { if (tree) { - using var table = Table("##Tasks", 2, ImGuiTableFlags.RowBg); + using var table = Im.Table.Begin("##Tasks"u8, 2, TableFlags.RowBackground); if (table) foreach (var task in _textureManager.Tasks) { @@ -420,11 +419,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var tree = TreeNode("Redraw Service")) + using (var tree = Im.Tree.Node("Redraw Service"u8)) { if (tree) { - using var table = Table("##redraws", 3, ImGuiTableFlags.RowBg); + using var table = Im.Table.Begin("##redraws"u8, 3, TableFlags.RowBackground); if (table) { ImGuiUtil.DrawTableColumn("In GPose"); @@ -494,7 +493,7 @@ public class DebugTab : Window, ITab, IUiService if (!ImGui.CollapsingHeader("Performance")) return; - using (var start = TreeNode("Startup Performance", ImGuiTreeNodeFlags.DefaultOpen)) + using (var start = Im.Tree.Node("Startup Performance"u8, TreeNodeFlags.DefaultOpen)) { if (start) ImGui.NewLine(); @@ -512,7 +511,7 @@ public class DebugTab : Window, ITab, IUiService { _objects.DrawDebug(); - using var table = Table("##actors", 8, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, + using var table = Im.Table.Begin("##actors"u8, 8, TableFlags.RowBackground | TableFlags.SizingFixedFit, -Vector2.UnitX); if (!table) return; @@ -581,11 +580,11 @@ public class DebugTab : Window, ITab, IUiService ImGui.TextUnformatted( $"Last Game Object: 0x{_collectionResolver.IdentifyLastGameObjectCollection(true).AssociatedGameObject:X} ({_collectionResolver.IdentifyLastGameObjectCollection(true).ModCollection.Identity.Name})"); - using (var drawTree = TreeNode("Draw Object to Object")) + using (var drawTree = Im.Tree.Node("Draw Object to Object"u8)) { if (drawTree) { - using var table = Table("###DrawObjectResolverTable", 8, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###DrawObjectResolverTable"u8, 8, TableFlags.SizingFixedFit); if (table) foreach (var (drawObject, (gameObjectPtr, idx, child)) in _drawObjectState .OrderBy(kvp => kvp.Value.Item2.Index) @@ -595,7 +594,7 @@ public class DebugTab : Window, ITab, IUiService ImGui.TableNextColumn(); ImUtf8.CopyOnClickSelectable($"{drawObject}"); ImUtf8.DrawTableColumn($"{gameObjectPtr.Index}"); - using (ImRaii.PushColor(ImGuiCol.Text, 0xFF0000FF, gameObjectPtr.Index != idx)) + using (ImGuiColor.Text.Push(new Vector4(1, 0, 0, 1), gameObjectPtr.Index != idx)) { ImUtf8.DrawTableColumn($"{idx}"); } @@ -603,7 +602,7 @@ public class DebugTab : Window, ITab, IUiService ImUtf8.DrawTableColumn(child ? "Child"u8 : "Main"u8); ImGui.TableNextColumn(); ImUtf8.CopyOnClickSelectable($"{gameObjectPtr}"); - using (ImRaii.PushColor(ImGuiCol.Text, 0xFF0000FF, _objects[idx] != gameObjectPtr)) + using (ImGuiColor.Text.Push(new Vector4(1, 0, 0, 1), _objects[idx] != gameObjectPtr)) { ImUtf8.DrawTableColumn($"{_objects[idx]}"); } @@ -615,11 +614,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var pathTree = TreeNode("Path Collections")) + using (var pathTree = Im.Tree.Node("Path Collections"u8)) { if (pathTree) { - using var table = Table("###PathCollectionResolverTable", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###PathCollectionResolverTable"u8, 2, TableFlags.SizingFixedFit); if (table) foreach (var data in _pathState.CurrentData) { @@ -631,11 +630,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var resourceTree = TreeNode("Subfile Collections")) + using (var resourceTree = Im.Tree.Node("Subfile Collections"u8)) { if (resourceTree) { - using var table = Table("###ResourceCollectionResolverTable", 4, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###ResourceCollectionResolverTable"u8, 4, TableFlags.SizingFixedFit); if (table) { ImGuiUtil.DrawTableColumn("Current Mtrl Data"); @@ -664,11 +663,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var identifiedTree = TreeNode("Identified Collections")) + using (var identifiedTree = Im.Tree.Node("Identified Collections"u8)) { if (identifiedTree) { - using var table = Table("##PathCollectionsIdentifiedTable", 4, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("##PathCollectionsIdentifiedTable"u8, 4, TableFlags.SizingFixedFit); if (table) foreach (var (address, identifier, collection) in _identifiedCollectionCache .OrderBy(kvp => ((GameObject*)kvp.Address)->ObjectIndex)) @@ -681,11 +680,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var cutsceneTree = TreeNode("Cutscene Actors")) + using (var cutsceneTree = Im.Tree.Node("Cutscene Actors"u8)) { if (cutsceneTree) { - using var table = Table("###PCutsceneResolverTable", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###PCutsceneResolverTable"u8, 2, TableFlags.SizingFixedFit); if (table) foreach (var (idx, actor) in _cutsceneService.Actors) { @@ -695,11 +694,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var groupTree = TreeNode("Group")) + using (var groupTree = Im.Tree.Node("Group"u8)) { if (groupTree) { - using var table = Table("###PGroupTable", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###PGroupTable"u8, 2, TableFlags.SizingFixedFit); if (table) { ImGuiUtil.DrawTableColumn("Group Members"); @@ -714,7 +713,7 @@ public class DebugTab : Window, ITab, IUiService } } - using (var bannerTree = TreeNode("Party Banner")) + using (var bannerTree = Im.Tree.Node("Party Banner"u8)) { if (bannerTree) { @@ -727,7 +726,7 @@ public class DebugTab : Window, ITab, IUiService Penumbra.Dynamis.DrawPointer((nint)agent); if (agent->Data != null) { - using var table = Table("###PBannerTable", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###PBannerTable"u8, 2, TableFlags.SizingFixedFit); if (table) for (var i = 0; i < 8; ++i) { @@ -744,11 +743,11 @@ public class DebugTab : Window, ITab, IUiService } } - using (var tmbCache = TreeNode("TMB Cache")) + using (var tmbCache = Im.Tree.Node("TMB Cache"u8)) { if (tmbCache) { - using var table = Table("###TmbTable", 2, ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("###TmbTable"u8, 2, TableFlags.SizingFixedFit); if (table) foreach (var (id, name) in _schedulerService.ListedTmbs.OrderBy(kvp => kvp.Key)) { @@ -777,7 +776,7 @@ public class DebugTab : Window, ITab, IUiService private void DrawFileTest() { - using var node = TreeNode("Game File Test"); + using var node = Im.Tree.Node("Game File Test"u8); if (!node) return; @@ -803,7 +802,7 @@ public class DebugTab : Window, ITab, IUiService private void DrawChangedItemTest() { - using var node = TreeNode("Changed Item Test"); + using var node = Im.Tree.Node("Changed Item Test"u8); if (!node) return; @@ -855,13 +854,13 @@ public class DebugTab : Window, ITab, IUiService private void DrawEmotes() { - using var mainTree = TreeNode("Emotes"); + using var mainTree = Im.Tree.Node("Emotes"u8); if (!mainTree) return; ImGui.InputText("File Name", ref _emoteSearchFile, 256); ImGui.InputText("Emote Name", ref _emoteSearchName, 256); - using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, + using var table = Im.Table.Begin("##table"u8, 2, TableFlags.RowBackground | TableFlags.ScrollY | TableFlags.SizingFixedFit, new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing())); if (!table) return; @@ -886,13 +885,13 @@ public class DebugTab : Window, ITab, IUiService private void DrawActionTmbs() { - using var mainTree = TreeNode("Action TMBs"); + using var mainTree = Im.Tree.Node("Action TMBs"u8); if (!mainTree) return; if (ImGui.InputText("Key", ref _tmbKeyFilter, 256)) _tmbKeyFilterU8 = CiByteString.FromString(_tmbKeyFilter, out var r, MetaDataComputation.All) ? r : CiByteString.Empty; - using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, + using var table = Im.Table.Begin("##table"u8, 2, TableFlags.RowBackground | TableFlags.ScrollY | TableFlags.SizingFixedFit, new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing())); if (!table) return; @@ -910,17 +909,17 @@ public class DebugTab : Window, ITab, IUiService private void DrawStainTemplates() { - using var mainTree = TreeNode("Staining Templates"); + using var mainTree = Im.Tree.Node("Staining Templates"u8); if (!mainTree) return; - using (var legacyTree = TreeNode("stainingtemplate.stm")) + using (var legacyTree = Im.Tree.Node("stainingtemplate.stm"u8)) { if (legacyTree) DrawStainTemplatesFile(_stains.LegacyStmFile); } - using (var gudTree = TreeNode("stainingtemplate_gud.stm")) + using (var gudTree = Im.Tree.Node("stainingtemplate_gud.stm"u8)) { if (gudTree) DrawStainTemplatesFile(_stains.GudStmFile); @@ -931,12 +930,12 @@ public class DebugTab : Window, ITab, IUiService { foreach (var (key, data) in stmFile.Entries) { - using var tree = TreeNode($"Template {key}"); + using var tree = Im.Tree.Node($"Template {key}"); if (!tree) continue; - using var table = Table("##table", data.Colors.Length + data.Scalars.Length, - ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); + using var table = Im.Table.Begin("##table"u8, data.Colors.Length + data.Scalars.Length, + TableFlags.SizingFixedFit | TableFlags.RowBackground); if (!table) continue; @@ -974,7 +973,7 @@ public class DebugTab : Window, ITab, IUiService if (!enableShaderReplacementFixer) return; - using var table = Table("##ShaderReplacementFixer", 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit, + using var table = Im.Table.Begin("##ShaderReplacementFixer"u8, 3, TableFlags.RowBackground | TableFlags.SizingFixedFit, -Vector2.UnitX); if (!table) return; @@ -1066,7 +1065,7 @@ public class DebugTab : Window, ITab, IUiService DrawCopyableAddress("CharacterBase"u8, model); - using (var t1 = Table("##table", 2, ImGuiTableFlags.SizingFixedFit)) + using (var t1 = Im.Table.Begin("##table"u8, 2, TableFlags.SizingFixedFit)) { if (t1) { @@ -1079,7 +1078,7 @@ public class DebugTab : Window, ITab, IUiService } } - using var table = Table($"##{name}DrawTable", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin($"##{name}DrawTable", 5, TableFlags.RowBackground | TableFlags.SizingFixedFit); if (!table) return; @@ -1120,7 +1119,7 @@ public class DebugTab : Window, ITab, IUiService private string _crcInput = string.Empty; private FullPath _crcPath = FullPath.Empty; - private unsafe void DrawCrcCache() + private void DrawCrcCache() { var header = ImUtf8.CollapsingHeader("CRC Cache"u8); if (!header) @@ -1188,7 +1187,7 @@ public class DebugTab : Window, ITab, IUiService if (!header) return; - using var table = Table("##ProblemsTable", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit); + using var table = Im.Table.Begin("##ProblemsTable"u8, 6, TableFlags.RowBackground | TableFlags.SizingFixedFit); if (!table) return; @@ -1240,10 +1239,7 @@ public class DebugTab : Window, ITab, IUiService ImUtf8.Text($"Is Cloud Synced? {_cloudTesterReturn}"); if (_cloudTesterError is not null) - { - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed); - ImUtf8.Text($"{_cloudTesterError}"); - } + Im.Text($"{_cloudTesterError}", ImGuiColors.DalamudRed); } diff --git a/Penumbra/UI/Tabs/Debug/RenderTargetDrawer.cs b/Penumbra/UI/Tabs/Debug/RenderTargetDrawer.cs index bb0431e3..c9fbcbe5 100644 --- a/Penumbra/UI/Tabs/Debug/RenderTargetDrawer.cs +++ b/Penumbra/UI/Tabs/Debug/RenderTargetDrawer.cs @@ -84,7 +84,7 @@ public class RenderTargetDrawer(RenderTargetHdrEnabler renderTargetHdrEnabler, D + record.Offset); if (texture != null) { - using var color = Dalamud.Interface.Utility.Raii.ImRaii.PushColor(ImGuiCol.Text, ImGuiUtil.HalfBlendText(0xFF), + using var color = ImGuiColor.Text.Push(ImGuiUtil.HalfBlendText(0xFF), texture->TextureFormat != record.OriginalTextureFormat); ImUtf8.Text($"{texture->TextureFormat}"); } diff --git a/Penumbra/UI/Tabs/Debug/ShapeInspector.cs b/Penumbra/UI/Tabs/Debug/ShapeInspector.cs index c28049c4..513ea517 100644 --- a/Penumbra/UI/Tabs/Debug/ShapeInspector.cs +++ b/Penumbra/UI/Tabs/Debug/ShapeInspector.cs @@ -1,6 +1,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; +using ImSharp; using OtterGui.Text; using Penumbra.Collections.Cache; using Penumbra.GameData.Enums; @@ -90,10 +91,10 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) private static void DrawValues(in ShapeAttributeString shapeAttribute, ShapeAttributeHashSet set) { ImGui.TableNextColumn(); - + var disabledColor = Im.Style[ImGuiColor.TextDisabled]; if (set.All is { } value) { - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !value); + using var color = ImGuiColor.Text.Push(disabledColor, !value); ImUtf8.Text("All, "u8); ImGui.SameLine(0, 0); } @@ -103,7 +104,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) if (set[slot] is not { } value2) continue; - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !value2); + using var color = ImGuiColor.Text.Push(disabledColor, !value2); ImUtf8.Text($"All {slot.ToName()}, "); ImGui.SameLine(0, 0); } @@ -112,7 +113,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) { if (set[gr] is { } value3) { - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !value3); + using var color = ImGuiColor.Text.Push(disabledColor, !value3); ImUtf8.Text($"All {gr.ToName()}, "); ImGui.SameLine(0, 0); } @@ -123,7 +124,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) if (set[slot, gr] is not { } value4) continue; - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !value4); + using var color = ImGuiColor.Text.Push(disabledColor, !value4); ImUtf8.Text($"All {gr.ToName()} {slot.ToName()}, "); ImGui.SameLine(0, 0); } @@ -138,7 +139,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) if (set[slot, GenderRace.Unknown] != enabled) { - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !enabled); + using var color = ImGuiColor.Text.Push(disabledColor, !enabled); ImUtf8.Text($"{slot.ToName()} {id.Id:D4}, "); ImGui.SameLine(0, 0); } @@ -153,7 +154,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) var gr = ShapeAttributeHashSet.GenderRaceValues[currentIndex]; if (set[slot, gr] != enabled) { - using var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !enabled); + using var color = ImGuiColor.Text.Push(disabledColor, !enabled); ImUtf8.Text($"{gr.ToName()} {slot.ToName()} #{id.Id:D4}, "); ImGui.SameLine(0, 0); } @@ -186,7 +187,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) ImGui.TableHeadersRow(); - var disabledColor = ImGui.GetColorU32(ImGuiCol.TextDisabled); + var disabledColor = Im.Style[ImGuiColor.TextDisabled]; for (var i = 0; i < human.AsHuman->SlotCount; ++i) { ImUtf8.DrawTableColumn($"{(uint)i:D2}"); @@ -205,7 +206,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) foreach (var (idx, (shape, flag)) in model->ModelResourceHandle->Shapes.Index()) { var disabled = (mask & (1u << flag)) is 0; - using var color = ImRaii.PushColor(ImGuiCol.Text, disabledColor, disabled); + using var color = ImGuiColor.Text.Push(disabledColor, disabled); ImUtf8.Text(shape.AsSpan()); ImGui.SameLine(0, 0); ImUtf8.Text(", "u8); @@ -243,7 +244,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) ImGui.TableHeadersRow(); - var disabledColor = ImGui.GetColorU32(ImGuiCol.TextDisabled); + var disabledColor = Im.Style[ImGuiColor.TextDisabled]; for (var i = 0; i < human.AsHuman->SlotCount; ++i) { ImUtf8.DrawTableColumn($"{(uint)i:D2}"); @@ -262,7 +263,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) foreach (var (idx, (attribute, flag)) in model->ModelResourceHandle->Attributes.Index()) { var disabled = (mask & (1u << flag)) is 0; - using var color = ImRaii.PushColor(ImGuiCol.Text, disabledColor, disabled); + using var color = ImGuiColor.Text.Push(disabledColor, disabled); ImUtf8.Text(attribute.AsSpan()); ImGui.SameLine(0, 0); ImUtf8.Text(", "u8); diff --git a/Penumbra/UI/Tabs/Debug/TexHeaderDrawer.cs b/Penumbra/UI/Tabs/Debug/TexHeaderDrawer.cs index 93d4956b..aeb8ed0a 100644 --- a/Penumbra/UI/Tabs/Debug/TexHeaderDrawer.cs +++ b/Penumbra/UI/Tabs/Debug/TexHeaderDrawer.cs @@ -1,6 +1,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.DragDrop; using Dalamud.Interface.Utility.Raii; +using ImSharp; using Lumina.Data.Files; using OtterGui.Text; using Penumbra.UI.Classes; @@ -47,7 +48,7 @@ public class TexHeaderDrawer(IDragDropManager dragDrop) : Luna.IUiService if (_exception != null) { - using var color = ImRaii.PushColor(ImGuiCol.Text, Colors.RegexWarningBorder); + using var color = ImGuiColor.Text.Push(Colors.RegexWarningBorder); ImUtf8.TextWrapped($"Failure to load file:\n{_exception}"); } else if (_tex != null) diff --git a/Penumbra/UI/Tabs/ModsTab.cs b/Penumbra/UI/Tabs/ModsTab.cs index f1980d6a..5ae39e3a 100644 --- a/Penumbra/UI/Tabs/ModsTab.cs +++ b/Penumbra/UI/Tabs/ModsTab.cs @@ -95,7 +95,7 @@ public class ModsTab( } var frameHeight = new Vector2(0, ImGui.GetFrameHeight()); - var frameColor = ImGui.GetColorU32(ImGuiCol.FrameBg); + var frameColor = ImGuiColor.FrameBackground.Get().Color; using (var _ = ImRaii.Group()) { using (ImRaii.PushFont(UiBuilder.IconFont)) diff --git a/Penumbra/UI/Tabs/SettingsTab.cs b/Penumbra/UI/Tabs/SettingsTab.cs index 0e2c66df..08a3b472 100644 --- a/Penumbra/UI/Tabs/SettingsTab.cs +++ b/Penumbra/UI/Tabs/SettingsTab.cs @@ -242,7 +242,7 @@ public class SettingsTab : ITab, IUiService /// private bool DrawPressEnterWarning(string newName, string old, float width, bool saved, bool selected) { - using var color = ImRaii.PushColor(ImGuiCol.Button, Colors.PressEnterWarningBg); + using var color = ImGuiColor.Button.Push(Colors.PressEnterWarningBg); var w = new Vector2(width, 0); var (text, valid) = CheckRootDirectoryPath(newName, old, selected); @@ -339,10 +339,9 @@ public class SettingsTab : ITab, IUiService using (ImRaii.Group()) { ImGui.SetNextItemWidth(UiHelpers.InputTextMinusButton3); - using (ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, !_modManager.Valid)) + using (var color = ImStyleBorder.Frame.Push(Colors.RegexWarningBorder, Im.Style.GlobalScale, !_modManager.Valid)) { - using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder) - .Push(ImGuiCol.TextDisabled, Colors.RegexWarningBorder, !_modManager.Valid); + color.Push(ImGuiColor.TextDisabled, Colors.RegexWarningBorder, !_modManager.Valid); save = ImGui.InputTextWithHint("##rootDirectory", "Enter Root Directory here (MANDATORY)...", ref _newModDirectory, RootDirectoryMaxLength, ImGuiInputTextFlags.EnterReturnsTrue); }