Implement ImRaii

This commit is contained in:
ItsBexy 2024-09-03 21:23:50 -06:00
parent bf8690fc60
commit e19f9284e5
17 changed files with 248 additions and 256 deletions

View file

@ -28,10 +28,8 @@ public unsafe partial class AddonTree
return null;
}
if (!AddonTypeDict.ContainsKey(this.AddonName))
if (AddonTypeDict.TryAdd(this.AddonName, null))
{
AddonTypeDict.Add(this.AddonName, null);
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
try
@ -104,13 +102,15 @@ public unsafe partial class AddonTree
}
}
return;
void ParseExplicitField(nint fieldAddr, FieldInfo field, MemberInfo fieldType, string name)
{
try
{
if (this.FieldNames.TryAdd(fieldAddr, new List<string>(path!) { name }) && fieldType.DeclaringType == baseType)
if (this.FieldNames.TryAdd(fieldAddr, [..path!, name]) && fieldType.DeclaringType == baseType)
{
this.PopulateFieldNames(field.GetValue(obj), fieldAddr, new List<string>(path) { name });
this.PopulateFieldNames(field.GetValue(obj), fieldAddr, [..path, name]);
}
}
catch (Exception ex)
@ -140,12 +140,12 @@ public unsafe partial class AddonTree
var itemAddr = fieldAddr + (size * i);
var itemName = $"{name}[{i}]";
this.FieldNames.TryAdd(itemAddr, new List<string>(path!) { itemName });
this.FieldNames.TryAdd(itemAddr, [..path!, itemName]);
var item = Marshal.PtrToStructure(itemAddr, itemType);
if (itemType.DeclaringType == baseType)
{
this.PopulateFieldNames(item, itemAddr, new List<string>(path) { name });
this.PopulateFieldNames(item, itemAddr, [..path, itemName]);
}
}
}
@ -176,16 +176,16 @@ public unsafe partial class AddonTree
return;
}
this.FieldNames.TryAdd(fieldAddr, new List<string>(path!) { name });
this.FieldNames.TryAdd(pointer, new List<string>(path) { name });
this.FieldNames.TryAdd(fieldAddr, [..path!, name]);
this.FieldNames.TryAdd(pointer, [..path, name]);
if (itemType?.DeclaringType != baseType || itemType.IsPointer)
if (itemType?.DeclaringType != baseType || itemType!.IsPointer)
{
return;
}
var item = Marshal.PtrToStructure(pointer, itemType);
this.PopulateFieldNames(item, pointer, new List<string>(path) { name });
this.PopulateFieldNames(item, pointer, [..path, name]);
}
catch (Exception ex)
{

View file

@ -1,4 +1,5 @@
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -25,10 +26,11 @@ public static class Events
return;
}
if (ImGui.TreeNode($"Events##{(nint)node:X}eventTree"))
{
if (ImGui.BeginTable($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg))
var tree = ImRaii.TreeNode($"Events##{(nint)node:X}eventTree");
if (tree)
{
var tab = ImRaii.Table($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg);
ImGui.TableSetupColumn("#", WidthFixed);
ImGui.TableSetupColumn("Type", WidthFixed);
ImGui.TableSetupColumn("Param", WidthFixed);
@ -59,10 +61,9 @@ public static class Events
evt = evt->NextEvent;
}
ImGui.EndTable();
tab.Dispose();
}
ImGui.TreePop();
}
tree.Dispose();
}
}

View file

@ -14,12 +14,8 @@ namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
/// </summary>
internal unsafe class ComponentNodeTree : ResNodeTree
{
private readonly AtkUldManager* uldManager;
private readonly ComponentType componentType;
private readonly AtkComponentBase* component;
/// <summary>
/// Initializes a new instance of the <see cref="ComponentNodeTree"/> class.
/// </summary>
@ -28,17 +24,21 @@ internal unsafe class ComponentNodeTree : ResNodeTree
internal ComponentNodeTree(AtkResNode* node, AddonTree addonTree)
: base(node, addonTree)
{
this.component = ((AtkComponentNode*)node)->Component;
this.uldManager = &this.component->UldManager;
this.NodeType = 0;
this.componentType = ((AtkUldComponentInfo*)this.uldManager->Objects)->ComponentType;
this.componentType = ((AtkUldComponentInfo*)this.UldManager->Objects)->ComponentType;
}
private AtkComponentBase* Component => this.CompNode->Component;
private AtkComponentNode* CompNode => (AtkComponentNode*)this.Node;
private AtkUldManager* UldManager => &this.Component->UldManager;
/// <inheritdoc/>
private protected override string GetHeaderText()
{
var childCount = (int)this.uldManager->NodeListCount;
return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)} (Node: {(nint)this.Node:X} / Comp: {(nint)this.component:X})";
var childCount = (int)this.UldManager->NodeListCount;
return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)} (Node: {(nint)this.Node:X} / Comp: {(nint)this.Component:X})";
}
/// <inheritdoc/>
@ -57,29 +57,30 @@ internal unsafe class ComponentNodeTree : ResNodeTree
private protected override void PrintChildNodes()
{
base.PrintChildNodes();
var count = this.uldManager->NodeListCount;
PrintNodeListAsTree(this.uldManager->NodeList, count, $"Node List [{count}]:", this.AddonTree, new(0f, 0.5f, 0.8f, 1f));
var count = this.UldManager->NodeListCount;
PrintNodeListAsTree(this.UldManager->NodeList, count, $"Node List [{count}]:", this.AddonTree, new(0f, 0.5f, 0.8f, 1f));
}
/// <inheritdoc/>
private protected override void PrintFieldNames()
{
this.PrintFieldName((nint)this.Node, new(0, 0.85F, 1, 1));
this.PrintFieldName((nint)this.component, new(0f, 0.5f, 0.8f, 1f));
this.PrintFieldName((nint)this.Component, new(0f, 0.5f, 0.8f, 1f));
}
/// <inheritdoc/>
private protected override void PrintFieldsForNodeType(bool isEditorOpen = false)
{
if (this.component == null)
if (this.Component == null)
{
return;
}
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (this.componentType)
{
case TextInput:
var textInputComponent = (AtkComponentTextInput*)this.component;
var textInputComponent = (AtkComponentTextInput*)this.Component;
ImGui.Text(
$"InputBase Text1: {Marshal.PtrToStringAnsi(new(textInputComponent->AtkComponentInputBase.UnkText1.StringPtr))}");
ImGui.Text(
@ -97,98 +98,96 @@ internal unsafe class ComponentNodeTree : ResNodeTree
break;
case List:
case TreeList:
var l = (AtkComponentList*)this.component;
var l = (AtkComponentList*)this.Component;
if (ImGui.SmallButton("Inc.Selected"))
{
l->SelectedItemIndex++;
}
break;
default:
break;
}
}
private void PrintComponentObject()
{
PrintFieldValuePair("Component", $"{(nint)this.component:X}");
PrintFieldValuePair("Component", $"{(nint)this.Component:X}");
ImGui.SameLine();
switch (this.componentType)
{
case Button:
ShowStruct((AtkComponentButton*)this.component);
ShowStruct((AtkComponentButton*)this.Component);
break;
case Slider:
ShowStruct((AtkComponentSlider*)this.component);
ShowStruct((AtkComponentSlider*)this.Component);
break;
case Window:
ShowStruct((AtkComponentWindow*)this.component);
ShowStruct((AtkComponentWindow*)this.Component);
break;
case CheckBox:
ShowStruct((AtkComponentCheckBox*)this.component);
ShowStruct((AtkComponentCheckBox*)this.Component);
break;
case GaugeBar:
ShowStruct((AtkComponentGaugeBar*)this.component);
ShowStruct((AtkComponentGaugeBar*)this.Component);
break;
case RadioButton:
ShowStruct((AtkComponentRadioButton*)this.component);
ShowStruct((AtkComponentRadioButton*)this.Component);
break;
case TextInput:
ShowStruct((AtkComponentTextInput*)this.component);
ShowStruct((AtkComponentTextInput*)this.Component);
break;
case Icon:
ShowStruct((AtkComponentIcon*)this.component);
ShowStruct((AtkComponentIcon*)this.Component);
break;
case NumericInput:
ShowStruct((AtkComponentNumericInput*)this.component);
ShowStruct((AtkComponentNumericInput*)this.Component);
break;
case List:
ShowStruct((AtkComponentList*)this.component);
ShowStruct((AtkComponentList*)this.Component);
break;
case TreeList:
ShowStruct((AtkComponentTreeList*)this.component);
ShowStruct((AtkComponentTreeList*)this.Component);
break;
case DropDownList:
ShowStruct((AtkComponentDropDownList*)this.component);
ShowStruct((AtkComponentDropDownList*)this.Component);
break;
case ScrollBar:
ShowStruct((AtkComponentScrollBar*)this.component);
ShowStruct((AtkComponentScrollBar*)this.Component);
break;
case ListItemRenderer:
ShowStruct((AtkComponentListItemRenderer*)this.component);
ShowStruct((AtkComponentListItemRenderer*)this.Component);
break;
case IconText:
ShowStruct((AtkComponentIconText*)this.component);
ShowStruct((AtkComponentIconText*)this.Component);
break;
case ComponentType.DragDrop:
ShowStruct((AtkComponentDragDrop*)this.component);
ShowStruct((AtkComponentDragDrop*)this.Component);
break;
case GuildLeveCard:
ShowStruct((AtkComponentGuildLeveCard*)this.component);
ShowStruct((AtkComponentGuildLeveCard*)this.Component);
break;
case TextNineGrid:
ShowStruct((AtkComponentTextNineGrid*)this.component);
ShowStruct((AtkComponentTextNineGrid*)this.Component);
break;
case JournalCanvas:
ShowStruct((AtkComponentJournalCanvas*)this.component);
ShowStruct((AtkComponentJournalCanvas*)this.Component);
break;
case HoldButton:
ShowStruct((AtkComponentHoldButton*)this.component);
ShowStruct((AtkComponentHoldButton*)this.Component);
break;
case Portrait:
ShowStruct((AtkComponentPortrait*)this.component);
ShowStruct((AtkComponentPortrait*)this.Component);
break;
default:
ShowStruct(this.component);
ShowStruct(this.Component);
break;
}
}
private void PrintComponentDataObject()
{
var componentData = this.component->UldManager.ComponentData;
var componentData = this.Component->UldManager.ComponentData;
PrintFieldValuePair("Data", $"{(nint)componentData:X}");
if (componentData != null)

View file

@ -1,8 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -25,11 +26,11 @@ internal unsafe partial class ResNodeTree
/// </summary>
private protected void DrawNodeEditorTable()
{
ImGui.BeginTable($"###Editor{(nint)this.Node}", 2, SizingStretchProp | NoHostExtendX);
var tab = ImRaii.Table($"###Editor{(nint)this.Node}", 2, SizingStretchProp | NoHostExtendX);
this.DrawEditorRows();
ImGui.EndTable();
tab.Dispose();
}
/// <summary>
@ -289,7 +290,7 @@ internal unsafe partial class NineGridNodeTree
/// <inheritdoc cref="TextNodeTree"/>
internal unsafe partial class TextNodeTree
{
private static readonly List<FontType> FontList = Enum.GetValues<FontType>().ToList();
private static readonly List<FontType> FontList = [.. Enum.GetValues<FontType>()];
private static readonly string[] FontNames = Enum.GetNames<FontType>();
@ -370,8 +371,8 @@ internal unsafe partial class TextNodeTree
var hAlign = (int)alignment % 3;
var vAlign = ((int)alignment - hAlign) / 3;
var hAlignInput = IconSelectInput($"{label}H", ref hAlign, new() { 0, 1, 2 }, new() { AlignLeft, AlignCenter, AlignRight });
var vAlignInput = IconSelectInput($"{label}V", ref vAlign, new() { 0, 1, 2 }, new() { ArrowsUpToLine, GripLines, ArrowsDownToLine });
var hAlignInput = IconSelectInput($"{label}H", ref hAlign, [0, 1, 2], [AlignLeft, AlignCenter, AlignRight]);
var vAlignInput = IconSelectInput($"{label}V", ref vAlign, [0, 1, 2], [ArrowsUpToLine, GripLines, ArrowsDownToLine]);
if (hAlignInput || vAlignInput)
{

View file

@ -1,6 +1,8 @@
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -11,6 +13,7 @@ using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.TextureType;
using static ImGuiNET.ImGuiTableColumnFlags;
using static ImGuiNET.ImGuiTableFlags;
using static ImGuiNET.ImGuiTreeNodeFlags;
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
@ -60,7 +63,9 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
return;
}
if (NestedTreePush($"Texture##texture{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", out _))
var tree = ImRaii.TreeNode($"Texture##texture{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", SpanFullWidth);
if (tree)
{
PrintFieldValuePairs(
("Texture Type", $"{this.TexData.TexType}"),
@ -93,9 +98,9 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
{
this.DrawFullTexture();
}
ImGui.TreePop();
}
tree.Dispose();
}
/// <summary>
@ -157,7 +162,8 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
if (ImGui.IsItemClicked())
{
ImGui.SetClipboardText(ImGui.IsKeyDown(ImGuiKey.ModShift)
ImGui.SetClipboardText(
ImGui.IsKeyDown(ImGuiKey.ModShift)
? $"new Vector4({u}{suffix}, {v}{suffix}, {w}{suffix}, {h}{suffix})"
: $"new Vector2({u}{suffix}, {v}{suffix});\nnew Vector2({w}{suffix}, {h}{suffix})");
}
@ -185,7 +191,7 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
private void PrintPartsTable()
{
ImGui.BeginTable($"partsTable##{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", 3, Borders | RowBg | Reorderable);
var tab = ImRaii.Table($"partsTable##{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", 3, Borders | RowBg | Reorderable);
ImGui.TableSetupColumn("Part ID", WidthFixed);
ImGui.TableSetupColumn("Part Texture", WidthFixed);
ImGui.TableSetupColumn("Coordinates", WidthFixed);
@ -200,17 +206,8 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
{
ImGui.TableNextColumn();
if (i == this.TexData.PartId)
{
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0, 0.85F, 1, 1));
}
ImGui.Text($"#{i.ToString().PadLeft(this.TexData.PartCount.ToString().Length, '0')}");
if (i == this.TexData.PartId)
{
ImGui.PopStyleColor(1);
}
var col = i == this.TexData.PartId ? new Vector4(0, 0.85F, 1, 1) : new(1);
ImGui.TextColored(col, $"#{i.ToString().PadLeft(this.TexData.PartCount.ToString().Length, '0')}");
ImGui.TableNextColumn();
@ -245,7 +242,7 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
PrintPartCoords(u / tWidth, v / tWidth, (u + width) / tWidth, (v + height) / tHeight, true, true);
}
ImGui.EndTable();
tab.Dispose();
}
/// <summary>

View file

@ -35,8 +35,7 @@ internal unsafe partial class NineGridNodeTree : ImageNodeTree
private NineGridOffsets Offsets => new(this.NgNode);
/// <inheritdoc/>
private protected override void DrawPartOutline(
uint partId, Vector2 cursorScreenPos, Vector2 cursorLocalPos, Vector4 col, bool reqHover = false)
private protected override void DrawPartOutline(uint partId, Vector2 cursorScreenPos, Vector2 cursorLocalPos, Vector4 col, bool reqHover = false)
{
var part = this.TexData.PartsList->Parts[partId];

View file

@ -3,6 +3,8 @@ using System.Numerics;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -15,6 +17,9 @@ using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui;
using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.NodeFlags;
using static ImGuiNET.ImGuiCol;
using static ImGuiNET.ImGuiTreeNodeFlags;
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
/// <summary>
@ -117,17 +122,27 @@ internal unsafe partial class ResNodeTree : IDisposable
return;
}
ImGui.PushStyleColor(ImGuiCol.Text, color);
var treeOpened = NestedTreePush($"{label}##{(nint)nodeList:X}", color, out var lineStart);
ImGui.PopStyleColor();
var c = ImRaii.PushColor(Text, color);
var tree = ImRaii.TreeNode($"{label}##{(nint)nodeList:X}", SpanFullWidth);
c.Pop();
if (treeOpened)
if (tree)
{
var lineStart = ImGui.GetCursorScreenPos() + new Vector2(-10, 2);
PrintNodeList(nodeList, count, addonTree);
NestedTreePop(lineStart, color);
var lineEnd = lineStart with { Y = ImGui.GetCursorScreenPos().Y - 7 };
if (lineStart.Y < lineEnd.Y)
{
ImGui.GetWindowDrawList().AddLine(lineStart, lineEnd, RgbaVector4ToUint(color), 1);
}
}
tree.Dispose();
}
/// <summary>
/// Prints this tree in the window.
/// </summary>
@ -250,7 +265,7 @@ internal unsafe partial class ResNodeTree : IDisposable
private void PrintTree(uint? index, bool forceOpen = false)
{
var visible = this.Node->NodeFlags.HasFlag(Visible);
var label = $"{(index == null ? string.Empty : $"[{index}] ")}[#{this.Node->NodeId}]###{(nint)this.Node:X}nodeTree";
var displayColor = !visible ? new Vector4(0.8f, 0.8f, 0.8f, 1) :
this.Node->Color.A == 0 ? new(0.015f, 0.575f, 0.355f, 1) :
new(0.1f, 1f, 0.1f, 1f);
@ -260,9 +275,8 @@ internal unsafe partial class ResNodeTree : IDisposable
ImGui.SetNextItemOpen(true, ImGuiCond.Always);
}
ImGui.PushStyleColor(ImGuiCol.Text, displayColor);
var treePush = NestedTreePush($"{(index == null ? string.Empty : $"[{index}] ")}[#{this.Node->NodeId}]###{(nint)this.Node:X}nodeTree", displayColor, out var lineStart);
var col = ImRaii.PushColor(Text, displayColor);
var tree = ImRaii.TreeNode(label, SpanFullWidth);
if (ImGui.IsItemHovered())
{
@ -272,10 +286,11 @@ internal unsafe partial class ResNodeTree : IDisposable
ImGui.SameLine();
this.WriteTreeHeading();
ImGui.PopStyleColor();
col.Pop();
if (treePush)
if (tree)
{
var lineStart = ImGui.GetCursorScreenPos() + new Vector2(-10, 2);
try
{
PrintFieldValuePair("Node", $"{(nint)this.Node:X}");
@ -309,10 +324,17 @@ internal unsafe partial class ResNodeTree : IDisposable
ImGui.TextDisabled($"Couldn't display node!\n\n{ex}");
}
NestedTreePop(lineStart, displayColor);
var lineEnd = lineStart with { Y = ImGui.GetCursorScreenPos().Y - 7 };
if (lineStart.Y < lineEnd.Y)
{
ImGui.GetWindowDrawList().AddLine(lineStart, lineEnd, RgbaVector4ToUint(displayColor), 1);
}
}
tree.Dispose();
}
private void DrawBasicControls()
{
ImGui.SameLine();

View file

@ -1,10 +1,12 @@
using System.Numerics;
using System.Runtime.InteropServices;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface.ImGuiSeStringRenderer;
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -51,19 +53,19 @@ internal unsafe partial class TextNodeTree : ResNodeTree
#pragma warning disable
try
{
var style = new SeStringDrawParams()
var style = new SeStringDrawParams
{
Color = TxtNode->TextColor.RGBA,
EdgeColor = TxtNode->EdgeColor.RGBA,
Color = this.TxtNode->TextColor.RGBA,
EdgeColor = this.TxtNode->EdgeColor.RGBA,
ForceEdgeColor = true,
EdgeStrength = 1f
};
ImGuiHelpers.SeStringWrapped(NodeText.AsSpan(), style);
ImGuiHelpers.SeStringWrapped(this.NodeText.AsSpan(), style);
}
catch
{
ImGui.Text(Marshal.PtrToStringAnsi(new(NodeText.StringPtr)) ?? "");
ImGui.Text(Marshal.PtrToStringAnsi(new(this.NodeText.StringPtr)) ?? "");
}
#pragma warning restore
@ -81,7 +83,9 @@ internal unsafe partial class TextNodeTree : ResNodeTree
private void PrintPayloads()
{
if (ImGui.TreeNode($"Text Payloads##{(nint)this.Node:X}"))
var tree = ImRaii.TreeNode($"Text Payloads##{(nint)this.Node:X}");
if (tree)
{
var utf8String = this.NodeText;
var seStringBytes = new byte[utf8String.BufUsed];
@ -100,15 +104,7 @@ internal unsafe partial class TextNodeTree : ResNodeTree
{
case PayloadType.RawText when payload is TextPayload tp:
{
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
ImGui.Text("Raw Text: '");
ImGui.SameLine();
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.6f, 0.6f, 0.6f, 1));
ImGui.Text(tp.Text);
ImGui.PopStyleColor();
ImGui.SameLine();
ImGui.PopStyleVar();
ImGui.Text("'");
Gui.PrintFieldValuePair("Raw Text", tp.Text ?? string.Empty);
break;
}
@ -119,8 +115,8 @@ internal unsafe partial class TextNodeTree : ResNodeTree
}
}
}
}
ImGui.TreePop();
}
tree.Dispose();
}
}

View file

@ -5,7 +5,7 @@ using ImGuiNET;
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
/// <inheritdoc cref="TimelineTree"/>
public partial struct TimelineTree
public readonly partial struct TimelineTree
{
/// <summary>
/// An interface for retrieving and printing the contents of a given column in an animation timeline table.

View file

@ -3,6 +3,8 @@ using System.Linq;
using System.Numerics;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -13,6 +15,7 @@ using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.NodeType;
using static ImGuiNET.ImGuiTableColumnFlags;
using static ImGuiNET.ImGuiTableFlags;
using static ImGuiNET.ImGuiTreeNodeFlags;
// ReSharper disable SuggestBaseTypeForParameter
namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
@ -20,9 +23,9 @@ namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
/// <summary>
/// A struct allowing a node's animation timeline to be printed and browsed.
/// </summary>
public unsafe partial struct TimelineTree
public readonly unsafe partial struct TimelineTree
{
private AtkResNode* node;
private readonly AtkResNode* node;
/// <summary>
/// Initializes a new instance of the <see cref="TimelineTree"/> struct.
@ -53,7 +56,9 @@ public unsafe partial struct TimelineTree
if (count > 0)
{
if (NestedTreePush($"Timeline##{(nint)this.node:X}timeline", out _))
var tree = ImRaii.TreeNode($"Timeline##{(nint)this.node:X}timeline", SpanFullWidth);
if (tree)
{
PrintFieldValuePair("Timeline", $"{(nint)this.NodeTimeline:X}");
@ -72,12 +77,12 @@ public unsafe partial struct TimelineTree
for (var a = 0; a < count; a++)
{
var animation = this.Resource->Animations[a];
var isActive = this.ActiveAnimation != null && animation.Equals(*this.ActiveAnimation);
var isActive = this.ActiveAnimation != null && &animation == this.ActiveAnimation;
this.PrintAnimation(animation, a, isActive, (nint)(this.NodeTimeline->Resource->Animations + (a * sizeof(AtkTimelineAnimation))));
}
ImGui.TreePop();
}
tree.Dispose();
}
}
@ -305,11 +310,11 @@ public unsafe partial struct TimelineTree
{
var columns = this.BuildColumns(animation);
ImGui.PushStyleColor(ImGuiCol.Text, isActive ? new Vector4(1, 0.65F, 0.4F, 1) : new(1));
var treePush = ImGui.TreeNode($"[#{a}] [Frames {animation.StartFrameIdx}-{animation.EndFrameIdx}] {(isActive ? " (Active)" : string.Empty)}###{(nint)this.node}animTree{a}");
ImGui.PopStyleColor();
var col = ImRaii.PushColor(ImGuiCol.Text, isActive ? new Vector4(1, 0.65F, 0.4F, 1) : new(1));
var tree = ImRaii.TreeNode($"[#{a}] [Frames {animation.StartFrameIdx}-{animation.EndFrameIdx}] {(isActive ? " (Active)" : string.Empty)}###{(nint)this.node}animTree{a}");
col.Dispose();
if (treePush)
if (tree)
{
PrintFieldValuePair("Animation", $"{address:X}");
@ -317,7 +322,7 @@ public unsafe partial struct TimelineTree
if (columns.Count > 0)
{
ImGui.BeginTable($"##{(nint)this.node}animTable{a}", columns.Count, Borders | SizingFixedFit | RowBg | NoHostExtendX);
var table = ImRaii.Table($"##{(nint)this.node}animTable{a}", columns.Count, Borders | SizingFixedFit | RowBg | NoHostExtendX);
foreach (var c in columns)
{
@ -339,11 +344,11 @@ public unsafe partial struct TimelineTree
}
}
ImGui.EndTable();
table.Dispose();
}
}
ImGui.TreePop();
}
tree.Dispose();
}
private List<IKeyGroupColumn> BuildColumns(AtkTimelineAnimation animation)

View file

@ -6,6 +6,8 @@ using System.Numerics;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -18,6 +20,7 @@ using static Dalamud.Interface.Utility.ImGuiHelpers;
using static FFXIVClientStructs.FFXIV.Component.GUI.NodeFlags;
using static ImGuiNET.ImGuiCol;
using static ImGuiNET.ImGuiWindowFlags;
// ReSharper disable StructLacksIEquatable.Global
#pragma warning disable CS0659
@ -76,10 +79,10 @@ internal unsafe class ElementSelector : IDisposable
/// </summary>
internal void DrawInterface()
{
ImGui.BeginChild("###sidebar_elementSelector", new(250, 0), true);
var ch = ImRaii.Child("###sidebar_elementSelector", new(250, 0), true);
ImGui.PushFont(IconFont);
ImGui.PushStyleColor(Text, this.Active ? new Vector4(1, 1, 0.2f, 1) : new(1));
var f = ImRaii.PushFont(IconFont);
var col = ImRaii.PushColor(Text, this.Active ? new Vector4(1, 1, 0.2f, 1) : new(1));
if (ImGui.Button($"{(char)ObjectUngroup}"))
{
this.Active = !this.Active;
@ -94,8 +97,8 @@ internal unsafe class ElementSelector : IDisposable
}
}
ImGui.PopStyleColor();
ImGui.PopFont();
col.Pop();
f.Pop();
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Element Selector");
@ -112,7 +115,7 @@ internal unsafe class ElementSelector : IDisposable
this.PerformSearch(address);
}
ImGui.EndChild();
ch.Dispose();
}
/// <summary>
@ -138,9 +141,9 @@ internal unsafe class ElementSelector : IDisposable
var mousePos = ImGui.GetMousePos() - MainViewport.Pos;
var addonResults = GetAtkUnitBaseAtPosition(mousePos);
ImGui.PushStyleColor(WindowBg, new Vector4(0.5f));
ImGui.BeginChild("noClick", new(800, 2000), false, NoInputs | NoBackground | NoScrollWithMouse);
ImGui.BeginGroup();
var col = ImRaii.PushColor(WindowBg, new Vector4(0.5f));
var ch = ImRaii.Child("noClick", new(800, 2000), false, NoInputs | NoBackground | NoScrollWithMouse);
var g = ImRaii.Group();
Gui.PrintFieldValuePair("Mouse Position", $"{mousePos.X}, {mousePos.Y}");
ImGui.Spacing();
@ -201,9 +204,9 @@ internal unsafe class ElementSelector : IDisposable
}
}
ImGui.EndGroup();
ImGui.EndChild();
ImGui.PopStyleColor();
g.Dispose();
ch.Dispose();
col.Pop();
}
private static List<AddonResult> GetAtkUnitBaseAtPosition(Vector2 position)
@ -381,9 +384,9 @@ internal unsafe class ElementSelector : IDisposable
return;
}
ImGui.PushStyleColor(Text, selected ? new Vector4(1, 1, 0.2f, 1) : new(0.6f, 0.6f, 0.6f, 1));
var col = ImRaii.PushColor(Text, selected ? new Vector4(1, 1, 0.2f, 1) : new(0.6f, 0.6f, 0.6f, 1));
ResNodeTree.GetOrCreate(node, tree).WriteTreeHeading();
ImGui.PopStyleColor();
col.Pop();
}
private void PerformSearch(nint address)

View file

@ -1,6 +1,7 @@
using System.Numerics;
using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using ImGuiNET;
@ -38,9 +39,9 @@ internal class AddonPopoutWindow : Window, IDisposable
/// <inheritdoc/>
public override void Draw()
{
ImGui.BeginChild($"{this.WindowName}child", new(-1, -1), true);
var ch = ImRaii.Child($"{this.WindowName}child", new(-1, -1), true);
this.addonTree.Draw();
ImGui.EndChild();
ch.Dispose();
}
/// <inheritdoc/>

View file

@ -1,6 +1,7 @@
using System.Numerics;
using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -49,9 +50,9 @@ internal unsafe class NodePopoutWindow : Window, IDisposable
{
if (this.Node != null && this.AddonTree.ContainsNode(this.Node))
{
ImGui.BeginChild($"{(nint)this.Node:X}popoutChild", new(-1, -1), true);
var ch = ImRaii.Child($"{(nint)this.Node:X}popoutChild", new(-1, -1), true);
ResNodeTree.GetOrCreate(this.Node, this.AddonTree).Print(null, this.firstDraw);
ImGui.EndChild();
ch.Dispose();
this.firstDraw = false;
}
else

View file

@ -2,6 +2,8 @@ using System.Collections.Generic;
using System.Numerics;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@ -51,18 +53,18 @@ internal unsafe partial class UiDebug2
private void DrawSidebar()
{
ImGui.BeginGroup();
var g = ImRaii.Group();
this.DrawNameSearch();
this.DrawAddonSelectionList();
this.elementSelector.DrawInterface();
ImGui.EndGroup();
g.Dispose();
}
private void DrawNameSearch()
{
ImGui.BeginChild("###sidebar_nameSearch", new(250, 40), true);
var ch = ImRaii.Child("###sidebar_nameSearch", new(250, 40), true);
var atkUnitBaseSearch = this.addonNameSearch;
Vector4? defaultColor = this.visFilter ? new(0.0f, 0.8f, 0.2f, 1f) : new Vector4(0.6f, 0.6f, 0.6f, 1);
@ -84,12 +86,12 @@ internal unsafe partial class UiDebug2
this.addonNameSearch = atkUnitBaseSearch;
}
ImGui.EndChild();
ch.Dispose();
}
private void DrawAddonSelectionList()
{
ImGui.BeginChild("###sideBar_addonList", new(250, -44), true, ImGuiWindowFlags.AlwaysVerticalScrollbar);
var ch = ImRaii.Child("###sideBar_addonList", new(250, -44), true, ImGuiWindowFlags.AlwaysVerticalScrollbar);
var unitListBaseAddr = GetUnitListBaseAddr();
@ -98,7 +100,7 @@ internal unsafe partial class UiDebug2
this.DrawUnitListOption(unitListBaseAddr, unit);
}
ImGui.EndChild();
ch.Dispose();
}
private void DrawUnitListOption(AtkUnitList* unitListBaseAddr, UnitListOption unit)
@ -144,26 +146,27 @@ internal unsafe partial class UiDebug2
return;
}
ImGui.PushStyleColor(ImGuiCol.Text, anyVisible ? new Vector4(1) : new Vector4(0.6f, 0.6f, 0.6f, 1));
var countStr = $"{(usingFilter ? $"{matchCount}/" : string.Empty)}{totalCount}";
var treePush = ImGui.TreeNodeEx($"{unit.Name} [{countStr}]###unitListTree{unit.Index}");
ImGui.PopStyleColor();
if (treePush)
var col1 = ImRaii.PushColor(ImGuiCol.Text, anyVisible ? new Vector4(1) : new Vector4(0.6f, 0.6f, 0.6f, 1));
var tree = ImRaii.TreeNode($"{unit.Name} [{countStr}]###unitListTree{unit.Index}");
col1.Pop();
if (tree)
{
foreach (var option in options)
{
ImGui.PushStyleColor(ImGuiCol.Text, option.Visible ? new Vector4(0.1f, 1f, 0.1f, 1f) : new Vector4(0.6f, 0.6f, 0.6f, 1));
var col2 = ImRaii.PushColor(ImGuiCol.Text, option.Visible ? new Vector4(0.1f, 1f, 0.1f, 1f) : new Vector4(0.6f, 0.6f, 0.6f, 1));
if (ImGui.Selectable($"{option.Name}##select{option.Name}", this.SelectedAddonName == option.Name))
{
this.SelectedAddonName = option.Name;
}
ImGui.PopStyleColor();
col2.Pop();
}
}
ImGui.TreePop();
}
tree.Dispose();
}
/// <summary>

View file

@ -2,6 +2,7 @@ using System.Collections.Generic;
using Dalamud.Game.Gui;
using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Services;
@ -43,7 +44,7 @@ internal partial class UiDebug2 : IDisposable
internal static IGameGui GameGui { get; set; } = null!;
/// <summary>
/// Gets a collection of <see cref="AddonTree"/> instances, each representing an <see cref="AtkUnitBase"/>.
/// Gets a collection of <see cref="AddonTree"/> instances, each representing an <see cref="FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase"/>.
/// </summary>
internal static Dictionary<string, AddonTree> AddonTrees { get; } = [];
@ -85,7 +86,7 @@ internal partial class UiDebug2 : IDisposable
private void DrawMainPanel()
{
ImGui.SameLine();
ImGui.BeginChild("###uiDebugMainPanel", new(-1, -1), true, HorizontalScrollbar);
var ch = ImRaii.Child("###uiDebugMainPanel", new(-1, -1), true, HorizontalScrollbar);
if (this.elementSelector.Active)
{
@ -107,6 +108,6 @@ internal partial class UiDebug2 : IDisposable
}
}
ImGui.EndChild();
ch.Dispose();
}
}

View file

@ -3,6 +3,8 @@ using System.Numerics;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics;
using ImGuiNET;
@ -16,54 +18,6 @@ namespace Dalamud.Interface.Internal.UiDebug2.Utility;
/// </summary>
internal static class Gui
{
/// <summary>
/// Begins a tree node that also displays a colored line to the left while open.
/// </summary>
/// <param name="label">The label of the tree.</param>
/// <param name="color">The color of the heading text.</param>
/// <param name="lineStart">A value representing where to begin drawing the left-side line.</param>
/// <param name="defOpen">Whether this tree should default to being open.</param>
/// <returns>true if the tree is open.</returns>
internal static bool NestedTreePush(string label, Vector4 color, out Vector2 lineStart, bool defOpen = false)
{
ImGui.PushStyleColor(Text, color);
var result = NestedTreePush(label, out lineStart, defOpen);
ImGui.PopStyleColor();
return result;
}
/// <inheritdoc cref="NestedTreePush(string, Vector4, out Vector2, bool)"/>
internal static bool NestedTreePush(string label, out Vector2 lineStart, bool defOpen = false)
{
var imGuiTreeNodeFlags = ImGuiTreeNodeFlags.SpanFullWidth;
if (defOpen)
{
imGuiTreeNodeFlags |= ImGuiTreeNodeFlags.DefaultOpen;
}
var treeNodeEx = ImGui.TreeNodeEx(label, imGuiTreeNodeFlags);
lineStart = ImGui.GetCursorScreenPos() + new Vector2(-10, 2);
return treeNodeEx;
}
/// <summary>
/// Completes a NestedTree.
/// </summary>
/// <param name="lineStart">The starting position calculated when the tree was pushed.</param>
/// <param name="color">The color of the left-side line.</param>
internal static void NestedTreePop(Vector2 lineStart, Vector4? color = null)
{
var lineEnd = lineStart with { Y = ImGui.GetCursorScreenPos().Y - 7 };
if (lineStart.Y < lineEnd.Y)
{
ImGui.GetWindowDrawList().AddLine(lineStart, lineEnd, RgbaVector4ToUint(color ?? new(1)), 1);
}
ImGui.TreePop();
}
/// <summary>
/// A radio-button-esque input that uses Fontawesome icon buttons.
/// </summary>
@ -150,31 +104,41 @@ 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)
{
var c = 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);
ImGui.SmallButton(fmt);
c.Pop(4);
return;
static double Luminosity(Vector4 vector4) =>
Math.Pow(
(Math.Pow(vector4.X, 2) * 0.299f) +
(Math.Pow(vector4.Y, 2) * 0.587f) +
(Math.Pow(vector4.Z, 2) * 0.114f),
0.5f) * vector4.W;
ImGui.PushStyleColor(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1));
ImGui.PushStyleColor(Button, color);
ImGui.PushStyleColor(ButtonActive, color);
ImGui.PushStyleColor(ButtonHovered, color);
ImGui.SmallButton(fmt);
ImGui.PopStyleColor(4);
}
/// <inheritdoc cref="ImGuiHelpers.ClickToCopyText"/>
internal static void ClickToCopyText(string text, string? textCopy = null)
{
ImGui.PushStyleColor(Text, new Vector4(0.6f, 0.6f, 0.6f, 1));
var c = ImRaii.PushColor(Text, new Vector4(0.6f, 0.6f, 0.6f, 1));
ImGuiHelpers.ClickToCopyText(text, textCopy);
ImGui.PopStyleColor();
c.Pop();
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip($"{textCopy ?? text}");
var t = ImRaii.Tooltip();
var f = ImRaii.PushFont(UiBuilder.IconFont);
ImGui.Text(FontAwesomeIcon.Copy.ToIconString());
f.Pop();
ImGui.SameLine();
ImGui.Text($"{textCopy ?? text}");
t.Dispose();
}
}
@ -197,7 +161,9 @@ internal static class Gui
var index = (int)Math.Floor(prog * tooltips.Length);
ImGui.SetTooltip(tooltips[index]);
var t = ImRaii.Tooltip();
ImGui.Text(tooltips[index]);
t.Dispose();
return true;
}

View file

@ -28,9 +28,7 @@ public unsafe struct NodeBounds
var w = node->Width;
var h = node->Height;
this.Points = w == 0 && h == 0 ?
new() { new(0) } :
new() { new(0), new(w, 0), new(w, h), new(0, h) };
this.Points = w == 0 && h == 0 ? [new(0)] : [new(0), new(w, 0), new(w, h), new(0, h)];
this.TransformPoints(node);
}
@ -149,8 +147,7 @@ public unsafe struct NodeBounds
var sinR = (float)Sin(r);
var d = (p - o) * s;
return new(o.X + (d.X * cosR) - (d.Y * sinR),
o.Y + (d.X * sinR) + (d.Y * cosR));
return new(o.X + (d.X * cosR) - (d.Y * sinR), o.Y + (d.X * sinR) + (d.Y * cosR));
}
private void TransformPoints(AtkResNode* transformNode)