mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-13 12:14:16 +01:00
Minor interface adjustments (#2121)
- Further ImRaii safety in UiDebug2 - Set some mistakenly internal methods in ImGuiComponents to public - Added SpanFullWidth flag to trees in Util.ShowStruct
This commit is contained in:
parent
de999b7895
commit
c950b15a22
18 changed files with 282 additions and 264 deletions
|
|
@ -270,7 +270,7 @@ public static partial class ImGuiComponents
|
|||
/// <param name="icon">Icon to use.</param>
|
||||
/// <param name="text">Text to use.</param>
|
||||
/// <returns>Width.</returns>
|
||||
internal static float GetIconButtonWithTextWidth(FontAwesomeIcon icon, string text)
|
||||
public static float GetIconButtonWithTextWidth(FontAwesomeIcon icon, string text)
|
||||
{
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public static partial class ImGuiComponents
|
|||
/// <param name="activeColor">The color of the actively-selected button.</param>
|
||||
/// <param name="hoveredColor">The color of the buttons when hovered.</param>
|
||||
/// <returns>True if any button is clicked.</returns>
|
||||
internal static bool IconButtonSelect<T>(string label, ref T val, IEnumerable<FontAwesomeIcon> optionIcons, IEnumerable<T> optionValues, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
public static bool IconButtonSelect<T>(string label, ref T val, IEnumerable<FontAwesomeIcon> optionIcons, IEnumerable<T> optionValues, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
{
|
||||
var options = optionIcons.Zip(optionValues, static (icon, value) => new KeyValuePair<FontAwesomeIcon, T>(icon, value));
|
||||
return IconButtonSelect(label, ref val, options, columns, buttonSize, defaultColor, activeColor, hoveredColor);
|
||||
|
|
@ -43,7 +43,7 @@ public static partial class ImGuiComponents
|
|||
/// <param name="activeColor">The color of the actively-selected button.</param>
|
||||
/// <param name="hoveredColor">The color of the buttons when hovered.</param>
|
||||
/// <returns>True if any button is clicked.</returns>
|
||||
internal static unsafe bool IconButtonSelect<T>(string label, ref T val, IEnumerable<KeyValuePair<FontAwesomeIcon, T>> options, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
public static unsafe bool IconButtonSelect<T>(string label, ref T val, IEnumerable<KeyValuePair<FontAwesomeIcon, T>> options, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
|
||||
{
|
||||
defaultColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.Button);
|
||||
activeColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.ButtonActive);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
|
|||
|
||||
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
|
||||
|
||||
/// <inheritdoc cref="AddonTree"/>
|
||||
public unsafe partial class AddonTree
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -23,12 +24,11 @@ public unsafe partial class AddonTree
|
|||
if (addon->AtkValuesCount > 0 && atkValue != null)
|
||||
{
|
||||
using var tree = ImRaii.TreeNode($"Atk Values [{addon->AtkValuesCount}]###atkValues_{addon->NameString}");
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
using (ImRaii.Table(
|
||||
"atkUnitBase_atkValueTable",
|
||||
3,
|
||||
ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg))
|
||||
using var tbl = ImRaii.Table("atkUnitBase_atkValueTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
|
||||
|
||||
if (tbl.Success)
|
||||
{
|
||||
ImGui.TableSetupColumn("Index");
|
||||
ImGui.TableSetupColumn("Type");
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@ public static class Events
|
|||
|
||||
using var tree = ImRaii.TreeNode($"Events##{(nint)node:X}eventTree");
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
using (ImRaii.Table($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg))
|
||||
using var tbl = ImRaii.Table($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg);
|
||||
|
||||
if (tbl.Success)
|
||||
{
|
||||
ImGui.TableSetupColumn("#", WidthFixed);
|
||||
ImGui.TableSetupColumn("Type", WidthFixed);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ internal unsafe partial class ResNodeTree
|
|||
/// </summary>
|
||||
private protected void DrawNodeEditorTable()
|
||||
{
|
||||
using (ImRaii.Table($"###Editor{(nint)this.Node}", 2, SizingStretchProp | NoHostExtendX))
|
||||
using var tbl = ImRaii.Table($"###Editor{(nint)this.Node}", 2, SizingStretchProp | NoHostExtendX);
|
||||
if (tbl.Success)
|
||||
{
|
||||
this.DrawEditorRows();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
|
|||
|
||||
using var tree = ImRaii.TreeNode($"Texture##texture{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", SpanFullWidth);
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
PrintFieldValuePairs(
|
||||
("Texture Type", $"{this.TexData.TexType}"),
|
||||
|
|
@ -189,7 +189,8 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
|
|||
|
||||
private void PrintPartsTable()
|
||||
{
|
||||
using (ImRaii.Table($"partsTable##{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", 3, Borders | RowBg | Reorderable))
|
||||
using var tbl = ImRaii.Table($"partsTable##{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", 3, Borders | RowBg | Reorderable);
|
||||
if (tbl.Success)
|
||||
{
|
||||
ImGui.TableSetupColumn("Part ID", WidthFixed);
|
||||
ImGui.TableSetupColumn("Part Texture", WidthFixed);
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
using System.Numerics;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui;
|
||||
|
||||
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
|
||||
|
||||
/// <inheritdoc cref="NineGridNodeTree"/>
|
||||
internal unsafe partial class NineGridNodeTree
|
||||
{
|
||||
/// <summary>
|
||||
/// A struct representing the four offsets of an <see cref="AtkNineGridNode"/>.
|
||||
/// </summary>
|
||||
internal struct NineGridOffsets
|
||||
{
|
||||
/// <summary>Top offset.</summary>
|
||||
internal int Top;
|
||||
|
||||
/// <summary>Left offset.</summary>
|
||||
internal int Left;
|
||||
|
||||
/// <summary>Right offset.</summary>
|
||||
internal int Right;
|
||||
|
||||
/// <summary>Bottom offset.</summary>
|
||||
internal int Bottom;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NineGridOffsets"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="top">The top offset.</param>
|
||||
/// <param name="right">The right offset.</param>
|
||||
/// <param name="bottom">The bottom offset.</param>
|
||||
/// <param name="left">The left offset.</param>
|
||||
internal NineGridOffsets(int top, int right, int bottom, int left)
|
||||
{
|
||||
this.Top = top;
|
||||
this.Right = right;
|
||||
this.Left = left;
|
||||
this.Bottom = bottom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NineGridOffsets"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="ngNode">The node using these offsets.</param>
|
||||
internal NineGridOffsets(AtkNineGridNode* ngNode)
|
||||
: this(ngNode->TopOffset, ngNode->RightOffset, ngNode->BottomOffset, ngNode->LeftOffset)
|
||||
{
|
||||
}
|
||||
|
||||
private NineGridOffsets(Vector4 v)
|
||||
: this((int)v.X, (int)v.Y, (int)v.Z, (int)v.W)
|
||||
{
|
||||
}
|
||||
|
||||
public static implicit operator NineGridOffsets(Vector4 v) => new(v);
|
||||
|
||||
public static implicit operator Vector4(NineGridOffsets v) => new(v.Top, v.Right, v.Bottom, v.Left);
|
||||
|
||||
public static NineGridOffsets operator *(float n, NineGridOffsets a) => n * (Vector4)a;
|
||||
|
||||
public static NineGridOffsets operator *(NineGridOffsets a, float n) => n * a;
|
||||
|
||||
/// <summary>Prints the offsets in ImGui.</summary>
|
||||
internal readonly void Print() => PrintFieldValuePairs(("Top", $"{this.Top}"), ("Bottom", $"{this.Bottom}"), ("Left", $"{this.Left}"), ("Right", $"{this.Right}"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
using Dalamud.Interface.Internal.UiDebug2.Utility;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using ImGuiNET;
|
||||
|
||||
|
|
@ -85,4 +87,62 @@ internal unsafe partial class NineGridNodeTree : ImageNodeTree
|
|||
|
||||
this.DrawTextureAndParts();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A struct representing the four offsets of an <see cref="AtkNineGridNode"/>.
|
||||
/// </summary>
|
||||
internal struct NineGridOffsets
|
||||
{
|
||||
/// <summary>Top offset.</summary>
|
||||
internal int Top;
|
||||
|
||||
/// <summary>Left offset.</summary>
|
||||
internal int Left;
|
||||
|
||||
/// <summary>Right offset.</summary>
|
||||
internal int Right;
|
||||
|
||||
/// <summary>Bottom offset.</summary>
|
||||
internal int Bottom;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NineGridOffsets"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="top">The top offset.</param>
|
||||
/// <param name="right">The right offset.</param>
|
||||
/// <param name="bottom">The bottom offset.</param>
|
||||
/// <param name="left">The left offset.</param>
|
||||
internal NineGridOffsets(int top, int right, int bottom, int left)
|
||||
{
|
||||
this.Top = top;
|
||||
this.Right = right;
|
||||
this.Left = left;
|
||||
this.Bottom = bottom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NineGridOffsets"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="ngNode">The node using these offsets.</param>
|
||||
internal NineGridOffsets(AtkNineGridNode* ngNode)
|
||||
: this(ngNode->TopOffset, ngNode->RightOffset, ngNode->BottomOffset, ngNode->LeftOffset)
|
||||
{
|
||||
}
|
||||
|
||||
private NineGridOffsets(Vector4 v)
|
||||
: this((int)v.X, (int)v.Y, (int)v.Z, (int)v.W)
|
||||
{
|
||||
}
|
||||
|
||||
public static implicit operator NineGridOffsets(Vector4 v) => new(v);
|
||||
|
||||
public static implicit operator Vector4(NineGridOffsets v) => new(v.Top, v.Right, v.Bottom, v.Left);
|
||||
|
||||
public static NineGridOffsets operator *(float n, NineGridOffsets a) => n * (Vector4)a;
|
||||
|
||||
public static NineGridOffsets operator *(NineGridOffsets a, float n) => n * a;
|
||||
|
||||
/// <summary>Prints the offsets in ImGui.</summary>
|
||||
internal readonly void Print() => Gui.PrintFieldValuePairs(("Top", $"{this.Top}"), ("Bottom", $"{this.Bottom}"), ("Left", $"{this.Left}"), ("Right", $"{this.Right}"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,11 +128,11 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
using var c = ImRaii.PushColor(Text, color);
|
||||
using var col = ImRaii.PushColor(Text, color);
|
||||
using var tree = ImRaii.TreeNode($"{label}##{(nint)nodeList:X}", SpanFullWidth);
|
||||
c.Pop();
|
||||
col.Pop();
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
var lineStart = ImGui.GetCursorScreenPos() + new Vector2(-10, 2);
|
||||
|
||||
|
|
@ -319,7 +319,7 @@ internal unsafe partial class ResNodeTree : IDisposable
|
|||
|
||||
col.Pop();
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
var lineStart = ImGui.GetCursorScreenPos() + new Vector2(-10, 2);
|
||||
try
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ internal unsafe partial class TextNodeTree : ResNodeTree
|
|||
{
|
||||
using var tree = ImRaii.TreeNode($"Text Payloads##{(nint)this.Node:X}");
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
var utf8String = this.NodeText;
|
||||
var seStringBytes = new byte[utf8String.BufUsed];
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public readonly unsafe partial struct TimelineTree
|
|||
{
|
||||
using var tree = ImRaii.TreeNode($"Timeline##{(nint)this.node:X}timeline", SpanFullWidth);
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
PrintFieldValuePair("Timeline", $"{(nint)this.NodeTimeline:X}");
|
||||
|
||||
|
|
@ -312,7 +312,7 @@ public readonly unsafe partial struct TimelineTree
|
|||
{
|
||||
using var tree = ImRaii.TreeNode($"[#{a}] [Frames {animation.StartFrameIdx}-{animation.EndFrameIdx}] {(isActive ? " (Active)" : string.Empty)}###{(nint)this.node}animTree{a}");
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
PrintFieldValuePair("Animation", $"{address:X}");
|
||||
|
||||
|
|
@ -320,10 +320,9 @@ public readonly unsafe partial struct TimelineTree
|
|||
|
||||
if (columns.Count > 0)
|
||||
{
|
||||
using (ImRaii.Table(
|
||||
$"##{(nint)this.node}animTable{a}",
|
||||
columns.Count,
|
||||
Borders | SizingFixedFit | RowBg | NoHostExtendX))
|
||||
using var tbl = ImRaii.Table($"##{(nint)this.node}animTable{a}", columns.Count, Borders | SizingFixedFit | RowBg | NoHostExtendX);
|
||||
|
||||
if (tbl.Success)
|
||||
{
|
||||
foreach (var c in columns)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -79,7 +79,9 @@ internal unsafe class ElementSelector : IDisposable
|
|||
/// </summary>
|
||||
internal void DrawInterface()
|
||||
{
|
||||
using (ImRaii.Child("###sidebar_elementSelector", new(250, -1), true))
|
||||
using var ch = ImRaii.Child("###sidebar_elementSelector", new(250, -1), true);
|
||||
|
||||
if (ch.Success)
|
||||
{
|
||||
using (ImRaii.PushFont(IconFont))
|
||||
{
|
||||
|
|
@ -153,9 +155,11 @@ internal unsafe class ElementSelector : IDisposable
|
|||
|
||||
using (ImRaii.PushColor(WindowBg, new Vector4(0.5f)))
|
||||
{
|
||||
using (ImRaii.Child("noClick", new(800, 2000), false, NoInputs | NoBackground | NoScrollWithMouse))
|
||||
using var ch = ImRaii.Child("noClick", new(800, 2000), false, NoInputs | NoBackground | NoScrollWithMouse);
|
||||
if (ch.Success)
|
||||
{
|
||||
using (ImRaii.Group())
|
||||
using var gr = ImRaii.Group();
|
||||
if (gr.Success)
|
||||
{
|
||||
Gui.PrintFieldValuePair("Mouse Position", $"{mousePos.X}, {mousePos.Y}");
|
||||
ImGui.Spacing();
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ internal class AddonPopoutWindow : Window, IDisposable
|
|||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
using (ImRaii.Child($"{this.WindowName}child", new(-1, -1), true))
|
||||
using var ch = ImRaii.Child($"{this.WindowName}child", new(-1, -1), true);
|
||||
if (ch.Success)
|
||||
{
|
||||
this.addonTree.Draw();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ internal unsafe class NodePopoutWindow : Window, IDisposable
|
|||
{
|
||||
if (this.Node != null && this.AddonTree.ContainsNode(this.Node))
|
||||
{
|
||||
using (ImRaii.Child($"{(nint)this.Node:X}popoutChild", new(-1, -1), true))
|
||||
using var ch = ImRaii.Child($"{(nint)this.Node:X}popoutChild", new(-1, -1), true);
|
||||
if (ch.Success)
|
||||
{
|
||||
ResNodeTree.GetOrCreate(this.Node, this.AddonTree).Print(null, this.firstDraw);
|
||||
this.firstDraw = false;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ internal unsafe partial class UiDebug2
|
|||
|
||||
private void DrawSidebar()
|
||||
{
|
||||
using (ImRaii.Group())
|
||||
using var gr = ImRaii.Group();
|
||||
if (gr.Success)
|
||||
{
|
||||
this.DrawNameSearch();
|
||||
this.DrawAddonSelectionList();
|
||||
|
|
@ -63,7 +64,9 @@ internal unsafe partial class UiDebug2
|
|||
|
||||
private void DrawNameSearch()
|
||||
{
|
||||
using (ImRaii.Child("###sidebar_nameSearch", new(250, 40), true))
|
||||
using var ch = ImRaii.Child("###sidebar_nameSearch", new(250, 40), true);
|
||||
|
||||
if (ch.Success)
|
||||
{
|
||||
var atkUnitBaseSearch = this.addonNameSearch;
|
||||
|
||||
|
|
@ -90,7 +93,8 @@ internal unsafe partial class UiDebug2
|
|||
|
||||
private void DrawAddonSelectionList()
|
||||
{
|
||||
using (ImRaii.Child("###sideBar_addonList", new(250, -44), true, ImGuiWindowFlags.AlwaysVerticalScrollbar))
|
||||
using var ch = ImRaii.Child("###sideBar_addonList", new(250, -44), true, ImGuiWindowFlags.AlwaysVerticalScrollbar);
|
||||
if (ch.Success)
|
||||
{
|
||||
var unitListBaseAddr = GetUnitListBaseAddr();
|
||||
|
||||
|
|
@ -146,11 +150,11 @@ internal unsafe partial class UiDebug2
|
|||
|
||||
var countStr = $"{(usingFilter ? $"{matchCount}/" : string.Empty)}{totalCount}";
|
||||
|
||||
using var col1 = ImRaii.PushColor(ImGuiCol.Text, anyVisible ? new Vector4(1) : new Vector4(0.6f, 0.6f, 0.6f, 1));
|
||||
using var col = ImRaii.PushColor(ImGuiCol.Text, anyVisible ? new Vector4(1) : new Vector4(0.6f, 0.6f, 0.6f, 1));
|
||||
using var tree = ImRaii.TreeNode($"{unit.Name} [{countStr}]###unitListTree{unit.Index}");
|
||||
col1.Pop();
|
||||
col.Pop();
|
||||
|
||||
if (tree)
|
||||
if (tree.Success)
|
||||
{
|
||||
foreach (var option in options)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,7 +83,9 @@ internal partial class UiDebug2 : IDisposable
|
|||
{
|
||||
ImGui.SameLine();
|
||||
|
||||
using (ImRaii.Child("###uiDebugMainPanel", new(-1, -1), true, HorizontalScrollbar))
|
||||
using var ch = ImRaii.Child("###uiDebugMainPanel", new(-1, -1), true, HorizontalScrollbar);
|
||||
|
||||
if (ch.Success)
|
||||
{
|
||||
if (this.elementSelector.Active)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ internal static class Gui
|
|||
/// <remarks>Colors the text itself either white or black, depending on the luminosity of the background color.</remarks>
|
||||
internal static void PrintColor(Vector4 color, string fmt)
|
||||
{
|
||||
using (new ImRaii.Color().Push(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1))
|
||||
.Push(Button, color)
|
||||
.Push(ButtonActive, color)
|
||||
.Push(ButtonHovered, color))
|
||||
using (ImRaii.PushColor(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1))
|
||||
.Push(Button, color)
|
||||
.Push(ButtonActive, color)
|
||||
.Push(ButtonHovered, color))
|
||||
{
|
||||
ImGui.SmallButton(fmt);
|
||||
}
|
||||
|
|
@ -105,7 +105,9 @@ internal static class Gui
|
|||
|
||||
var index = (int)Math.Floor(prog * tooltips.Length);
|
||||
|
||||
using (ImRaii.Tooltip())
|
||||
using var tt = ImRaii.Tooltip();
|
||||
|
||||
if (tt.Success)
|
||||
{
|
||||
ImGui.TextUnformatted(tooltips[index]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ using Windows.Win32.Storage.FileSystem;
|
|||
using Windows.Win32.System.Memory;
|
||||
using Windows.Win32.System.Ole;
|
||||
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
using static TerraFX.Interop.Windows.Windows;
|
||||
|
||||
using Win32_PInvoke = Windows.Win32.PInvoke;
|
||||
|
|
@ -1028,74 +1030,71 @@ public static class Util
|
|||
dm.Invoke(null, new[] { obj, path, addr });
|
||||
}
|
||||
|
||||
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||
|
||||
private static unsafe void ShowSpanPrivate<T>(ulong addr, IList<string> path, int offset, bool isTop, in Span<T> spanobj)
|
||||
{
|
||||
#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||
if (isTop)
|
||||
{
|
||||
fixed (void* p = spanobj)
|
||||
{
|
||||
if (!ImGui.TreeNode(
|
||||
$"Span<{typeof(T).Name}> of length {spanobj.Length:n0} (0x{spanobj.Length:X})" +
|
||||
$"##print-obj-{addr:X}-{string.Join("-", path)}-head"))
|
||||
using var tree = ImRaii.TreeNode($"Span<{typeof(T).Name}> of length {spanobj.Length:n0} (0x{spanobj.Length:X})" + $"##print-obj-{addr:X}-{string.Join("-", path)}-head", ImGuiTreeNodeFlags.SpanFullWidth);
|
||||
if (tree.Success)
|
||||
{
|
||||
return;
|
||||
ShowSpanEntryPrivate(addr, path, offset, spanobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
else
|
||||
{
|
||||
const int batchSize = 20;
|
||||
if (spanobj.Length > batchSize)
|
||||
{
|
||||
var skip = batchSize;
|
||||
while ((spanobj.Length + skip - 1) / skip > batchSize)
|
||||
skip *= batchSize;
|
||||
for (var i = 0; i < spanobj.Length; i += skip)
|
||||
{
|
||||
var next = Math.Min(i + skip, spanobj.Length);
|
||||
path.Add($"{offset + i:X}_{skip}");
|
||||
if (ImGui.TreeNode(
|
||||
$"{offset + i:n0} ~ {offset + next - 1:n0} (0x{offset + i:X} ~ 0x{offset + next - 1:X})" +
|
||||
$"##print-obj-{addr:X}-{string.Join("-", path)}"))
|
||||
{
|
||||
try
|
||||
{
|
||||
ShowSpanPrivate(addr, path, offset + i, false, spanobj[i..next]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ImGui.TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
path.RemoveAt(path.Count - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (T* p = spanobj)
|
||||
{
|
||||
var pointerType = typeof(T*);
|
||||
for (var i = 0; i < spanobj.Length; i++)
|
||||
{
|
||||
ImGui.TextUnformatted($"[{offset + i:n0} (0x{offset + i:X})] ");
|
||||
ImGui.SameLine();
|
||||
path.Add($"{offset + i}");
|
||||
ShowValue(addr, path, pointerType, Pointer.Box(p + i, pointerType), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
ShowSpanEntryPrivate(addr, path, offset, spanobj);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isTop)
|
||||
ImGui.TreePop();
|
||||
}
|
||||
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||
}
|
||||
|
||||
private static unsafe void ShowSpanEntryPrivate<T>(ulong addr, IList<string> path, int offset, Span<T> spanobj) {
|
||||
const int batchSize = 20;
|
||||
if (spanobj.Length > batchSize)
|
||||
{
|
||||
var skip = batchSize;
|
||||
while ((spanobj.Length + skip - 1) / skip > batchSize)
|
||||
{
|
||||
skip *= batchSize;
|
||||
}
|
||||
|
||||
for (var i = 0; i < spanobj.Length; i += skip)
|
||||
{
|
||||
var next = Math.Min(i + skip, spanobj.Length);
|
||||
path.Add($"{offset + i:X}_{skip}");
|
||||
|
||||
using (var tree = ImRaii.TreeNode($"{offset + i:n0} ~ {offset + next - 1:n0} (0x{offset + i:X} ~ 0x{offset + next - 1:X})" + $"##print-obj-{addr:X}-{string.Join("-", path)}", ImGuiTreeNodeFlags.SpanFullWidth))
|
||||
{
|
||||
if (tree.Success)
|
||||
{
|
||||
ShowSpanEntryPrivate(addr, path, offset + i, spanobj[i..next]);
|
||||
}
|
||||
}
|
||||
|
||||
path.RemoveAt(path.Count - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (T* p = spanobj)
|
||||
{
|
||||
var pointerType = typeof(T*);
|
||||
for (var i = 0; i < spanobj.Length; i++)
|
||||
{
|
||||
ImGui.TextUnformatted($"[{offset + i:n0} (0x{offset + i:X})] ");
|
||||
ImGui.SameLine();
|
||||
path.Add($"{offset + i}");
|
||||
ShowValue(addr, path, pointerType, Pointer.Box(p + i, pointerType), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type
|
||||
|
||||
private static unsafe void ShowValue(ulong addr, IList<string> path, Type type, object value, bool hideAddress)
|
||||
{
|
||||
if (type.IsPointer)
|
||||
|
|
@ -1111,9 +1110,10 @@ public static class Util
|
|||
if (moduleStartAddr > 0 && unboxedAddr >= moduleStartAddr && unboxedAddr <= moduleEndAddr)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, 0xffcbc0ff);
|
||||
ImGuiHelpers.ClickToCopyText($"ffxiv_dx11.exe+{unboxedAddr - moduleStartAddr:X}");
|
||||
ImGui.PopStyleColor();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, 0xffcbc0ff))
|
||||
{
|
||||
ImGuiHelpers.ClickToCopyText($"ffxiv_dx11.exe+{unboxedAddr - moduleStartAddr:X}");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
@ -1165,125 +1165,135 @@ public static class Util
|
|||
/// <param name="hideAddress">Do not print addresses. Use when displaying a copied value.</param>
|
||||
private static void ShowStructInternal(object obj, ulong addr, bool autoExpand = false, IEnumerable<string>? path = null, bool hideAddress = false)
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(3, 2));
|
||||
path ??= new List<string>();
|
||||
var pathList = path is List<string> ? (List<string>)path : path.ToList();
|
||||
|
||||
if (moduleEndAddr == 0 && moduleStartAddr == 0)
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(3, 2)))
|
||||
{
|
||||
try
|
||||
path ??= new List<string>();
|
||||
var pathList = path as List<string> ?? path.ToList();
|
||||
|
||||
if (moduleEndAddr == 0 && moduleStartAddr == 0)
|
||||
{
|
||||
var processModule = Process.GetCurrentProcess().MainModule;
|
||||
if (processModule != null)
|
||||
try
|
||||
{
|
||||
moduleStartAddr = (ulong)processModule.BaseAddress.ToInt64();
|
||||
moduleEndAddr = moduleStartAddr + (ulong)processModule.ModuleMemorySize;
|
||||
var processModule = Process.GetCurrentProcess().MainModule;
|
||||
if (processModule != null)
|
||||
{
|
||||
moduleStartAddr = (ulong)processModule.BaseAddress.ToInt64();
|
||||
moduleEndAddr = moduleStartAddr + (ulong)processModule.ModuleMemorySize;
|
||||
}
|
||||
else
|
||||
{
|
||||
moduleEndAddr = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
catch
|
||||
{
|
||||
moduleEndAddr = 1;
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
||||
if (autoExpand)
|
||||
{
|
||||
moduleEndAddr = 1;
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, 0xFF00FFFF);
|
||||
if (autoExpand)
|
||||
{
|
||||
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
|
||||
}
|
||||
using var col = ImRaii.PushColor(ImGuiCol.Text, 0xFF00FFFF);
|
||||
using var tree = ImRaii.TreeNode($"{obj}##print-obj-{addr:X}-{string.Join("-", pathList)}", ImGuiTreeNodeFlags.SpanFullWidth);
|
||||
col.Pop();
|
||||
|
||||
if (ImGui.TreeNode($"{obj}##print-obj-{addr:X}-{string.Join("-", pathList)}"))
|
||||
{
|
||||
ImGui.PopStyleColor();
|
||||
foreach (var f in obj.GetType()
|
||||
.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))
|
||||
if (tree.Success)
|
||||
{
|
||||
var fixedBuffer = (FixedBufferAttribute)f.GetCustomAttribute(typeof(FixedBufferAttribute));
|
||||
var offset = (FieldOffsetAttribute)f.GetCustomAttribute(typeof(FieldOffsetAttribute));
|
||||
ImGui.PopStyleColor();
|
||||
foreach (var f in obj.GetType()
|
||||
.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
var fixedBuffer = (FixedBufferAttribute)f.GetCustomAttribute(typeof(FixedBufferAttribute));
|
||||
var offset = (FieldOffsetAttribute)f.GetCustomAttribute(typeof(FieldOffsetAttribute));
|
||||
|
||||
if (fixedBuffer != null)
|
||||
{
|
||||
ImGui.Text($"fixed");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1),
|
||||
$"{fixedBuffer.ElementType.Name}[0x{fixedBuffer.Length:X}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (offset != null)
|
||||
if (fixedBuffer != null)
|
||||
{
|
||||
ImGui.TextDisabled($"[0x{offset.Value:X}]");
|
||||
ImGui.Text("fixed");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{fixedBuffer.ElementType.Name}[0x{fixedBuffer.Length:X}]");
|
||||
}
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{f.FieldType.Name}");
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.4f, 1), $"{f.Name}: ");
|
||||
ImGui.SameLine();
|
||||
|
||||
pathList.Add(f.Name);
|
||||
try
|
||||
{
|
||||
if (f.FieldType.IsGenericType && (f.FieldType.IsByRef || f.FieldType.IsByRefLike))
|
||||
ImGui.Text("Cannot preview ref typed fields."); // object never contains ref struct
|
||||
else if (f.FieldType == typeof(bool) && offset != null)
|
||||
ShowValue(addr, pathList, f.FieldType, Marshal.ReadByte((nint)addr + offset.Value) > 0, hideAddress);
|
||||
else
|
||||
ShowValue(addr, pathList, f.FieldType, f.GetValue(obj), hideAddress);
|
||||
{
|
||||
if (offset != null)
|
||||
{
|
||||
ImGui.TextDisabled($"[0x{offset.Value:X}]");
|
||||
ImGui.SameLine();
|
||||
}
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{f.FieldType.Name}");
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.4f, 1), $"{f.Name}: ");
|
||||
ImGui.SameLine();
|
||||
|
||||
pathList.Add(f.Name);
|
||||
try
|
||||
{
|
||||
if (f.FieldType.IsGenericType && (f.FieldType.IsByRef || f.FieldType.IsByRefLike))
|
||||
{
|
||||
ImGui.Text("Cannot preview ref typed fields."); // object never contains ref struct
|
||||
}
|
||||
else if (f.FieldType == typeof(bool) && offset != null)
|
||||
{
|
||||
ShowValue(addr, pathList, f.FieldType, Marshal.ReadByte((nint)addr + offset.Value) > 0, hideAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowValue(addr, pathList, f.FieldType, f.GetValue(obj), hideAddress);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f)))
|
||||
{
|
||||
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pathList.RemoveAt(pathList.Count - 1);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
foreach (var p in obj.GetType().GetProperties().Where(static p => p.GetGetMethod()?.GetParameters().Length == 0))
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f));
|
||||
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
finally
|
||||
{
|
||||
pathList.RemoveAt(pathList.Count - 1);
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{p.PropertyType.Name}");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.6f, 0.4f, 1), $"{p.Name}: ");
|
||||
ImGui.SameLine();
|
||||
|
||||
pathList.Add(p.Name);
|
||||
try
|
||||
{
|
||||
if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == GenericSpanType)
|
||||
{
|
||||
ShowSpanProperty(addr, pathList, p, obj);
|
||||
}
|
||||
else if (p.PropertyType.IsGenericType && (p.PropertyType.IsByRef || p.PropertyType.IsByRefLike))
|
||||
{
|
||||
ImGui.Text("Cannot preview ref typed properties.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowValue(addr, pathList, p.PropertyType, p.GetValue(obj), hideAddress);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f)))
|
||||
{
|
||||
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
pathList.RemoveAt(pathList.Count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var p in obj.GetType().GetProperties().Where(p => p.GetGetMethod()?.GetParameters().Length == 0))
|
||||
{
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.9f, 0.9f, 1), $"{p.PropertyType.Name}");
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored(new Vector4(0.2f, 0.6f, 0.4f, 1), $"{p.Name}: ");
|
||||
ImGui.SameLine();
|
||||
|
||||
pathList.Add(p.Name);
|
||||
try
|
||||
{
|
||||
if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == GenericSpanType)
|
||||
ShowSpanProperty(addr, pathList, p, obj);
|
||||
else if (p.PropertyType.IsGenericType && (p.PropertyType.IsByRef || p.PropertyType.IsByRefLike))
|
||||
ImGui.Text("Cannot preview ref typed properties.");
|
||||
else
|
||||
ShowValue(addr, pathList, p.PropertyType, p.GetValue(obj), hideAddress);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0.4f, 0.4f, 1f));
|
||||
ImGui.TextUnformatted($"Error: {ex.GetType().Name}: {ex.Message}");
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
finally
|
||||
{
|
||||
pathList.RemoveAt(pathList.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TreePop();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue