From 694b42a378f338fb90e44ed40de06e908d66e46b Mon Sep 17 00:00:00 2001 From: srkizer Date: Mon, 5 Aug 2024 00:46:05 +0900 Subject: [PATCH] Fix UIColor handling per theme (#1995) UIColor sheet has color sets per theme. Updated `UIColorWidget` to reflect that, and added `SeStringDrawParams.ThemeIndex` to let users choose which theme color set to use while drawing SeString from Dalamud. --- Dalamud/Interface/ColorHelpers.cs | 6 + .../Internal/SeStringColorStackSet.cs | 60 ++++---- .../Internal/SeStringRenderer.cs | 46 ++++-- .../SeStringDrawParams.cs | 7 + .../SeStringDrawState.cs | 6 + .../Internal/Windows/Data/DataWindow.cs | 2 +- .../Widgets/SeStringRendererTestWidget.cs | 55 ++----- .../Windows/Data/Widgets/UIColorWidget.cs | 140 +++++++++++++++--- 8 files changed, 215 insertions(+), 107 deletions(-) diff --git a/Dalamud/Interface/ColorHelpers.cs b/Dalamud/Interface/ColorHelpers.cs index e99d80cd8..a3ae6799e 100644 --- a/Dalamud/Interface/ColorHelpers.cs +++ b/Dalamud/Interface/ColorHelpers.cs @@ -256,6 +256,12 @@ public static class ColorHelpers public static uint ApplyOpacity(uint rgba, float opacity) => ((uint)MathF.Round((rgba >> 24) * opacity) << 24) | (rgba & 0xFFFFFFu); + /// Swaps red and blue channels of a given color in ARGB(BB GG RR AA) and ABGR(RR GG BB AA). + /// Color to process. + /// Swapped color. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint SwapRedBlue(uint x) => (x & 0xFF00FF00u) | ((x >> 16) & 0xFF) | ((x & 0xFF) << 16); + /// /// Fade a color. /// diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs index 6d7b0a21a..dc99b7faa 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringColorStackSet.cs @@ -1,6 +1,5 @@ using System.Buffers.Binary; using System.Collections.Generic; -using System.Runtime.CompilerServices; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Component.Text; @@ -16,13 +15,9 @@ namespace Dalamud.Interface.ImGuiSeStringRenderer.Internal; /// Color stacks to use while evaluating a SeString. internal sealed class SeStringColorStackSet { - /// Parsed , containing colors to use with - /// . - private readonly uint[] colorTypes; - - /// Parsed , containing colors to use with + /// Parsed , containing colors to use with and /// . - private readonly uint[] edgeColorTypes; + private readonly uint[,] colorTypes; /// Foreground color stack while evaluating a SeString for rendering. /// Touched only from the main thread. @@ -38,28 +33,30 @@ internal sealed class SeStringColorStackSet /// Initializes a new instance of the class. /// UIColor sheet. - public SeStringColorStackSet(ExcelSheet uiColor) + public unsafe SeStringColorStackSet(ExcelSheet uiColor) { var maxId = 0; foreach (var row in uiColor) maxId = (int)Math.Max(row.RowId, maxId); - this.colorTypes = new uint[maxId + 1]; - this.edgeColorTypes = new uint[maxId + 1]; + this.colorTypes = new uint[maxId + 1, 4]; foreach (var row in uiColor) { // Contains ABGR. - this.colorTypes[row.RowId] = row.UIForeground; - this.edgeColorTypes[row.RowId] = row.UIGlow; + this.colorTypes[row.RowId, 0] = row.UIForeground; + this.colorTypes[row.RowId, 1] = row.UIGlow; + this.colorTypes[row.RowId, 2] = row.Unknown0; + this.colorTypes[row.RowId, 3] = row.Unknown1; } if (BitConverter.IsLittleEndian) { // ImGui wants RGBA in LE. - foreach (ref var r in this.colorTypes.AsSpan()) - r = BinaryPrimitives.ReverseEndianness(r); - foreach (ref var r in this.edgeColorTypes.AsSpan()) - r = BinaryPrimitives.ReverseEndianness(r); + fixed (uint* p = this.colorTypes) + { + foreach (ref var r in new Span(p, this.colorTypes.GetLength(0) * this.colorTypes.GetLength(1))) + r = BinaryPrimitives.ReverseEndianness(r); + } } } @@ -107,7 +104,8 @@ internal sealed class SeStringColorStackSet internal void HandleShadowColorPayload( scoped ref SeStringDrawState drawState, ReadOnlySePayloadSpan payload) => - drawState.ShadowColor = ColorHelpers.ApplyOpacity(AdjustStack(this.shadowColorStack, payload), drawState.Opacity); + drawState.ShadowColor = + ColorHelpers.ApplyOpacity(AdjustStack(this.shadowColorStack, payload), drawState.Opacity); /// Handles a payload. /// Draw state. @@ -115,7 +113,9 @@ internal sealed class SeStringColorStackSet internal void HandleColorTypePayload( scoped ref SeStringDrawState drawState, ReadOnlySePayloadSpan payload) => - drawState.Color = ColorHelpers.ApplyOpacity(AdjustStack(this.colorStack, this.colorTypes, payload), drawState.Opacity); + drawState.Color = ColorHelpers.ApplyOpacity( + this.AdjustStackByType(this.colorStack, payload, drawState.ThemeIndex), + drawState.Opacity); /// Handles a payload. /// Draw state. @@ -124,19 +124,13 @@ internal sealed class SeStringColorStackSet scoped ref SeStringDrawState drawState, ReadOnlySePayloadSpan payload) { - var newColor = AdjustStack(this.edgeColorStack, this.edgeColorTypes, payload); + var newColor = this.AdjustStackByType(this.edgeColorStack, payload, drawState.ThemeIndex); if (!drawState.ForceEdgeColor) drawState.EdgeColor = ColorHelpers.ApplyOpacity(newColor, drawState.EdgeOpacity); this.HasAdditionalEdgeColor = this.edgeColorStack.Count > 1; } - /// Swaps red and blue channels of a given color in ARGB(BB GG RR AA) and ABGR(RR GG BB AA). - /// Color to process. - /// Swapped color. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint SwapRedBlue(uint x) => (x & 0xFF00FF00u) | ((x >> 16) & 0xFF) | ((x & 0xFF) << 16); - private static unsafe uint AdjustStack(List rgbaStack, ReadOnlySePayloadSpan payload) { if (!payload.TryGetExpression(out var expr)) @@ -154,7 +148,10 @@ internal sealed class SeStringColorStackSet if (expr.TryGetUInt(out var bgra)) { - rgbaStack.Add(SwapRedBlue(bgra) | 0xFF000000u); + // NOTE: if it reads a `0`, then it seems to be doing something else. + // See case 0x12 from `Component::GUI::AtkFontAnalyzerBase.vf4`. + // Fix when someone figures what's this about. + rgbaStack.Add(ColorHelpers.SwapRedBlue(bgra) | 0xFF000000u); return rgbaStack[^1]; } @@ -166,7 +163,7 @@ internal sealed class SeStringColorStackSet i > 0 && i <= rtm->TextModule.MacroDecoder.GlobalParameters.Count && rtm->TextModule.MacroDecoder.GlobalParameters[i - 1] is { Type: TextParameterType.Integer } gp) { - rgbaStack.Add(SwapRedBlue((uint)gp.IntValue) | 0xFF000000u); + rgbaStack.Add(ColorHelpers.SwapRedBlue((uint)gp.IntValue) | 0xFF000000u); return rgbaStack[^1]; } @@ -175,13 +172,14 @@ internal sealed class SeStringColorStackSet return rgbaStack[^1]; } - private static uint AdjustStack(List rgbaStack, uint[] colorTypes, ReadOnlySePayloadSpan payload) + private uint AdjustStackByType(List rgbaStack, ReadOnlySePayloadSpan payload, int themeIndex) { if (!payload.TryGetExpression(out var expr)) return rgbaStack[^1]; if (!expr.TryGetUInt(out var colorTypeIndex)) return rgbaStack[^1]; + // Component::GUI::AtkFontAnalyzerBase.vf4: passing 0 will pop the color off the stack. if (colorTypeIndex == 0) { // First item in the stack is the color we started to draw with. @@ -191,8 +189,12 @@ internal sealed class SeStringColorStackSet } // Opacity component is ignored. - rgbaStack.Add((colorTypeIndex < colorTypes.Length ? colorTypes[colorTypeIndex] : 0u) | 0xFF000000u); + var color = themeIndex >= 0 && themeIndex < this.colorTypes.GetLength(1) && + colorTypeIndex < this.colorTypes.GetLength(0) + ? this.colorTypes[colorTypeIndex, themeIndex] + : 0u; + rgbaStack.Add(color | 0xFF000000u); return rgbaStack[^1]; } } diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs index 23b672a3b..bdd1f30d8 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs @@ -547,9 +547,8 @@ internal unsafe class SeStringRenderer : IInternalDisposableService Rune lastRune, int link) { - var gfdTextureSrv = - (nint)UIModule.Instance()->GetRaptureAtkModule()->AtkModule.AtkFontManager.Gfd->Texture-> - D3D11ShaderResourceView; + // This might temporarily return 0 while logging in. + var gfdTextureSrv = GetGfdTextureSrv(); var x = 0f; var width = 0f; foreach (var c in UtfEnumerator.From(span, UtfEnumeratorFlags.Utf8SeString)) @@ -569,13 +568,17 @@ internal unsafe class SeStringRenderer : IInternalDisposableService { var size = gfdEntry.CalculateScaledSize(state.FontSize, out var useHq); state.SetCurrentChannel(SeStringDrawChannel.Foreground); - state.Draw( - gfdTextureSrv, - offset + new Vector2(x, MathF.Round((state.LineHeight - size.Y) / 2)), - size, - useHq ? gfdEntry.HqUv0 : gfdEntry.Uv0, - useHq ? gfdEntry.HqUv1 : gfdEntry.Uv1, - ColorHelpers.ApplyOpacity(uint.MaxValue, state.Opacity)); + if (gfdTextureSrv != 0) + { + state.Draw( + gfdTextureSrv, + offset + new Vector2(x, MathF.Round((state.LineHeight - size.Y) / 2)), + size, + useHq ? gfdEntry.HqUv0 : gfdEntry.Uv0, + useHq ? gfdEntry.HqUv1 : gfdEntry.Uv1, + ColorHelpers.ApplyOpacity(uint.MaxValue, state.Opacity)); + } + if (link != -1) state.DrawLinkUnderline(offset + new Vector2(x, 0), size.X); @@ -602,6 +605,29 @@ internal unsafe class SeStringRenderer : IInternalDisposableService width = Math.Max(width, x + dist + (g.X1 * state.FontSizeScale)); x += dist + advanceWidth; } + + return; + + static nint GetGfdTextureSrv() + { + var uim = UIModule.Instance(); + if (uim is null) + return 0; + + var ram = uim->GetRaptureAtkModule(); + if (ram is null) + return 0; + + var gfd = ram->AtkModule.AtkFontManager.Gfd; + if (gfd is null) + return 0; + + var tex = gfd->Texture; + if (tex is null) + return 0; + + return (nint)tex->D3D11ShaderResourceView; + } } /// Determines a bitmap icon to display for the given SeString payload. diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawParams.cs b/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawParams.cs index cdd5e1db6..e03f60a32 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawParams.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawParams.cs @@ -56,6 +56,13 @@ public record struct SeStringDrawParams /// of 0.25f that might be subject to change in the future. public float? EdgeStrength { get; set; } + /// Gets or sets the theme that will decide the colors to use for + /// and . + /// 0 to use colors for Dark theme, 1 to use colors for Light theme, 2 to use colors + /// for Classic FF theme, 3 to use colors for Clear Blue theme, or null to use the theme set from the + /// game configuration. + public int? ThemeIndex { get; set; } + /// Gets or sets the color of the rendered text. /// Color in RGBA, or null to use (the default). public uint? Color { get; set; } diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs b/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs index d8348e5f2..5f95ac1b9 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs @@ -6,6 +6,8 @@ using System.Text; using Dalamud.Interface.ImGuiSeStringRenderer.Internal; using Dalamud.Interface.Utility; +using FFXIVClientStructs.FFXIV.Component.GUI; + using ImGuiNET; using Lumina.Text.Payloads; @@ -55,6 +57,7 @@ public unsafe ref struct SeStringDrawState this.LinkHoverBackColor = ssdp.LinkHoverBackColor ?? ImGui.GetColorU32(ImGuiCol.ButtonHovered); this.LinkActiveBackColor = ssdp.LinkActiveBackColor ?? ImGui.GetColorU32(ImGuiCol.ButtonActive); this.ForceEdgeColor = ssdp.ForceEdgeColor; + this.ThemeIndex = ssdp.ThemeIndex ?? AtkStage.Instance()->AtkUIColorHolder->ActiveColorThemeType; this.Bold = ssdp.Bold; this.Italic = ssdp.Italic; this.Edge = ssdp.Edge; @@ -100,6 +103,9 @@ public unsafe ref struct SeStringDrawState /// public float EdgeOpacity { get; } + /// + public int ThemeIndex { get; } + /// public uint Color { get; set; } diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs index 9e1464105..8115987a0 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs @@ -56,7 +56,7 @@ internal class DataWindow : Window, IDisposable new TaskSchedulerWidget(), new TexWidget(), new ToastWidget(), - new UIColorWidget(), + new UiColorWidget(), }; private readonly IOrderedEnumerable orderedModules; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs index d0dffce75..2119ebc4d 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs @@ -12,6 +12,8 @@ using Dalamud.Interface.Utility; using Dalamud.Storage.Assets; using Dalamud.Utility; +using FFXIVClientStructs.FFXIV.Component.GUI; + using ImGuiNET; using Lumina.Excel.GeneratedSheets2; @@ -28,10 +30,10 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal unsafe class SeStringRendererTestWidget : IDataWindowWidget { + private static readonly string[] ThemeNames = ["Dark", "Light", "Classic FF", "Clear Blue"]; private ImVectorWrapper testStringBuffer; private string testString = string.Empty; private Addon[]? addons; - private ReadOnlySeString? uicolor; private ReadOnlySeString? logkind; private SeStringDrawParams style; private bool interactable; @@ -51,7 +53,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget { this.style = new() { GetEntity = this.GetEntity }; this.addons = null; - this.uicolor = null; this.logkind = null; this.testString = string.Empty; this.interactable = this.useEntity = true; @@ -117,6 +118,12 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget if (ImGui.Checkbox("Shadow", ref t)) this.style.Shadow = t; + ImGui.SameLine(); + var t4 = this.style.ThemeIndex ?? AtkStage.Instance()->AtkUIColorHolder->ActiveColorThemeType; + ImGui.PushItemWidth(ImGui.CalcTextSize("WWWWWWWWWWWWWW").X); + if (ImGui.Combo("##theme", ref t4, ThemeNames, ThemeNames.Length)) + this.style.ThemeIndex = t4; + ImGui.SameLine(); t = this.style.LinkUnderlineThickness > 0f; if (ImGui.Checkbox("Link Underline", ref t)) @@ -136,50 +143,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget if (ImGui.Checkbox("Use Entity Replacements", ref t)) this.useEntity = t; - if (ImGui.CollapsingHeader("UIColor Preview")) - { - if (this.uicolor is null) - { - var tt = new SeStringBuilder(); - foreach (var uc in Service.Get().GetExcelSheet()!) - { - tt.Append($"#{uc.RowId}: ") - .BeginMacro(MacroCode.EdgeColorType).AppendUIntExpression(uc.RowId).EndMacro() - .Append("Edge ") - .BeginMacro(MacroCode.ColorType).AppendUIntExpression(uc.RowId).EndMacro() - .Append("Edge+Color ") - .BeginMacro(MacroCode.EdgeColorType).AppendUIntExpression(0).EndMacro() - .Append("Color ") - .BeginMacro(MacroCode.ColorType).AppendUIntExpression(0).EndMacro(); - if (uc.RowId >= 500) - { - if (uc.RowId % 2 == 0) - { - tt.BeginMacro(MacroCode.EdgeColorType).AppendUIntExpression(uc.RowId).EndMacro() - .BeginMacro(MacroCode.ColorType).AppendUIntExpression(uc.RowId + 1).EndMacro() - .Append($" => color#{uc.RowId + 1} + edge#{uc.RowId}") - .BeginMacro(MacroCode.EdgeColorType).AppendUIntExpression(0).EndMacro() - .BeginMacro(MacroCode.ColorType).AppendUIntExpression(0).EndMacro(); - } - else - { - tt.BeginMacro(MacroCode.EdgeColorType).AppendUIntExpression(uc.RowId).EndMacro() - .BeginMacro(MacroCode.ColorType).AppendUIntExpression(uc.RowId - 1).EndMacro() - .Append($" => color#{uc.RowId - 1} + edge#{uc.RowId}") - .BeginMacro(MacroCode.EdgeColorType).AppendUIntExpression(0).EndMacro() - .BeginMacro(MacroCode.ColorType).AppendUIntExpression(0).EndMacro(); - } - } - - tt.BeginMacro(MacroCode.NewLine).EndMacro(); - } - - this.uicolor = tt.ToReadOnlySeString(); - } - - ImGuiHelpers.SeStringWrapped(this.uicolor.Value.Data.Span, this.style); - } - if (ImGui.CollapsingHeader("LogKind Preview")) { if (this.logkind is null) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index 1f8b4c62c..b3e7346df 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -1,8 +1,13 @@ -using System.Numerics; +using System.Buffers.Binary; +using System.Linq; +using System.Numerics; using Dalamud.Data; +using Dalamud.Interface.ImGuiSeStringRenderer.Internal; +using Dalamud.Storage.Assets; using ImGuiNET; + using Lumina.Excel.GeneratedSheets; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -10,13 +15,15 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// /// Widget for displaying all UI Colors from Lumina. /// -internal class UIColorWidget : IDataWindowWidget +internal class UiColorWidget : IDataWindowWidget { + private UIColor[]? colors; + /// - public string[]? CommandShortcuts { get; init; } = { "uicolor" }; - + public string[]? CommandShortcuts { get; init; } = ["uicolor"]; + /// - public string DisplayName { get; init; } = "UIColor"; + public string DisplayName { get; init; } = "UIColor"; /// public bool Ready { get; set; } @@ -25,33 +32,124 @@ internal class UIColorWidget : IDataWindowWidget public void Load() { this.Ready = true; + this.colors = null; } /// - public void Draw() + public unsafe void Draw() { - var colorSheet = Service.Get().GetExcelSheet(); - if (colorSheet is null) return; + this.colors ??= Service.Get().GetExcelSheet()?.ToArray(); + if (this.colors is null) return; - foreach (var color in colorSheet) + ImGui.TextUnformatted("Color notation is #RRGGBB."); + if (!ImGui.BeginTable("UIColor", 5)) + return; + + ImGui.TableSetupScrollFreeze(0, 1); + var basew = ImGui.CalcTextSize("9").X; + ImGui.TableSetupColumn("Row ID", ImGuiTableColumnFlags.WidthFixed, basew * 7); + ImGui.TableSetupColumn("Dark", ImGuiTableColumnFlags.WidthFixed, basew * 17); + ImGui.TableSetupColumn("Light", ImGuiTableColumnFlags.WidthFixed, basew * 17); + ImGui.TableSetupColumn("Classic FF", ImGuiTableColumnFlags.WidthFixed, basew * 17); + ImGui.TableSetupColumn("Clear Blue", ImGuiTableColumnFlags.WidthFixed, basew * 17); + ImGui.TableHeadersRow(); + + var clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper()); + clipper.Begin(this.colors.Length); + while (clipper.Step()) { - this.DrawUiColor(color); + for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + { + var id = this.colors[i].RowId; + ImGui.TableNextRow(); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted($"{id}"); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.PushID($"row{id}_col1"); + DrawColorColumn(this.colors[i].UIForeground); + if (id is >= 500 and < 580) + DrawEdgePreview(id, this.colors[i].UIForeground, this.colors[i + 1].UIForeground); + ImGui.PopID(); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.PushID($"row{id}_col2"); + DrawColorColumn(this.colors[i].UIGlow); + if (id is >= 500 and < 580) + DrawEdgePreview(id, this.colors[i].UIGlow, this.colors[i + 1].UIGlow); + ImGui.PopID(); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.PushID($"row{id}_col3"); + DrawColorColumn(this.colors[i].Unknown2); + if (id is >= 500 and < 580) + DrawEdgePreview(id, this.colors[i].Unknown2, this.colors[i + 1].Unknown2); + ImGui.PopID(); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.PushID($"row{id}_col4"); + DrawColorColumn(this.colors[i].Unknown3); + if (id is >= 500 and < 580) + DrawEdgePreview(id, this.colors[i].Unknown3, this.colors[i + 1].Unknown3); + ImGui.PopID(); + } } + + clipper.Destroy(); + ImGui.EndTable(); } - - private void DrawUiColor(UIColor color) + + private static void DrawColorColumn(uint sheetColor) { - ImGui.Text($"[{color.RowId:D3}] "); + sheetColor = BinaryPrimitives.ReverseEndianness(sheetColor); + ImGui.Image( + Service.Get().White4X4.ImGuiHandle, + new(ImGui.GetFrameHeight()), + Vector2.Zero, + Vector2.One, + ImGui.ColorConvertU32ToFloat4(sheetColor | 0xFF000000u)); ImGui.SameLine(); - ImGui.TextColored(this.ConvertToVector4(color.Unknown2), $"Unknown2 "); - ImGui.SameLine(); - ImGui.TextColored(this.ConvertToVector4(color.UIForeground), "UIForeground "); - ImGui.SameLine(); - ImGui.TextColored(this.ConvertToVector4(color.Unknown3), "Unknown3 "); - ImGui.SameLine(); - ImGui.TextColored(this.ConvertToVector4(color.UIGlow), "UIGlow"); + ImGui.TextUnformatted($"#{sheetColor & 0xFF:X02}{(sheetColor >> 8) & 0xFF:X02}{(sheetColor >> 16) & 0xFF:X02}"); } - + + private static void DrawEdgePreview(uint id, uint sheetColor, uint sheetColor2) + { + ImGui.SameLine(); + if (Service.Get().Draw( + new("+E"u8), + new() + { + Edge = true, + Color = BinaryPrimitives.ReverseEndianness(sheetColor) | 0xFF000000u, + EdgeColor = BinaryPrimitives.ReverseEndianness(sheetColor2) | 0xFF000000u, + }, + "+E"u8).Clicked) + ImGui.SetClipboardText($"+E"); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip($"+E"); + + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + if (Service.Get().Draw( + new("+F"u8), + new() + { + Edge = true, + Color = BinaryPrimitives.ReverseEndianness(sheetColor2) | 0xFF000000u, + EdgeColor = BinaryPrimitives.ReverseEndianness(sheetColor) | 0xFF000000u, + }, + "+F"u8).Clicked) + ImGui.SetClipboardText($"+E"); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip($"+E"); + } + private Vector4 ConvertToVector4(uint color) { var r = (byte)(color >> 24);