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

View file

@ -1,4 +1,5 @@
using Dalamud.Interface.Internal.UiDebug2.Utility; using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
@ -25,44 +26,44 @@ public static class Events
return; return;
} }
if (ImGui.TreeNode($"Events##{(nint)node:X}eventTree")) var tree = ImRaii.TreeNode($"Events##{(nint)node:X}eventTree");
if (tree)
{ {
if (ImGui.BeginTable($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg)) var tab = ImRaii.Table($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg);
ImGui.TableSetupColumn("#", WidthFixed);
ImGui.TableSetupColumn("Type", WidthFixed);
ImGui.TableSetupColumn("Param", WidthFixed);
ImGui.TableSetupColumn("Flags", WidthFixed);
ImGui.TableSetupColumn("Unk29", WidthFixed);
ImGui.TableSetupColumn("Target", WidthFixed);
ImGui.TableSetupColumn("Listener", WidthFixed);
ImGui.TableHeadersRow();
var i = 0;
while (evt != null)
{ {
ImGui.TableSetupColumn("#", WidthFixed); ImGui.TableNextColumn();
ImGui.TableSetupColumn("Type", WidthFixed); ImGui.Text($"{i++}");
ImGui.TableSetupColumn("Param", WidthFixed); ImGui.TableNextColumn();
ImGui.TableSetupColumn("Flags", WidthFixed); ImGui.Text($"{evt->Type}");
ImGui.TableSetupColumn("Unk29", WidthFixed); ImGui.TableNextColumn();
ImGui.TableSetupColumn("Target", WidthFixed); ImGui.Text($"{evt->Param}");
ImGui.TableSetupColumn("Listener", WidthFixed); ImGui.TableNextColumn();
ImGui.Text($"{evt->Flags}");
ImGui.TableHeadersRow(); ImGui.TableNextColumn();
ImGui.Text($"{evt->Unk29}");
var i = 0; ImGui.TableNextColumn();
while (evt != null) Gui.ClickToCopyText($"{(nint)evt->Target:X}");
{ ImGui.TableNextColumn();
ImGui.TableNextColumn(); Gui.ClickToCopyText($"{(nint)evt->Listener:X}");
ImGui.Text($"{i++}"); evt = evt->NextEvent;
ImGui.TableNextColumn();
ImGui.Text($"{evt->Type}");
ImGui.TableNextColumn();
ImGui.Text($"{evt->Param}");
ImGui.TableNextColumn();
ImGui.Text($"{evt->Flags}");
ImGui.TableNextColumn();
ImGui.Text($"{evt->Unk29}");
ImGui.TableNextColumn();
Gui.ClickToCopyText($"{(nint)evt->Target:X}");
ImGui.TableNextColumn();
Gui.ClickToCopyText($"{(nint)evt->Listener:X}");
evt = evt->NextEvent;
}
ImGui.EndTable();
} }
ImGui.TreePop(); tab.Dispose();
} }
tree.Dispose();
} }
} }

View file

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

View file

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

View file

@ -1,6 +1,8 @@
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
@ -11,6 +13,7 @@ using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.TextureType; using static FFXIVClientStructs.FFXIV.Component.GUI.TextureType;
using static ImGuiNET.ImGuiTableColumnFlags; using static ImGuiNET.ImGuiTableColumnFlags;
using static ImGuiNET.ImGuiTableFlags; using static ImGuiNET.ImGuiTableFlags;
using static ImGuiNET.ImGuiTreeNodeFlags;
namespace Dalamud.Interface.Internal.UiDebug2.Browsing; namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
@ -60,7 +63,9 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
return; 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( PrintFieldValuePairs(
("Texture Type", $"{this.TexData.TexType}"), ("Texture Type", $"{this.TexData.TexType}"),
@ -93,9 +98,9 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
{ {
this.DrawFullTexture(); this.DrawFullTexture();
} }
ImGui.TreePop();
} }
tree.Dispose();
} }
/// <summary> /// <summary>
@ -157,7 +162,8 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
if (ImGui.IsItemClicked()) 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 Vector4({u}{suffix}, {v}{suffix}, {w}{suffix}, {h}{suffix})"
: $"new Vector2({u}{suffix}, {v}{suffix});\nnew Vector2({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() 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 ID", WidthFixed);
ImGui.TableSetupColumn("Part Texture", WidthFixed); ImGui.TableSetupColumn("Part Texture", WidthFixed);
ImGui.TableSetupColumn("Coordinates", WidthFixed); ImGui.TableSetupColumn("Coordinates", WidthFixed);
@ -200,17 +206,8 @@ internal unsafe partial class ImageNodeTree : ResNodeTree
{ {
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (i == this.TexData.PartId) 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.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);
}
ImGui.TableNextColumn(); 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); PrintPartCoords(u / tWidth, v / tWidth, (u + width) / tWidth, (v + height) / tHeight, true, true);
} }
ImGui.EndTable(); tab.Dispose();
} }
/// <summary> /// <summary>

View file

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

View file

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

View file

@ -1,10 +1,12 @@
using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Interface.ImGuiSeStringRenderer; using Dalamud.Interface.ImGuiSeStringRenderer;
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.System.String;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
@ -51,19 +53,19 @@ internal unsafe partial class TextNodeTree : ResNodeTree
#pragma warning disable #pragma warning disable
try try
{ {
var style = new SeStringDrawParams() var style = new SeStringDrawParams
{ {
Color = TxtNode->TextColor.RGBA, Color = this.TxtNode->TextColor.RGBA,
EdgeColor = TxtNode->EdgeColor.RGBA, EdgeColor = this.TxtNode->EdgeColor.RGBA,
ForceEdgeColor = true, ForceEdgeColor = true,
EdgeStrength = 1f EdgeStrength = 1f
}; };
ImGuiHelpers.SeStringWrapped(NodeText.AsSpan(), style); ImGuiHelpers.SeStringWrapped(this.NodeText.AsSpan(), style);
} }
catch catch
{ {
ImGui.Text(Marshal.PtrToStringAnsi(new(NodeText.StringPtr)) ?? ""); ImGui.Text(Marshal.PtrToStringAnsi(new(this.NodeText.StringPtr)) ?? "");
} }
#pragma warning restore #pragma warning restore
@ -81,7 +83,9 @@ internal unsafe partial class TextNodeTree : ResNodeTree
private void PrintPayloads() 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 utf8String = this.NodeText;
var seStringBytes = new byte[utf8String.BufUsed]; var seStringBytes = new byte[utf8String.BufUsed];
@ -100,15 +104,7 @@ internal unsafe partial class TextNodeTree : ResNodeTree
{ {
case PayloadType.RawText when payload is TextPayload tp: case PayloadType.RawText when payload is TextPayload tp:
{ {
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); Gui.PrintFieldValuePair("Raw Text", tp.Text ?? string.Empty);
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("'");
break; 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; namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
/// <inheritdoc cref="TimelineTree"/> /// <inheritdoc cref="TimelineTree"/>
public partial struct TimelineTree public readonly partial struct TimelineTree
{ {
/// <summary> /// <summary>
/// An interface for retrieving and printing the contents of a given column in an animation timeline table. /// 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 System.Numerics;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics; using FFXIVClientStructs.FFXIV.Client.Graphics;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
@ -13,6 +15,7 @@ using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.NodeType; using static FFXIVClientStructs.FFXIV.Component.GUI.NodeType;
using static ImGuiNET.ImGuiTableColumnFlags; using static ImGuiNET.ImGuiTableColumnFlags;
using static ImGuiNET.ImGuiTableFlags; using static ImGuiNET.ImGuiTableFlags;
using static ImGuiNET.ImGuiTreeNodeFlags;
// ReSharper disable SuggestBaseTypeForParameter // ReSharper disable SuggestBaseTypeForParameter
namespace Dalamud.Interface.Internal.UiDebug2.Browsing; namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
@ -20,9 +23,9 @@ namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
/// <summary> /// <summary>
/// A struct allowing a node's animation timeline to be printed and browsed. /// A struct allowing a node's animation timeline to be printed and browsed.
/// </summary> /// </summary>
public unsafe partial struct TimelineTree public readonly unsafe partial struct TimelineTree
{ {
private AtkResNode* node; private readonly AtkResNode* node;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TimelineTree"/> struct. /// Initializes a new instance of the <see cref="TimelineTree"/> struct.
@ -53,7 +56,9 @@ public unsafe partial struct TimelineTree
if (count > 0) 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}"); PrintFieldValuePair("Timeline", $"{(nint)this.NodeTimeline:X}");
@ -72,12 +77,12 @@ public unsafe partial struct TimelineTree
for (var a = 0; a < count; a++) for (var a = 0; a < count; a++)
{ {
var animation = this.Resource->Animations[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)))); 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); var columns = this.BuildColumns(animation);
ImGui.PushStyleColor(ImGuiCol.Text, isActive ? new Vector4(1, 0.65F, 0.4F, 1) : new(1)); var col = ImRaii.PushColor(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}"); var tree = ImRaii.TreeNode($"[#{a}] [Frames {animation.StartFrameIdx}-{animation.EndFrameIdx}] {(isActive ? " (Active)" : string.Empty)}###{(nint)this.node}animTree{a}");
ImGui.PopStyleColor(); col.Dispose();
if (treePush) if (tree)
{ {
PrintFieldValuePair("Animation", $"{address:X}"); PrintFieldValuePair("Animation", $"{address:X}");
@ -317,7 +322,7 @@ public unsafe partial struct TimelineTree
if (columns.Count > 0) 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) 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) private List<IKeyGroupColumn> BuildColumns(AtkTimelineAnimation animation)

View file

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

View file

@ -1,6 +1,7 @@
using System.Numerics; using System.Numerics;
using Dalamud.Interface.Internal.UiDebug2.Browsing; using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using ImGuiNET; using ImGuiNET;
@ -38,9 +39,9 @@ internal class AddonPopoutWindow : Window, IDisposable
/// <inheritdoc/> /// <inheritdoc/>
public override void Draw() 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(); this.addonTree.Draw();
ImGui.EndChild(); ch.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>

View file

@ -1,6 +1,7 @@
using System.Numerics; using System.Numerics;
using Dalamud.Interface.Internal.UiDebug2.Browsing; using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
@ -49,9 +50,9 @@ internal unsafe class NodePopoutWindow : Window, IDisposable
{ {
if (this.Node != null && this.AddonTree.ContainsNode(this.Node)) 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); ResNodeTree.GetOrCreate(this.Node, this.AddonTree).Print(null, this.firstDraw);
ImGui.EndChild(); ch.Dispose();
this.firstDraw = false; this.firstDraw = false;
} }
else else

View file

@ -2,6 +2,8 @@ using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using Dalamud.Interface.Components; using Dalamud.Interface.Components;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET; using ImGuiNET;
@ -14,7 +16,7 @@ namespace Dalamud.Interface.Internal.UiDebug2;
/// <inheritdoc cref="UiDebug2"/> /// <inheritdoc cref="UiDebug2"/>
internal unsafe partial class UiDebug2 internal unsafe partial class UiDebug2
{ {
/// <summary> /// <summary>
/// All unit lists to check for addons. /// All unit lists to check for addons.
/// </summary> /// </summary>
internal static readonly List<UnitListOption> UnitListOptions = internal static readonly List<UnitListOption> UnitListOptions =
@ -51,18 +53,18 @@ internal unsafe partial class UiDebug2
private void DrawSidebar() private void DrawSidebar()
{ {
ImGui.BeginGroup(); var g = ImRaii.Group();
this.DrawNameSearch(); this.DrawNameSearch();
this.DrawAddonSelectionList(); this.DrawAddonSelectionList();
this.elementSelector.DrawInterface(); this.elementSelector.DrawInterface();
ImGui.EndGroup(); g.Dispose();
} }
private void DrawNameSearch() 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; 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); 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; this.addonNameSearch = atkUnitBaseSearch;
} }
ImGui.EndChild(); ch.Dispose();
} }
private void DrawAddonSelectionList() 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(); var unitListBaseAddr = GetUnitListBaseAddr();
@ -98,7 +100,7 @@ internal unsafe partial class UiDebug2
this.DrawUnitListOption(unitListBaseAddr, unit); this.DrawUnitListOption(unitListBaseAddr, unit);
} }
ImGui.EndChild(); ch.Dispose();
} }
private void DrawUnitListOption(AtkUnitList* unitListBaseAddr, UnitListOption unit) private void DrawUnitListOption(AtkUnitList* unitListBaseAddr, UnitListOption unit)
@ -144,26 +146,27 @@ internal unsafe partial class UiDebug2
return; 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 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) 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)) if (ImGui.Selectable($"{option.Name}##select{option.Name}", this.SelectedAddonName == option.Name))
{ {
this.SelectedAddonName = option.Name; this.SelectedAddonName = option.Name;
} }
ImGui.PopStyleColor(); col2.Pop();
} }
ImGui.TreePop();
} }
tree.Dispose();
} }
/// <summary> /// <summary>

View file

@ -2,6 +2,7 @@ using System.Collections.Generic;
using Dalamud.Game.Gui; using Dalamud.Game.Gui;
using Dalamud.Interface.Internal.UiDebug2.Browsing; using Dalamud.Interface.Internal.UiDebug2.Browsing;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
@ -43,7 +44,7 @@ internal partial class UiDebug2 : IDisposable
internal static IGameGui GameGui { get; set; } = null!; internal static IGameGui GameGui { get; set; } = null!;
/// <summary> /// <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> /// </summary>
internal static Dictionary<string, AddonTree> AddonTrees { get; } = []; internal static Dictionary<string, AddonTree> AddonTrees { get; } = [];
@ -85,7 +86,7 @@ internal partial class UiDebug2 : IDisposable
private void DrawMainPanel() private void DrawMainPanel()
{ {
ImGui.SameLine(); ImGui.SameLine();
ImGui.BeginChild("###uiDebugMainPanel", new(-1, -1), true, HorizontalScrollbar); var ch = ImRaii.Child("###uiDebugMainPanel", new(-1, -1), true, HorizontalScrollbar);
if (this.elementSelector.Active) 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.Components;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics; using FFXIVClientStructs.FFXIV.Client.Graphics;
using ImGuiNET; using ImGuiNET;
@ -16,54 +18,6 @@ namespace Dalamud.Interface.Internal.UiDebug2.Utility;
/// </summary> /// </summary>
internal static class Gui 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> /// <summary>
/// A radio-button-esque input that uses Fontawesome icon buttons. /// A radio-button-esque input that uses Fontawesome icon buttons.
/// </summary> /// </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> /// <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) 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) => static double Luminosity(Vector4 vector4) =>
Math.Pow( Math.Pow(
(Math.Pow(vector4.X, 2) * 0.299f) + (Math.Pow(vector4.X, 2) * 0.299f) +
(Math.Pow(vector4.Y, 2) * 0.587f) + (Math.Pow(vector4.Y, 2) * 0.587f) +
(Math.Pow(vector4.Z, 2) * 0.114f), (Math.Pow(vector4.Z, 2) * 0.114f),
0.5f) * vector4.W; 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"/> /// <inheritdoc cref="ImGuiHelpers.ClickToCopyText"/>
internal static void ClickToCopyText(string text, string? textCopy = null) 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); ImGuiHelpers.ClickToCopyText(text, textCopy);
ImGui.PopStyleColor(); c.Pop();
if (ImGui.IsItemHovered()) 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); var index = (int)Math.Floor(prog * tooltips.Length);
ImGui.SetTooltip(tooltips[index]); var t = ImRaii.Tooltip();
ImGui.Text(tooltips[index]);
t.Dispose();
return true; return true;
} }

View file

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