feat: a frame's id, which FrameXML builds names out of

id="1" is how a frame in a numbered set knows which one it is, and neither
the emitter nor the widget API supported it at all — GetID and SetID simply
did not exist. FrameXML concatenates the result straight into a name:
PartyMemberFrame_RefreshPetDebuffs reaches for
_G["PartyMemberFrame" .. self:GetID() .. "PetFrame"], so every one of the
848 ids declared across 57 files was looking up the wrong frame.

Zero when unset, which is what the real client answers and what FrameXML
concatenates without checking.
This commit is contained in:
Kelsi
2026-08-01 16:02:15 -07:00
parent c3592b49a1
commit 30a8c0fd48
3 changed files with 21 additions and 0 deletions

View File

@@ -1397,6 +1397,10 @@ void LuaEngine::registerCoreAPI() {
"function mt:GetHorizontalScrollRange() return 0 end\n"
"function mt:GetVerticalScroll() return 0 end\n"
"function mt:GetHorizontalScroll() return 0 end\n"
// Zero when unset, which is what the real client answers and what
// FrameXML concatenates into a name without checking.
"function mt:SetID(id) self.__id = id end\n"
"function mt:GetID() return self.__id or 0 end\n"
"function mt:SetScrollChild(child) self.__scrollChild = child end\n"
"function mt:GetScrollChild() return self.__scrollChild end\n"
"function mt:SetFontString(fs) self.__fontString = fs end\n"

View File

@@ -408,6 +408,14 @@ struct Emitter {
if (const std::string* strata = node.attr("frameStrata")) {
line(var + ":SetFrameStrata(" + quote(*strata) + ")");
}
// How a frame in a numbered set knows which one it is, and FrameXML
// builds names out of it: PartyMemberFrame_RefreshPetDebuffs reaches
// for _G["PartyMemberFrame" .. self:GetID() .. "PetFrame"]. Ignoring
// the attribute left every one of the 848 declared across 57 files
// answering zero.
if (const std::string* id = node.attr("id"); id && !id->empty()) {
line(var + ":SetID(" + *id + ")");
}
if (node.attr("enableMouse")) {
line(var + ":EnableMouse(" + (node.attrBool("enableMouse") ? "true" : "false") + ")");
}

View File

@@ -229,6 +229,15 @@ TEST_CASE("A template installs OnLoad but does not run it", "[framexml][emit]")
REQUIRE(has(r.lua, "SetScript(\"OnLoad\""));
}
TEST_CASE("A frame's id becomes SetID", "[framexml][emit]") {
// How a frame in a numbered set knows which one it is. FrameXML builds
// names out of it — PartyMemberFrame_RefreshPetDebuffs reaches for
// _G["PartyMemberFrame" .. self:GetID() .. "PetFrame"] — and 848 of these
// are declared across 57 files.
XmlNode root = parseOrFail("<Ui><Frame name=\"F\" id=\"3\"/></Ui>");
REQUIRE(has(emitFrameXml(root).lua, ":SetID(3)"));
}
TEST_CASE("parentKey binds a region to a field on its owner", "[framexml][emit]") {
// How FrameXML's handlers reach their own pieces: QuestHonorFrameTemplate's
// OnLoad opens with self.icon:SetTexture(...), and the icon is bound only