ui: the ClassicAPI-era templates addons inherit by name

`CreateFrame(): Couldn't find inherited node "DialogBorderOpaqueTemplate"` is where
OpenMapClassic stopped — on its first file, inside Ace3, before a line of its own code ran.
It is not that addon's problem: `BackdropTemplate` is named **unguarded** by Ace3 itself
(`AceGUIContainer-Frame.lua:179` and `:206`, `AceGUIContainer-DropDownGroup.lua:128`), so
every Ace3 addon on this install hits it.

`assets/ui` does not grow, so this file carries its reason on that wall's own list: there is
no stock 1.12 file to migrate from, because 1.12 has neither template. They are the same kind
of surface as `script/compat/`'s verbs and live in XML only because `inherits=` is resolved by
the loader and cannot be answered from Lua.

**`BackdropTemplate` is correctly empty.** 9.0 moved the backdrop off the C side and invented
`BackdropTemplateMixin` to put it back; 1.12 still has `SetBackdrop`/`GetBackdrop`/
`SetBackdropColor`/`SetBackdropBorderColor` as real frame methods, so a frame inheriting the
template already answers all four. The mixin table exists for the
`BackdropTemplateMixin and "BackdropTemplate" or nil` idiom and for `Mixin()`, its rows
forwarding to the stock methods. **No getter rows**: a forwarding `GetBackdropColor` would
call itself once `Mixin()` had written it onto the frame, and the stock one already answers.

The dialog border is one `<Backdrop>` over this client's own dialog art — the shape every
stock 1.12 dialog draws, and the same block `GameMenuFrame.xml` uses — rather than a
transcription of Era's nine `SharedUIPanelTemplates.xml` textures. The opaque variant differs
only in background alpha, which is the one thing the two names disagree about. `enableMouse`
stays off: it is a decoration over a frame that handles its own input, and a border that ate
clicks would make an Ace options window unusable.

Movement: openmap `AceConfigDialog:573` → `:586`, now wanting `SetNormalFontObject`.

Full chain green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
2026-11-01 14:45:49 -07:00
co-authored by Claude Opus 5
parent e731a77a42
commit 164eb7e624
3 changed files with 104 additions and 0 deletions
@@ -0,0 +1,93 @@
<Ui>
<!--
The ClassicAPI-era FrameXML templates addons on this install inherit by name. Not windows:
there is nothing to migrate, because 1.12 does not have these templates at all — they are
the same kind of surface as `script/compat/`'s verbs, declared here because `inherits=` is
resolved by the XML loader and cannot be answered from Lua.
Both are used **unguarded inside Ace3 itself**, so this is not one addon's problem:
`AceGUIContainer-Frame.lua:179` and `:206` and `AceGUIContainer-DropDownGroup.lua:128`
name `BackdropTemplate`, and `AceConfigDialog-3.0.lua:573` names
`DialogBorderOpaqueTemplate`. A missing template makes `CreateFrame` raise
("Couldn't find inherited node"), which is where OpenMapClassic stopped — on its first
file, in a library, before a line of its own code ran.
-->
<!--
9.0 moved the backdrop off the C side and gave addons `BackdropTemplateMixin` to put it
back; 1.12 has `SetBackdrop`/`GetBackdrop`/`SetBackdropColor`/`SetBackdropBorderColor` as
real frame methods, so the template is correctly **empty** — a frame inheriting it already
answers all four. The global the mixin idiom tests for
(`BackdropTemplateMixin and "BackdropTemplate" or nil`) is set beside it, its methods
forwarding to those stock ones so `Mixin(f, BackdropTemplateMixin)` is a no-op rather than
a shadow. `OnBackdropLoaded`/`OnBackdropSizeChanged` are the hooks 9.0's own template
fires; ours have nothing to recompute, and an addon that calls one gets a function rather
than a nil.
-->
<Frame name="BackdropTemplate" virtual="true"/>
<!--
A dialog border frame, which is all Ace3 wants of it: `local border = CreateFrame("Frame",
nil, frame, "DialogBorderOpaqueTemplate")` then `border:SetAllPoints(frame)`. Era's own is
nine textures out of `SharedUIPanelTemplates.xml`; the same shape in 1.12's vocabulary is
one `<Backdrop>` over this client's dialog art, which is what every stock 1.12 dialog
draws and what our `GameMenuFrame.xml` already uses. The opaque variant differs only in
its background alpha, hence the two rows.
`enableMouse` stays off: it is a decoration over a frame that handles its own input, and a
border that ate clicks would make an Ace options window unusable.
-->
<Frame name="DialogBorderTemplate" virtual="true">
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
<TileSize><AbsValue val="32"/></TileSize>
<EdgeSize><AbsValue val="32"/></EdgeSize>
<Color r="1" g="1" b="1" a="0.85"/>
</Backdrop>
</Frame>
<Frame name="DialogBorderOpaqueTemplate" virtual="true">
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
<TileSize><AbsValue val="32"/></TileSize>
<EdgeSize><AbsValue val="32"/></EdgeSize>
<Color r="1" g="1" b="1" a="1"/>
</Backdrop>
</Frame>
<Script><![CDATA[
-- The mixin 9.0 shipped so addons could call the backdrop methods it had removed. Here
-- the stock methods are the real ones, so each row forwards; the table exists for the
-- `BackdropTemplateMixin and "BackdropTemplate"` test and for `Mixin()`.
BackdropTemplateMixin = {}
function BackdropTemplateMixin.OnBackdropLoaded(self) end
function BackdropTemplateMixin.OnBackdropSizeChanged(self) end
function BackdropTemplateMixin.SetupTextureCoordinates(self) end
function BackdropTemplateMixin.ApplyBackdrop(self)
-- 9.0's own ApplyBackdrop re-reads `self.backdropInfo`; ours hands it to the stock
-- setter, which is the same journey with the C side still present.
if self.backdropInfo then
self:SetBackdrop(self.backdropInfo)
if self.backdropColor then
local c = self.backdropColor
self:SetBackdropColor(c.r, c.g, c.b, self.backdropColorAlpha or 1)
end
if self.backdropBorderColor then
local c = self.backdropBorderColor
self:SetBackdropBorderColor(c.r, c.g, c.b, self.backdropBorderColorAlpha or 1)
end
end
end
function BackdropTemplateMixin.ClearBackdrop(self)
self:SetBackdrop(nil)
end
-- No getter rows: 1.12's own `GetBackdrop`/`GetBackdropColor`/`GetBackdropBorderColor`
-- already answer, and a forwarding copy would call *itself* once `Mixin()` had written it
-- onto the frame.
]]></Script>
</Ui>
+4
View File
@@ -86,6 +86,10 @@ Interface\FrameXML\ComboFrame.xml
# Ours: the scroll parts of our options window and script log.
ScrollTemplates.xml
# The ClassicAPI-era templates addons inherit by name (Ace3 names two of them unguarded).
# Templates only, so anywhere above the addon load is correct; here, beside our other one.
CompatTemplates.xml
Interface\FrameXML\UIPanelTemplates.lua
Interface\FrameXML\UIPanelTemplates.xml
@@ -1974,6 +1974,13 @@ fn assets_ui_does_not_grow() {
// falls through into `attempt to call local 'handledata'`. There is no stock file to
// migrate — AIO is the realm's, not Blizzard's. The file's own header has the trace.
"AIOHandlers.lua",
// Not a window either: the ClassicAPI-era FrameXML templates addons inherit by name,
// which have no stock 1.12 file to migrate from because 1.12 has no such templates. They
// live in XML rather than `script/compat/` only because `inherits=` is resolved by the
// loader and cannot be answered from Lua. Ace3 names two of them **unguarded**, so a
// missing one raises inside the library: `CreateFrame(): Couldn't find inherited node
// "DialogBorderOpaqueTemplate"` is where OpenMapClassic stopped, on its first file.
"CompatTemplates.xml",
"ContainerFrameAdapters.xml",
"GameMenuFrame.xml",
"KeyBindingsPage.xml",