using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Component.GUI; namespace LightlessSync.Utils; internal static unsafe class AtkNodeHelpers { internal const ushort DefaultTextNodeWidth = 200; internal const ushort DefaultTextNodeHeight = 14; internal static AtkTextNode* CreateNewTextNode(AtkUnitBase* pAddon, uint nodeID) { if (pAddon == null) return null; var pNewNode = CreateOrphanTextNode(nodeID); if (pNewNode != null) AttachTextNode(pAddon, pNewNode); return pNewNode; } internal static void HideNode(AtkUnitBase* pAddon, uint nodeID) { var pNode = GetTextNodeByID(pAddon, nodeID); if (pNode != null) ((AtkResNode*)pNode)->ToggleVisibility(false); } internal static AtkTextNode* GetTextNodeByID(AtkUnitBase* pAddon, uint nodeID) { if (pAddon == null) return null; for (var i = 0; i < pAddon->UldManager.NodeListCount; ++i) { if (pAddon->UldManager.NodeList[i] == null) continue; if (pAddon->UldManager.NodeList[i]->NodeId == nodeID) { return (AtkTextNode*)pAddon->UldManager.NodeList[i]; } } return null; } internal static void AttachTextNode(AtkUnitBase* pAddon, AtkTextNode* pNode) { if (pAddon == null) return; if (pNode != null) { var lastNode = pAddon->RootNode; if (lastNode->ChildNode != null) { lastNode = lastNode->ChildNode; while (lastNode->PrevSiblingNode != null) { lastNode = lastNode->PrevSiblingNode; } pNode->AtkResNode.NextSiblingNode = lastNode; pNode->AtkResNode.ParentNode = pAddon->RootNode; lastNode->PrevSiblingNode = (AtkResNode*)pNode; } else { lastNode->ChildNode = (AtkResNode*)pNode; pNode->AtkResNode.ParentNode = lastNode; } pAddon->UldManager.UpdateDrawNodeList(); } } internal static AtkTextNode* CreateOrphanTextNode(uint nodeID, TextFlags textFlags = TextFlags.Edge) { var pNewNode = (AtkTextNode*)IMemorySpace.GetUISpace()->Malloc((ulong)sizeof(AtkTextNode), 8); if (pNewNode != null) { IMemorySpace.Memset(pNewNode, 0, (ulong)sizeof(AtkTextNode)); pNewNode->Ctor(); pNewNode->AtkResNode.Type = NodeType.Text; pNewNode->AtkResNode.NodeFlags = NodeFlags.AnchorLeft | NodeFlags.AnchorTop; pNewNode->AtkResNode.DrawFlags = 0; pNewNode->AtkResNode.SetPositionShort(0, 0); pNewNode->AtkResNode.SetWidth(DefaultTextNodeWidth); pNewNode->AtkResNode.SetHeight(DefaultTextNodeHeight); pNewNode->LineSpacing = 24; pNewNode->CharSpacing = 1; pNewNode->AlignmentFontType = (byte)AlignmentType.BottomLeft; pNewNode->FontSize = 12; pNewNode->TextFlags = textFlags; pNewNode->AtkResNode.NodeId = nodeID; pNewNode->AtkResNode.Color.A = 0xFF; pNewNode->AtkResNode.Color.R = 0xFF; pNewNode->AtkResNode.Color.G = 0xFF; pNewNode->AtkResNode.Color.B = 0xFF; } return pNewNode; } }