Dalamud/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Component.cs
Infi 672636c3bf
Remove UiDebug V1 in favor of V2 (#2586)
* - Remove UiDebug1 in favor of UiDebug2

* - Remove all mentions of 2
2026-01-25 19:21:03 -08:00

315 lines
12 KiB
C#

using System.Runtime.InteropServices;
using Dalamud.Bindings.ImGui;
using FFXIVClientStructs.FFXIV.Component.GUI;
using Lumina.Text.ReadOnly;
using static Dalamud.Interface.Internal.UiDebug.Utility.Gui;
using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.ComponentType;
namespace Dalamud.Interface.Internal.UiDebug.Browsing;
/// <summary>
/// A tree for an <see cref="AtkComponentNode"/> that can be printed and browsed via ImGui.
/// </summary>
internal unsafe class ComponentNodeTree : ResNodeTree
{
private readonly ComponentType componentType;
/// <summary>
/// Initializes a new instance of the <see cref="ComponentNodeTree"/> class.
/// </summary>
/// <param name="node">The node to create a tree for.</param>
/// <param name="addonTree">The tree representing the containing addon.</param>
internal ComponentNodeTree(AtkResNode* node, AddonTree addonTree)
: base(node, addonTree)
{
this.NodeType = 0;
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;
private int? ComponentFieldOffset { get; set; }
/// <inheritdoc/>
private protected override string GetHeaderText()
{
var childCount = (int)this.UldManager->NodeListCount;
return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)}";
}
/// <inheritdoc/>
private protected override void PrintNodeObject()
{
base.PrintNodeObject();
this.PrintComponentObject();
ImGui.SameLine();
ImGui.NewLine();
this.PrintComponentDataObject();
ImGui.SameLine();
ImGui.NewLine();
}
/// <inheritdoc/>
private protected override void PrintChildNodes()
{
var prevNode = this.CompNode->Component->UldManager.RootNode;
while (prevNode != null)
{
GetOrCreate(prevNode, this.AddonTree).Print(null);
prevNode = prevNode->PrevSiblingNode;
}
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 PrintFieldLabels()
{
this.PrintFieldLabel((nint)this.Node, new(0, 0.85F, 1, 1), this.NodeFieldOffset);
this.PrintFieldLabel((nint)this.Component, new(0f, 0.5f, 0.8f, 1f), this.ComponentFieldOffset);
}
/// <inheritdoc/>
private protected override void PrintFieldsForNodeType(bool isEditorOpen = false)
{
if (this.Component == null)
{
return;
}
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (this.componentType)
{
case TextInput:
var textInputComponent = (AtkComponentTextInput*)this.Component;
ImGui.Text($"InputBase Text1 (Lumina): {new ReadOnlySeStringSpan(textInputComponent->AtkComponentInputBase.EvaluatedString.AsSpan()).ToMacroString()}");
ImGui.Text($"InputBase Text2 (Lumina): {new ReadOnlySeStringSpan(textInputComponent->AtkComponentInputBase.RawString.AsSpan()).ToMacroString()}");
// TODO: Reenable when unknowns have been unprivated / named
// ImGui.Text($"Text1: {new ReadOnlySeStringSpan(textInputComponent->UnkText01.AsSpan()).ToMacroString()}");
// ImGui.Text($"Text2: {new ReadOnlySeStringSpan(textInputComponent->UnkText02.AsSpan()).ToMacroString()}");
ImGui.Text($"AvailableLines: {new ReadOnlySeStringSpan(textInputComponent->AvailableLines.AsSpan()).ToMacroString()}");
ImGui.Text($"HighlightedAutoTranslateOptionColorPrefix: {new ReadOnlySeStringSpan(textInputComponent->HighlightedAutoTranslateOptionColorPrefix.AsSpan()).ToMacroString()}");
ImGui.Text($"HighlightedAutoTranslateOptionColorSuffix: {new ReadOnlySeStringSpan(textInputComponent->HighlightedAutoTranslateOptionColorSuffix.AsSpan()).ToMacroString()}");
break;
case List:
case TreeList:
var l = (AtkComponentList*)this.Component;
if (ImGui.SmallButton("Inc.Selected"u8))
{
l->SelectedItemIndex++;
}
break;
}
}
/// <inheritdoc/>
private protected override void GetFieldOffset()
{
var nodeFound = false;
var componentFound = false;
for (var i = 0; i < this.AddonTree.AddonSize; i += 0x8)
{
var readPtr = Marshal.ReadIntPtr(this.AddonTree.InitialPtr + i);
if (readPtr == (nint)this.Node)
{
this.NodeFieldOffset = i;
nodeFound = true;
}
if (readPtr == (nint)this.Component)
{
this.ComponentFieldOffset = i;
componentFound = true;
}
if (nodeFound && componentFound)
{
break;
}
}
}
private void PrintComponentObject()
{
PrintFieldValuePair("Component", $"{(nint)this.Component:X}");
ImGui.SameLine();
switch (this.componentType)
{
case Button:
ShowStruct((AtkComponentButton*)this.Component);
break;
case Slider:
ShowStruct((AtkComponentSlider*)this.Component);
break;
case Window:
ShowStruct((AtkComponentWindow*)this.Component);
break;
case CheckBox:
ShowStruct((AtkComponentCheckBox*)this.Component);
break;
case GaugeBar:
ShowStruct((AtkComponentGaugeBar*)this.Component);
break;
case RadioButton:
ShowStruct((AtkComponentRadioButton*)this.Component);
break;
case TextInput:
ShowStruct((AtkComponentTextInput*)this.Component);
break;
case Icon:
ShowStruct((AtkComponentIcon*)this.Component);
break;
case NumericInput:
ShowStruct((AtkComponentNumericInput*)this.Component);
break;
case List:
ShowStruct((AtkComponentList*)this.Component);
break;
case TreeList:
ShowStruct((AtkComponentTreeList*)this.Component);
break;
case DropDownList:
ShowStruct((AtkComponentDropDownList*)this.Component);
break;
case ScrollBar:
ShowStruct((AtkComponentScrollBar*)this.Component);
break;
case ListItemRenderer:
ShowStruct((AtkComponentListItemRenderer*)this.Component);
break;
case IconText:
ShowStruct((AtkComponentIconText*)this.Component);
break;
case ComponentType.DragDrop:
ShowStruct((AtkComponentDragDrop*)this.Component);
break;
case GuildLeveCard:
ShowStruct((AtkComponentGuildLeveCard*)this.Component);
break;
case TextNineGrid:
ShowStruct((AtkComponentTextNineGrid*)this.Component);
break;
case JournalCanvas:
ShowStruct((AtkComponentJournalCanvas*)this.Component);
break;
case HoldButton:
ShowStruct((AtkComponentHoldButton*)this.Component);
break;
case Portrait:
ShowStruct((AtkComponentPortrait*)this.Component);
break;
default:
ShowStruct(this.Component);
break;
}
}
private void PrintComponentDataObject()
{
var componentData = this.Component->UldManager.ComponentData;
PrintFieldValuePair("Data", $"{(nint)componentData:X}");
if (componentData != null)
{
ImGui.SameLine();
switch (this.componentType)
{
case Base:
ShowStruct(componentData);
break;
case Button:
ShowStruct((AtkUldComponentDataButton*)componentData);
break;
case Window:
ShowStruct((AtkUldComponentDataWindow*)componentData);
break;
case CheckBox:
ShowStruct((AtkUldComponentDataCheckBox*)componentData);
break;
case RadioButton:
ShowStruct((AtkUldComponentDataRadioButton*)componentData);
break;
case GaugeBar:
ShowStruct((AtkUldComponentDataGaugeBar*)componentData);
break;
case Slider:
ShowStruct((AtkUldComponentDataSlider*)componentData);
break;
case TextInput:
ShowStruct((AtkUldComponentDataTextInput*)componentData);
break;
case NumericInput:
ShowStruct((AtkUldComponentDataNumericInput*)componentData);
break;
case List:
ShowStruct((AtkUldComponentDataList*)componentData);
break;
case DropDownList:
ShowStruct((AtkUldComponentDataDropDownList*)componentData);
break;
case Tab:
ShowStruct((AtkUldComponentDataTab*)componentData);
break;
case TreeList:
ShowStruct((AtkUldComponentDataTreeList*)componentData);
break;
case ScrollBar:
ShowStruct((AtkUldComponentDataScrollBar*)componentData);
break;
case ListItemRenderer:
ShowStruct((AtkUldComponentDataListItemRenderer*)componentData);
break;
case Icon:
ShowStruct((AtkUldComponentDataIcon*)componentData);
break;
case IconText:
ShowStruct((AtkUldComponentDataIconText*)componentData);
break;
case ComponentType.DragDrop:
ShowStruct((AtkUldComponentDataDragDrop*)componentData);
break;
case GuildLeveCard:
ShowStruct((AtkUldComponentDataGuildLeveCard*)componentData);
break;
case TextNineGrid:
ShowStruct((AtkUldComponentDataTextNineGrid*)componentData);
break;
case JournalCanvas:
ShowStruct((AtkUldComponentDataJournalCanvas*)componentData);
break;
case Multipurpose:
ShowStruct((AtkUldComponentDataMultipurpose*)componentData);
break;
case Map:
ShowStruct((AtkUldComponentDataMap*)componentData);
break;
case Preview:
ShowStruct((AtkUldComponentDataPreview*)componentData);
break;
case HoldButton:
ShowStruct((AtkUldComponentDataHoldButton*)componentData);
break;
case Portrait:
ShowStruct((AtkUldComponentDataPortrait*)componentData);
break;
default:
ShowStruct(componentData);
break;
}
}
}
}