fix(ui): keep spell components in authored foreground
Install examination formula icons as the template root UIRegion image, matching retail ClearImage/SetImage behavior while retaining the authored missing-component overlay. Add the real DAT template fixture and conformance coverage. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
d4ce64f56b
commit
2c3da8e153
14 changed files with 231 additions and 34 deletions
|
|
@ -5,8 +5,8 @@ namespace AcDream.App.UI.Layout;
|
|||
|
||||
/// <summary>
|
||||
/// Instantiates the authored formula-icon template used by retail
|
||||
/// <c>SpellExamineUI::ExamineSpell @ 0x004B6210</c>. The controller replaces
|
||||
/// the template root's placeholder image with the resolved component icon while
|
||||
/// <c>SpellExamineUI::ExamineSpell @ 0x004B6210</c>. The controller installs
|
||||
/// the component icon as the template root's own <c>UIRegion</c> image while
|
||||
/// retaining child <c>0x10000330</c> as the missing-component overlay.
|
||||
/// </summary>
|
||||
public sealed class SpellExamineComponentTemplateFactory
|
||||
|
|
@ -62,20 +62,13 @@ public sealed class SpellExamineComponentTemplateFactory
|
|||
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
|
||||
if (content.Root is not UiDatElement root)
|
||||
{
|
||||
Width = root.Width,
|
||||
Height = root.Height,
|
||||
Anchors = AnchorEdges.Left | AnchorEdges.Top
|
||||
| AnchorEdges.Right | AnchorEdges.Bottom,
|
||||
Texture = iconTexture,
|
||||
ZOrder = int.MinValue / 2,
|
||||
};
|
||||
root.AddChild(icon);
|
||||
throw new InvalidOperationException(
|
||||
$"Retail spell-component template 0x{TemplateId:X8} "
|
||||
+ "must resolve to a UIRegion-compatible element.");
|
||||
}
|
||||
root.RuntimeImageTexture = iconTexture;
|
||||
|
||||
if (content.FindElement(MissingOverlayId) is { } missing)
|
||||
missing.Visible = !owned;
|
||||
|
|
|
|||
|
|
@ -165,8 +165,37 @@ public sealed class UiDatElement : UiElement, IUiDatStateful
|
|||
/// </summary>
|
||||
public bool MediaVisible { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Runtime image installed on this region in place of its authored state media.
|
||||
/// A non-null value mirrors retail <c>UIRegion::ClearImage</c> followed by
|
||||
/// <c>UIRegion::SetImage</c>; zero deliberately leaves the region image-less.
|
||||
/// The image remains this element's own media, so authored descendants retain
|
||||
/// their normal foreground relationship.
|
||||
/// </summary>
|
||||
public uint? RuntimeImageTexture { get; set; }
|
||||
|
||||
protected override void OnDraw(UiRenderContext ctx)
|
||||
{
|
||||
if (MediaVisible && RuntimeImageTexture is uint runtimeTexture)
|
||||
{
|
||||
if (runtimeTexture != 0u)
|
||||
{
|
||||
ctx.DrawSprite(
|
||||
runtimeTexture,
|
||||
0f,
|
||||
0f,
|
||||
Width,
|
||||
Height,
|
||||
0f,
|
||||
0f,
|
||||
1f,
|
||||
1f,
|
||||
Vector4.One);
|
||||
}
|
||||
DrawLabel(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
var (file, _) = ActiveMedia();
|
||||
if (MediaVisible && file != 0)
|
||||
{
|
||||
|
|
@ -180,6 +209,11 @@ public sealed class UiDatElement : UiElement, IUiDatStateful
|
|||
}
|
||||
}
|
||||
|
||||
DrawLabel(ctx);
|
||||
}
|
||||
|
||||
private void DrawLabel(UiRenderContext ctx)
|
||||
{
|
||||
// Centered text label over the sprite (retail draws button captions as text;
|
||||
// their dat sprites are blank frames).
|
||||
if (Label is { Length: > 0 } label && LabelFont is { } lf)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue