Dalamud/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs
2025-11-20 19:32:37 +01:00

319 lines
12 KiB
C#

using System.Runtime.InteropServices;
using Dalamud.Bindings.ImGui;
using FFXIVClientStructs.FFXIV.Component.GUI;
using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui;
using static Dalamud.Utility.Util;
using static FFXIVClientStructs.FFXIV.Component.GUI.ComponentType;
namespace Dalamud.Interface.Internal.UiDebug2.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: {Marshal.PtrToStringAnsi(new(textInputComponent->AtkComponentInputBase.EvaluatedString.StringPtr))}");
ImGui.Text(
$"InputBase Text2: {Marshal.PtrToStringAnsi(new(textInputComponent->AtkComponentInputBase.RawString.StringPtr))}");
ImGui.Text(
$"Text1: {Marshal.PtrToStringAnsi(new(textInputComponent->UnkText01.StringPtr))}");
ImGui.Text(
$"Text2: {Marshal.PtrToStringAnsi(new(textInputComponent->UnkText02.StringPtr))}");
ImGui.Text(
$"AvailableLines: {Marshal.PtrToStringAnsi(new(textInputComponent->AvailableLines.StringPtr))}");
ImGui.Text(
$"HighlightedAutoTranslateOptionColorPrefix: {Marshal.PtrToStringAnsi(new(textInputComponent->HighlightedAutoTranslateOptionColorPrefix.StringPtr))}");
ImGui.Text(
$"HighlightedAutoTranslateOptionColorSuffix: {Marshal.PtrToStringAnsi(new(textInputComponent->HighlightedAutoTranslateOptionColorSuffix.StringPtr))}");
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;
}
}
}
}