using AcDream.Content; using DatReaderWriter; namespace AcDream.App.UI.Layout; /// /// Instantiates the authored formula-icon template used by retail /// SpellExamineUI::ExamineSpell @ 0x004B6210. The controller replaces /// the template root's placeholder image with the resolved component icon while /// retaining child 0x10000330 as the missing-component overlay. /// public sealed class SpellExamineComponentTemplateFactory { public const uint TemplateId = 0x1000032Eu; public const uint MissingOverlayId = 0x10000330u; private readonly ElementInfo _template; private readonly Func _resolveSprite; private readonly UiDatFont? _defaultFont; private readonly IReadOnlyDictionary _fonts; public SpellExamineComponentTemplateFactory( ElementInfo template, Func resolveSprite, UiDatFont? defaultFont, IReadOnlyDictionary? fonts = null) { _template = template ?? throw new ArgumentNullException(nameof(template)); _resolveSprite = resolveSprite ?? throw new ArgumentNullException(nameof(resolveSprite)); _defaultFont = defaultFont; _fonts = fonts ?? new Dictionary(); } public static SpellExamineComponentTemplateFactory? TryLoad( IDatReaderWriter dats, Func resolveSprite, UiDatFont? defaultFont, Func? resolveFont) { ElementInfo? template = LayoutImporter.ImportInfos( dats, AppraisalUiController.LayoutId, TemplateId); if (template is null) return null; var fonts = new Dictionary(); CaptureFonts(template, resolveFont, fonts); return new SpellExamineComponentTemplateFactory( template, resolveSprite, defaultFont, fonts); } public UiElement Create(uint iconTexture, bool owned) { ImportedLayout content = LayoutImporter.Build( _template, _resolveSprite, _defaultFont, did => _fonts.TryGetValue(did, out UiDatFont? font) ? font : _defaultFont); UiElement root = content.Root; if (root is UiDatElement datRoot) datRoot.MediaVisible = false; var icon = new UiTextureElement { Width = root.Width, Height = root.Height, Anchors = AnchorEdges.Left | AnchorEdges.Top | AnchorEdges.Right | AnchorEdges.Bottom, Texture = iconTexture, ZOrder = int.MinValue / 2, }; root.AddChild(icon); if (content.FindElement(MissingOverlayId) is { } missing) missing.Visible = !owned; return root; } private static void CaptureFonts( ElementInfo info, Func? resolveFont, Dictionary fonts) { if (info.FontDid != 0u && !fonts.ContainsKey(info.FontDid)) fonts[info.FontDid] = resolveFont?.Invoke(info.FontDid); foreach (ElementInfo child in info.Children) CaptureFonts(child, resolveFont, fonts); } }