the world map's arrow shows on zone sheets, and UIParent goes stock

- the world map's arrow shows on every zone sheet, and alt-clicking a town jumps there: the stock file creates the player arrow as a `Model` child of `WorldMapFrame` and lays a zone sheet's explored-area overlays as ARTWORK textures on `WorldMapDetailFrame` — one `(strata, level)` bucket, where the draw layer outranks the frame — and benilla drew a model's scene at the frame's own layer-0 slot, so every overlay painted over it (the continent sheet has no overlays, which is why it was the only sheet with an arrow); wow-re's carve: a layer batch carries three sub-arrays — quads, the string batch, a render-callback list — that `0x76fb00` drains in that order, and `0x76d160` registers a model's callback only for layer 2 (`0x76d17f cmp ebx,2`), so a model's scene is ARTWORK content, neither a separate pass nor a layer-0 slot; a `ModelPane` quad now keys at the ARTWORK content rank, which re-orders the pet page's happiness icon (a sibling's BACKGROUND quad) under the pane's scene — the reference's own order, harmless because the bake is transparent where the model is not; a model against a LATER-linked ARTWORK font string in the same bucket is still ordered by link stamp, named not built; and the alt-click jump, which required the topmost frame under the cursor to be `WorldMapButton` itself while the stock file parents every POI icon and blip to that button, now walks up from whatever was hit to the button and takes its rect — the map's own chrome still answers nothing (1992)
- `UIParent` is the reference's own: `UIParent.xml` loads off the chain at its toc's slot, right after `WorldFrame.xml`, sourcing `UIParent.lua` and `LocaleProperties.lua` itself, and our `UIParent.xml` + `UiPanels.xml` — 3086 lines of transcribed `UIParent.lua` — are deleted; the one unbound verb the stock file ticks, `CheckReadyCheckTime`, was already 1989's; back from the reference: all sixty-six registered events and their arms (`PLAYER_CONTROL_LOST`/`_GAINED`, `RAID_ROSTER_UPDATE`, the trade-request pair, `PLAYER_SKINNED`, `GOSSIP_ENTER_CODE`), the ESC ladder as written — StaticPopup, the options window's Cancel, the game menu, `CloseMenus`, `SpellStopCasting`, `SpellStopTargeting`, `CloseAllWindows`, `ClearTarget`, else open — so ESC no longer clears a held cursor item or cancels the colour picker, two arms ours had grown that the reference does not have; the fade/flash/pulse kits walked from `UIParent`'s own OnUpdate in place of three 1×1 driver frames of ours, so a cinematic's `UIParent:Hide()` stops the walks as it does there; the managed bottom-stack positions without our `UIParent_RegisterManagedPositionListener` extension, which no shipped file registered any more; `LowHealthFrame`/`OutOfControlFrame`; and the `firstTimeLoaded` close on re-show; what stayed ours moved out — the window tab template and its OnUpdate settle (1004's async-measure adapter) and `BENILLA_FALLBACK_ICON` to `ScrollTemplates.xml`, 0561's bag verbs to `ContainerFrameAdapters`, the script log's slot row to its own file, `OptionsFrameCancel = OptionsFrameCloseButton` beside the two options aliases — and the Auction/Inspect/Macro/Talent panel rows, verbatim copies of the LoadOnDemand addons' own registrations, go; the reference also decides that the area spirit healer's dialog accepts on show with one CANCEL button, that losing control closes every window bar the reference's exceptions, and that the bottom-bar clearance reads the saved globals `SHOW_MULTI_ACTIONBAR_1`/`_2` rather than the bars' shown state; three integration binaries that kept private copies of the manifest loader use the shared one now (1988)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-09-06 19:30:54 +07:00
co-authored by Claude Fable 5.1
parent bc1a2428dd
commit 7a825111ab
99 changed files with 1191 additions and 3779 deletions
@@ -96,25 +96,72 @@
refItemButtonOnEnter(button)
end
-- ══ Re-publishing the three bag verbs 0561 shadows, and why it is HERE ═════════════
-- ══ The three bag verbs benilla answers differently (decisions 0561 + 1751) ═════════
--
-- `OpenBackpack`, `CloseBackpack` and `CloseAllBags` are all defined by the sourced
-- `ContainerFrame.lua` (l.187-217, l.702-707) — and benilla answers all three differently,
-- for one reason: **0561, the director's call that a window opening your bags opens EVERY
-- equipped bag**, not just the backpack. The vendor, bank, mail and trade windows call
-- `OpenBackpack` from their OnShow so your bags come up with them and you can sell or
-- deposit from one.
-- `CloseAllBags`, `OpenBackpack` and `CloseBackpack` all exist in the sourced
-- `ContainerFrame.lua` too, and benilla's differ for one reason, not three: **0561, the
-- director's call that a window which opens your bags opens EVERY equipped bag**, not just
-- the backpack. The vendor/bank/mail/trade windows call `OpenBackpack` from their OnShow so
-- your bags come up with them and you can sell or deposit from one; the reference's own
-- body touches bag 0 alone. `CloseBackpack` is its inverse and has to match it, and
-- `CloseAllBags` is the same family's unconditional form.
--
-- The bodies live in `UiPanels.xml`, because every window that calls them is loaded by
-- harnesses that have no bag stack at all, and a nil `OpenBackpack` in a merchant test is
-- a nil for no reason. But UiPanels is manifest entry 7 and the reference's container file
-- is entry 46, so **its publications lose the collision** — the reference's bodies land on
-- top and the vendor silently stops opening your bags. That is not hypothetical: it is
-- what shipped for the length of one session before a test caught it.
-- **The `Benilla*` names, and the publish under them, are load ORDER** (1751). Order
-- decides every collision and the manifest is the order: this file loads after the
-- reference's `ContainerFrame.xml`, so the three publishes at the foot are the ones that
-- stand. The bodies lived in our UIParent.lua counterpart until 1988 retired it — a
-- harness with no bag stack now meets the loader's stand-ins for the three names
-- (`test_ui::UIPARENT_STAND_INS`), not a nil.
--
-- So the bodies stay where their callers can reach them, under `Benilla*` names that
-- nothing overwrites, and this file — entry 49, after the reference's — puts them back on
-- the reference's names. Three lines, and they are the whole of the fix.
-- What CHANGED with the swap is only the plumbing: these used to walk five benilla windows
-- by name and stash `wasOpen` on each frame. The windows are the reference's recycled
-- `ContainerFrame1..12` now — frame N is a different bag every time it opens — so the
-- was-open memory is keyed by BAG ID, and every open and close goes through the
-- reference's own `OpenBag`/`CloseBag`/`IsBagOpen` rather than a raw Show/Hide. That buys
-- the reference's own guards for free (OpenBag's CanOpenPanels + NotWhileDeadError,
-- ToggleBag's `size > 0`) and means an addon replacing those verbs is honoured here too.
BENILLA_BAG_WAS_OPEN = {}
-- The UNCONDITIONAL close, called by ShowUIPanel's native-center branch above: a centre
-- frame takes the whole screen, so nothing is being "restored afterwards" the way a vendor
-- window restores the bags it opened, and the was-open memory is deliberately ignored.
-- Range 0..NUM_CONTAINER_FRAMES rather than the old five names — the reference's own
-- CloseAllBags covers the bank bags too (l.702-707), and now so does this.
function BenillaCloseAllBags()
for bagId = 0, (NUM_CONTAINER_FRAMES or -1) do
CloseBag(bagId)
end
end
-- OpenBackpack — 0561's all-bags form. A bag already open is REMEMBERED and left alone, so
-- the paired CloseBackpack does not close a window the player opened themselves; that
-- memory is the reference's own `backpackWasOpen`, one entry per bag instead of one flag.
function BenillaOpenBackpack()
for bagId = 0, (NUM_BAG_FRAMES or -1) do
-- The backpack always exists; an equipped-bag window only when a bag is in the
-- slot — `OpenBag` makes the same test itself, but the memory has to agree with it.
if bagId == 0 or GetContainerNumSlots(bagId) > 0 then
if IsBagOpen(bagId) then
BENILLA_BAG_WAS_OPEN[bagId] = 1
else
BENILLA_BAG_WAS_OPEN[bagId] = nil
OpenBag(bagId)
end
end
end
end
function BenillaCloseBackpack()
for bagId = 0, (NUM_BAG_FRAMES or -1) do
if not BENILLA_BAG_WAS_OPEN[bagId] then
CloseBag(bagId)
end
end
end
-- The publish — after the reference's container file, so these are the definitions that
-- stand (the stock `ShowUIPanel` calls `CloseAllBags` and the vendor's OnShow
-- `OpenBackpack`, and they reach 0561's bodies).
OpenBackpack = BenillaOpenBackpack
CloseBackpack = BenillaCloseBackpack
CloseAllBags = BenillaCloseAllBags
@@ -39,7 +39,7 @@
· **The two logout dialogs** — ref `StaticPopup.lua` l.564-600 (CAMP + QUIT) is the
SPECIFICATION for them: the two dialog keys, the field names, the 20 s timeout and the
asymmetric button sets are contract, and the entries carrying them are written here in
our own shape on the shared popup engine (UiPanels.xml), whose countdown-text branch
our own shape on the shared popup engine (the stock StaticPopup), whose countdown-text branch
already lists both `which` names. Their driver events are the reference's own
(`re/events/event-catalog.tsv`: 276 PLAYER_CAMPING, 277 PLAYER_QUITING,
278 LOGOUT_CANCEL), fired by `crate::ui_logout` off `SMSG_LOGOUT_RESPONSE`.
@@ -119,7 +119,7 @@
button:Disable()
end
-- The CAMP/QUIT dialogs and the three-event driver MOVED OUT, to UiPanels.xml — the
-- The CAMP/QUIT dialogs and the three-event driver MOVED OUT, to our UIParent.lua counterpart (the stock UIParent.lua since 1988) — the
-- reference's own homes for both (StaticPopup.lua l.564/586; UIParent.lua l.304-315).
-- They were here only because this is where they were first needed, and 1751 moving them
-- is one less thing to carry when this window follows them onto the chain.
@@ -287,7 +287,7 @@
while the menu is up, and the bag bar greys out under it (you cannot open bags from
behind the menu — ShowUIPanel's center gate would refuse the window anyway, so the
greying is the visible half of a rule the panel manager already enforces). Guarded, the
UiPanels.xml `CloseMenus and CloseMenus()` posture: a headless test loads this file
the old UiPanels.xml `CloseMenus and CloseMenus()` posture: a headless test loads this file
without the action bar behind it. -->
<Scripts>
<OnLoad>GameMenuFrameTitle:SetText(MAIN_MENU)</OnLoad>
@@ -152,7 +152,7 @@
-- ── Key display ── the 1.12 GetBindingText law by hand: modifier prefixes stay the
-- canonical uppercase tokens, the base key reads its KEY_* global (Spacebar, Up Arrow,
-- Mouse Button 4...) else itself. "CTRL--" renders CTRL + the minus key. (The action
-- bar's ABBREVIATED labels ride our own GetBindingText in UIParent.xml;
-- bar's ABBREVIATED labels ride the stock GetBindingText (UIParent.lua);
-- this page and the tooltips show the full form, both references' own split.)
function KeyBindings_KeyText(key)
if not key then
@@ -4063,9 +4063,14 @@
is down (MainMenuBarMicroButtons.lua l.47-52; decision 1987). These two aliases are the
adapter: a stock read of either sibling is answered by this window, which is the honest
answer — while ours is up, the reference's question "is an options window open" is yes.
BENILLA_ALLOW_OWN_UI=1 -->
The third alias is the ESC ladder's: the stock `ToggleGameMenu` (UIParent.lua l.1465-1497,
off the chain since 1988) closes an open options window with `OptionsFrameCancel:Click()`,
the reference's Cancel button; ours has a corner X whose click is the same discard-and-hide
(`HideUIPanel(OptionsFrame)`, and OnHide discards the pending page), so that button answers
to the reference's name. BENILLA_ALLOW_OWN_UI=1 -->
<Script><![CDATA[
UIOptionsFrame = OptionsFrame
SoundOptionsFrame = OptionsFrame
OptionsFrameCancel = OptionsFrameCloseButton
]]></Script>
</Ui>
@@ -26,7 +26,8 @@
attached, so the detail is genuinely variable-height content, which is what the real kit is
for; `GossipFrame.xml`'s greeting pane is the same wiring).
The window is registered in `UIPanelWindows` (`UiPanels.xml`), which is what seats it in the
The window registers itself in `UIPanelWindows` (below; the table is the stock UIParent.lua's
since 1988), which is what seats it in the
left slot and gets it closed by `CloseAllWindows()` — i.e. by ESC — with no code here. Our
own toplevels deliberately stay OUT of `UISpecialFrames`: that table is the addons' (0544's
note, 1206).
@@ -40,6 +41,10 @@
feed and nothing to keep in step — the window polls the log it is a view of.
-->
<Script><![CDATA[
-- The slot-manager row (decision 1495): a left-area window one tier above every stock
-- panel's pushable, so opening a game window pushes the log aside rather than the reverse.
UIPanelWindows["BenillaScriptLogFrame"] = { area = "left", pushable = 9, whileDead = 1 }
BENILLA_SCRIPTLOG_ROWS = 13
BENILLA_SCRIPTLOG_ROW_HEIGHT = 16
-- How much of a message a ROW shows. The full text is the detail pane's job; a row is an
@@ -394,6 +394,207 @@
</Layers>
</Frame>
<!-- ══ Carried here from UiPanels.xml when that file went stock (decision 1988) ══
Three things our UIParent.lua counterpart held that are not the reference's, seated in
the earliest file of ours every consumer loads after: the placeholder icon, the tab
settle, and the window tab template the settle drives. -->
<Script><![CDATA[
-- The placeholder icon for an item/spell whose texture has not arrived yet (Craft, Quest,
-- QuestLog, Trainer and TradeSkill read it). Was ActionBar.xml's (stock since 1938), then
-- UiPanels.xml's (stock since 1988); this file is the earliest of ours every reader loads
-- after. A benilla name, so nothing stock reads it.
BENILLA_FALLBACK_ICON = "Interface\\Icons\\INV_Misc_QuestionMark"
-- The tab kit — `PanelTemplates_*` — is the REFERENCE's, off the player's chain
-- (`Interface\FrameXML\UIPanelTemplates.lua`, seated below this file in the manifest).
-- Moved here from our UIParent.lua counterpart with 1988, beside the template that calls it.
-- Our eleven transcribed copies stood here dead from the day that entry landed, and one
-- of them was carrying a benilla-only return the settle below read (1855/1860). What
-- stays is that settle, which is ours because our text measure is a frame late and the
-- reference's is not.
-- The tab template's per-frame settle: the ref does TabResize(0) once, in OnShow
-- (CharacterFrameTemplates.xml l.77-80), trusting a synchronous text measure. Our
-- GetStringWidth has a frame of latency, so the template's OnUpdate calls this until the
-- measured width settles (then it's a no-op compare per frame). The ref sizes the hover
-- highlight alongside it; this kit does not — both tab templates anchor their highlight to
-- their own side edges, so it is the tab by construction and no settle can desync it
-- (decision 1004).
--
-- The fit PARAMETERS live on the tab (`benillaTabPadding`/`benillaTabMaxWidth`, defaulting
-- to the +0 fit every window tab has always used) rather than at the call site, because
-- there is exactly one call site and it is this settle loop: an instance that ran its own
-- TabResize in OnLoad — as the reference's macro tabs do — would just be overwritten on the
-- next frame. Setting the two fields IS how an instance asks for the reference's own fit.
-- THE STRUCTURAL CLAMP — a tab may never grow past its window's drawn right edge, whatever
-- the instance asked for (decision 1002; the director's "fix this properly to prevent it
-- ever again"). The reference's own caps are numbers hand-tuned to ITS font: the macro
-- window's 150 is right for the enUS FRIZQT__ the 1.12 client rasterizes and for nothing
-- else in particular, and the label it guards carries a CHARACTER NAME — the one string
-- whose width no window author can know. So the instance's cap is a preference and the
-- window's edge is the law.
--
-- `benillaTabRightInset` is how a window declares how far its DRAWN plate stops short of
-- its frame rect, because no kit can introspect an art margin. The macro window's is 40:
-- its 384-unit frame is painted by a 256-wide slice plus a 128-wide one that carries a
-- transparent tail. Clamping to the frame rect instead — the first attempt — clamped to a
-- boundary the player cannot see, and the tab still walked out over the world.
--
-- The clamp is applied to the RESULT, through TabResize's own `absoluteSize` arm, rather
-- than folded into `maxWidth`: that parameter is compared against `text + padding` but
-- assigned as `maxWidth + padding`, so a room budget expressed through it is off by the
-- padding and silently fails to bind. `absoluteSize` sets the tab width outright, which is
-- exactly what a room budget is.
function BenillaTab_Room(tab)
local parent = tab:GetParent()
if not parent then return nil end
local left, right = tab:GetLeft(), parent:GetRight()
if not left or not right then return nil end
local room = (right - (tab.benillaTabRightInset or 0)) - left
if room < 1 then room = 1 end
return room
end
function BenillaTabButton_OnUpdate(tab)
local name = tab:GetName()
local text = getglobal(name .. "Text")
local w = (text and text:GetStringWidth()) or 0
if w <= 0 then return end
local pad = tab.benillaTabPadding or 0
local room = BenillaTab_Room(tab)
if tab.benillaFitWidth == w and tab.benillaFitRoom == room then return end
tab.benillaFitWidth, tab.benillaFitRoom = w, room
PanelTemplates_TabResize(pad, tab, nil, tab.benillaTabMaxWidth)
-- THE CLAMP READS THE FIT BACK OFF THE ART, not off a return value and not off the
-- button. `PanelTemplates_TabResize` is the REFERENCE's now (1837 put
-- `UIPanelTemplates.lua` on the chain below this file, so its definition wins) and it
-- returns nothing; our own copy's benilla-only `return tabWidth` had already stopped
-- running, which is what took 1002's clamp off the air silently. `tab:GetWidth()`
-- cannot serve either — it reads the last RESOLVED rect, this frame's stale input
-- inside a settle, which is the whole reason 1002 added that return.
--
-- `$parentMiddle` can. `PanelTemplates_TabResize` sets it on its way out, a Texture's
-- width is its AUTHORED size, and a region's GetWidth reports the authored value
-- without consulting a resolved rect (region::virtual_span) — so it is the number the
-- verb just computed, same tick. The tab is that plus its two end caps, which is the
-- reference's own `tabWidth = width + sideWidths`.
if room then
local middle = getglobal(name .. "Middle")
local left = getglobal(name .. "Left")
local fitted = (middle and middle:GetWidth() or 0)
+ 2 * (left and left:GetWidth() or 0)
if fitted > room then
PanelTemplates_TabResize(pad, tab, room)
end
end
-- No highlight sizing here on purpose — BOTH tab templates anchor their highlight to
-- their own two side edges, so it IS the tab by construction (decision 1004).
end
]]></Script>
<!--
The window tab button (ref CharacterFrameTabButtonTemplate — Interface\FrameXML\
CharacterFrameTemplates.xml in patch.MPQ, NOT the base FrameXML.toc set; extracted via
mpqx, transcribed VERBATIM: 115x32, the Active/InActive three-slice pair with the ref's
exact TexCoords, text CENTER +2, the ADD highlight inset 10px). "Disabled" IS "selected"
here — PanelTemplates_SelectTab (script kit above) disables the button and shows the
*Disabled (= Active) slices. The ref's OnShow text-fit (PanelTemplates_TabResize(0)) runs
from OnUpdate here instead — BenillaTabButton_OnUpdate settles once the async text measure
lands, then no-ops (the ref's C measure is synchronous; the 115px XML width is just the
pre-fit state). Its OnShow *also* sets the highlight width, which is dead code in the
reference and dropped here: this highlight is anchored LEFT/RIGHT, and two opposing anchors
resolve the size from the span without consulting the width at all (wow-re layout.md,
VERIFIED). The small tab now says the same thing the same way (1004).
**The OnLoad raise and the OnClick are the reference's own, and both were dropped here
until decision 1810.** The note that stood in their place said the raise was unnecessary —
"the tabs sit below the window art's hit-rect so nothing overlaps them" — and that "OnClick
is the instance's to define". Both were true of our own CharacterFrame.xml, and both are
false of the reference's, which is the file that runs now:
- the reference's `PaperDollFrame` is `setAllPoints enableMouse="true"` with a
`bottom=45` hit inset, and the reference's tabs are anchored INSIDE the window (CENTER
to BOTTOMLEFT +60,+62), so the page's hit rect covers the whole row. Frame levels come
out CharacterFrame 1 / PaperDollFrame 2 / tabs 2, later-created winning — the page eats
every tab click. `SetFrameLevel(+4)` is what lifts the row out, and is why the
reference has it.
- stock `CharacterFrame.xml` gives its five tabs only `<OnEnter>`/`<OnLeave>`; the
dispatch lives HERE. Without it `CharacterFrameTab4:GetScript("OnClick")` is nil and
the character window's tabs do nothing at all.
The body hardcodes `CharacterFrame`, which reads odd on a shared template until you check
the other consumers: the reference's `MerchantFrameTab1/2` and every one of ours
(Auction/Friends/Inspect/Mail/Talent) declares its own `<OnClick>`, and an instance's
handler REPLACES the inherited one rather than adding to it. So this reaches exactly the
window it names, which is the reference's own arrangement.
Still ours (moved here from UiPanels.xml with 1988 — that file is the reference's
UIParent.lua now), and still why this template is not simply sourced off the chain:
`Interface\FrameXML\CharacterFrameTemplates.xml` fits its text in `<OnShow>` through
`PanelTemplates_TabResize(0)`, which needs the reference's SYNCHRONOUS string measure. Ours
lands a frame late, so the fit runs from `BenillaTabButton_OnUpdate` instead and an
OnShow-only fit would leave every tab at its pre-fit 115px. That divergence is 1004's, it
spans six windows, and it is what this template's own migration waits on.
-->
<Button name="CharacterFrameTabButtonTemplate" virtual="true">
<Size><AbsDimension x="115" y="32"/></Size>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentLeftDisabled" file="Interface\PaperDollInfoFrame\UI-Character-ActiveTab">
<Size><AbsDimension x="20" y="32"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="5"/></Offset></Anchor></Anchors>
<TexCoords left="0" right="0.15625" top="0" bottom="1.0"/>
</Texture>
<Texture name="$parentMiddleDisabled" file="Interface\PaperDollInfoFrame\UI-Character-ActiveTab">
<Size><AbsDimension x="88" y="32"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentLeftDisabled" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.15625" right="0.84375" top="0" bottom="1.0"/>
</Texture>
<Texture name="$parentRightDisabled" file="Interface\PaperDollInfoFrame\UI-Character-ActiveTab">
<Size><AbsDimension x="20" y="32"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentMiddleDisabled" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.84375" right="1.0" top="0" bottom="1.0"/>
</Texture>
<Texture name="$parentLeft" file="Interface\PaperDollInfoFrame\UI-Character-InActiveTab">
<Size><AbsDimension x="20" y="32"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
<TexCoords left="0" right="0.15625" top="0" bottom="1.0"/>
</Texture>
<Texture name="$parentMiddle" file="Interface\PaperDollInfoFrame\UI-Character-InActiveTab">
<Size><AbsDimension x="88" y="32"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.15625" right="0.84375" top="0" bottom="1.0"/>
</Texture>
<Texture name="$parentRight" file="Interface\PaperDollInfoFrame\UI-Character-InActiveTab">
<Size><AbsDimension x="20" y="32"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.84375" right="1.0" top="0" bottom="1.0"/>
</Texture>
</Layer>
</Layers>
<ButtonText name="$parentText">
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="0" y="2"/></Offset></Anchor></Anchors>
</ButtonText>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontHighlightSmall"/>
<HighlightTexture name="$parentHighlightTexture" file="Interface\PaperDollInfoFrame\UI-Character-Tab-Highlight" alphaMode="ADD">
<Anchors>
<Anchor point="LEFT"><Offset><AbsDimension x="10" y="2"/></Offset></Anchor>
<Anchor point="RIGHT"><Offset><AbsDimension x="-10" y="2"/></Offset></Anchor>
</Anchors>
</HighlightTexture>
<Scripts>
<!-- ref CharacterFrameTemplates.xml:69-81, verbatim. -->
<OnLoad>this:SetFrameLevel(this:GetFrameLevel() + 4)</OnLoad>
<OnClick>
PanelTemplates_Tab_OnClick(CharacterFrame)
CharacterFrameTab_OnClick()
</OnClick>
<OnUpdate>BenillaTabButton_OnUpdate(self)</OnUpdate>
</Scripts>
</Button>
<!-- `FauxScrollFrameTemplate` and the `FauxScrollFrame_*`/`ScrollFrame_*`/`ScrollingEdit_*`
API are the REFERENCE's, off the player's chain (`Interface\FrameXML\UIPanelTemplates`,
seated below this file — so its declarations win). Our transcriptions stood here dead
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+29 -15
View File
@@ -124,7 +124,21 @@ Interface\FrameXML\BasicControls.xml
# the reference's toc has it (l.7-8). Needs Fonts.xml's SystemFont above; everything else it
# names is call-time.
Interface\FrameXML\WorldFrame.xml
UIParent.xml
# UIParent itself and its Lua — the reference's own file (1751; decision 1988), at the slot its
# toc gives it (l.8, right after BasicControls). UIParent.lua is the whole of the glue this
# engine used to carry as UIParent.xml + UiPanels.xml: the UIPanelWindows table and the slot
# manager (Show/HideUIPanel, CloseAllWindows, ToggleGameMenu's ESC ladder), the fade/flash/pulse
# kits (ticked from UIParent's own OnUpdate, so the three driver frames of ours retired with
# it), the managed bottom-stack positions, the model turntable, the LoadOnDemand shims, and the
# sixty-six globally-routed events and their arms. It sources LocaleProperties.lua itself. Its
# OnUpdate also ticks FCF_OnUpdate, UnitPopup_OnUpdate, BattlefieldFrame_OnUpdate, the
# battlefield-position ask (1980) and the ready-check timeout (1989) — call-time names, all of
# them below. LowHealthFrame (parent WorldFrame, above) and OutOfControlFrame ride along.
# What stayed ours moved out: the window tab template and its settle + the placeholder icon
# (ScrollTemplates.xml), 0561's bag verbs (ContainerFrameAdapters.xml), the script log's row
# (ScriptLogFrame.xml), and three aliases in OptionsFrame.xml that answer the reference's three
# options windows and its Cancel button.
Interface\FrameXML\UIParent.xml
# ══ THE ITEM-SLOT BASE — the reference's own, off the player's chain (1751, window 24) ══
# `ItemButtonTemplate` and the eight `SetItemButton*` verbs out of `ItemButtonTemplate.lua`. It
# sits as early as it can be read: no frames, no dependencies of its own, and every window that
@@ -169,12 +183,6 @@ Interface\FrameXML\MoneyFrame.xml
# `every_chain_xml_brings_its_own_lua` is now a gate so neither can recur.
Interface\FrameXML\MoneyInputFrame.lua
Interface\FrameXML\MoneyInputFrame.xml
# The UIPanel slot manager (decision 0084 §2) and the fade/flash/pulse kits — the UIParent.lua
# halves this engine still carries itself: script-only but for the kits' tick drivers, loaded
# before any panel frame so ShowUIPanel/HideUIPanel already exist when those frames' OnLoad/OnEvent
# reference them. The StaticPopup engine and every dialog it used to carry are the reference's
# own file now, far below at the reference's own slot after UIPanelTemplates (decision 1960).
UiPanels.xml
# ══ THE TOOLTIP — the reference's own, off the player's chain (1751; decision 1968) ══
# GameTooltip.xml sources HealthBar.lua and GameTooltip.lua and <Include>s GameTooltipTemplate.xml:
# the two virtual templates (GameTooltipTemplate, ShoppingTooltipTemplate — thirty declared line
@@ -592,14 +600,6 @@ Interface\FrameXML\CastingBarFrame.xml
# 1.12 never reaches it — vmangos refuses to send that packet and substitutes a full START,
# saying so in `Player::SendMirrorTimers` — and `ui_mirror.rs`'s Pause edge carries the note.
Interface\FrameXML\MirrorTimer.xml
# ══ THE WORLD-STATE FRAMES — the reference's own, off the player's chain (1751; decision 1972) ══
# WorldStateFrame.xml + WorldStateFrame.lua: the always-up readout 1586 built (the tower/flag/base
# counters at top-centre, `UPDATE_WORLD_STATES` from `crate::world_state_ui`), the capture bars,
# and the battleground SCOREBOARD ours never had — `WorldStateScoreFrame`, over the score family
# 1972 built (`MSG_PVP_LOG_DATA`, the eleven verbs, `UPDATE_BATTLEFIELD_SCORE`) and UIParent.xml's
# `BattlefieldMinimap_LoadUI`. Needs Fonts, GameTooltip, the panel kit (its close button, tabs,
# faux scroll frame) — all above; sits beside the mirror timers, which share its top-centre lane.
Interface\FrameXML\WorldStateFrame.xml
# ══ THE DURABILITY ALERT — the reference's own, off the player's chain (1751, window 4) ══
# The "armor guy" under the minimap: `DurabilityFrame`, its eleven glyph textures, and
# `DurabilityFrame_SetAlerts` / `_OnUpdate` with `INVENTORY_ALERT_STATUS_SLOTS` and
@@ -1053,6 +1053,20 @@ Interface\FrameXML\QuestTimerFrame.xml
# CHAT_MSG_* events the reference's ChatFrame_OnEvent prints from — it no longer prints them itself.
Interface\FrameXML\ChatFrame.xml
Interface\FrameXML\FloatingChatFrame.xml
# ══ THE WORLD-STATE FRAMES — the reference's own, off the player's chain (1751; decision 1972) ══
# WorldStateFrame.xml + WorldStateFrame.lua: the always-up readout 1586 built (the tower/flag/base
# counters at top-centre, `UPDATE_WORLD_STATES` from `crate::world_state_ui`), the capture bars,
# and the battleground SCOREBOARD ours never had — `WorldStateScoreFrame`, over the score family
# 1972 built (`MSG_PVP_LOG_DATA`, the eleven verbs, `UPDATE_BATTLEFIELD_SCORE`) and UIParent.xml's
# `BattlefieldMinimap_LoadUI`. Needs Fonts, GameTooltip, the panel kit (its close button, tabs,
# faux scroll frame) — all above. It sat beside the mirror timers until 1988: the always-up
# frame's OnLoad runs the stock UIParent_ManageFramePositions, and that pass indexes half the
# HUD unguarded — ReputationWatchBar, QuestTimerFrame, QuestWatchFrame (QuestLogFrame.xml),
# MinimapCluster, DurabilityFrame, the bars and their sliding textures — and ends by calling
# FCF_DockUpdate and re-anchoring the container frames. So this file sits after all of them,
# which is why the reference's own toc has it at l.89, near the end (1988).
Interface\FrameXML\WorldStateFrame.xml
# ══ THE MACRO WINDOW — the reference's own, off the player's chain (1751, window 32) ══
# A LoadOnDemand addon with no row here since 1967 (the addons header far above); what stays in
# this slot is the FrameXML file it needs loaded first.
+38 -28
View File
@@ -451,7 +451,7 @@ fn chat_vm() -> benilla_ui::script::UiScript {
"Interface\\FrameXML\\ChatFrame.xml",
"Interface\\FrameXML\\UIPanelTemplates.lua",
"Interface\\FrameXML\\UIPanelTemplates.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"Interface\\FrameXML\\FloatingChatFrame.xml",
@@ -2039,37 +2039,47 @@ fn both_dock_windows_carry_the_same_chrome() {
}
}
/// **No docked chat window may appear in `UIParent.xml`'s managed-position table.**
/// **A docked chat window survives the managed-position pass.**
///
/// The structural guard on the root cause. That pass owns a frame's whole seat — it
/// `ClearAllPoints()` first, by design (decision 1499) — so a row naming a *docked* window wipes
/// the anchors that tie it to the dock and re-seats it with a single point and no size: an
/// unresolvable rect. The reference's own ChatFrame2 row is for an UNDOCKED window, which is chat
/// settings and not built (0288 §2); carrying it here cost B297 a visible fix.
///
/// A string check because that is the level the bug lives at — the row's mere presence is the
/// defect, whatever it contains.
/// The pass owns a frame's whole seat — it `ClearAllPoints()` first, by design (decision 1499) —
/// and the reference's own table carries a `ChatFrame2` row. That row cost B297 a visible fix
/// while the pass was ours, and our answer then was to drop the row from our copy. The stock pass
/// is the one that runs now (1988), row and all, and it ends by calling `FCF_DockUpdate()` —
/// which re-anchors every docked window onto `DEFAULT_CHAT_FRAME` in the same breath. That is the
/// reference's answer to its own row, and this is the behavioural check that it holds: after the
/// pass, the docked window is still exactly on the dock.
#[test]
fn no_docked_chat_window_is_managed_by_uiparent() {
fn a_docked_chat_window_survives_the_managed_position_pass() {
let _data = benilla_formats::wow_data_or_skip!();
let xml = std::fs::read_to_string(
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/ui/UIParent.xml"),
)
.expect("UIParent.xml");
for line in xml.lines() {
let code = line.trim_start();
if code.starts_with("--") {
continue; // the comment explaining why the row is gone names it, deliberately
}
assert!(
!code.starts_with("ChatFrame2 ="),
"ChatFrame2 is DOCKED — a managed row clears its dock anchors: {code}"
);
}
assert!(
xml.contains("ChatFrame1 = {baseY = 85"),
"ChatFrame1 IS managed (it is the dock's own seat) — this test must not pass vacuously"
let mut s = benilla_ui::script::UiScript::new().expect("VM");
s.set_screen_size(1024.0, 768.0);
s.set_unit(
"player",
Some(benilla_ui::script::UnitState {
exists: true,
name: Some("Probefour".into()),
level: 60,
..Default::default()
}),
);
assert!(crate::ui_script::load_default_ui(&s).is_empty());
s.resolve();
// Dock the combat log the way the reference's own default layout does, then run the pass.
s.run("FCF_DockFrame(ChatFrame2, 2, nil) UIParent_ManageFramePositions()")
.unwrap();
s.resolve();
let rect = |name: &str| {
s.eval::<(f64, f64, f64, f64)>(&format!(
"return {name}:GetLeft(), {name}:GetBottom(), {name}:GetRight(), {name}:GetTop()"
))
.unwrap_or_else(|e| panic!("{name}: {e}"))
};
assert_eq!(
rect("ChatFrame2"),
rect("ChatFrame1"),
"the docked window still sits exactly on the dock"
);
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
}
/// **What does NOT gate a `/sit` underwater** — the negative that sends B155's refusal to the
+1 -2
View File
@@ -1176,12 +1176,11 @@ mod bind_confirm_tests {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
] {
crate::ui_script::load_ui_for_test(s, file);
}
@@ -21,7 +21,7 @@ fn shipped_action_bar_drives_end_to_end() {
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\Fonts.xml");
super::test_ui::load_ui(&s, "UIParent.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\UIParent.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\MoneyFrame.lua");
super::test_ui::load_ui(&s, r"Interface\FrameXML\MoneyFrame.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\GameTooltip.xml");
@@ -185,7 +185,7 @@ fn load_action_bar(s: &UiScript) {
super::test_ui::load_ui(s, "Interface\\FrameXML\\TextStatusBar.lua");
super::test_ui::load_ui(s, "Interface\\FrameXML\\TextStatusBar.xml");
super::test_ui::load_ui(s, "Interface\\FrameXML\\Fonts.xml");
super::test_ui::load_ui(s, "UIParent.xml");
super::test_ui::load_ui(s, r"Interface\FrameXML\UIParent.xml");
super::test_ui::load_ui(s, "Interface\\FrameXML\\GlobalStrings.lua");
super::test_ui::load_ui(s, "Interface\\FrameXML\\MainMenuBar.xml");
super::test_ui::load_ui(s, r"Interface\FrameXML\MoneyFrame.lua");
@@ -208,7 +208,6 @@ fn load_action_bar(s: &UiScript) {
// The options window: `LOCK_ACTIONBAR` and `ALWAYS_SHOW_MULTIBARS` are declared there, as the
// reference declares them in UIOptionsFrame_Init (1938) — and the manifest loads it before
// the bars.
super::test_ui::load_ui(s, "UiPanels.xml");
// The dialog engine — the keybindings page registers its two confirms into its table (1960).
super::test_ui::load_ui(s, r"Interface\FrameXML\BasicControls.xml"); // `TEXT`
super::test_ui::load_ui(s, r"Interface\FrameXML\LocaleProperties.lua"); // `GetText`
@@ -835,7 +834,8 @@ fn shipped_bag_frame_drives_end_to_end() {
load_ui(&s, "Interface\\FrameXML\\TextStatusBar.lua");
load_ui(&s, "Interface\\FrameXML\\TextStatusBar.xml");
load_ui(&s, "Interface\\FrameXML\\Fonts.xml");
load_ui(&s, "UIParent.xml");
load_ui(&s, r"Interface\FrameXML\UIParent.xml");
load_ui(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_ui(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_ui(&s, "Interface\\FrameXML\\MainMenuBar.xml");
load_ui(&s, "Interface\\FrameXML\\ActionBarFrame.xml");
@@ -1350,7 +1350,7 @@ fn the_main_bar_pages_and_a_bonus_page_still_outranks_it() {
for file in [
// Fonts first: the pane's check-box labels colour from `RED_FONT_COLOR` in their own OnLoad.
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Cooldown.xml",
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
@@ -1371,7 +1371,6 @@ fn the_main_bar_pages_and_a_bonus_page_still_outranks_it() {
r"Interface\FrameXML\OptionsFrameTemplates.xml",
r"Interface\FrameXML\ReputationFrame.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -1523,7 +1522,7 @@ fn bonus_bar_slides_up_with_sound_and_down_without() {
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\Fonts.xml");
super::test_ui::load_ui(&s, "UIParent.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\UIParent.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\GlobalStrings.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\MainMenuBar.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\MoneyFrame.lua");
@@ -1745,7 +1744,7 @@ fn bonus_bar_turnaround_continues_from_position() {
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\Fonts.xml");
super::test_ui::load_ui(&s, "UIParent.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\UIParent.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\GlobalStrings.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\MainMenuBar.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\MoneyFrame.lua");
@@ -1827,7 +1826,7 @@ fn the_page_arrows_do_not_steal_each_other_s_clicks() {
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\TextStatusBar.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\Fonts.xml");
super::test_ui::load_ui(&s, "UIParent.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\UIParent.xml");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\GlobalStrings.lua");
super::test_ui::load_ui(&s, "Interface\\FrameXML\\MainMenuBar.xml");
super::test_ui::load_ui(&s, r"Interface\FrameXML\MoneyFrame.lua");
@@ -133,6 +133,7 @@ fn b_opens_the_backpack_alone_and_closes_every_bag() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -214,6 +215,7 @@ fn shift_b_toggles_every_bag_at_once() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s.set_container(
@@ -295,6 +297,7 @@ fn bag_bar_buttons_light_while_their_bag_is_open() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s.set_container(
@@ -412,6 +415,7 @@ fn bag_tooltip_hangs_left_when_the_slot_sits_in_the_right_half() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -489,6 +493,7 @@ fn hovered_bag_tooltip_fills_itself_when_the_stats_land() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -593,6 +598,7 @@ fn vendor_bag_hover_shows_sell_price_and_arms_the_pouch_cursor() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -729,6 +735,7 @@ fn readable_letter_hover_shows_the_inspect_magnifier() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -799,6 +806,7 @@ fn drag_across_two_slots_queues_the_same_move_a_click_pickup_would() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -883,6 +891,7 @@ fn a_second_bag_window_feeds_and_paints_via_the_bag_bar() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -956,6 +965,7 @@ fn equipped_bag_window_snug_fits_its_row_count() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -1015,6 +1025,7 @@ fn open_backpack_with_a_five_stack(s: &mut UiScript) -> (f32, f32) {
for file in BAG_UI {
load_xml(s, file);
}
load_xml(s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(s, "Interface\\FrameXML\\StackSplitFrame.xml");
s.set_money(0);
@@ -1356,6 +1367,7 @@ fn bag_slot_cooldown_sweeps_through_the_xml() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s.tick(100.0); // a nonzero clock epoch, like the engine cooldown tests
@@ -1429,6 +1441,7 @@ fn the_bar_bag_buttons_name_themselves_on_hover() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.resolve();
@@ -1563,6 +1576,7 @@ fn keyring_surface(s: &UiScript) {
for file in BAG_UI {
load_xml(s, file);
}
load_xml(s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(s, "Interface\\FrameXML\\UIErrorsFrame.xml");
}
@@ -1837,6 +1851,7 @@ fn an_item_push_drops_its_icon_into_the_bag_that_took_it() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.resolve();
@@ -2093,6 +2108,7 @@ fn an_addon_that_hooks_toggle_backpack_receives_the_click() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
@@ -2149,6 +2165,7 @@ fn the_bag_slots_carry_the_references_names_and_icon_names() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
for i in 0..4 {
@@ -2209,6 +2226,7 @@ fn the_backpack_buttons_ring_follows_its_own_window_through_real_clicks() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
// The reference's `ToggleBag` opens nothing for a container of size 0, so the backpack has to
@@ -34,10 +34,9 @@ fn session() -> UiScript {
"Interface\\FrameXML\\Localization.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\BasicControls.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -14,14 +14,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s.set_binder_pending(true);
s
}
@@ -100,7 +100,7 @@ fn shipped_xml() -> Vec<(String, String)> {
fn no_shipped_file_declares_its_own_copy_of_a_managed_offset() {
let mut offences = Vec::new();
for (name, text) in shipped_xml() {
if name == "UIParent.xml" {
if name == r"Interface\FrameXML\UIParent.xml" {
continue; // the owner: its var rows are where these numbers are defined
}
for (n, line) in without_xml_comments(&text).lines().enumerate() {
@@ -208,11 +208,17 @@ const BOTTOM_EXEMPT: &[(&str, &str)] = &[
/// not need to. Failing here is not a bug report; it is a prompt to pick one.
#[test]
fn every_bottom_anchored_top_level_frame_is_accounted_for() {
let pass = std::fs::read_to_string(ui_dir().join("UIParent.xml")).expect("UIParent.xml");
// The pass is the stock `UIParent.lua`'s since 1988 — read off the player's chain.
let _data = benilla_formats::wow_data_or_skip!();
let pass = String::from_utf8_lossy(
&super::reference_ui::read(r"Interface\FrameXML\UIParent.lua")
.expect("the stock UIParent.lua off the chain"),
)
.into_owned();
for f in MANAGED_FRAMES {
assert!(
pass.contains(f),
"{f} is listed here as managed but does not appear in UIParent.xml's pass — this \
"{f} is listed here as managed but does not appear in UIParent.lua's pass — this \
list has drifted from the file it mirrors"
);
}
@@ -222,8 +228,7 @@ fn every_bottom_anchored_top_level_frame_is_accounted_for() {
let doc = benilla_ui::framexml::parse(&text).unwrap_or_else(|e| panic!("{file}: {e}"));
for (name, anchors) in bottom_anchored_top_level(&doc) {
let known = MANAGED_FRAMES.contains(&name.as_str())
|| BOTTOM_EXEMPT.iter().any(|(n, _)| *n == name)
|| registers_a_listener(&text, &name);
|| BOTTOM_EXEMPT.iter().any(|(n, _)| *n == name);
if !known {
unaccounted.push(format!("{file}: {name} ({anchors})"));
}
@@ -233,21 +238,12 @@ fn every_bottom_anchored_top_level_frame_is_accounted_for() {
unaccounted.is_empty(),
"these top-level frames anchor to the screen's bottom edge but nothing decides their \
clearance over the action bars. Give each one a row in \
UIPARENT_MANAGED_FRAME_POSITIONS (UIParent.xml), or seat it from a managed global and \
register UIParent_RegisterManagedPositionListener, or add it to BOTTOM_EXEMPT here with \
the reason it needs neither (decision 1499):\n{}",
UIPARENT_MANAGED_FRAME_POSITIONS (the stock UIParent.lua's table, since 1988), or add \
it to BOTTOM_EXEMPT here with the reason it needs no row (decision 1499):\n{}",
unaccounted.join("\n")
);
}
/// A file that registers a managed-position listener is seating something itself; the frames it
/// declares are covered by that registration. Coarse on purpose — the listener seats a whole
/// family (the bag stack is five windows), and naming each one here would be the same drift trap
/// `MANAGED_FRAMES` guards against.
fn registers_a_listener(text: &str, _frame: &str) -> bool {
text.contains("UIParent_RegisterManagedPositionListener")
}
/// Every top-level INSTANCE (a `<Frame>`/`<Button>`/… that is not `virtual` and carries no
/// `parent` attribute) whose own `<Anchors>` name a BOTTOM point against the screen root — an
/// anchor with no `relativeTo`, or one naming `UIParent`/`WorldFrame`, all three of which resolve
@@ -358,6 +354,20 @@ fn no_bottom_band_frame_overlaps_a_raised_bar() {
let mut raised = Vec::new();
for (i, bar) in RAISABLE_BARS.iter().enumerate() {
let on = mask & (1 << i) != 0;
// **Through the saved globals, not a bare Show.** The stock pass reads
// `SHOW_MULTI_ACTIONBAR_1`/`_2` for its bottom-bar flags (`UIParent.lua:1598-1606`),
// never the frames' shown state, so raising a bar by hand and running the pass is a
// state the client never reaches — and it clears nothing (1988; our retired copy of
// the pass read `IsShown`, which is what let this drive work before).
let global = match *bar {
"MultiBarBottomLeft" => Some("SHOW_MULTI_ACTIONBAR_1"),
"MultiBarBottomRight" => Some("SHOW_MULTI_ACTIONBAR_2"),
_ => None,
};
if let Some(g) = global {
s.run(&format!("{g} = {}", if on { "1" } else { "nil" }))
.unwrap();
}
s.run(&format!(
"if {bar} then {bar}:{}() end",
if on { "Show" } else { "Hide" }
@@ -36,13 +36,12 @@ fn harness() -> UiScript {
// `SecondsToTimeAbbrev`, which 1.12 keeps in UIParent.lua and so do we since window 18.
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
+12 -5
View File
@@ -386,7 +386,7 @@ fn managed_positions_track_the_bottom_bar_stack() {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\CastingBarFrame.xml");
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml"); // the kit the chat menus build from
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
@@ -398,7 +398,6 @@ fn managed_positions_track_the_bottom_bar_stack() {
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
@@ -417,7 +416,12 @@ fn managed_positions_track_the_bottom_bar_stack() {
// The bar stubs carry a no-op SetPoint: `MultiBarBottomLeft` and `ShapeshiftBarFrame` are
// themselves rows in UIPARENT_MANAGED_FRAME_POSITIONS, so since those frames wear their
// reference names the pass positions them as well as reading their visibility.
s.run("MultiBarBottomLeft = { IsShown = function() return true end, SetPoint = function() end, ClearAllPoints = function() end }; MultiBarBottomRight = MultiBarBottomLeft; UIParent_ManageFramePositions()")
// **The bottom-bar flags come from the SAVED GLOBALS, not from the frames.** The stock pass
// reads `SHOW_MULTI_ACTIONBAR_1`/`_2` (`UIParent.lua:1598-1606`) and never asks the bars
// whether they are shown — our retired copy asked, which is why this drive used to fake a
// frame with an `IsShown`. The fake also had no `IsObjectType`, which the pass calls on every
// row it seats (1988).
s.run("SHOW_MULTI_ACTIONBAR_1 = 1 SHOW_MULTI_ACTIONBAR_2 = 1 UIParent_ManageFramePositions()")
.unwrap();
s.resolve();
assert_eq!(bottom(&s, "CastingBarFrame"), 100.0, "60 + bottomEither 40");
@@ -432,7 +436,10 @@ fn managed_positions_track_the_bottom_bar_stack() {
ShapeshiftBarLeft, ShapeshiftBarMiddle, ShapeshiftBarRight = t, t, t",
)
.unwrap();
s.run("ShapeshiftBarFrame = { IsShown = function() return true end, SetPoint = function() end, ClearAllPoints = function() end }; UIParent_ManageFramePositions()")
s.run(
"ShapeshiftBarFrame = ShapeshiftBarFrame or CreateFrame(\"Frame\", \"ShapeshiftBarFrame\") \
ShapeshiftBarFrame:Show() UIParent_ManageFramePositions()",
)
.unwrap();
s.resolve();
assert_eq!(bottom(&s, "CastingBarFrame"), 140.0, "60 + 40 + pet 40");
@@ -443,7 +450,7 @@ fn managed_positions_track_the_bottom_bar_stack() {
);
// It hides again (a druid leaving forms is the live case): everything settles back.
s.run("ShapeshiftBarFrame = { IsShown = function() return false end, SetPoint = function() end, ClearAllPoints = function() end }; UIParent_ManageFramePositions()")
s.run("ShapeshiftBarFrame:Hide() UIParent_ManageFramePositions()")
.unwrap();
s.resolve();
assert_eq!(bottom(&s, "CastingBarFrame"), 100.0);
@@ -1207,10 +1207,11 @@ fn an_addons_tab_click_selects_through_the_generic_entry_point() {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
// The reference's `PanelTemplates_SelectTab` ends with `if GameTooltip:IsOwned(tab)` —
// an arm our deleted copy omitted ("our tabs set no tooltip"), so selecting a tab now needs
// the tooltip to exist (1860).
load_xml(&s, "ScrollTemplates.xml"); // our window tab template (1988)
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
@@ -1218,7 +1219,6 @@ fn an_addons_tab_click_selects_through_the_generic_entry_point() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
// A conforming row: tabs named `<frame>Tab1..N` (what `PanelTemplates_UpdateTabs` getglobals)
// and each carrying its own id, exactly as an addon's XML declares them.
@@ -42,8 +42,7 @@ fn chat_with_menu() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
@@ -20,8 +20,7 @@ fn chat_ui() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
@@ -29,10 +29,9 @@ fn chat_frame() -> UiScript {
// The UIParent slice (RaiseFrameLevel, MouseIsOver, the fade and flash kits) ahead of the
// bar and the chat files; `FCF_OnUpdate` — the dock's hover, fade and drag driver — runs
// from UIParent's OnUpdate, as in the reference.
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
// `FCF_ValidateChatFramePosition` (a tab-drag stop) reads `MainMenuBar:GetHeight()`; the bar's
// own load-time chain precedes it, as in the action-bar harness.
load_xml(&s, "Cooldown.xml");
@@ -995,7 +994,7 @@ fn the_chat_menu_builds_its_rows_on_the_references_kit() {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -23,10 +23,9 @@ fn ui_with_the_cinematic_frame() -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua"); // StaticPopup's money row, or UiPanels errors at load
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -20,8 +20,7 @@ fn picker() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
@@ -327,7 +326,7 @@ fn cancel_restores_the_previous_colour_through_cancel_func() {
/// the rung cancel-CLICKS rather than hiding — so the colour comes back and the game menu does not
/// open behind it.
#[test]
fn escape_cancels_rather_than_merely_hiding() {
fn escape_hides_the_picker_and_cancel_is_what_reverts() {
let _data = benilla_formats::wow_data_or_skip!();
let s = picker();
dewdrop_open(&s, 0.1, 0.5, 0.9, 0.25);
@@ -338,14 +337,26 @@ fn escape_cancels_rather_than_merely_hiding() {
assert!(!s
.eval::<bool>("return ColorPickerFrame:IsVisible()")
.unwrap());
// **The reference's ESC is a bare hide, and the previewed colour stands.** `ColorPickerFrame`
// is a `UISpecialFrames` row (`UIParent.lua:52-55`), so the ladder's `CloseAllWindows` hides
// it — the stock file runs `cancelFunc` from the Cancel button's own OnClick and from nowhere
// else, and its OnHide has no such arm. Our retired ladder clicked Cancel for the player;
// that arm went with the file (1988).
let (r, g, b): (f64, f64, f64) = s
.eval("local t = applied[table.getn(applied)] return t.r, t.g, t.b")
.unwrap();
assert_eq!(
(r, g, b),
(0.1, 0.5, 0.9),
"ESC ran cancelFunc, not a bare Hide"
(1.0, 0.0, 0.0),
"ESC hid the picker and left the previewed colour applied"
);
// The Cancel button is still what reverts it, which is the reference's whole cancel path.
s.run("ColorPickerFrame:Show() ColorPickerCancelButton:Click()")
.unwrap();
let (r, g, b): (f64, f64, f64) = s
.eval("local t = applied[table.getn(applied)] return t.r, t.g, t.b")
.unwrap();
assert_eq!((r, g, b), (0.1, 0.5, 0.9), "Cancel runs cancelFunc");
}
/// `AceConsole-2.0.lua` l.1402-1406, verbatim in shape: fetch the Okay button's own handler, replace
@@ -21,7 +21,7 @@ fn load_combat_text() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua"); // ENTERING_COMBAT & co.
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); // TEXT()
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
// The reference's own addon, LoadOnDemand off the chain, loaded the way the options window
// loads it (1964).
super::test_ui::seat_chain_addon(&mut s, "Blizzard_CombatText");
@@ -19,7 +19,7 @@ fn load_combo_frame() -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
@@ -28,7 +28,6 @@ fn load_combo_frame() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -13,14 +13,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s
}
@@ -59,7 +59,7 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -72,7 +72,6 @@ fn setup() -> UiScript {
load_xml(&s, r"Interface\FrameXML\UIDropDownMenu.xml");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, r"Interface\FrameXML\FloatingChatFrame.xml"); // declares ChatFrameEditBox
load_xml(&s, "UIParent.xml");
s.set_money(0);
s
}
@@ -88,6 +87,7 @@ fn bag_setup() -> UiScript {
}
// `ContainerFrame_Update` reads `MerchantFrame:IsShown()` on any slot the tooltip owns, and
// `BankFrame` (BAG_UI's last entry) fills its purse through `BenillaMoney_Set`.
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s
@@ -38,6 +38,7 @@ const ROOM_UI: &[&str] = &[
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
"Interface\\FrameXML\\UnitPopup.xml",
"Interface\\FrameXML\\ItemRef.xml",
"ScrollTemplates.xml", // our window tab template, before the window that inherits it (1988)
"Interface\\FrameXML\\MerchantFrame.xml",
"Interface\\FrameXML\\StackSplitFrame.xml",
"Interface\\FrameXML\\UIMenu.xml", // the kit ChatMenu/EmoteMenu/VoiceMacroMenu build from
@@ -49,7 +50,7 @@ const ROOM_UI: &[&str] = &[
// The reference's own room (1969): its Close/Reset buttons inherit the panel kit's templates,
// which resolve at load — so after it, as the manifest has it.
"Interface\\FrameXML\\DressUpFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\FloatingChatFrame.xml",
];
@@ -63,14 +64,13 @@ fn load_room(s: &UiScript) {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Cooldown.xml",
] {
@@ -89,7 +89,7 @@ fn load_room(s: &UiScript) {
/// **Needs client data**: `BAG_UI` names a chain entry, so its callers open with
/// `wow_data_or_skip!`.
fn load_room_with_bags(s: &UiScript) {
load_xml(s, "UIParent.xml");
load_xml(s, r"Interface\FrameXML\UIParent.xml");
for file in BAG_UI {
load_xml(s, file);
}
@@ -125,7 +125,7 @@ fn shown_paper_doll() -> UiScript {
"Interface\\FrameXML\\UIPanelTemplates.xml",
// The reference's room (1969), after the panel kit its buttons inherit from.
"Interface\\FrameXML\\DressUpFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\FloatingChatFrame.xml",
] {
@@ -21,7 +21,7 @@ use super::test_ui::load_ui as load_xml;
fn load_dropdown_kit(s: &UiScript) {
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GameTooltip.xml",
@@ -13,14 +13,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s
}
@@ -18,14 +18,13 @@ fn harness() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"Interface\\FrameXML\\BattlefieldFrame.xml",
@@ -398,13 +397,12 @@ fn the_quest_tracker_stacks_below_the_durability_guy() {
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"Interface\\FrameXML\\BattlefieldFrame.xml",
@@ -18,14 +18,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s
}
@@ -113,7 +113,7 @@ fn an_error_toast_draws_over_an_open_panel_window() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
@@ -122,13 +122,11 @@ fn an_error_toast_draws_over_an_open_panel_window() {
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml");
load_xml(&s, "Cooldown.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); // BenillaMoney_* — QuestLogDetail's reward money row
// ScrollTemplates.xml (the faux kit the list rides) + UIPanelTemplates.xml (the detail
// pane's UIPanelScrollFrameTemplate). A MISSING template is a loader *warning*, so an
// under-loaded list passes and then dies on the first FauxScrollFrame_Update.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -77,6 +77,7 @@ fn escape_closes_bag_and_panel_releases_loot_and_clears_cursor() {
load_xml(&s, file);
}
load_xml(&s, "Interface\\FrameXML\\LootFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); // BenillaMoney_Set, BankFrame's purse helper
s.set_money(0);
s.set_container(0, Some(one_item_backpack()));
@@ -133,7 +134,16 @@ fn escape_closes_bag_and_panel_releases_loot_and_clears_cursor() {
s.take_loot_close(),
"closing the loot fired the release (OnHide → CloseLoot)"
);
assert!(s.cursor_item().is_none(), "ESC dropped the held cursor");
// **ESC does NOT drop the cursor's item.** Our retired ladder opened with
// `if CursorHasItem() then ClearCursor() end`; the reference's `ToggleGameMenu`
// (`UIParent.lua:1465-1497`) has no such arm, and wow-re's cursor carve places the
// ESC→ClearCursor wiring in FrameXML rather than the engine
// (`ui/scratch/cursor-dragdrop-payload.md`) — so in 1.12 the held item survives the key
// (1988).
assert!(
s.cursor_item().is_some(),
"the held item survives ESC, as it does in the reference"
);
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
}
@@ -149,6 +159,7 @@ fn escape_is_consumed_by_a_focused_editbox_and_leaves_windows_open() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml"); // the kit the chat menus build from
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
@@ -157,7 +168,7 @@ fn escape_is_consumed_by_a_focused_editbox_and_leaves_windows_open() {
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
s.set_money(0);
@@ -193,7 +204,7 @@ fn escape_closes_the_options_window_before_opening_the_menu() {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
@@ -252,6 +263,7 @@ fn escape_closes_an_open_stack_split_frame() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); // ContainerFrameItemButton_OnClick reads MerchantFrame
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
@@ -259,7 +271,7 @@ fn escape_closes_an_open_stack_split_frame() {
load_xml(&s, "Interface\\FrameXML\\ChatFrame.xml"); // …and ChatFrameEditBox, the shift fork's first test
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
load_xml(&s, "Interface\\FrameXML\\StackSplitFrame.xml");
@@ -340,6 +352,7 @@ fn escape_ladder_cast_then_windows_then_target_one_eater_per_press() {
// GameTooltip.xml (BAG_UI's, for the bag slots' tooltips) also carries TOOLTIP_DEFAULT_COLOR,
// which the dropdown backdrop's OnLoad reads — so the kit can load straight after it.
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s.set_container(0, Some(one_item_backpack()));
@@ -441,6 +454,7 @@ fn escape_ladder_targeting_rung_after_cast_before_windows() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s.set_container(0, Some(one_item_backpack()));
@@ -507,7 +521,7 @@ fn an_addon_frame_registered_in_uispecialframes_closes_on_escape() {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -16,7 +16,7 @@ fn exp_bar_harness() -> UiScript {
// wrong store — and would leave its `<Script file="TextStatusBar.lua"/>` unresolved besides.
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GameTooltip.xml",
+14 -87
View File
@@ -1,68 +1,21 @@
//! The fade kit's driver (`UIFrameFade` / `BenillaFadeDriver`, UiPanels.xml) — the park/wake
//! lifecycle that keeps the per-frame fade walk off the tick while nothing is fading. Split from
//! `panel_tests.rs` (1507's round): the slot manager and the fade kit share a source file, not a
//! concern.
//! The fade and flash kits — the stock `UIParent.lua`'s since 1988, walked from `UIParent`'s own
//! `<OnUpdate>` (`UIFrameFadeUpdate` / `UIFrameFlashUpdate`), which is what the reference does
//! too: no tick driver of ours, and a cinematic's `UIParent:Hide()` stops both walks the way it
//! stops the reference's. What these guard is the arithmetic and the list discipline — a fade
//! ramps linearly to its endAlpha and leaves `FADEFRAMES`; a flash alternates for its duration,
//! refuses a re-arm while flashing, and ends hidden when `showWhenDone` is nil.
use benilla_ui::script::UiScript;
use super::test_ui::load_ui as load_xml;
/// **The idle fade driver parks itself** (decision 1396's class, the audit's driver-hide item):
/// with `FADEFRAMES` empty there is nothing to walk, so the driver's OnUpdate hides its own frame
/// — and the engine dispatches OnUpdate only to visible frames (`tick.rs`), which stops the
/// per-frame walk cold. The probe wraps `UIFrameFadeUpdate` in a counter BEFORE the first tick:
/// ten idle ticks later it has never run, and the driver is hidden.
#[test]
fn an_idle_fade_driver_parks_itself_off_the_tick() {
fn a_started_fade_ramps_off_uiparents_tick_and_completes() {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
s.resolve();
s.run(
"BENILLA_TEST_FADE_TICKS = 0\n\
local real = UIFrameFadeUpdate\n\
function UIFrameFadeUpdate(elapsed)\n\
BENILLA_TEST_FADE_TICKS = BENILLA_TEST_FADE_TICKS + 1\n\
real(elapsed)\n\
end",
)
.unwrap();
for _ in 0..10 {
s.tick(0.016);
s.resolve();
}
assert!(s.errors().is_empty(), "{:?}", s.errors());
assert!(
!s.eval::<bool>("return BenillaFadeDriver:IsShown()")
.unwrap(),
"an empty FADEFRAMES parks the driver"
);
assert_eq!(
s.eval::<i64>("return BENILLA_TEST_FADE_TICKS").unwrap(),
0,
"a parked driver never runs the fade walk"
);
}
/// The control for the guard above: the gate must not cost the fades it gates. `UIFrameFade` (the
/// kit's single insertion point — `UIFrameFadeIn`/`Out` both land there) wakes the driver beside
/// its `table.insert`; the fade then ramps on real ticks, completes, and the driver re-parks on
/// the first empty tick after.
#[test]
fn a_started_fade_still_ramps_and_the_driver_reparks_after() {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -72,19 +25,11 @@ fn a_started_fade_still_ramps_and_the_driver_reparks_after() {
s.resolve();
s.run(r#"CreateFrame("Frame", "BenillaFadeProbe")"#)
.unwrap();
for _ in 0..2 {
s.tick(0.016); // settle: the driver parks
s.resolve();
}
assert!(!s
.eval::<bool>("return BenillaFadeDriver:IsShown()")
.unwrap());
s.run("UIFrameFadeIn(BenillaFadeProbe, 1.0)").unwrap();
assert!(
s.eval::<bool>("return BenillaFadeDriver:IsShown()")
s.eval::<bool>("return UIFrameIsFading(BenillaFadeProbe) == 1")
.unwrap(),
"starting a fade wakes the driver"
"on the fade list"
);
assert_eq!(
s.eval::<f64>("return BenillaFadeProbe:GetAlpha()").unwrap(),
@@ -107,12 +52,10 @@ fn a_started_fade_still_ramps_and_the_driver_reparks_after() {
1.0,
"the fade completes at its endAlpha"
);
s.tick(0.016); // the first empty tick re-parks the driver
s.resolve();
assert!(
!s.eval::<bool>("return BenillaFadeDriver:IsShown()")
!s.eval::<bool>("return UIFrameIsFading(BenillaFadeProbe) == 1")
.unwrap(),
"the driver re-parks once the list is empty"
"…and leaves the list"
);
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
}
@@ -123,12 +66,12 @@ fn a_started_fade_still_ramps_and_the_driver_reparks_after() {
/// Driven rather than merely loaded: a kit that is present but never exercised is exactly how
/// twelve faux lists shipped unable to scroll (1868), so this runs a real flash to completion.
#[test]
fn a_flash_alternates_then_stops_and_the_driver_reparks() {
fn a_flash_alternates_then_stops() {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -138,12 +81,6 @@ fn a_flash_alternates_then_stops_and_the_driver_reparks() {
s.resolve();
// Parked until something asks — the whole point of the driver over UIParent's own OnUpdate.
assert!(
!s.eval::<bool>("return BenillaFlashDriver:IsShown()")
.unwrap(),
"an empty FLASHFRAMES parks the driver"
);
s.run(
r#"Probe = CreateFrame("Frame", "BenillaFlashProbe", UIParent)
Probe:SetWidth(10) Probe:SetHeight(10) Probe:SetPoint("TOPLEFT")
@@ -155,11 +92,6 @@ fn a_flash_alternates_then_stops_and_the_driver_reparks() {
.unwrap(),
"the frame is on the flash list"
);
assert!(
s.eval::<bool>("return BenillaFlashDriver:IsShown()")
.unwrap(),
"UIFrameFlash is the single inserter and wakes the driver"
);
// Re-arming an already-flashing frame is a no-op, not a second entry (ref UIParent.lua:1234).
s.run("UIFrameFlash(BenillaFlashProbe, 1, 1, 1, nil, 0, 0)")
@@ -187,9 +119,4 @@ fn a_flash_alternates_then_stops_and_the_driver_reparks() {
.unwrap(),
"showWhenDone was nil, so it ends hidden"
);
assert!(
!s.eval::<bool>("return BenillaFlashDriver:IsShown()")
.unwrap(),
"and the driver re-parks on the first empty tick"
);
}
@@ -40,10 +40,9 @@ fn harness_with(extra: &[&str]) -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
// `GameMenuFrame` and the panels it opens declare `parent="UIParent"`, resolved at LOAD
// (decision 1734) — UIParent must already be there, as it is in the manifest.
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -207,7 +206,13 @@ fn the_unbacked_entries_are_disabled_and_the_rest_are_live() {
#[test]
fn escape_opens_the_menu_only_when_nothing_else_wants_the_press_and_then_closes_it() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = bag_harness_with(&[], &["Interface\\FrameXML\\MerchantFrame.xml"]);
let mut s = bag_harness_with(
&[],
&[
"ScrollTemplates.xml",
"Interface\\FrameXML\\MerchantFrame.xml",
],
);
s.set_money(0);
s.set_container(0, Some(backpack()));
@@ -244,7 +249,13 @@ fn escape_opens_the_menu_only_when_nothing_else_wants_the_press_and_then_closes_
#[test]
fn the_clicked_form_closes_everything_and_opens_the_menu_in_one_go() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = bag_harness_with(&[], &["Interface\\FrameXML\\MerchantFrame.xml"]);
let mut s = bag_harness_with(
&[],
&[
"ScrollTemplates.xml",
"Interface\\FrameXML\\MerchantFrame.xml",
],
);
s.set_money(0);
s.set_container(0, Some(backpack()));
s.run("MainMenuBarBackpackButton:Click()").unwrap();
@@ -271,6 +282,7 @@ fn the_open_menu_takes_the_screen_and_refuses_every_other_panel() {
let mut s = bag_harness_with(
&[],
&[
"ScrollTemplates.xml", // our window tab template, before the window that inherits it (1988)
"Interface\\FrameXML\\MerchantFrame.xml",
// The loot window is the reference's own since 1751 — `test_ui::LOOT_UI` carries
// what it needs and why, and PartyFrame's `MAX_PARTY_MEMBERS` is needed at LOAD.
@@ -697,7 +709,8 @@ fn the_bag_row_greys_under_the_menu_without_any_of_it_disappearing() {
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"ScrollTemplates.xml", // the window tab template, ours (1004/1988)
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\MainMenuBar.xml",
"Interface\\FrameXML\\GameTooltip.xml",
@@ -78,7 +78,7 @@ fn setup() -> UiScript {
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
@@ -87,7 +87,6 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "Interface\\FrameXML\\MainMenuBar.xml");
load_xml(&s, "Interface\\FrameXML\\ActionBarFrame.xml");
@@ -155,7 +154,7 @@ fn rolls() -> LootRollsState {
fn shipped_group_loot_frame_loads_clean_and_starts_hidden() {
let _data = benilla_formats::wow_data_or_skip!();
let s = setup();
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIDropDownMenu.xml");
load_xml(&s, r"Interface\FrameXML\PartyMemberFrame.lua");
// The four roll popups arrive INSIDE the chain's loot window, so there is no exact frame count
@@ -547,14 +546,13 @@ fn managed_positions_engage_for_the_bare_frame_name() {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
// UiPanels.xml before GroupLootFrame.xml, mirroring the shipped manifest order
// (`ui_script::load_default_ui`): the roll file's CONFIRM_LOOT_ROLL entry indexes
// `StaticPopupDialogs`, and indexing a nil there aborts the WHOLE inline <Script> chunk —
// taking every BenillaGroupLootFrame_* function down with it, not just the popup.
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -578,7 +576,12 @@ fn managed_positions_engage_for_the_bare_frame_name() {
// The bar stubs carry a no-op SetPoint: `MultiBarBottomLeft` and `ShapeshiftBarFrame` are
// themselves rows in UIPARENT_MANAGED_FRAME_POSITIONS, so since those frames wear their
// reference names the pass positions them as well as reading their visibility.
s.run("MultiBarBottomLeft = { IsShown = function() return true end, SetPoint = function() end, ClearAllPoints = function() end }; MultiBarBottomRight = MultiBarBottomLeft; UIParent_ManageFramePositions()")
// **The bottom-bar flags come from the SAVED GLOBALS, not from the frames.** The stock pass
// reads `SHOW_MULTI_ACTIONBAR_1`/`_2` (`UIParent.lua:1598-1606`) and never asks the bars
// whether they are shown — our retired copy asked, which is why this drive used to fake a
// frame with an `IsShown`. The fake also had no `IsObjectType`, which the pass calls on every
// row it seats (1988).
s.run("SHOW_MULTI_ACTIONBAR_1 = 1 SHOW_MULTI_ACTIONBAR_2 = 1 UIParent_ManageFramePositions()")
.unwrap();
s.resolve();
assert_eq!(bottom(&s), 102.0, "60 + bottomEither 42 — the row engaged");
@@ -592,13 +595,16 @@ fn managed_positions_engage_for_the_bare_frame_name() {
ShapeshiftBarLeft, ShapeshiftBarMiddle, ShapeshiftBarRight = t, t, t",
)
.unwrap();
s.run("ShapeshiftBarFrame = { IsShown = function() return true end, SetPoint = function() end, ClearAllPoints = function() end }; UIParent_ManageFramePositions()")
s.run(
"ShapeshiftBarFrame = ShapeshiftBarFrame or CreateFrame(\"Frame\", \"ShapeshiftBarFrame\") \
ShapeshiftBarFrame:Show() UIParent_ManageFramePositions()",
)
.unwrap();
s.resolve();
assert_eq!(bottom(&s), 144.0, "60 + 42 + pet 42");
// And it settles back when the stance bar hides.
s.run("ShapeshiftBarFrame = { IsShown = function() return false end, SetPoint = function() end, ClearAllPoints = function() end }; UIParent_ManageFramePositions()")
s.run("ShapeshiftBarFrame:Hide() UIParent_ManageFramePositions()")
.unwrap();
s.resolve();
assert_eq!(bottom(&s), 102.0, "back to the multibar-only stack");
@@ -617,7 +623,7 @@ fn ctrl_and_shift_on_the_roll_icon_preview_and_post_its_link() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = setup();
load_group_loot(&s);
load_xml(&s, "UIParent.xml"); // BenillaChatEdit_InsertLink, the shared shift-insert helper
load_xml(&s, r"Interface\FrameXML\UIParent.xml"); // UIParent + UIParent.lua, the reference's own (1988)
load_xml(&s, "Interface\\FrameXML\\DressUpFrame.xml");
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml"); // the kit the chat menus build from
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
@@ -626,7 +632,6 @@ fn ctrl_and_shift_on_the_roll_icon_preview_and_post_its_link() {
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, "Interface\\FrameXML\\FloatingChatFrame.xml");
s.set_loot_rolls(rolls());
@@ -33,7 +33,7 @@ fn setup() -> UiScript {
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
// The stock file's `HelpFrame_OnShow` calls `UpdateMicroButtons()` before
@@ -43,7 +43,6 @@ fn setup() -> UiScript {
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"UIParent.xml",
"Interface\\FrameXML\\MainMenuBar.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
"Interface\\FrameXML\\BonusActionBarFrame.xml",
@@ -371,14 +371,14 @@ fn shown_inspect_honor_page() -> UiScript {
"Interface\\FrameXML\\BasicControls.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"ScrollTemplates.xml", // the window tab template, ours (1004/1988)
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
// `InspectUnit`'s home since 1832.
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
// Before the inspect addon — its honor page inherits this file's row templates and calls
// its two shared painters, and `inherits=` resolves at load (the manifest's own order).
@@ -119,14 +119,14 @@ fn armed() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
// `InspectUnit` lives here now — the reference's own home for that name, and no longer in the
// window's own file (decision 1832). The manifest's order, and 49 other harnesses'.
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
// Before InspectFrame.xml, and required rather than tidy: this window's honor page inherits
// HonorFrame.xml's five row templates and `inherits=` resolves at LOAD, so without it the
@@ -162,14 +162,14 @@ fn shipped_inspect_frame_loads_clean() {
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
// `InspectUnit` lives here now — the reference's own home for that name, and no longer in the
// window's own file (decision 1832). The manifest's order, and 49 other harnesses'.
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
// Before InspectFrame.xml, and required rather than tidy: this window's honor page inherits
// HonorFrame.xml's five row templates and `inherits=` resolves at LOAD, so without it the
@@ -88,10 +88,9 @@ fn the_self_menu_row_gates_on_the_binding_and_confirms_before_sending() {
.unwrap();
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -47,7 +47,7 @@ pub(crate) fn harness() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\BasicControls.xml",
@@ -57,7 +57,6 @@ pub(crate) fn harness() -> UiScript {
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
"UIParent.xml",
"KeyBindingsPage.xml",
"OptionsFrame.xml",
"GameMenuFrame.xml",
@@ -478,6 +478,7 @@ fn shipped_loot_pushed_to_center_by_merchant() {
load_xml(&s, f);
}
load_xml(&s, "Interface\\FrameXML\\LootFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// Loot opens onto the empty left slot.
@@ -607,7 +608,7 @@ fn ctrl_and_shift_on_a_loot_row_preview_and_post_without_looting() {
load_xml(&s, f);
}
for file in [
"UIParent.xml", // BenillaChatEdit_InsertLink, the shared shift-insert helper
r"Interface\FrameXML\UIParent.xml", // UIParent + UIParent.lua, the reference's own (1988)
"Interface\\FrameXML\\LootFrame.xml",
"Interface\\FrameXML\\DressUpFrame.xml",
"Interface\\FrameXML\\UIMenu.xml", // the kit ChatMenu/EmoteMenu/VoiceMacroMenu build from
@@ -617,7 +618,6 @@ fn ctrl_and_shift_on_a_loot_row_preview_and_post_without_looting() {
"Interface\\FrameXML\\UIDropDownMenu.xml",
"Interface\\FrameXML\\UIPanelTemplates.lua",
"Interface\\FrameXML\\UIPanelTemplates.xml",
"UiPanels.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\FloatingChatFrame.xml",
] {
@@ -93,12 +93,11 @@ fn harness_with(player: &str) -> UiScript {
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
// The chain's `PanelTemplates_SelectTab` reaches for `GameTooltip` unguarded.
"Interface\\FrameXML\\GameTooltip.xml",
"UIParent.xml", // `ShowMacroFrame` lives here now
// **ScrollTemplates BEFORE UIPanelTemplates, the manifest's own order.** Ours still
// carries dead `FauxScrollFrame_*` copies the chain overrides by loading after (1846's
// step 3, deliberately not done); the other way round OUR copies win — the silent
+5 -5
View File
@@ -55,7 +55,7 @@ pub(super) fn shipped_manifest_files() -> Vec<String> {
/// Run decision 0272's load-time `UIParent_ManageFramePositions()` pass.
///
/// Only meaningful once the frames that table names exist, so the font-registry-only load
/// ([`load_font_registry`]) skips it. It is defined in `UIParent.xml`, which is in the deferred
/// ([`load_font_registry`]) skips it. It is defined in the stock `UIParent.lua`, which is in the deferred
/// half; calling it after `Fonts.xml` alone is a nil-global error, not a no-op.
///
/// The ref applies `UIPARENT_MANAGED_FRAME_POSITIONS` once at load, then re-fires from the bottom
@@ -112,8 +112,8 @@ pub(super) fn apply_buff_durations(script: &UiScript) -> Result<(), String> {
/// that home rather than a FrameXML one: `assets/ui` does not grow (1779), and this is the wrong
/// side of the line for a `ContainerFrameAdapters`-class shim anyway — that clause is for a genuine
/// engine difference (1751 §2), and this is a deliberate repair of a reference defect. Rust is also
/// the durable home: our `UIParent.xml` is itself a transcription awaiting its own window, and a
/// hook parked there would be homeless again the day it migrates.
/// the durable home: our `UIParent.xml` was a transcription awaiting its own window (it migrated
/// with 1988), and a hook parked there would have been homeless that day.
///
/// Idempotent by its own latch, so a `ReloadUI` cannot stack wrappers. The reference's handler
/// still runs first and unchanged: `this`, `event` and `arg1` are globals the engine has already
@@ -340,7 +340,7 @@ mod tests {
/// not fail, it *half-works* — the frame keeps drawing, keeps answering `IsShown`, and simply
/// never joins the cascade `UIParent:Hide()` walks. That is precisely how it would be missed.
///
/// It nearly was: `UIParent.xml` sat below `UiPanels.xml` until decision 1734, so restoring
/// It nearly was: our `UIParent.xml` sat below `UiPanels.xml` until decision 1734, so restoring
/// `StaticPopup1`/`StaticPopup2`'s parents there would have written two declarations that did
/// nothing at all. The reference's own order is the fix (FrameXML.toc: BasicControls.xml l.6,
/// UIParent.xml l.8), and this keeps it.
@@ -349,7 +349,7 @@ mod tests {
let files = manifest_files();
let at = files
.iter()
.position(|f| f == "UIParent.xml")
.position(|f| f == r"Interface\FrameXML\UIParent.xml")
.expect("the manifest lists UIParent.xml");
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("assets/ui");
for early in &files[..at] {
@@ -343,6 +343,7 @@ fn merchant_show_hide_plays_open_and_close_kits() {
for f in super::test_ui::MERCHANT_UI {
load_xml(&s, f);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// Hidden at load: no open sound (never transitions on startup).
@@ -392,6 +393,7 @@ fn vendor_open_opens_the_backpack_and_layers_the_sound() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
equip_bag(&mut s, 0, "Backpack", 16);
@@ -442,6 +444,7 @@ fn vendor_leaves_an_already_open_backpack_alone() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
equip_bag(&mut s, 0, "Backpack", 16);
@@ -490,6 +493,7 @@ fn vendor_opens_and_closes_all_equipped_bags() {
for file in BAG_UI {
load_xml(&s, file);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
equip_bag(&mut s, 0, "Backpack", 16);
@@ -526,6 +530,7 @@ fn merchant_switch_plays_close_then_open_and_queues_the_consumable_close() {
for f in super::test_ui::MERCHANT_UI {
load_xml(&s, f);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// Vendor A open.
@@ -579,6 +584,7 @@ fn shipped_merchant_hover_scopes_highlight_and_anchors_item_tooltip() {
// every FrameXML file loads before any hover fires, so load it here too — with the dropdown
// kit its GroupLootDropDown initializes against at load (benilla.toc l.64 vs 383).
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_merchant(Some(MerchantState {
@@ -818,6 +824,7 @@ fn merchant_tabs_drive_buyback_page_and_repair_pair() {
for f in super::test_ui::MERCHANT_UI {
load_xml(&s, f);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(500);
@@ -939,6 +946,7 @@ fn merchant_tabs_fit_their_labels() {
for f in super::test_ui::MERCHANT_UI {
load_xml(&s, f);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
s.set_money(0);
s.set_merchant(Some(MerchantState::default()));
@@ -988,6 +996,7 @@ fn shipped_merchant_frame_arms_the_buy_cursor_on_hover() {
for f in super::test_ui::MERCHANT_UI {
load_xml(&s, f);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// A purse of 50c: row 1 (25c) is affordable, row 2 (100c) is not.
@@ -1081,6 +1090,7 @@ fn trade_recipient_money_renders_the_digit_not_ellipsis() {
for f in super::test_ui::MERCHANT_UI {
load_xml(&s, f);
}
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); // the BenillaMoney_* helpers
// TradeFrame's money entry is the chain's own since 1882 — its OnLoad calls MoneyInputFrame_*.
load_xml(&s, "Interface\\FrameXML\\MoneyInputFrame.lua");
@@ -1140,7 +1150,8 @@ fn ctrl_and_shift_on_a_vendor_row_preview_and_post_without_buying() {
load_xml(&s, f);
}
for file in [
"UIParent.xml", // BenillaChatEdit_InsertLink, the shared shift-insert helper
r"Interface\FrameXML\UIParent.xml", // UIParent + UIParent.lua, the reference's own (1988)
"ScrollTemplates.xml", // the window tab template, ours (1004/1988)
"Interface\\FrameXML\\MerchantFrame.xml",
"Interface\\FrameXML\\DressUpFrame.xml",
"Interface\\FrameXML\\UIMenu.xml", // the kit ChatMenu/EmoteMenu/VoiceMacroMenu build from
@@ -36,7 +36,7 @@ fn harness() -> UiScript {
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
// The eight labels and their NEWBIE_TOOLTIP_* lines, read at each button's OnLoad…
"Interface\\FrameXML\\GlobalStrings.lua",
// …through `TEXT()`.
@@ -403,10 +403,9 @@ fn the_meeting_stone_icon_follows_the_queue_across_meetingstone_changed() {
"Interface\\FrameXML\\Localization.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\BasicControls.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -19,13 +19,12 @@ fn harness() -> UiScript {
// The bars' START driver: `UIParent_OnEvent`'s MIRROR_TIMER_START arm is what calls
// `MirrorTimer_Show`, which is where the reference keeps it (UIParent.lua l.97 + l.374-377)
// and where window 7 moved ours back to. Without this file the event reaches nothing.
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
// `STATICPOPUP_NUMDIALOGS`, which the reference's own `MirrorTimer_Show` bounds its free-bar
// search by (MirrorTimer.lua l.32 — a copy-paste from StaticPopup.lua, and its own bug). A
// session without it searches `1, nil` and finds no free bar at all, so this is not scenery.
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -19,7 +19,7 @@ use super::test_ui::load_ui as load_xml;
fn load_action_bar(s: &UiScript) {
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GameTooltip.xml",
@@ -43,7 +43,6 @@ fn load_action_bar(s: &UiScript) {
// window publishes — the reference's own load order (UIOptionsFrame.xml l.21 before
// MultiActionBars.xml l.39), and the manifest's since 1938.
"Interface\\FrameXML\\UIDropDownMenu.xml",
"UiPanels.xml", // StaticPopupDialogs, which the options window's pages register into
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
@@ -280,8 +279,7 @@ fn shipped_stance_bar_drives_end_to_end() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -463,7 +461,7 @@ fn multibar_hover_renders_the_buttons_own_action() {
s.set_screen_size(1024.0, 768.0);
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GameTooltip.xml",
@@ -484,7 +482,6 @@ fn multibar_hover_renders_the_buttons_own_action() {
r"Interface\FrameXML\OptionsFrameTemplates.xml",
r"Interface\FrameXML\ReputationFrame.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -585,8 +582,7 @@ fn the_vertical_multibars_exist_hidden_on_the_reference_pages() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -648,8 +644,7 @@ fn every_extra_bar_stays_down_until_its_own_toggle_is_set() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -736,8 +731,7 @@ fn raising_a_bottom_bar_moves_the_managed_bottom_stack() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -801,8 +795,7 @@ fn viewable_action_bar_pages_follow_the_bar_toggles() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -868,8 +861,7 @@ fn the_grid_option_holds_the_extra_bars_empty_wells_open() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -972,8 +964,7 @@ fn a_held_payload_ghosts_the_empty_wells_it_opens() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -1116,8 +1107,7 @@ fn a_bar_toggle_sends_the_byte_its_globals_pack_to() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -1204,8 +1194,7 @@ fn the_shipped_setter_passes_exactly_four_arguments() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -1257,8 +1246,7 @@ fn the_stance_bar_sits_where_the_pass_puts_it() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -1318,8 +1306,8 @@ fn the_stance_bar_sits_where_the_pass_puts_it() {
/// the missing border the DEFAULT look rather than an edge case.
///
/// The last block is the point of the whole test: one `MultiActionBar_Update()` flips the seat AND
/// the art, which is what proves the art rides `UIParent_RegisterManagedPositionListener` rather
/// than having been set once at load.
/// the art, which is what proves the art rides the managed-position pass rather than having been
/// set once at load.
#[test]
fn the_stance_shelf_follows_the_bottom_left_bar() {
use benilla_ui::script::ShapeshiftFormView;
@@ -1330,8 +1318,7 @@ fn the_stance_shelf_follows_the_bottom_left_bar() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -1452,8 +1439,7 @@ fn the_stance_shelf_is_as_long_as_the_form_count() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -1570,8 +1556,7 @@ fn an_extra_bars_empty_well_keeps_its_bound_hotkey_label() {
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
@@ -50,10 +50,9 @@ fn harness_on(mut s: UiScript) -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
// Every panel window declares `parent="UIParent"`, resolved at LOAD — so UIParent has to
// exist by the time they are read, exactly as it does in the manifest (decision 1734).
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -700,7 +699,7 @@ fn audio_harness() -> UiScript {
fn combat_harness() -> UiScript {
let mut s = audio_harness();
s.set_screen_size(1024.0, 768.0);
load_definers(&s, &["UIParent.xml"]);
load_definers(&s, &[r"Interface\FrameXML\UIParent.xml"]);
// The family's definers are the options window's own since 1964 (the reference's
// UIOptionsFrame.lua block); the addon itself is LoadOnDemand off the chain, seated so the
// master row's apply can load it the way the client does.
@@ -743,13 +742,12 @@ fn interface_harness() -> UiScript {
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
// The target-of-target pair's definer (1576) and the three files ahead of it, all in
// their manifest seats. The chain is a real load-ORDER requirement rather than
// tidiness: `UnitFrames`' three menu hosts initialize into the dropdown kit at load
@@ -818,14 +816,13 @@ fn chat_harness() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"Interface\\FrameXML\\UIMenu.xml", // the kit ChatMenu/EmoteMenu/VoiceMacroMenu build from
@@ -852,7 +849,7 @@ fn actionbars_harness() -> UiScript {
&s,
&[
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Cooldown.xml",
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
@@ -873,7 +870,6 @@ fn actionbars_harness() -> UiScript {
r"Interface\FrameXML\OptionsFrameTemplates.xml",
r"Interface\FrameXML\ReputationFrame.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -44,10 +44,9 @@ fn harness() -> UiScript {
s.set_screen_size(1024.0, 768.0);
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"ScrollTemplates.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
+17 -27
View File
@@ -50,7 +50,7 @@ fn shipped_gossip_frame_drives_end_to_end() {
s.set_text_measurer(Box::new(super::FixedWidthFont(6.0)));
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
// UIPanelScrollFrameTemplate lives here, and the gossip scroll frame inherits it. NOT
// optional: a missing template is a loader *warning*, not an error, so an under-loaded
@@ -61,7 +61,6 @@ fn shipped_gossip_frame_drives_end_to_end() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
// The window + its scroll frame (bar + child) + the 32-row shared pool (quest rows and option
// rows both draw from it, decision 0088 §3 — the reference's own NUMGOSSIPBUTTONS) + the close
// button + the GOODBYE button. The greeting and the NPC-name banner are FontString layers (the
@@ -256,7 +255,7 @@ fn shipped_gossip_frame_renders_quest_rows_above_options() {
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
// UIPanelScrollFrameTemplate lives here, and the gossip scroll frame inherits it. NOT
// optional: a missing template is a loader *warning*, not an error, so an under-loaded
@@ -267,7 +266,6 @@ fn shipped_gossip_frame_renders_quest_rows_above_options() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
s.set_gossip(Some(GossipMenu {
@@ -420,7 +418,7 @@ fn shipped_gossip_rows_grow_to_their_wrapped_labels() {
s.set_text_measurer(Box::new(super::FixedWidthFont(6.0)));
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
// UIPanelScrollFrameTemplate lives here, and the gossip scroll frame inherits it. NOT
// optional: a missing template is a loader *warning*, not an error, so an under-loaded
@@ -431,7 +429,6 @@ fn shipped_gossip_rows_grow_to_their_wrapped_labels() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
// Three long options — the shape of a real judgement/roleplay menu, every one of them wrapping
@@ -539,7 +536,7 @@ fn gossip_show_hide_plays_open_and_close_kits() {
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
// UIPanelScrollFrameTemplate lives here, and the gossip scroll frame inherits it. NOT
// optional: a missing template is a loader *warning*, not an error, so an under-loaded
@@ -550,7 +547,6 @@ fn gossip_show_hide_plays_open_and_close_kits() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
// Hidden at load: no open sound (never transitions on startup).
@@ -586,7 +582,7 @@ fn shipped_panel_slot_replaces_gossip_with_merchant() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
// UIPanelScrollFrameTemplate lives here, and the gossip scroll frame inherits it. NOT
// optional: a missing template is a loader *warning*, not an error, so an under-loaded
@@ -596,7 +592,6 @@ fn shipped_panel_slot_replaces_gossip_with_merchant() {
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
// The vendor window is the reference's own since 1751, and its `MerchantFrame_UpdateMerchantInfo`
// calls `TEXT()` while building every row — see `test_ui::MERCHANT_UI` for the rest.
@@ -682,7 +677,7 @@ fn displacing_an_npc_window_ends_the_displaced_session() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
// UIPanelScrollFrameTemplate lives here, and the gossip scroll frame inherits it. NOT
// optional: a missing template is a loader *warning*, not an error, so an under-loaded
@@ -692,7 +687,6 @@ fn displacing_an_npc_window_ends_the_displaced_session() {
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
// The vendor window is the reference's own since 1751, and its `MerchantFrame_UpdateMerchantInfo`
// calls `TEXT()` while building every row — see `test_ui::MERCHANT_UI` for the rest.
@@ -742,13 +736,13 @@ fn shipped_panel_slot_pushable_promotes_to_center() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, "UIParent.xml");
// The vendor window is the reference's own since 1751, and its `MerchantFrame_UpdateMerchantInfo`
// calls `TEXT()` while building every row — see `test_ui::MERCHANT_UI` for the rest.
for f in super::test_ui::MERCHANT_UI {
@@ -851,12 +845,11 @@ fn gossip_bank_option_hands_the_left_slot_to_the_bank() {
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); // the reference bank's slot buttons inherit it
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Cooldown.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
@@ -940,7 +933,7 @@ fn an_overflowing_gossip_menu_scrolls_instead_of_spilling() {
s.set_text_measurer(Box::new(super::FixedWidthFont(6.0)));
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml"); // UIPanelScrollFrameTemplate — see the note above
@@ -948,7 +941,6 @@ fn an_overflowing_gossip_menu_scrolls_instead_of_spilling() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
// Eight wrapping options: ~4 lines each, far past the 334 px scroll frame.
@@ -1102,7 +1094,7 @@ fn an_addons_own_frame_registered_in_uipanelwindows_takes_the_left_slot() {
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml"); // UIPanelScrollFrameTemplate — see the note above
@@ -1110,7 +1102,6 @@ fn an_addons_own_frame_registered_in_uipanelwindows_takes_the_left_slot() {
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GossipFrame.xml");
// The addon's three lines, in the order an addon writes them.
@@ -1184,14 +1175,14 @@ fn the_1507_registry_rows_match_the_reference_bytes() {
let s = UiScript::new().unwrap();
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
for probe in [
// ItemTextFrame — UIParent.lua l.20 (the B288 row).
"UIPanelWindows['ItemTextFrame'].area == 'left'",
@@ -1203,8 +1194,9 @@ fn the_1507_registry_rows_match_the_reference_bytes() {
// The whileDead flags the ref authors and 1507 carried (l.21, l.25, Blizzard_TalentUI:71).
"UIPanelWindows['SpellBookFrame'].whileDead == 1",
"UIPanelWindows['QuestLogFrame'].whileDead == 1",
"UIPanelWindows['TalentFrame'].whileDead == 1",
// UIChildWindows — UIParent.lua l.44-50 verbatim, all four shipped.
// `TalentFrame`'s row is `Blizzard_TalentUI.lua:71`'s, registered when that addon loads
// (1988 retired our copy of it, which the reference does not keep in UIParent.lua).
"table.getn(UIChildWindows) == 4",
"UIChildWindows[1] == 'OpenMailFrame'",
"UIChildWindows[2] == 'GuildControlPopupFrame'",
@@ -1229,14 +1221,13 @@ fn a_dead_player_opens_only_whiledead_windows() {
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s.set_unit(
"player",
Some(benilla_ui::script::UnitState {
@@ -1303,14 +1294,13 @@ fn a_frame_arriving_at_center_puts_the_child_windows_away() {
s.set_screen_size(1024.0, 768.0);
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
// The letter is open; two shipped-row stand-ins take the seats: MerchantFrame (pushable 0)
// holds left, TradeFrame (pushable 1) then ARRIVES at center (UIParent.lua l.734-741's
@@ -19,7 +19,7 @@ fn harness(extra: &[&str]) -> UiScript {
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "Interface\\FrameXML\\MainMenuBar.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
@@ -229,7 +229,7 @@ fn get_net_stats_reports_the_pushed_latency() {
/// tooltip that is quietly one line short.
#[test]
fn hovering_the_meter_shows_the_live_latency() {
let mut s = harness(&["UIParent.xml"]);
let mut s = harness(&[r"Interface\FrameXML\UIParent.xml"]);
s.set_latency_ms(Some(42));
// 1.12 ships detailed tips ON — `SHOW_NEWBIE_TIPS = "1"` is UIOptionsFrame_Init's (ref
// UIOptionsFrame.lua l.100; ours sits in OptionsFrame.xml's uvar block, 1968), and a harness
@@ -18,7 +18,7 @@ use super::test_ui::load_ui as load_xml;
pub(super) fn load_pet_bar(s: &UiScript) {
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Cooldown.xml",
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
@@ -35,7 +35,6 @@ pub(super) fn load_pet_bar(s: &UiScript) {
r"Interface\FrameXML\UIPanelTemplates.xml",
r"Interface\FrameXML\OptionsFrameTemplates.xml",
r"Interface\FrameXML\ReputationFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
@@ -27,7 +27,7 @@ fn load_pet_frame() -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
@@ -479,9 +479,18 @@ fn hovering_the_diet_icon_lists_what_the_pet_eats() {
&& pane_rect.top >= rect.top,
"the icon sits wholly inside the pane, which is what makes the z-order matter"
);
// **The pane's scene draws AFTER the icon, and that is the reference's own order.**
// `PetPaperDollPetInfo` is a sibling frame of `PetModelFrame` (same parent, so the same
// `(strata, level)` bucket) and its happiness art is a BACKGROUND texture on it; a model's
// scene drains out of that bucket's ARTWORK batch, last (wow-re
// `ui/scratch/model-frame-draw-order.md`: `0x76d160` registers the render callback only for
// layer 2, and `0x76fb00` drains quads, then text, then callbacks). The icon stays visible
// because a model pane is not an opaque quad — the bake is transparent everywhere the pet
// is not, here as in the client. This assertion is the ordering, not the pixels.
assert!(
icon.z > pane.z,
"the diet icon must paint over the pane it sits in (icon z={:#x}, pane z={:#x})",
pane.z > icon.z,
"the pane's scene draws out of the ARTWORK batch, after a sibling's BACKGROUND art \
(icon z={:#x}, pane z={:#x})",
icon.z,
pane.z
);
@@ -94,7 +94,7 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
@@ -105,7 +105,6 @@ fn setup() -> UiScript {
// without this the rows build with no art at all and nothing goes red — which is exactly the
// failure `load_ui_strict` exists to turn into a red test.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -16,14 +16,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s
}
+20 -31
View File
@@ -21,7 +21,7 @@ fn questgiver_show_hide_plays_open_and_close_kits() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
@@ -30,10 +30,9 @@ fn questgiver_show_hide_plays_open_and_close_kits() {
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
// The BenillaMoney_* purse helpers the quest reward/progress panels repaint through live in
// MerchantFrame.xml (the same documented cross-window dep the bag tests load).
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -92,17 +91,16 @@ fn panel_events_show_exactly_one_child_panel_and_hide_the_others() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -191,17 +189,16 @@ fn detail_panel_reward_grid_follows_the_refs_two_per_row_layout() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -294,17 +291,16 @@ fn reward_panel_choice_click_selects_and_completes_with_zero_based_index() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -374,17 +370,16 @@ fn greeting_goodbye_button_closes_the_window() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -432,17 +427,16 @@ fn detail_panel_action_buttons_resolve_to_real_onscreen_rects() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -561,17 +555,16 @@ fn write_on_still_fades_when_instant_text_is_off() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -639,17 +632,16 @@ fn npc_name_reaches_the_title_bar_on_open_and_on_refresh() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -723,17 +715,16 @@ fn greeting_panel_title_rows_grow_to_their_wrapped_titles() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml"); // the shared scroll kit the window rides
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
@@ -824,21 +815,19 @@ fn reward_rows_preview_and_post_without_selecting_the_choice() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
load_xml(&s, "UIParent.xml"); // BenillaChatEdit_InsertLink lives here
load_xml(&s, "Interface\\FrameXML\\DressUpFrame.xml"); // DressUpItemLink lives here
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml"); // the kit its menus build from
load_xml(&s, "Interface\\FrameXML\\ChatFrame.xml"); // ChatFrameEditBox lives here
@@ -28,13 +28,12 @@ fn harness() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
// `SecondsToTime`, which the reference's `QuestTimerFrame_Update` formats every row with, and
// `UIParent_ManageFramePositions`, which its OnShow/OnHide call.
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
// `MAX_QUESTS`, the loop bound the reference's repaint hides its spare rows with. 1.12
// declares it on QuestLogFrame.lua:2 and so do we (1751 window 16) — a nil there is
// `'for' limit must be a number` on the first repaint, not a missing row.
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
@@ -88,21 +88,19 @@ fn shipped_questlog_frame_loads_clean() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -122,21 +120,19 @@ fn shipped_questlog_frame_drives_end_to_end() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -332,27 +328,24 @@ fn shift_click_toggles_the_watch_checkbox_and_the_tracker_hud() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
// A shift-click reaches stock QuestLogTitleButton_OnClick's unguarded `ChatFrameEditBox:IsVisible()`
// (QuestLogFrame.lua:478) — the chat window is on the manifest long before the log (1944).
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml");
load_xml(&s, "Interface\\FrameXML\\ChatFrame.xml");
@@ -480,28 +473,25 @@ fn watch_guards_no_op_without_erroring() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "Interface\\FrameXML\\UIErrorsFrame.xml"); // the guards' red-line surface
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
// A shift-click reaches stock QuestLogTitleButton_OnClick's unguarded `ChatFrameEditBox:IsVisible()`
// (QuestLogFrame.lua:478) — the chat window is on the manifest long before the log (1944).
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml");
load_xml(&s, "Interface\\FrameXML\\ChatFrame.xml");
@@ -597,21 +587,19 @@ fn progress_auto_watches_for_five_minutes() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
// AUTO_QUEST_WATCH is the options window's (UIOptionsFrame_Init in the reference; 1944), so the
// auto-watch needs that window loaded, as the manifest has it long before the log.
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
@@ -682,7 +670,7 @@ fn the_auto_watch_flag_is_the_references_uvar_and_gates_the_watch() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
@@ -691,7 +679,6 @@ fn the_auto_watch_flag_is_the_references_uvar_and_gates_the_watch() {
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
// The flag is declared by the options window's init since 1944, as the reference declares it
// in UIOptionsFrame_Init — so the window that owns it loads first, as in the manifest.
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "KeyBindingsPage.xml");
@@ -748,17 +735,16 @@ fn the_row_tag_is_its_own_right_flush_string_and_the_state_word_wins() {
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -827,21 +813,19 @@ fn empty_quest_log_hides_rows_and_disables_abandon() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -892,21 +876,19 @@ fn reward_rows_follow_the_refs_two_per_row_layout() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1081,21 +1063,19 @@ fn overflowing_detail_content_clips_to_the_scrollframe_rect() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1156,21 +1136,19 @@ fn wheel_over_the_detail_pane_changes_vertical_scroll() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1221,21 +1199,19 @@ fn selection_change_resets_detail_scroll_but_a_quest_log_update_refresh_does_not
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1298,7 +1274,7 @@ fn reward_row_hover_serves_the_shared_item_tooltip() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
@@ -1310,14 +1286,12 @@ fn reward_row_hover_serves_the_shared_item_tooltip() {
// Fonts.xml alone is the source now. Formerly: it
// needs the dropdown kit its GroupLootDropDown initializes against (benilla.toc l.64 vs 383).
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1401,7 +1375,8 @@ fn popup_children_inherit_the_dialog_stratum() {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -1458,21 +1433,19 @@ fn reward_rows_preview_and_post_and_a_plain_click_stays_inert() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1480,7 +1453,6 @@ fn reward_rows_preview_and_post_and_a_plain_click_stays_inert() {
// (QuestLogFrame.lua:478) — the chat window is on the manifest long before the log (1944).
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
load_xml(&s, "UIParent.xml"); // BenillaChatEdit_InsertLink lives here
load_xml(&s, "Interface\\FrameXML\\DressUpFrame.xml"); // DressUpItemLink lives here
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml"); // the kit its menus build from
load_xml(&s, "Interface\\FrameXML\\ChatFrame.xml"); // ChatFrameEditBox lives here
@@ -1557,21 +1529,19 @@ fn shift_click_on_a_title_posts_the_quest_name_with_chat_open_and_watches_with_i
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1579,7 +1549,6 @@ fn shift_click_on_a_title_posts_the_quest_name_with_chat_open_and_watches_with_i
// (QuestLogFrame.lua:478) — the chat window is on the manifest long before the log (1944).
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
load_xml(&s, "Interface\\FrameXML\\QuestLogFrame.xml");
load_xml(&s, "UIParent.xml"); // BenillaChatEdit_InsertLink lives here
load_xml(&s, "Interface\\FrameXML\\UIMenu.xml"); // the kit its menus build from
load_xml(&s, "Interface\\FrameXML\\ChatFrame.xml"); // ChatFrameEditBox lives here
load_xml(&s, "Interface\\FrameXML\\UIPanelTemplates.lua");
@@ -1667,21 +1636,19 @@ fn share_quest_needs_both_a_sharable_selection_and_a_party() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1754,21 +1721,19 @@ fn share_quest_is_dark_on_an_empty_log_even_in_a_party() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1795,21 +1760,19 @@ fn share_quest_click_queues_the_selected_quests_id() {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "ScrollTemplates.xml"); // our window tab template, before the window that inherits it (1988)
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
// ScrollTemplates.xml + UIPanelTemplates.xml are NOT optional: the detail pane inherits
// UIPanelScrollFrameTemplate, and a MISSING template is a loader *warning*, not an error —
// an under-loaded list passes load_xml and then loses the wheel, the arrows and the bar
// silently.
load_xml(&s, "ScrollTemplates.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, r"Interface\FrameXML\MainMenuBarMicroButtons.xml");
@@ -1777,7 +1777,7 @@ mod tests {
"Interface/FrameXML/ContainerFrame.xml"
));
assert!(!super::is_chain_entry("BagFrame.xml"));
assert!(!super::is_chain_entry("UIParent.xml"));
assert!(!super::is_chain_entry("ScrollTemplates.xml"));
}
/// Every global function and virtual template name a manifest entry declares.
///
@@ -2252,6 +2252,72 @@ mod tests {
// Registered by a chain file we load, produced by nothing. Each is a feature we have not
// built; none is 1819-shaped, because no PAIR is split (a half-fired pair is the tell).
const UNPRODUCED: &[(&str, &str)] = &[
// ── The stock `UIParent.lua`'s own listeners (1988) — every one is a dialog or a
// notice the reference's engine raises for a condition benilla's session does not
// reach yet. Each names the arm that would fire.
(
"ADDON_ACTION_FORBIDDEN",
"UIParent.lua — the protected-action refusal; benilla has no protected-call \
taint model, so nothing can raise it",
),
(
"MACRO_ACTION_FORBIDDEN",
"UIParent.lua — the macro half of ADDON_ACTION_FORBIDDEN, same reason",
),
(
"AUTOEQUIP_BIND_CONFIRM",
"UIParent.lua — the bind-on-equip confirm for an AUTOEQUIP (right-click) path; \
benilla's equip path fires the EQUIP_BIND_CONFIRM sibling only",
),
(
"EQUIP_BIND_CONFIRM",
"UIParent.lua — the bind-on-equip confirm; benilla's inventory feed does not \
derive the server's confirm ask yet",
),
(
"USE_BIND_CONFIRM",
"UIParent.lua — the bind-on-use confirm, the same gap from the use path",
),
(
"BILLING_NAG_DIALOG",
"UIParent.lua — the subscription-time nag; vmangos never sends it",
),
(
"IGR_BILLING_NAG_DIALOG",
"UIParent.lua — the internet-cafe billing nag, likewise never sent",
),
(
"GOSSIP_ENTER_CODE",
"UIParent.lua — the code-entry gossip option (a door with a combination); \
benilla's gossip feed carries no code-entry option kind yet",
),
(
"MEMORY_EXHAUSTED",
"UIParent.lua — the client's own out-of-memory dialog; benilla's allocator \
failure is a Rust abort, not a Lua event",
),
(
"MEMORY_RECOVERED",
"UIParent.lua — the other half of MEMORY_EXHAUSTED",
),
(
"PLAYER_SKINNED",
"UIParent.lua — the corpse-skinned notice; benilla's loot feed does not derive it",
),
(
"TRADE_REQUEST",
"UIParent.lua — the trade ASK dialog; benilla's trade session (0633's sibling) \
opens the window on the wire's own open and never asks",
),
(
"TRADE_REQUEST_CANCEL",
"UIParent.lua — the cancel of that ask, same reason",
),
(
"TRADE_REPLACE_ENCHANT",
"UIParent.lua — the enchant-replacement confirm inside a trade; benilla's trade \
feed does not derive it",
),
("BAG_OPEN", "ContainerFrame.lua"),
(
"CLOSE_WORLD_MAP",
@@ -17,7 +17,7 @@ fn harness() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -25,7 +25,6 @@ fn harness() -> UiScript {
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
r"Interface\FrameXML\WorldFrame.xml",
"UIParent.xml",
] {
load_xml(&s, f);
}
@@ -1335,10 +1335,9 @@ fn the_inspect_cursor_pair_takes_both_arms() {
///
/// - `CinematicFrame` — the frame being *shown*. The reference declares it with no parent for
/// exactly this reason, and `SetFullScreenFrame` shows it in the same breath as hiding UIParent.
/// - `BenillaFadeDriver` — a 1x1 frame with no textures and no layers, whose only content is an
/// `OnUpdate` running `UIFrameFadeUpdate`. It draws nothing, and it must not be hidden: a hidden
/// frame's `OnUpdate` does not run, so parenting it would freeze every in-flight `UIFrameFade`
/// the instant a cinematic started and leave frames stranded mid-fade.
/// - (Until 1988 a `BenillaFadeDriver` survived beside it — our fade kit's tick frame. The stock
/// `UIFrameFadeUpdate` runs from UIParent's own OnUpdate, which a cinematic's `UIParent:Hide()`
/// stops exactly as the reference's does.)
#[test]
fn a_cinematic_leaves_nothing_of_the_interface_on_screen() {
let mut s = benilla_ui::script::UiScript::new().unwrap();
@@ -1360,7 +1359,26 @@ fn a_cinematic_leaves_nothing_of_the_interface_on_screen() {
assert!(failures.is_empty(), "manifest load errors: {failures:#?}");
s.resolve();
let names = shipped_frame_names();
// The sweep's subjects: the frames OUR files declare — plus the reference's own HUD, because
// `assets/ui` is nearly empty now (1988 retired the last of the glue) and a sweep over what is
// left would pass without ever looking at the interface the cascade actually hides.
let mut names = shipped_frame_names();
names.extend(
[
"MainMenuBar",
"ChatFrame1",
"PlayerFrame",
"MinimapCluster",
"BuffFrame",
"MainMenuBarBackpackButton",
"CharacterMicroButton",
"UIErrorsFrame",
// The frame being SHOWN — the sweep's one expected survivor.
"CinematicFrame",
]
.into_iter()
.map(String::from),
);
let visible = |s: &benilla_ui::script::UiScript, n: &str| -> bool {
s.eval::<i64>(&format!(
"local f = getglobal(\"{n}\") \
@@ -1376,9 +1394,9 @@ fn a_cinematic_leaves_nothing_of_the_interface_on_screen() {
assert!(
// 50 until 1938 took the three bar files stock, 20 until 1974 took the minimap cluster
// (its 22 named frames were most of what this sweep counted), 12 until 1987 took the
// micro row; the floor follows the census of OUR files down, and 2 is what is left —
// the glue and dev frames.
before >= 2,
// micro row and 1988 the glue. The floor is over the named HUD above now, not over our
// files' census, so it stops following the migration down.
before >= 6,
"only {before} frames visible before the cinematic — the sweep found no interface to \
hide, so it would pass no matter what the cascade did"
);
@@ -1395,7 +1413,7 @@ fn a_cinematic_leaves_nothing_of_the_interface_on_screen() {
after.sort_unstable();
assert_eq!(
after,
["BenillaFadeDriver", "CinematicFrame"],
["CinematicFrame"],
"something is drawing over the fly-by (see this test's header for why exactly these \
two are allowed to survive)"
);
@@ -89,7 +89,7 @@ pub(super) fn spellbook_ui(w: f32, h: f32) -> UiScript {
s.set_screen_size(w, h);
for f in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Cooldown.xml",
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
@@ -106,7 +106,6 @@ pub(super) fn spellbook_ui(w: f32, h: f32) -> UiScript {
r"Interface\FrameXML\UIPanelTemplates.xml",
r"Interface\FrameXML\OptionsFrameTemplates.xml",
r"Interface\FrameXML\ReputationFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
@@ -132,7 +131,8 @@ fn shipped_spellbook_loads_clean() {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
@@ -687,11 +687,10 @@ fn the_macro_editor_takes_a_shift_click_and_only_a_shift_click() {
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
// `ShowMacroFrame` lives here since 1848.
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Cooldown.xml",
// **ScrollTemplates BEFORE UIPanelTemplates, which is the manifest's own order.** Ours
@@ -13,7 +13,7 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
@@ -271,7 +271,7 @@ fn hide_and_find_address_one_instance_by_data_only_for_a_multiple_dialog() {
fn the_verb_dialogs_open_from_their_events_and_call_their_verbs() {
use benilla_ui::script::ScriptValue;
let mut s = setup();
load_xml(&s, "UIParent.xml"); // the arms
load_xml(&s, r"Interface\FrameXML\UIParent.xml"); // the arms
s.set_money(50_000);
// The pet trainer's question: the dialog, its money frame at the cost, Accept → the confirm.
s.fire_event("CONFIRM_PET_UNLEARN", vec![ScriptValue::Int(12_345)]);
@@ -306,9 +306,22 @@ fn the_verb_dialogs_open_from_their_events_and_call_their_verbs() {
assert!(s
.eval::<bool>("return StaticPopup_Visible(\"AREA_SPIRIT_HEAL\") ~= nil")
.unwrap());
// **The reference's dialog accepts on SHOW and its one button CANCELS** — the 1.12 file keeps
// the old two-button version commented out and ships the auto-accepting one
// (`StaticPopup.lua:1204-1240`): `OnShow` calls `AcceptAreaSpiritHeal()`, `button1` is CANCEL,
// and its `OnAccept` calls `CancelAreaSpiritHeal()`. So the accept is already in by the time
// the popup is on screen (1988 — our retired UIParent arm showed it without that OnShow).
assert!(
s.take_area_spirit_accepts() >= 1,
"showing the dialog IS the accept"
);
s.run("StaticPopup_OnClick(StaticPopup_FindVisible(\"AREA_SPIRIT_HEAL\"), 1)")
.unwrap();
assert_eq!(s.take_area_spirit_accepts(), 1);
assert_eq!(
s.take_area_spirit_accepts(),
0,
"the button cancels; it does not accept again"
);
s.fire_event("AREA_SPIRIT_HEALER_OUT_OF_RANGE", vec![]);
s.tick(0.0);
assert!(!s
@@ -29,14 +29,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s.set_summon_confirm(SummonConfirmUiState {
summoner: "Twomage".into(),
area: "Stormwind City".into(),
@@ -37,10 +37,10 @@ fn harness(rank: u32) -> UiScript {
}
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"ScrollTemplates.xml", // the window tab template, ours (1004/1988)
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -15,14 +15,13 @@ fn setup() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\GlobalStrings.lua");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
s.set_talent_master_pending(true);
s
}
@@ -28,7 +28,7 @@ fn harness() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\ActionButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.lua");
load_xml(&s, "Interface\\FrameXML\\TextStatusBar.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "Interface\\FrameXML\\MainMenuBar.xml");
load_xml(&s, "Interface\\FrameXML\\ActionBarFrame.xml");
@@ -18,7 +18,7 @@ fn taxi_script() -> UiScript {
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
+108 -14
View File
@@ -70,14 +70,14 @@ fn load_entry(s: &UiScript, entry: &str, strict_templates: bool, no_warnings: bo
"{entry}: loader errors: {:?}",
report.errors
);
if path
.rsplit('/')
.next()
.is_some_and(|leaf| leaf.eq_ignore_ascii_case("MainMenuBarMicroButtons.xml"))
{
let leaf = path.rsplit('/').next().unwrap_or("");
if leaf.eq_ignore_ascii_case("MainMenuBarMicroButtons.xml") {
s.run(MICRO_BUTTON_STAND_INS)
.expect("the micro-button stand-ins");
}
if leaf.eq_ignore_ascii_case("UIParent.xml") && super::reference_ui::is_chain_entry(&path) {
s.run(UIPARENT_STAND_INS).expect("the UIParent stand-ins");
}
if no_warnings {
assert!(
report.warnings.is_empty(),
@@ -118,6 +118,102 @@ fn load_entry(s: &UiScript, entry: &str, strict_templates: bool, no_warnings: bo
/// kits' seventy-odd consumers because the dependency is the row's, not any one window's — and
/// the shipped manifest never needs it. `tests/common/mod.rs` carries the same chunk for the
/// integration tests, which cannot reach this module (decision 1987).
/// **What a kit owes the stock `UIParent.xml`.** Its `<OnUpdate>` calls `FCF_OnUpdate`,
/// `UnitPopup_OnUpdate` and `BattlefieldFrame_OnUpdate` unguarded (the chat, unit-menu and
/// battlefield files, far below it in the manifest), `UIParent_OnEvent`'s `PLAYER_ENTERING_WORLD`
/// arm calls `MultiActionBar_Update`, and `ShowUIPanel` calls `CloseAllBags` (the container file's).
/// A kit that stops short of those files would raise on its first tick or first shown panel, so
/// [`load_entry`] seats a no-op stand-in under each name the moment the stock file loads. Unlike
/// the micro row's frames these are FUNCTIONS: a later chunk's `function X()` overwrites a global
/// outright, so seating at load is safe and the kit's order does not matter (decision 1988).
pub(super) const UIPARENT_STAND_INS: &str = r#"
-- Callees of the stock UIParent.xml's <OnUpdate> and of UIParent_OnEvent's arms that live in
-- files a kit may stop short of, plus the bag verbs the stock ShowUIPanel calls and the two
-- container constants its window walks read: no-op stand-ins, each overwritten by the real
-- definition when its file loads (a chunk's `function X()` is a plain global write, unlike a
-- frame's non-overwriting publish — which is why the FRAMES below are seated on first use).
FCF_OnUpdate = FCF_OnUpdate or function() end
FCF_DockUpdate = FCF_DockUpdate or function() end
UnitPopup_OnUpdate = UnitPopup_OnUpdate or function() end
BattlefieldFrame_OnUpdate = BattlefieldFrame_OnUpdate or function() end
MultiActionBar_Update = MultiActionBar_Update or function() end
RaidOptionsFrame_UpdatePartyFrames = RaidOptionsFrame_UpdatePartyFrames or function() end
LocalizeFrames = LocalizeFrames or function() end
updateContainerFrameAnchors = updateContainerFrameAnchors or function() end
-- Ours, not the reference's file: 1.12 keeps UpdateNameplates in UIOptionsFrame.lua and
-- benilla's own options window carries it (the options family stays ours).
UpdateNameplates = UpdateNameplates or function() end
CloseAllBags = CloseAllBags or function() end
OpenBackpack = OpenBackpack or function() end
CloseBackpack = CloseBackpack or function() end
NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES or 0
-- The reference's own initial values (`ContainerFrame.lua:11-12`), not zeroes: the tooltip's
-- default corner is `-CONTAINER_OFFSET_X - 13, CONTAINER_OFFSET_Y`, so a kit reading zero here
-- would seat every default-anchored plate 70 units low.
CONTAINER_OFFSET_X = CONTAINER_OFFSET_X or 0
CONTAINER_OFFSET_Y = CONTAINER_OFFSET_Y or 70
BATTLEFIELD_TAB_OFFSET_Y = BATTLEFIELD_TAB_OFFSET_Y or 210
-- The pass writes its `isVar` rows with `setglobal`, but only for a name that already reads
-- non-nil (`frame = getglobal(index); if frame then`), so an unseeded one is never written at
-- all. These four are the reference's own seeds, from the files that declare them
-- (ContainerFrame.lua, PetActionBarFrame.lua, WorldStateFrame.lua).
PETACTIONBAR_YPOS = PETACTIONBAR_YPOS or 98
PETACTIONBAR_XPOS = PETACTIONBAR_XPOS or 36
-- The frames these three read UNGUARDED, seated on the call rather than at load: a frame's
-- publish to _G is non-overwriting (RF-0023), so a stand-in seated before the real file loads
-- would shadow the real window for good.
local function benilla_seat(names)
for _, name in ipairs(names) do
if not getglobal(name) then local f = CreateFrame("Frame") f:Hide() setglobal(name, f) end
end
end
local real_manage = UIParent_ManageFramePositions
function UIParent_ManageFramePositions()
benilla_seat({ "MainMenuBar", "MultiBarLeft", "MultiBarRight", "MultiBarBottomLeft",
"PetActionBarFrame", "ShapeshiftBarFrame", "ReputationWatchBar", "MainMenuExpBar",
"MainMenuBarMaxLevelBar", "CastingBarFrame", "QuestTimerFrame", "QuestWatchFrame",
"DurabilityFrame", "DurabilityShield", "DurabilityOffWeapon", "DurabilityRanged",
"MinimapCluster", "ChatFrame1", "ChatFrame2", "ShapeshiftBarLeft",
"ShapeshiftBarMiddle", "ShapeshiftBarRight", "BattlefieldMinimapTab" })
-- …and every FRAME the managed table itself names (`frame:IsObjectType` on a nil is what
-- a kit missing one raises) — read off the table, so a row added there needs nothing here.
-- The `isVar` rows are skipped: those keys are global NUMBERS the pass writes
-- (CONTAINER_OFFSET_X/Y, PETACTIONBAR_YPOS…), and a frame seated under one of those names
-- would be arithmetic's problem two files later.
local named = {}
for name, row in pairs(UIPARENT_MANAGED_FRAME_POSITIONS) do
if not row.isVar then table.insert(named, name) end
end
benilla_seat(named)
for _, name in ipairs({ "SlidingActionBarTexture0", "SlidingActionBarTexture1" }) do
if not getglobal(name) then setglobal(name, UIParent:CreateTexture()) end
end
return real_manage()
end
-- The four options/menu windows `IsOptionFrameOpen` (l.997) and `ToggleGameMenu` (l.1467)
-- index unguarded. `IsOptionFrameOpen` is on the path of every window close, so a kit that
-- loads no options window raised on the first bag click; ours answers all three of the
-- reference's options windows (1987) and a kit may load none of them.
local function benilla_seat_options()
benilla_seat({ "GameMenuFrame", "OptionsFrame", "UIOptionsFrame", "SoundOptionsFrame" })
if not OptionsFrameCancel then
OptionsFrameCancel = CreateFrame("Button")
OptionsFrameCancel:Hide()
end
end
local real_option_open = IsOptionFrameOpen
function IsOptionFrameOpen()
benilla_seat_options()
return real_option_open()
end
local real_toggle_menu = ToggleGameMenu
function ToggleGameMenu(clicked)
benilla_seat_options()
return real_toggle_menu(clicked)
end
"#;
pub(super) const MICRO_BUTTON_STAND_INS: &str = r#"
local real = UpdateMicroButtons
function UpdateMicroButtons()
@@ -188,9 +284,10 @@ pub(super) const MERCHANT_UI: &[&str] = &[
"Interface\\FrameXML\\ItemButtonTemplate.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"ScrollTemplates.xml", // our window tab template, before the window that inherits it (1988)
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"Interface\\FrameXML\\GameTooltip.xml", // app load order: tooltip before merchant
@@ -202,7 +299,7 @@ pub(super) const LOOT_UI: &[&str] = &[
"Interface\\FrameXML\\ItemButtonTemplate.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml", // StaticPopup, and the LOOT_BIND / CONFIRM_LOOT_DISTRIBUTION dialogs
r"Interface\FrameXML\UIParent.xml", // UIParent + UIParent.lua (the slot manager, the fades; 1988)
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
@@ -214,7 +311,6 @@ pub(super) const LOOT_UI: &[&str] = &[
// exactly as the reference's own UnitPopup.lua:47-49 does — so its declarer has to precede it.
// That declarer is UIParent (ref UIParent.lua:65); 1888 moved the table there when Fonts.xml
// went on the chain, because the reference's Fonts.xml does not declare it.
"UIParent.xml",
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which UnitPopup.lua reads at file scope
"Interface\\FrameXML\\UnitPopup.xml",
// …and what its rows' OnLoad calls: every `PartyMemberFrame<N>` and its pet frame runs
@@ -285,8 +381,7 @@ pub(super) const CHARACTER_UI: &[&str] = &[
"Interface\\FrameXML\\ItemButtonTemplate.xml", // PaperDollItemSlotButtonTemplate's base
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UIParent.xml", // Model_OnLoad/_Rotate*/_OnUpdate — the model panes' turntable
"UiPanels.xml", // CharacterFrameTabButtonTemplate, UIPanelWindows, Show/HideUIPanel
r"Interface\FrameXML\UIParent.xml", // Model_OnLoad/_Rotate*/_OnUpdate — the model panes' turntable
"Interface\\FrameXML\\GameTooltip.xml",
"Cooldown.xml", // CooldownFrameTemplate + CooldownFrame_SetTimer, per equipment slot
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -353,7 +448,7 @@ pub(super) const SOCIAL_UI: &[&str] = &[
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\BasicControls.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Cooldown.xml",
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
@@ -369,7 +464,6 @@ pub(super) const SOCIAL_UI: &[&str] = &[
"Interface\\FrameXML\\UIPanelTemplates.xml",
"Interface\\FrameXML\\OptionsFrameTemplates.xml",
"Interface\\FrameXML\\ReputationFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\StaticPopup.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"KeyBindingsPage.xml",
@@ -418,11 +512,11 @@ pub(super) const BAG_UI: &[&str] = &[
// `updateContainerFrameAnchors` anchors each open bag to `frame:GetParent()` while
// `OpenAllBags` opens with `if not UIParent:IsVisible() then return end`. Without it the
// windows fall out of the cascade and the reference's own layout pass has nothing to measure.
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"ScrollTemplates.xml", // the window tab template, ours (1004/1988)
"Interface\\FrameXML\\ItemButtonTemplate.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\GameTooltip.xml",
"Cooldown.xml",
@@ -21,7 +21,7 @@ fn harness(extra: &[&str]) -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
@@ -246,7 +246,7 @@ fn action_button_hover_takes_the_default_corner() {
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\MainMenuBar.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
@@ -287,13 +287,12 @@ fn ubertooltips_off_seats_action_bar_plates_beside_the_button() {
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\MainMenuBar.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
"Interface\\FrameXML\\BonusActionBarFrame.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
@@ -368,7 +367,7 @@ fn ubertooltips_off_seats_stance_plates_beside_the_button() {
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\MainMenuBar.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
@@ -421,7 +420,7 @@ fn buff_hover_hangs_below_left_of_the_button() {
"Interface\\FrameXML\\TextStatusBar.lua",
"Interface\\FrameXML\\TextStatusBar.xml",
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\MainMenuBar.xml",
"Interface\\FrameXML\\ActionBarFrame.xml",
@@ -58,7 +58,8 @@ fn harness() -> UiScript {
/// the other window the compare flow crosses, and `ItemRef.xml`, which declares the chat-link
/// router's own `ItemRefTooltip`. Both were in this harness's hand-copied list before 1751; the
/// manifest's order is the one kept (`FrameXML.toc` 63 → 77).
const ROUTER_UI: [&str; 2] = [
const ROUTER_UI: [&str; 3] = [
"ScrollTemplates.xml", // our window tab template, before the window that inherits it (1988)
"Interface\\FrameXML\\MerchantFrame.xml",
"Interface\\FrameXML\\ItemRef.xml",
];
@@ -43,7 +43,7 @@ fn harness() -> UiScript {
s.set_screen_size(1024.0, 768.0);
for f in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GameTooltip.xml",
@@ -61,7 +61,7 @@ fn load_tot() -> UiScript {
let mut s = UiScript::new().unwrap();
s.set_screen_size(1024.0, 768.0);
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "Interface\\FrameXML\\GameTooltip.xml");
@@ -48,7 +48,7 @@ fn trainer_script_base() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
"Cooldown.xml",
"Interface\\FrameXML\\ActionButtonTemplate.xml",
"Interface\\FrameXML\\TextStatusBar.lua",
@@ -64,7 +64,6 @@ fn trainer_script_base() -> UiScript {
r"Interface\FrameXML\UIPanelTemplates.xml",
r"Interface\FrameXML\OptionsFrameTemplates.xml",
r"Interface\FrameXML\ReputationFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
@@ -17,10 +17,9 @@ fn session() -> UiScript {
"Interface\\FrameXML\\Localization.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\BasicControls.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
"Interface\\FrameXML\\GameTooltip.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
@@ -11,7 +11,10 @@ fn ui_parent() -> UiScript {
let mut s = UiScript::new().unwrap();
// Through the chain-aware reader: this list names chain files now, and a
// reader that joins `assets/ui` cannot resolve one (1838, 1887, 1888).
for file in ["Interface\\FrameXML\\Fonts.xml", "UIParent.xml"] {
for file in [
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\UIParent.xml",
] {
crate::ui_script::test_ui::load_ui(&s, file);
}
s.set_screen_size(1024.0, 768.0);
@@ -20,7 +20,7 @@ fn load_unit_frames(s: &UiScript) {
// own file; naming the file is the only version that cannot drift. (`DEAD` is l.898 of it.)
load_xml(s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(s, "Interface\\FrameXML\\Fonts.xml");
load_xml(s, "UIParent.xml");
load_xml(s, r"Interface\FrameXML\UIParent.xml");
// The bars' numerals machinery (decision 1082), which the manifest loads immediately ahead of
// UnitFrames.xml and which every bar's OnLoad wires into since 1143.
load_xml(s, "Interface\\FrameXML\\TextStatusBar.lua");
@@ -652,7 +652,8 @@ fn shipped_target_frame_runs_the_level_law() {
load_unit_frames(&s);
// GetDifficultyColor's own load chain (the quest log window, its ref home).
load_xml(&s, "Interface\\FrameXML\\GlobalStrings.lua");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, "ScrollTemplates.xml"); // the window tab template, ours (1004/1988)
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
@@ -661,7 +662,6 @@ fn shipped_target_frame_runs_the_level_law() {
load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml");
load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml");
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
@@ -1218,7 +1218,7 @@ fn the_party_art_paints_over_the_bars() {
load_xml(&s, "Interface\\FrameXML\\Fonts.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\BasicControls.xml");
@@ -1229,7 +1229,6 @@ fn the_party_art_paints_over_the_bars() {
load_xml(&s, "Interface\\FrameXML\\UIDropDownMenu.xml");
// Before UnitPopup: that file reads ITEM_QUALITY_COLORS at FILE SCOPE and its
// declarer is UIParent (ref UIParent.lua:65) since 1888.
load_xml(&s, "UIParent.xml");
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, "Interface\\FrameXML\\UnitPopup.xml");
// The reference's own kit, in the manifest's order. `UIParent.xml` is not decoration here:
@@ -16,13 +16,12 @@ use super::test_ui::load_ui as load_xml;
fn load_popup_frames(s: &UiScript) {
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
// `SmallMoneyFrame_OnLoad`, which UiPanels' own StaticPopup money rows call at load.
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
// `StaticPopupDialogs` and the `PanelTemplates_*` family, both of which FriendsFrame.xml
// reaches at LOAD (its tab row and its confirm dialogs).
"UiPanels.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua", // `TEXT`, read at file scope below
@@ -484,11 +483,10 @@ fn solo_target_inspect_click_reaches_inspect_unit() {
fn load_pet_menu_frames(s: &UiScript) {
for file in [
"Interface\\FrameXML\\Fonts.xml",
"UIParent.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"UiPanels.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\BasicControls.xml",
@@ -19,7 +19,7 @@ fn harness() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -588,3 +588,130 @@ fn hovering_the_player_blip_on_a_scaled_map_names_the_player() {
);
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
}
/// **The player arrow draws over the zone's explored-area overlays** — the director's report: on a
/// zone sheet the arrow was nowhere, and only the zoomed-out continent sheet (which has no
/// overlays) showed it.
///
/// The stock file creates those overlays as `WorldMapDetailFrame:CreateTexture(…, "ARTWORK")`
/// (`WorldMapFrame.lua:108`) and the arrow as a `Model` child of `WorldMapFrame`
/// (`WorldMapFrame.lua:15`) — two frames at the SAME level, and inside one `(strata, level)`
/// bucket the draw layer outranks the frame (decision 0884). A frame's own slot is layer 0, so
/// the arrow lost to every one of those ARTWORK textures. Reproduced here with the reference's own
/// call, and asserted as the render list's order rather than a z-key's internals.
#[test]
fn the_player_arrow_draws_over_the_zones_explored_overlays() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = UiScript::new().unwrap();
s.set_screen_size(1600.0, 900.0);
s.set_unit(
"player",
Some(benilla_ui::script::UnitState {
exists: true,
name: Some("Probefour".into()),
level: 60,
..Default::default()
}),
);
assert!(super::load_default_ui(&s).is_empty());
s.resolve();
s.run("ShowUIPanel(WorldMapFrame)").unwrap();
s.resolve();
s.set_world_map_feed(None, Some((0.5, 0.5)), 0.0, None, Vec::new(), Vec::new());
update(&mut s);
// The overlay the stock file lays over a zone sheet, in its own words — covering the whole
// detail frame, which is what an explored zone's art amounts to.
s.run(
r#"local o = WorldMapDetailFrame:CreateTexture("WorldMapOverlay1", "ARTWORK")
o:SetTexture("Interface\\WorldMap\\Elwynn\\ElwynnForest1")
o:SetAllPoints(WorldMapDetailFrame)
o:Show()"#,
)
.unwrap();
s.resolve();
let quads = s.extract();
let arrow = quads
.iter()
.find(|q| {
matches!(&q.content, QuadContent::ModelPane { model: Some(m), .. } if m == ARROW_MODEL)
})
.expect("the arrow pane is in the render list");
let overlay = quads
.iter()
.find(|q| {
matches!(
&q.content,
QuadContent::Texture { path: Some(p), .. } if p.contains("ElwynnForest1")
)
})
.expect("the overlay texture is in the render list");
assert!(
arrow.z > overlay.z,
"the arrow must paint after the zone overlay (arrow {:#x}, overlay {:#x})",
arrow.z,
overlay.z
);
}
/// **A click over a map POI still answers the map's UV** — the director's report: alt-clicking to
/// jump did nothing while the cursor was over a town like Goldshire, "like the name display is
/// blocking it".
///
/// It was: the stock file makes every POI icon a child of `WorldMapButton`
/// (`WorldMapFrame.lua:178`), so the topmost frame over a town is the icon, and the UV query
/// demanded the button itself. The player's own blip (a child of the button too) is the same
/// story, which is what this drives — it needs no landmark data to be real.
#[test]
fn a_click_over_a_blip_still_answers_the_maps_uv() {
let _data = benilla_formats::wow_data_or_skip!();
let mut s = UiScript::new().unwrap();
s.set_screen_size(1600.0, 900.0);
s.set_unit(
"player",
Some(benilla_ui::script::UnitState {
exists: true,
name: Some("Probefour".into()),
level: 60,
..Default::default()
}),
);
assert!(super::load_default_ui(&s).is_empty());
s.resolve();
s.run("ShowUIPanel(WorldMapFrame)").unwrap();
s.resolve();
s.set_world_map_feed(None, Some((0.4, 0.6)), 0.0, None, Vec::new(), Vec::new());
update(&mut s);
s.resolve();
let (px, py, eff) = s
.eval::<(f64, f64, f64)>(
"local x, y = WorldMapPlayer:GetCenter() return x, y, WorldMapPlayer:GetEffectiveScale()",
)
.unwrap();
let (x, y) = ((px * eff) as f32, (py * eff) as f32);
assert_eq!(
s.hit_test_name(x, y).as_deref(),
Some("WorldMapPlayer"),
"the blip is what the mouse is over"
);
let (u, v) = s
.world_map_uv_at(x, y)
.expect("the click still lands on the map");
// The blip sits where the feed put it, so the UV under it is that position.
assert!(
(u - 0.4).abs() < 0.01 && (v - 0.6).abs() < 0.01,
"the UV under the blip is the blip's own: {u}, {v}"
);
// …and a click on the map's own chrome is still not a map click.
let (cx, cy, ceff) = s
.eval::<(f64, f64, f64)>(
"local x, y = WorldMapFrameCloseButton:GetCenter() return x, y, WorldMapFrameCloseButton:GetEffectiveScale()",
)
.unwrap();
assert!(
s.world_map_uv_at((cx * ceff) as f32, (cy * ceff) as f32)
.is_none(),
"the close button is not the map"
);
}
@@ -18,14 +18,13 @@ pub(crate) fn harness() -> UiScript {
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml",
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\WorldStateFrame.xml", // the reference's own (1972)
] {
@@ -45,12 +45,11 @@ fn harness() -> UiScript {
load_xml(&s, "Interface\\FrameXML\\BasicControls.xml");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.lua");
load_xml(&s, r"Interface\FrameXML\MoneyFrame.xml");
load_xml(&s, "UiPanels.xml");
load_xml(&s, r"Interface\FrameXML\UIParent.xml");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.lua");
load_xml(&s, r"Interface\FrameXML\UIPanelTemplates.xml");
load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua");
load_xml(&s, r"Interface\FrameXML\StaticPopup.xml");
load_xml(&s, "UIParent.xml");
// The fading kit, its own manifest entry since window 8 — as it is in the reference's TOC.
load_xml(&s, "Interface\\FrameXML\\FadingFrame.xml");
load_xml(&s, "Interface\\FrameXML\\ZoneText.xml");
+1 -1
View File
@@ -47,7 +47,7 @@
//! **send a name query** (`0x55f1fa`), whose arrival signals nothing. So the real name surfaces
//! only because the popup engine re-reads all three getters every OnUpdate frame — *a client
//! that formats the text once shows an empty summoner forever.* That is what makes
//! `UiPanels.xml`'s `CONFIRM_SUMMON` countdown arm the mechanism rather than a transcription,
//! `UIParent.lua`'s `CONFIRM_SUMMON` countdown arm the mechanism rather than a transcription,
//! and it is why the event is not held back for the name the way `DUEL_REQUESTED` (0633) is:
//! that event carries its name as `arg1`, and this one has no argument to hold.
//!
+1 -2
View File
@@ -28,10 +28,9 @@ const FILES: &[&str] = &[
// the `MoneyInputFrame_*` verbs, replacing our own verbatim copy of both.
r"Interface\FrameXML\MoneyInputFrame.lua",
r"Interface\FrameXML\MoneyInputFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
// `auctionRowName` colours each row from ITEM_QUALITY_COLORS, whose declarer is
// UIParent (ref UIParent.lua:65) since 1888 put the font registry on the chain.
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
"Interface\\FrameXML\\UIDropDownMenu.xml",
"ScrollTemplates.xml",
+1 -2
View File
@@ -44,8 +44,7 @@ const FILES: &[&str] = &[
// `Model_OnLoad` — the model pane's `<OnLoad>` calls it, so this is a LOAD-time dependency of
// the paper doll, not of the window. The reference declares it in `UIParent.lua`; ours lives
// in our counterpart of that file.
"UIParent.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\LocaleProperties.lua",
+97 -5
View File
@@ -52,20 +52,112 @@ pub fn load_ui(script: &UiScript, entry: &str) {
"{entry}: loader errors: {:#?}",
report.errors
);
if entry
.rsplit(['\\', '/'])
.next()
.is_some_and(|leaf| leaf.eq_ignore_ascii_case("MainMenuBarMicroButtons.xml"))
{
let leaf = entry.rsplit(['\\', '/']).next().unwrap_or("");
if leaf.eq_ignore_ascii_case("MainMenuBarMicroButtons.xml") {
script
.run(MICRO_BUTTON_STAND_INS)
.expect("the micro-button stand-ins");
}
if leaf.eq_ignore_ascii_case("UIParent.xml") && entry.contains('\\') {
script
.run(UIPARENT_STAND_INS)
.expect("the UIParent stand-ins");
}
}
/// The stock micro-button row's unguarded reads, stood in for on the row's first call — one copy
/// per store, like the loader itself. `ui_script::test_ui::MICRO_BUTTON_STAND_INS` is the
/// original and carries the why (decision 1987).
/// The stock `UIParent.xml`'s unguarded callees, stood in for at load — see
/// `ui_script::test_ui::UIPARENT_STAND_INS` (decision 1988).
const UIPARENT_STAND_INS: &str = r#"
-- Callees of the stock UIParent.xml's <OnUpdate> and of UIParent_OnEvent's arms that live in
-- files a kit may stop short of, plus the bag verbs the stock ShowUIPanel calls and the two
-- container constants its window walks read: no-op stand-ins, each overwritten by the real
-- definition when its file loads (a chunk's `function X()` is a plain global write, unlike a
-- frame's non-overwriting publish — which is why the FRAMES below are seated on first use).
FCF_OnUpdate = FCF_OnUpdate or function() end
FCF_DockUpdate = FCF_DockUpdate or function() end
UnitPopup_OnUpdate = UnitPopup_OnUpdate or function() end
BattlefieldFrame_OnUpdate = BattlefieldFrame_OnUpdate or function() end
MultiActionBar_Update = MultiActionBar_Update or function() end
RaidOptionsFrame_UpdatePartyFrames = RaidOptionsFrame_UpdatePartyFrames or function() end
LocalizeFrames = LocalizeFrames or function() end
updateContainerFrameAnchors = updateContainerFrameAnchors or function() end
-- Ours, not the reference's file: 1.12 keeps UpdateNameplates in UIOptionsFrame.lua and
-- benilla's own options window carries it (the options family stays ours).
UpdateNameplates = UpdateNameplates or function() end
CloseAllBags = CloseAllBags or function() end
OpenBackpack = OpenBackpack or function() end
CloseBackpack = CloseBackpack or function() end
NUM_CONTAINER_FRAMES = NUM_CONTAINER_FRAMES or 0
-- The reference's own initial values (`ContainerFrame.lua:11-12`), not zeroes: the tooltip's
-- default corner is `-CONTAINER_OFFSET_X - 13, CONTAINER_OFFSET_Y`, so a kit reading zero here
-- would seat every default-anchored plate 70 units low.
CONTAINER_OFFSET_X = CONTAINER_OFFSET_X or 0
CONTAINER_OFFSET_Y = CONTAINER_OFFSET_Y or 70
BATTLEFIELD_TAB_OFFSET_Y = BATTLEFIELD_TAB_OFFSET_Y or 210
-- The pass writes its `isVar` rows with `setglobal`, but only for a name that already reads
-- non-nil (`frame = getglobal(index); if frame then`), so an unseeded one is never written at
-- all. These four are the reference's own seeds, from the files that declare them
-- (ContainerFrame.lua, PetActionBarFrame.lua, WorldStateFrame.lua).
PETACTIONBAR_YPOS = PETACTIONBAR_YPOS or 98
PETACTIONBAR_XPOS = PETACTIONBAR_XPOS or 36
-- The frames these three read UNGUARDED, seated on the call rather than at load: a frame's
-- publish to _G is non-overwriting (RF-0023), so a stand-in seated before the real file loads
-- would shadow the real window for good.
local function benilla_seat(names)
for _, name in ipairs(names) do
if not getglobal(name) then local f = CreateFrame("Frame") f:Hide() setglobal(name, f) end
end
end
local real_manage = UIParent_ManageFramePositions
function UIParent_ManageFramePositions()
benilla_seat({ "MainMenuBar", "MultiBarLeft", "MultiBarRight", "MultiBarBottomLeft",
"PetActionBarFrame", "ShapeshiftBarFrame", "ReputationWatchBar", "MainMenuExpBar",
"MainMenuBarMaxLevelBar", "CastingBarFrame", "QuestTimerFrame", "QuestWatchFrame",
"DurabilityFrame", "DurabilityShield", "DurabilityOffWeapon", "DurabilityRanged",
"MinimapCluster", "ChatFrame1", "ChatFrame2", "ShapeshiftBarLeft",
"ShapeshiftBarMiddle", "ShapeshiftBarRight", "BattlefieldMinimapTab" })
-- …and every FRAME the managed table itself names (`frame:IsObjectType` on a nil is what
-- a kit missing one raises) — read off the table, so a row added there needs nothing here.
-- The `isVar` rows are skipped: those keys are global NUMBERS the pass writes
-- (CONTAINER_OFFSET_X/Y, PETACTIONBAR_YPOS…), and a frame seated under one of those names
-- would be arithmetic's problem two files later.
local named = {}
for name, row in pairs(UIPARENT_MANAGED_FRAME_POSITIONS) do
if not row.isVar then table.insert(named, name) end
end
benilla_seat(named)
for _, name in ipairs({ "SlidingActionBarTexture0", "SlidingActionBarTexture1" }) do
if not getglobal(name) then setglobal(name, UIParent:CreateTexture()) end
end
return real_manage()
end
-- The four options/menu windows `IsOptionFrameOpen` (l.997) and `ToggleGameMenu` (l.1467)
-- index unguarded. `IsOptionFrameOpen` is on the path of every window close, so a kit that
-- loads no options window raised on the first bag click; ours answers all three of the
-- reference's options windows (1987) and a kit may load none of them.
local function benilla_seat_options()
benilla_seat({ "GameMenuFrame", "OptionsFrame", "UIOptionsFrame", "SoundOptionsFrame" })
if not OptionsFrameCancel then
OptionsFrameCancel = CreateFrame("Button")
OptionsFrameCancel:Hide()
end
end
local real_option_open = IsOptionFrameOpen
function IsOptionFrameOpen()
benilla_seat_options()
return real_option_open()
end
local real_toggle_menu = ToggleGameMenu
function ToggleGameMenu(clicked)
benilla_seat_options()
return real_toggle_menu(clicked)
end
"#;
const MICRO_BUTTON_STAND_INS: &str = r#"
local real = UpdateMicroButtons
function UpdateMicroButtons()
@@ -14,9 +14,9 @@
//! FrameXML above it, a font registry, an anchor graph — not a four-line fixture. Every assertion
//! below is a global an addon would reach for.
use benilla_ui::script::UiScript;
mod common;
const UI_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/ui");
use benilla_ui::script::UiScript;
/// The prefix of `benilla.toc`'s load order these templates need: the font registry, the panel kit,
/// UIParent (the parent every addon passes), and the faux-scroll kit.
@@ -43,63 +43,19 @@ const FILES: &[&str] = &[
"Interface\\FrameXML\\FadingFrame.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"Interface\\FrameXML\\BasicControls.xml", // `TEXT`, which StaticPopup.lua reads at file scope
"Interface\\FrameXML\\LocaleProperties.lua",
"Interface\\FrameXML\\StaticPopup.xml", // the dialog engine (1960)
"UIParent.xml",
"ScrollTemplates.xml",
];
fn load_ui(script: &UiScript) {
let dir = std::path::Path::new(UI_DIR);
// A manifest entry carrying a path separator is the PLAYER's own file and has to come off the
// patch chain; a bare name is ours, under `assets/ui`. The shipped loader draws the same line
// (`reference_ui::is_chain_entry`), and this test grew the chain half when 1860 moved two of
// the templates it exercises onto it.
let chain = benilla_formats::wow_data().and_then(|d| benilla_formats::open_chain(&d).ok());
let read = |req: &str| -> Option<Vec<u8>> {
let norm = req.replace('\\', "/");
if norm.contains('/') {
if let Some(c) = chain.as_ref() {
if let Ok(b) = c.read(&norm) {
return Some(b);
}
}
}
let base = norm.rsplit('/').next().unwrap_or(&norm);
std::fs::read(dir.join(&norm))
.or_else(|_| std::fs::read(dir.join(base)))
.ok()
};
let provider = |req: &str| -> Option<Vec<u8>> { read(req) };
for file in FILES {
let bytes = read(file).unwrap_or_else(|| panic!("reading {file}"));
// A `.lua` manifest entry is a CHUNK, not a document — the shipped loader draws the same
// line, and `UIPanelTemplates` is split that way because the reference splits it that way.
if file.to_ascii_lowercase().ends_with(".lua") {
script
.run_chunk_named(&bytes, &format!("@{file}"))
.unwrap_or_else(|e| panic!("{file}: {e}"));
continue;
}
let text = benilla_ui::source::decode(&bytes);
let doc =
benilla_ui::framexml::parse(&text).unwrap_or_else(|e| panic!("parsing {file}: {e}"));
// The document's OWN path, not the path-less `load` (1923). The base is what every
// relative `<Script file=>` / `<Include file=>` inside resolves against (1186); with
// an empty base they stay bare and miss the provider entirely, so a self-sourcing
// stock file loads as an empty shell and every handler in it goes missing — silently,
// because nothing in these lists used to be self-sourcing.
let report = benilla_ui::loader::load_in(script, &doc, &file.replace('\\', "/"), &provider);
assert!(
report.errors.is_empty(),
"{file} loaded with errors: {:#?}",
report.errors
);
common::load_ui(script, file);
}
}
+1 -2
View File
@@ -26,10 +26,9 @@ const FILES: &[&str] = &[
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
// `GetMaterialTextColors`, which the reference's own `ItemTextFrame_OnEvent` calls to pick the
// page and title ink. 1.12 keeps it in UIParent.lua and ours does the same (1751 window 9).
"UIParent.xml",
"ScrollTemplates.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
+5 -44
View File
@@ -5,9 +5,9 @@
//! named regions exist, the rows populate from a fed `MailState`, the paging math is right, and the
//! unread/read row state tracks the wire `wasRead` flag.
use benilla_ui::script::{MailInboxRow, MailInvoice, MailState, UiScript};
mod common;
const UI_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/ui");
use benilla_ui::script::{MailInboxRow, MailInvoice, MailState, UiScript};
/// The mail window's load prefix — the app's own order (`ui_script/mod.rs`), members only.
/// MerchantFrame.xml rides along because MailFrame.xml reuses its global `BenillaMoney_*` coin
@@ -21,7 +21,8 @@ const FILES: &[&str] = &[
r"Interface\FrameXML\MoneyInputFrame.lua",
r"Interface\FrameXML\MoneyInputFrame.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
"ScrollTemplates.xml", // the window tab template, ours (1004/1988)
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\BasicControls.xml",
@@ -37,48 +38,8 @@ const FILES: &[&str] = &[
];
fn load_ui(script: &UiScript) {
let dir = std::path::Path::new(UI_DIR);
// A manifest entry carrying a path separator is the PLAYER's own file and comes off the patch
// chain; a bare name is ours, under `assets/ui`. `tests/common` already draws this line — this
// binary grew it when 1860 moved `PanelTemplates_*` onto the chain.
let chain = benilla_formats::wow_data().and_then(|d| benilla_formats::open_chain(&d).ok());
let read = |req: &str| -> Option<Vec<u8>> {
let norm = req.replace('\\', "/");
if norm.contains('/') {
if let Some(b) = chain.as_ref().and_then(|c| c.read(&norm).ok()) {
return Some(b);
}
}
let base = norm.rsplit('/').next().unwrap_or(&norm);
std::fs::read(dir.join(&norm))
.or_else(|_| std::fs::read(dir.join(base)))
.ok()
};
let provider = |req: &str| -> Option<Vec<u8>> { read(req) };
for file in FILES {
let bytes = read(file).unwrap_or_else(|| panic!("reading {file}"));
// A `.lua` entry is a CHUNK, not a document.
if file.to_ascii_lowercase().ends_with(".lua") {
script
.run_chunk_named(&bytes, &format!("@{file}"))
.unwrap_or_else(|e| panic!("{file}: {e}"));
continue;
}
let text = benilla_ui::source::decode(&bytes);
let doc = benilla_ui::framexml::parse(&text).unwrap_or_else(|e| {
panic!("parsing {file}: {e}");
});
// The document's OWN path, not the path-less `load` (1923). The base is what every
// relative `<Script file=>` / `<Include file=>` inside resolves against (1186); with
// an empty base they stay bare and miss the provider entirely, so a self-sourcing
// stock file loads as an empty shell and every handler in it goes missing — silently,
// because nothing in these lists used to be self-sourcing.
let report = benilla_ui::loader::load_in(script, &doc, &file.replace('\\', "/"), &provider);
assert!(
report.errors.is_empty(),
"{file} loaded with errors: {:#?}",
report.errors
);
common::load_ui(script, file);
}
}
+1 -2
View File
@@ -29,9 +29,8 @@ const FILES: &[&str] = &[
"Interface\\FrameXML\\ItemButtonTemplate.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
// `ToggleTalentFrame` lives here now, not in the window's own file (decision 1833).
"UIParent.xml",
"Interface\\FrameXML\\GameTooltip.xml",
// `UIPanelScrollFrameTemplate` — the stock scroll frame's whole substance: its `$parentScrollBar`
// Slider AND its `<OnMouseWheel>`. Nothing else in the tree declares it, and a missing template
+4 -44
View File
@@ -6,9 +6,9 @@
//! `TRADE_ACCEPT_UPDATE(my, his)` args. This is the machine gate for the XML (a Lua error / missing
//! global / wrong region name fails here); the director's eye judges only the *look*.
use benilla_ui::script::{ScriptValue, TradeSideState, TradeSlotItem, TradeState, UiScript};
mod common;
const UI_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/assets/ui");
use benilla_ui::script::{ScriptValue, TradeSideState, TradeSlotItem, TradeState, UiScript};
/// The trade window's load prefix — the app's own order (`ui_script/mod.rs`), members only.
/// MerchantFrame.xml rides along because TradeFrame.xml reuses its global `BenillaMoney_*` coin
@@ -22,7 +22,7 @@ const FILES: &[&str] = &[
// which is benilla.toc's own order.
r"Interface\FrameXML\MoneyInputFrame.lua",
r"Interface\FrameXML\MoneyInputFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -36,48 +36,8 @@ const FILES: &[&str] = &[
];
fn load_ui(script: &UiScript) {
let dir = std::path::Path::new(UI_DIR);
// A manifest entry carrying a path separator is the PLAYER's own file and comes off the patch
// chain; a bare name is ours, under `assets/ui`. `tests/common` already draws this line — this
// binary grew it when 1860 moved `PanelTemplates_*` onto the chain.
let chain = benilla_formats::wow_data().and_then(|d| benilla_formats::open_chain(&d).ok());
let read = |req: &str| -> Option<Vec<u8>> {
let norm = req.replace('\\', "/");
if norm.contains('/') {
if let Some(b) = chain.as_ref().and_then(|c| c.read(&norm).ok()) {
return Some(b);
}
}
let base = norm.rsplit('/').next().unwrap_or(&norm);
std::fs::read(dir.join(&norm))
.or_else(|_| std::fs::read(dir.join(base)))
.ok()
};
let provider = |req: &str| -> Option<Vec<u8>> { read(req) };
for file in FILES {
let bytes = read(file).unwrap_or_else(|| panic!("reading {file}"));
// A `.lua` entry is a CHUNK, not a document.
if file.to_ascii_lowercase().ends_with(".lua") {
script
.run_chunk_named(&bytes, &format!("@{file}"))
.unwrap_or_else(|e| panic!("{file}: {e}"));
continue;
}
let text = benilla_ui::source::decode(&bytes);
let doc = benilla_ui::framexml::parse(&text).unwrap_or_else(|e| {
panic!("parsing {file}: {e}");
});
// The document's OWN path, not the path-less `load` (1923). The base is what every
// relative `<Script file=>` / `<Include file=>` inside resolves against (1186); with
// an empty base they stay bare and miss the provider entirely, so a self-sourcing
// stock file loads as an empty shell and every handler in it goes missing — silently,
// because nothing in these lists used to be self-sourcing.
let report = benilla_ui::loader::load_in(script, &doc, &file.replace('\\', "/"), &provider);
assert!(
report.errors.is_empty(),
"{file} loaded with errors: {:#?}",
report.errors
);
common::load_ui(script, file);
}
}
+1 -2
View File
@@ -24,7 +24,7 @@ const FILES: &[&str] = &[
"Interface\\FrameXML\\Fonts.xml",
r"Interface\FrameXML\MoneyFrame.lua",
r"Interface\FrameXML\MoneyFrame.xml",
"UiPanels.xml",
r"Interface\FrameXML\UIParent.xml",
r"Interface\FrameXML\UIPanelTemplates.lua",
r"Interface\FrameXML\UIPanelTemplates.xml",
"Interface\\FrameXML\\GlobalStrings.lua",
@@ -38,7 +38,6 @@ const FILES: &[&str] = &[
// `*_LoadUI` then `*_Show`), not from a registration of their own — so UIParent.xml is a
// dependency of the event path this suite drives (1973). With no addon registry here the
// load reports ADDON_LOAD_FAILED through `message`, which is a shown frame, not an error.
"UIParent.xml",
// The reference's own addons (1973), off the chain — both inherit the trainer window's
// list/detail kit, which the manifest seats above them. An integration test has no addon
// registry, so the files load as chain files, the way the manifest's own entries do.
+15 -1
View File
@@ -465,9 +465,23 @@ impl UiScript {
(rect, alpha, content, clip, scale)
}
};
// **A `Model` frame's scene draws out of its bucket's ARTWORK batch, last** — wow-re
// `ui/scratch/model-frame-draw-order.md` (2026-09-04): the batch object carries a
// third sub-array beside the quads and the text, a render-callback list, and
// `0x76fb00` drains the three in that order; `0x76d160` registers the model's callback
// only for `layer == 2` (`0x76d17f cmp ebx,2`). So a model is neither a separate pass
// nor the frame's own layer-0 slot — it is ARTWORK content, after that layer's quads.
// This is what puts the world map's player arrow over the zone overlays: both frames
// sit at `WorldMapFrame.level + 1`, the overlays are ARTWORK quads there, and the
// arrow's callback drains after them (the director's report, and the case the carve
// was dispatched on). A model's own OVERLAY/HIGHLIGHT regions still draw over it.
let z = match &content {
QuadContent::ModelPane { .. } => zkey.content(order::DrawLayer::Artwork).raw(),
_ => zkey.raw(),
};
out.push(ExtractedQuad {
target,
z: zkey.raw(),
z,
rect,
alpha,
content,
+11 -3
View File
@@ -354,9 +354,17 @@ impl super::UiScript {
pub fn world_map_uv_at(&self, x: f32, y: f32) -> Option<(f32, f32)> {
let id = self.hit_test(x, y)?;
let model = self.model_ref();
let fh = model.id_to_frame.get(&id).copied()?;
if model.arena.frame(fh)?.name.as_deref() != Some("WorldMapButton") {
return None;
let hit = model.id_to_frame.get(&id).copied()?;
// The map button, or **anything sitting on it**: the stock file makes every POI icon a
// child of `WorldMapButton` (`WorldMapFrame.lua:178`), and so are the player arrow's clear
// button and the party/raid blips, so the topmost frame over a town or a teammate is one
// of those and not the button. Requiring the button itself made the click deaf exactly
// where the map has something to show — the director's report on the stock map. Walking
// up rather than widening the name test keeps everything else out: a click on the
// continent dropdown or the close button is over neither the button nor its subtree.
let mut fh = hit;
while model.arena.frame(fh)?.name.as_deref() != Some("WorldMapButton") {
fh = model.arena.frame(fh)?.parent?;
}
let r = model.resolved.get(&fh)?;
let (w, h) = (r.right - r.left, r.top - r.bottom);