mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-13 20:24:16 +01:00
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.
This commit is contained in:
parent
eb2724f366
commit
694b42a378
8 changed files with 215 additions and 107 deletions
|
|
@ -256,6 +256,12 @@ public static class ColorHelpers
|
||||||
public static uint ApplyOpacity(uint rgba, float opacity) =>
|
public static uint ApplyOpacity(uint rgba, float opacity) =>
|
||||||
((uint)MathF.Round((rgba >> 24) * opacity) << 24) | (rgba & 0xFFFFFFu);
|
((uint)MathF.Round((rgba >> 24) * opacity) << 24) | (rgba & 0xFFFFFFu);
|
||||||
|
|
||||||
|
/// <summary>Swaps red and blue channels of a given color in ARGB(BB GG RR AA) and ABGR(RR GG BB AA).</summary>
|
||||||
|
/// <param name="x">Color to process.</param>
|
||||||
|
/// <returns>Swapped color.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static uint SwapRedBlue(uint x) => (x & 0xFF00FF00u) | ((x >> 16) & 0xFF) | ((x & 0xFF) << 16);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fade a color.
|
/// Fade a color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
using FFXIVClientStructs.FFXIV.Component.Text;
|
using FFXIVClientStructs.FFXIV.Component.Text;
|
||||||
|
|
@ -16,13 +15,9 @@ namespace Dalamud.Interface.ImGuiSeStringRenderer.Internal;
|
||||||
/// <summary>Color stacks to use while evaluating a SeString.</summary>
|
/// <summary>Color stacks to use while evaluating a SeString.</summary>
|
||||||
internal sealed class SeStringColorStackSet
|
internal sealed class SeStringColorStackSet
|
||||||
{
|
{
|
||||||
/// <summary>Parsed <see cref="UIColor.UIForeground"/>, containing colors to use with
|
/// <summary>Parsed <see cref="UIColor"/>, containing colors to use with <see cref="MacroCode.ColorType"/> and
|
||||||
/// <see cref="MacroCode.ColorType"/>.</summary>
|
|
||||||
private readonly uint[] colorTypes;
|
|
||||||
|
|
||||||
/// <summary>Parsed <see cref="UIColor.UIGlow"/>, containing colors to use with
|
|
||||||
/// <see cref="MacroCode.EdgeColorType"/>.</summary>
|
/// <see cref="MacroCode.EdgeColorType"/>.</summary>
|
||||||
private readonly uint[] edgeColorTypes;
|
private readonly uint[,] colorTypes;
|
||||||
|
|
||||||
/// <summary>Foreground color stack while evaluating a SeString for rendering.</summary>
|
/// <summary>Foreground color stack while evaluating a SeString for rendering.</summary>
|
||||||
/// <remarks>Touched only from the main thread.</remarks>
|
/// <remarks>Touched only from the main thread.</remarks>
|
||||||
|
|
@ -38,28 +33,30 @@ internal sealed class SeStringColorStackSet
|
||||||
|
|
||||||
/// <summary>Initializes a new instance of the <see cref="SeStringColorStackSet"/> class.</summary>
|
/// <summary>Initializes a new instance of the <see cref="SeStringColorStackSet"/> class.</summary>
|
||||||
/// <param name="uiColor">UIColor sheet.</param>
|
/// <param name="uiColor">UIColor sheet.</param>
|
||||||
public SeStringColorStackSet(ExcelSheet<UIColor> uiColor)
|
public unsafe SeStringColorStackSet(ExcelSheet<UIColor> uiColor)
|
||||||
{
|
{
|
||||||
var maxId = 0;
|
var maxId = 0;
|
||||||
foreach (var row in uiColor)
|
foreach (var row in uiColor)
|
||||||
maxId = (int)Math.Max(row.RowId, maxId);
|
maxId = (int)Math.Max(row.RowId, maxId);
|
||||||
|
|
||||||
this.colorTypes = new uint[maxId + 1];
|
this.colorTypes = new uint[maxId + 1, 4];
|
||||||
this.edgeColorTypes = new uint[maxId + 1];
|
|
||||||
foreach (var row in uiColor)
|
foreach (var row in uiColor)
|
||||||
{
|
{
|
||||||
// Contains ABGR.
|
// Contains ABGR.
|
||||||
this.colorTypes[row.RowId] = row.UIForeground;
|
this.colorTypes[row.RowId, 0] = row.UIForeground;
|
||||||
this.edgeColorTypes[row.RowId] = row.UIGlow;
|
this.colorTypes[row.RowId, 1] = row.UIGlow;
|
||||||
|
this.colorTypes[row.RowId, 2] = row.Unknown0;
|
||||||
|
this.colorTypes[row.RowId, 3] = row.Unknown1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
// ImGui wants RGBA in LE.
|
// ImGui wants RGBA in LE.
|
||||||
foreach (ref var r in this.colorTypes.AsSpan())
|
fixed (uint* p = this.colorTypes)
|
||||||
r = BinaryPrimitives.ReverseEndianness(r);
|
{
|
||||||
foreach (ref var r in this.edgeColorTypes.AsSpan())
|
foreach (ref var r in new Span<uint>(p, this.colorTypes.GetLength(0) * this.colorTypes.GetLength(1)))
|
||||||
r = BinaryPrimitives.ReverseEndianness(r);
|
r = BinaryPrimitives.ReverseEndianness(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,7 +104,8 @@ internal sealed class SeStringColorStackSet
|
||||||
internal void HandleShadowColorPayload(
|
internal void HandleShadowColorPayload(
|
||||||
scoped ref SeStringDrawState drawState,
|
scoped ref SeStringDrawState drawState,
|
||||||
ReadOnlySePayloadSpan payload) =>
|
ReadOnlySePayloadSpan payload) =>
|
||||||
drawState.ShadowColor = ColorHelpers.ApplyOpacity(AdjustStack(this.shadowColorStack, payload), drawState.Opacity);
|
drawState.ShadowColor =
|
||||||
|
ColorHelpers.ApplyOpacity(AdjustStack(this.shadowColorStack, payload), drawState.Opacity);
|
||||||
|
|
||||||
/// <summary>Handles a <see cref="MacroCode.ColorType"/> payload.</summary>
|
/// <summary>Handles a <see cref="MacroCode.ColorType"/> payload.</summary>
|
||||||
/// <param name="drawState">Draw state.</param>
|
/// <param name="drawState">Draw state.</param>
|
||||||
|
|
@ -115,7 +113,9 @@ internal sealed class SeStringColorStackSet
|
||||||
internal void HandleColorTypePayload(
|
internal void HandleColorTypePayload(
|
||||||
scoped ref SeStringDrawState drawState,
|
scoped ref SeStringDrawState drawState,
|
||||||
ReadOnlySePayloadSpan payload) =>
|
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);
|
||||||
|
|
||||||
/// <summary>Handles a <see cref="MacroCode.EdgeColorType"/> payload.</summary>
|
/// <summary>Handles a <see cref="MacroCode.EdgeColorType"/> payload.</summary>
|
||||||
/// <param name="drawState">Draw state.</param>
|
/// <param name="drawState">Draw state.</param>
|
||||||
|
|
@ -124,19 +124,13 @@ internal sealed class SeStringColorStackSet
|
||||||
scoped ref SeStringDrawState drawState,
|
scoped ref SeStringDrawState drawState,
|
||||||
ReadOnlySePayloadSpan payload)
|
ReadOnlySePayloadSpan payload)
|
||||||
{
|
{
|
||||||
var newColor = AdjustStack(this.edgeColorStack, this.edgeColorTypes, payload);
|
var newColor = this.AdjustStackByType(this.edgeColorStack, payload, drawState.ThemeIndex);
|
||||||
if (!drawState.ForceEdgeColor)
|
if (!drawState.ForceEdgeColor)
|
||||||
drawState.EdgeColor = ColorHelpers.ApplyOpacity(newColor, drawState.EdgeOpacity);
|
drawState.EdgeColor = ColorHelpers.ApplyOpacity(newColor, drawState.EdgeOpacity);
|
||||||
|
|
||||||
this.HasAdditionalEdgeColor = this.edgeColorStack.Count > 1;
|
this.HasAdditionalEdgeColor = this.edgeColorStack.Count > 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Swaps red and blue channels of a given color in ARGB(BB GG RR AA) and ABGR(RR GG BB AA).</summary>
|
|
||||||
/// <param name="x">Color to process.</param>
|
|
||||||
/// <returns>Swapped color.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static uint SwapRedBlue(uint x) => (x & 0xFF00FF00u) | ((x >> 16) & 0xFF) | ((x & 0xFF) << 16);
|
|
||||||
|
|
||||||
private static unsafe uint AdjustStack(List<uint> rgbaStack, ReadOnlySePayloadSpan payload)
|
private static unsafe uint AdjustStack(List<uint> rgbaStack, ReadOnlySePayloadSpan payload)
|
||||||
{
|
{
|
||||||
if (!payload.TryGetExpression(out var expr))
|
if (!payload.TryGetExpression(out var expr))
|
||||||
|
|
@ -154,7 +148,10 @@ internal sealed class SeStringColorStackSet
|
||||||
|
|
||||||
if (expr.TryGetUInt(out var bgra))
|
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];
|
return rgbaStack[^1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +163,7 @@ internal sealed class SeStringColorStackSet
|
||||||
i > 0 && i <= rtm->TextModule.MacroDecoder.GlobalParameters.Count &&
|
i > 0 && i <= rtm->TextModule.MacroDecoder.GlobalParameters.Count &&
|
||||||
rtm->TextModule.MacroDecoder.GlobalParameters[i - 1] is { Type: TextParameterType.Integer } gp)
|
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];
|
return rgbaStack[^1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,13 +172,14 @@ internal sealed class SeStringColorStackSet
|
||||||
return rgbaStack[^1];
|
return rgbaStack[^1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uint AdjustStack(List<uint> rgbaStack, uint[] colorTypes, ReadOnlySePayloadSpan payload)
|
private uint AdjustStackByType(List<uint> rgbaStack, ReadOnlySePayloadSpan payload, int themeIndex)
|
||||||
{
|
{
|
||||||
if (!payload.TryGetExpression(out var expr))
|
if (!payload.TryGetExpression(out var expr))
|
||||||
return rgbaStack[^1];
|
return rgbaStack[^1];
|
||||||
if (!expr.TryGetUInt(out var colorTypeIndex))
|
if (!expr.TryGetUInt(out var colorTypeIndex))
|
||||||
return rgbaStack[^1];
|
return rgbaStack[^1];
|
||||||
|
|
||||||
|
// Component::GUI::AtkFontAnalyzerBase.vf4: passing 0 will pop the color off the stack.
|
||||||
if (colorTypeIndex == 0)
|
if (colorTypeIndex == 0)
|
||||||
{
|
{
|
||||||
// First item in the stack is the color we started to draw with.
|
// 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.
|
// 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];
|
return rgbaStack[^1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -547,9 +547,8 @@ internal unsafe class SeStringRenderer : IInternalDisposableService
|
||||||
Rune lastRune,
|
Rune lastRune,
|
||||||
int link)
|
int link)
|
||||||
{
|
{
|
||||||
var gfdTextureSrv =
|
// This might temporarily return 0 while logging in.
|
||||||
(nint)UIModule.Instance()->GetRaptureAtkModule()->AtkModule.AtkFontManager.Gfd->Texture->
|
var gfdTextureSrv = GetGfdTextureSrv();
|
||||||
D3D11ShaderResourceView;
|
|
||||||
var x = 0f;
|
var x = 0f;
|
||||||
var width = 0f;
|
var width = 0f;
|
||||||
foreach (var c in UtfEnumerator.From(span, UtfEnumeratorFlags.Utf8SeString))
|
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);
|
var size = gfdEntry.CalculateScaledSize(state.FontSize, out var useHq);
|
||||||
state.SetCurrentChannel(SeStringDrawChannel.Foreground);
|
state.SetCurrentChannel(SeStringDrawChannel.Foreground);
|
||||||
state.Draw(
|
if (gfdTextureSrv != 0)
|
||||||
gfdTextureSrv,
|
{
|
||||||
offset + new Vector2(x, MathF.Round((state.LineHeight - size.Y) / 2)),
|
state.Draw(
|
||||||
size,
|
gfdTextureSrv,
|
||||||
useHq ? gfdEntry.HqUv0 : gfdEntry.Uv0,
|
offset + new Vector2(x, MathF.Round((state.LineHeight - size.Y) / 2)),
|
||||||
useHq ? gfdEntry.HqUv1 : gfdEntry.Uv1,
|
size,
|
||||||
ColorHelpers.ApplyOpacity(uint.MaxValue, state.Opacity));
|
useHq ? gfdEntry.HqUv0 : gfdEntry.Uv0,
|
||||||
|
useHq ? gfdEntry.HqUv1 : gfdEntry.Uv1,
|
||||||
|
ColorHelpers.ApplyOpacity(uint.MaxValue, state.Opacity));
|
||||||
|
}
|
||||||
|
|
||||||
if (link != -1)
|
if (link != -1)
|
||||||
state.DrawLinkUnderline(offset + new Vector2(x, 0), size.X);
|
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));
|
width = Math.Max(width, x + dist + (g.X1 * state.FontSizeScale));
|
||||||
x += dist + advanceWidth;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Determines a bitmap icon to display for the given SeString payload.</summary>
|
/// <summary>Determines a bitmap icon to display for the given SeString payload.</summary>
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,13 @@ public record struct SeStringDrawParams
|
||||||
/// of <c>0.25f</c> that might be subject to change in the future.</value>
|
/// of <c>0.25f</c> that might be subject to change in the future.</value>
|
||||||
public float? EdgeStrength { get; set; }
|
public float? EdgeStrength { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Gets or sets the theme that will decide the colors to use for <see cref="MacroCode.ColorType"/>
|
||||||
|
/// and <see cref="MacroCode.EdgeColorType"/>.</summary>
|
||||||
|
/// <value><c>0</c> to use colors for Dark theme, <c>1</c> to use colors for Light theme, <c>2</c> to use colors
|
||||||
|
/// for Classic FF theme, <c>3</c> to use colors for Clear Blue theme, or <c>null</c> to use the theme set from the
|
||||||
|
/// game configuration.</value>
|
||||||
|
public int? ThemeIndex { get; set; }
|
||||||
|
|
||||||
/// <summary>Gets or sets the color of the rendered text.</summary>
|
/// <summary>Gets or sets the color of the rendered text.</summary>
|
||||||
/// <value>Color in RGBA, or <c>null</c> to use <see cref="ImGuiCol.Text"/> (the default).</value>
|
/// <value>Color in RGBA, or <c>null</c> to use <see cref="ImGuiCol.Text"/> (the default).</value>
|
||||||
public uint? Color { get; set; }
|
public uint? Color { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ using System.Text;
|
||||||
using Dalamud.Interface.ImGuiSeStringRenderer.Internal;
|
using Dalamud.Interface.ImGuiSeStringRenderer.Internal;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
using Lumina.Text.Payloads;
|
using Lumina.Text.Payloads;
|
||||||
|
|
@ -55,6 +57,7 @@ public unsafe ref struct SeStringDrawState
|
||||||
this.LinkHoverBackColor = ssdp.LinkHoverBackColor ?? ImGui.GetColorU32(ImGuiCol.ButtonHovered);
|
this.LinkHoverBackColor = ssdp.LinkHoverBackColor ?? ImGui.GetColorU32(ImGuiCol.ButtonHovered);
|
||||||
this.LinkActiveBackColor = ssdp.LinkActiveBackColor ?? ImGui.GetColorU32(ImGuiCol.ButtonActive);
|
this.LinkActiveBackColor = ssdp.LinkActiveBackColor ?? ImGui.GetColorU32(ImGuiCol.ButtonActive);
|
||||||
this.ForceEdgeColor = ssdp.ForceEdgeColor;
|
this.ForceEdgeColor = ssdp.ForceEdgeColor;
|
||||||
|
this.ThemeIndex = ssdp.ThemeIndex ?? AtkStage.Instance()->AtkUIColorHolder->ActiveColorThemeType;
|
||||||
this.Bold = ssdp.Bold;
|
this.Bold = ssdp.Bold;
|
||||||
this.Italic = ssdp.Italic;
|
this.Italic = ssdp.Italic;
|
||||||
this.Edge = ssdp.Edge;
|
this.Edge = ssdp.Edge;
|
||||||
|
|
@ -100,6 +103,9 @@ public unsafe ref struct SeStringDrawState
|
||||||
/// <inheritdoc cref="SeStringDrawParams.EdgeStrength"/>
|
/// <inheritdoc cref="SeStringDrawParams.EdgeStrength"/>
|
||||||
public float EdgeOpacity { get; }
|
public float EdgeOpacity { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="SeStringDrawParams.ThemeIndex"/>
|
||||||
|
public int ThemeIndex { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="SeStringDrawParams.Color"/>
|
/// <inheritdoc cref="SeStringDrawParams.Color"/>
|
||||||
public uint Color { get; set; }
|
public uint Color { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ internal class DataWindow : Window, IDisposable
|
||||||
new TaskSchedulerWidget(),
|
new TaskSchedulerWidget(),
|
||||||
new TexWidget(),
|
new TexWidget(),
|
||||||
new ToastWidget(),
|
new ToastWidget(),
|
||||||
new UIColorWidget(),
|
new UiColorWidget(),
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly IOrderedEnumerable<IDataWindowWidget> orderedModules;
|
private readonly IOrderedEnumerable<IDataWindowWidget> orderedModules;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Storage.Assets;
|
using Dalamud.Storage.Assets;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
using Lumina.Excel.GeneratedSheets2;
|
using Lumina.Excel.GeneratedSheets2;
|
||||||
|
|
@ -28,10 +30,10 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
|
internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
|
||||||
{
|
{
|
||||||
|
private static readonly string[] ThemeNames = ["Dark", "Light", "Classic FF", "Clear Blue"];
|
||||||
private ImVectorWrapper<byte> testStringBuffer;
|
private ImVectorWrapper<byte> testStringBuffer;
|
||||||
private string testString = string.Empty;
|
private string testString = string.Empty;
|
||||||
private Addon[]? addons;
|
private Addon[]? addons;
|
||||||
private ReadOnlySeString? uicolor;
|
|
||||||
private ReadOnlySeString? logkind;
|
private ReadOnlySeString? logkind;
|
||||||
private SeStringDrawParams style;
|
private SeStringDrawParams style;
|
||||||
private bool interactable;
|
private bool interactable;
|
||||||
|
|
@ -51,7 +53,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
|
||||||
{
|
{
|
||||||
this.style = new() { GetEntity = this.GetEntity };
|
this.style = new() { GetEntity = this.GetEntity };
|
||||||
this.addons = null;
|
this.addons = null;
|
||||||
this.uicolor = null;
|
|
||||||
this.logkind = null;
|
this.logkind = null;
|
||||||
this.testString = string.Empty;
|
this.testString = string.Empty;
|
||||||
this.interactable = this.useEntity = true;
|
this.interactable = this.useEntity = true;
|
||||||
|
|
@ -117,6 +118,12 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
|
||||||
if (ImGui.Checkbox("Shadow", ref t))
|
if (ImGui.Checkbox("Shadow", ref t))
|
||||||
this.style.Shadow = 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();
|
ImGui.SameLine();
|
||||||
t = this.style.LinkUnderlineThickness > 0f;
|
t = this.style.LinkUnderlineThickness > 0f;
|
||||||
if (ImGui.Checkbox("Link Underline", ref t))
|
if (ImGui.Checkbox("Link Underline", ref t))
|
||||||
|
|
@ -136,50 +143,6 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget
|
||||||
if (ImGui.Checkbox("Use Entity Replacements", ref t))
|
if (ImGui.Checkbox("Use Entity Replacements", ref t))
|
||||||
this.useEntity = t;
|
this.useEntity = t;
|
||||||
|
|
||||||
if (ImGui.CollapsingHeader("UIColor Preview"))
|
|
||||||
{
|
|
||||||
if (this.uicolor is null)
|
|
||||||
{
|
|
||||||
var tt = new SeStringBuilder();
|
|
||||||
foreach (var uc in Service<DataManager>.Get().GetExcelSheet<UIColor>()!)
|
|
||||||
{
|
|
||||||
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 (ImGui.CollapsingHeader("LogKind Preview"))
|
||||||
{
|
{
|
||||||
if (this.logkind is null)
|
if (this.logkind is null)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
using System.Numerics;
|
using System.Buffers.Binary;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
using Dalamud.Data;
|
using Dalamud.Data;
|
||||||
|
using Dalamud.Interface.ImGuiSeStringRenderer.Internal;
|
||||||
|
using Dalamud.Storage.Assets;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||||
|
|
@ -10,10 +15,12 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Widget for displaying all UI Colors from Lumina.
|
/// Widget for displaying all UI Colors from Lumina.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class UIColorWidget : IDataWindowWidget
|
internal class UiColorWidget : IDataWindowWidget
|
||||||
{
|
{
|
||||||
|
private UIColor[]? colors;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string[]? CommandShortcuts { get; init; } = { "uicolor" };
|
public string[]? CommandShortcuts { get; init; } = ["uicolor"];
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string DisplayName { get; init; } = "UIColor";
|
public string DisplayName { get; init; } = "UIColor";
|
||||||
|
|
@ -25,31 +32,122 @@ internal class UIColorWidget : IDataWindowWidget
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
this.Ready = true;
|
this.Ready = true;
|
||||||
|
this.colors = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Draw()
|
public unsafe void Draw()
|
||||||
{
|
{
|
||||||
var colorSheet = Service<DataManager>.Get().GetExcelSheet<UIColor>();
|
this.colors ??= Service<DataManager>.Get().GetExcelSheet<UIColor>()?.ToArray();
|
||||||
if (colorSheet is null) return;
|
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<DalamudAssetManager>.Get().White4X4.ImGuiHandle,
|
||||||
|
new(ImGui.GetFrameHeight()),
|
||||||
|
Vector2.Zero,
|
||||||
|
Vector2.One,
|
||||||
|
ImGui.ColorConvertU32ToFloat4(sheetColor | 0xFF000000u));
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.TextColored(this.ConvertToVector4(color.Unknown2), $"Unknown2 ");
|
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();
|
ImGui.SameLine();
|
||||||
ImGui.TextColored(this.ConvertToVector4(color.UIForeground), "UIForeground ");
|
if (Service<SeStringRenderer>.Get().Draw(
|
||||||
|
new("+E"u8),
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Edge = true,
|
||||||
|
Color = BinaryPrimitives.ReverseEndianness(sheetColor) | 0xFF000000u,
|
||||||
|
EdgeColor = BinaryPrimitives.ReverseEndianness(sheetColor2) | 0xFF000000u,
|
||||||
|
},
|
||||||
|
"+E"u8).Clicked)
|
||||||
|
ImGui.SetClipboardText($"<colortype({id})><edgecolortype({id + 1})>+E<edgecolortype(0)><colortype(0)>");
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip($"<colortype({id})><edgecolortype({id + 1})>+E<edgecolortype(0)><colortype(0)>");
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.TextColored(this.ConvertToVector4(color.Unknown3), "Unknown3 ");
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.SameLine();
|
if (Service<SeStringRenderer>.Get().Draw(
|
||||||
ImGui.TextColored(this.ConvertToVector4(color.UIGlow), "UIGlow");
|
new("+F"u8),
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Edge = true,
|
||||||
|
Color = BinaryPrimitives.ReverseEndianness(sheetColor2) | 0xFF000000u,
|
||||||
|
EdgeColor = BinaryPrimitives.ReverseEndianness(sheetColor) | 0xFF000000u,
|
||||||
|
},
|
||||||
|
"+F"u8).Clicked)
|
||||||
|
ImGui.SetClipboardText($"<colortype({id + 1})><edgecolortype({id})>+E<edgecolortype(0)><colortype(0)>");
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip($"<colortype({id + 1})><edgecolortype({id})>+E<edgecolortype(0)><colortype(0)>");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector4 ConvertToVector4(uint color)
|
private Vector4 ConvertToVector4(uint color)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue