Files
benilla-octo/crates/benilla-app/assets/ui/GameMenuFrame.xml
T
SamandClaude Fable 5.1 112e82d276 the vendor and gossip windows are the reference's own
- the vendor window is the reference's own `MerchantFrame.xml`, which took three things in order: the vendor cursor, the coin kit's move, and `GameTooltip:SetMerchantCompareItem` — where `offset` is the ordinal among CANDIDATE slots (empty ones skipped without decrementing) and a candidate matches by item CLASS and never by entry (two of four RE workers read it as an entry match, which would have fired the compare tooltip only when you already wear the identical item, i.e. never, with the window looking finished); two visible changes ride with the reference's rows — the coin columns take `SmallMoneyFrameTemplate`'s own geometry, and only the ICON takes the mouse, so hovering a row's name shows nothing, which is the client's behaviour
- the gossip window is the reference's own, and its deferral was wrong: the "2px rows" were a harness gap (a bare test VM with no text measurer, while the app always installs one), not an engine one; four things the reference does that ours did not are pinned — a hidden SPACER row between the quest groups, coded options are NOT greyed (a coded row is clickable, and the send path's missing code is named as its own gap), the row label is the Button's own text, and the scroll child is not grown
- the CAMP/QUIT dialogs and the PARTY_INVITE dialog move to `StaticPopup`'s home — the fourth such rehome of a dialog that had lived in whichever window first needed it — and moving them found a real bug: `button1 = CANCEL` captured a nil at load because `CANCEL` was declared below the insertion point, so the popup engine fell back and put "Yes" on the camp dialog's cancel button
- three instruments: the gap report stops counting commented-out calls (`ShowInventorySellCursor` blocked the character sheet on three commented lines — a whole RE round spent on an over-report), it runs the load itself and answers in ONE table (29 "free" became 24 actually unblocked), and a shadow report predicts which swaps will fail by intersecting the names our files define with the names the chain files in our own manifest define — 38 collisions across 5 files, ours winning every one

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:01:00 +07:00

315 lines
21 KiB
XML

<Ui>
<!--
The GAME MENU — the frame ESC opens (decision 0674). The last hole in the game shell's
outermost layer: until now ESC's chain ran out of things to close and did nothing, and the
Main Menu micro button was drawn but dead (MicroMenu.xml's SCOPE note).
PROVENANCE (0985 — the three-source split, stated the same way in every era-shaped
window; OptionsFrame.xml carries the sibling block):
· STRUCTURE & BEHAVIOR — the 1.15 era client (wow-ui-source-era @ 1.15.9.68940): the
ladder shape, its groups and gaps, which entries exist (the SCOPE section below).
If 1.15 has the mechanism, it STAYS.
· CHROME MECHANISM — this window predates 1.13: the 1.12 client's OWN GameMenuFrame
is the chrome ground truth (the dialog backdrop, header plate, red buttons — the
same dialog family the 1.13/1.14 options windows kept), quoted below.
· ART BYTES — the 1.12 MPQ chain only; nothing later-client at runtime (0978's law).
Ground truth, all quoted rather than re-derived:
· **The frame** — ref `GameMenuFrame.xml` (patch.MPQ, extracted): 195x246, `frameStrata`
DIALOG, the UI-DialogBox backdrop with the 11/12/12/11 insets and 32px tile/edge, the
256x64 UI-DialogBox-Header at TOP +12 with MAIN_MENU centered 14px down it, and the
eight-button ladder — first button CENTER on the frame's TOP at (0,-37), each next one
TOP-to-BOTTOM at (0,-1), and Return to Game hung (0,-16) below Exit Game (the one gap in
the stack, which is what makes the last entry read as separate).
· **The button** — ref `GameMenuButtonTemplate` (UIPanelTemplates.xml l.403-410): a 144x21
`UIPanelButtonTemplate` (the UI-Panel-Button Up/Down/Disabled/Highlight four-state art,
TexCoords 0..0.625 / 0..0.6875) whose label trio is overridden to
GameFontHighlight/GameFontHighlight/GameFontDisable — i.e. the menu's labels are WHITE,
not the gold a normal panel button wears, and grey when disabled.
· **The labels** — GlobalStrings.lua (patch-2.MPQ), verbatim: VIDEOOPTIONS_MENU "Video
Options", SOUNDOPTIONS_MENU "Sound Options", UIOPTIONS_MENU "Interface Options",
MACROS "Macros", LOGOUT "Logout", EXIT_GAME "Exit Game",
RETURN_TO_GAME "Return to Game", MAIN_MENU "Main Menu". Declared as the real globals
(they are addon-visible API, decision 0068) and read back into each button's label in its
OnLoad — the ref's `text="LOGOUT"` attribute IS a global lookup, which this engine's
literal `text=` is not.
· **The sounds** — the ref's own OnClick lines: igMainMenuOption (the five option buttons),
igMainMenuLogout, igMainMenuQuit, igMainMenuContinue. All four kits verified present in
SoundEntries.dbc (patch-2.MPQ) alongside the igMainMenuOpen/Close pair already in use.
· **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
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`.
NAMES are the reference's, unprefixed (`GameMenuFrame`, `GameMenuButton*`) — the same call
MicroMenu.xml made for its straight transcriptions, and required here besides: `ToggleGameMenu`
and `GameMenuFrame` are Era API surface an addon addresses by name.
SCOPE / divergences (noted, not bugs):
- **The ladder is the ERA menu's** (director's call on the 0951 review — supersedes 0951
§3's five-button collapse): the Era client's own ESC menu shape, greyed where benilla
has nothing behind the entry yet. Geometry quoted from the era dump @ 1.15.9 (Gethe
wow-ui-source, classic_era, the 0950 pin):
· Blizzard_SharedXML/Classic/Frame/MainMenuFrameTemplates.xml l.18-33 — the menu is a
VerticalLayoutFrame, buttonTemplate MainMenuFrameButtonTemplate, padding
top/bottom/left/right = 32/28/28/28, spacing 0; l.11-16 — the button is a 144x21
UIPanelButtonTemplate with the white/white/grey label trio (the SAME art + trio the
1.12 GameMenuButtonTemplate carries — no era-only art in this menu at all).
· Shared/Frame/MainMenuFrameTemplates.lua l.61-71 — AddSection() puts a 20-unit gap
(the next button's topPadding) between groups; AddCloseButton uses the same 20.
· Shared/GameMenuFrame.lua l.62-162 — the Era ladder: Options · [gap] · AddOns, Edit
Mode, Support, Macros · [gap] · Logout, Exit Game · [gap] · Return to Game. (Store /
Rewards / What's New / Ratings are structurally off in Era — store disabled, no
account store, IsStandard() false, koKR only.)
· The layout math those constants produce, precomputed here (this engine has no layout
frames) — for OUR seven rungs, the era's eight minus AddOns (next bullet): width
28+144+28 = 200; button tops 32/73/94/115/156/177/218; height 218+21+28 = 267.
Anchored as a TOPLEFT chain so the gaps read in the XML.
· No Key Bindings rung — the era menu's own shape: 1.15 ceded the entry to the
Settings panel, and since decision 1008 ours lives there too (the Options window's
Keybindings category, KeyBindingsPage.xml). 0997 had carved the 1.13/1.14 seat back
in for its standalone window; that seat left with the window.
· No AddOns rung — the director's call: the char-select AddOns screen
(`char_select::addons`, the reference's own glue-side home for this list) is the only
addon UI. The in-game panel 1197 put behind this rung (AddonList.xml) is retired,
and the rung left with it — 1.12's own ESC menu has no AddOns row either.
· The header — Classic/Dialog/DialogTemplates.xml l.11-43 (ClassicDialogHeaderTemplate):
the same 256x64 UI-DialogBox-Header art, text = MAINMENU_BUTTON, swapped to
GameFontNormalMed1 (13px) by MainMenuFrameMixin:OnLoad. Both header idioms (1.12's
TOP+12 texture / era's 39-tall frame with the art centered) seat the art within half
a unit of each other; the 1.12 transcription is kept, the font and string are era's.
- **Edit Mode / Support ship DISABLED** — nothing behind them yet
(`GameMenuButton_Pending`): the template's own `-Disabled` art + grey label, exactly
how the era menu greys a dead entry (SetEnabled(false) → DisabledFont). Each goes live
by deleting one `GameMenuButton_Pending` call and writing its OnClick.
- The Options label stays a literal "Options": 1.12 GlobalStrings has no era
GAMEMENU_OPTIONS (checked; its OPTIONS_MENU is "Options Menu", a different string).
- The ref frame is `toplevel="true" movable="true" parent="UIParent"`. `parent="UIParent"` is
ours too, and it attaches for real: the loader does read a cross-file `parent=`, resolving
the name by global lookup at load (decision 1734), and the frame below declares it. Only
`movable` is dropped, and it is inert in the ref too (GameMenuFrame defines no drag
scripts, so it never actually moves).
`frameStrata="DIALOG"` is what puts it over the world UI, and that is kept.
**The "no frame-level raise" half of that reason is gone**: the raise law is built
(`script::object::toplevel`, wow-re `ui/scratch/toplevel-raise.md`) and the loader honours
`toplevel="true"`. Re-adding it here is a one-word change and would make the Esc menu come
to the front over any other DIALOG-strata frame it overlaps; left off pending the
director's call on the look, not on the mechanism.
-->
<Script><![CDATA[
-- The reference GlobalStrings (patch-2.MPQ Interface\FrameXML\GlobalStrings.lua), quoted
-- verbatim. `X = X or "..."` so a later real strings table wins, the MicroMenu.xml idiom.
MAIN_MENU = MAIN_MENU or "Main Menu"
HUD_EDIT_MODE_MENU = HUD_EDIT_MODE_MENU or "Edit Mode"
GAMEMENU_SUPPORT = GAMEMENU_SUPPORT or "Support"
MACROS = MACROS or "Macros"
LOGOUT = LOGOUT or "Logout"
EXIT_GAME = EXIT_GAME or "Exit Game"
RETURN_TO_GAME = RETURN_TO_GAME or "Return to Game"
CANCEL = CANCEL or "Cancel"
-- One label setter for a button with nothing behind it yet (Edit Mode and Support): set
-- the ref's text, then disable (grey label + the template's -Disabled art). Making it
-- live is deleting the call and writing its ref OnClick.
function GameMenuButton_Pending(button, text)
button:SetText(text)
button:Disable()
end
-- The CAMP/QUIT dialogs and the three-event driver MOVED OUT, to UiPanels.xml — 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.
]]></Script>
<!-- The era header text size (Classic/Dialog/DialogTemplates.xml + the OnLoad font swap):
GameFontNormalMed1 = SystemFont_Med2 = FRIZQT 13, gold, the MasterFont shadow. Era's
name, declared here beside its one consumer (the 0951 residue convention: Fonts.xml
stays the complete 1.12 set). -->
<Font name="GameFontNormalMed1" inherits="GameFontNormal" virtual="true">
<FontHeight><AbsValue val="13"/></FontHeight>
</Font>
<!-- `GameMenuButtonTemplate` MOVED OUT, to UIPanelTemplates.xml — the reference's own file for
it (ref UIPanelTemplates.xml l.403-410), and now ColorPickerFrame.xml's Okay/Cancel need it
too, from far above this file's LAST-in-the-toc seat. It lived here, with its four state
textures inlined, only because `UIPanelButtonTemplate` had not been transcribed yet; it now
has been, so the reference's actual body (`inherits="UIPanelButtonTemplate"`, 144x21, the
white/white/grey label trio) replaces the private copy verbatim. Era's
MainMenuFrameButtonTemplate (Classic/Frame/MainMenuFrameTemplates.xml l.11-16) is that same
button — same art, same trio, same size — so the header's ART BYTES note is unchanged. -->
<!-- `toplevel` is the ref's own (GameMenuFrame.xml l.3) and was dropped here: without the bit
a DIALOG-strata window opened over another one stays behind it (the B180/Bagnon class,
decision 1318). Restored alone; the ref's `movable`/`parent` stay off deliberately. -->
<Frame name="GameMenuFrame" parent="UIParent" frameStrata="DIALOG" toplevel="true" enableMouse="true" hidden="true">
<!-- The era layout engine's own numbers (header SCOPE note): 28+144+28 wide, 32-top /
28-bottom padding around our seven 21-unit rungs with three 20-unit section gaps. -->
<Size><AbsDimension x="200" y="267"/></Size>
<Anchors><Anchor point="CENTER"/></Anchors>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
<TileSize><AbsValue val="32"/></TileSize>
<EdgeSize><AbsValue val="32"/></EdgeSize>
</Backdrop>
<Layers>
<Layer level="ARTWORK">
<Texture name="GameMenuFrameHeader" file="Interface\DialogFrame\UI-DialogBox-Header">
<Size><AbsDimension x="256" y="64"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="12"/></Offset></Anchor></Anchors>
</Texture>
<!-- Era swaps the header text to 13px (MainMenuFrameMixin:OnLoad →
SetHeaderFont(GameFontNormalMed1)); the seat is the 1.12 one (within half a
unit of era's — header SCOPE note). -->
<FontString name="GameMenuFrameTitle" inherits="GameFontNormalMed1">
<Anchors>
<Anchor point="TOP" relativeTo="GameMenuFrameHeader"><Offset><AbsDimension x="0" y="-14"/></Offset></Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<!-- The era ladder minus its AddOns rung (header SCOPE notes): Options · gap ·
Edit Mode, Support, Macros · gap · Logout, Exit Game · gap · Return to Game.
A TOPLEFT chain at the era layout engine's numbers — x 28, first top -32, 0
between group members, -20 at each section break. Live entries wire the era
OnClick intent; pending ones grey out through GameMenuButton_Pending until
something exists behind them. -->
<!-- Options — live: the era GameMenuFrame.lua l.88 entry (ShowUIPanel(SettingsPanel)
there, OptionsFrame here) plus an explicit HideUIPanel first. The ref leans on
the center-replacement rule for the swap (ShowUIPanel l.697-702: native-center
frames replace each other); hiding the menu explicitly says the same thing
without relying on the eviction path. -->
<Button name="GameMenuButtonOptions" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="28" y="-32"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnLoad>self:SetText("Options")</OnLoad>
<OnClick>
PlaySound("igMainMenuOption")
HideUIPanel(GameMenuFrame)
ShowUIPanel(OptionsFrame)
</OnClick>
</Scripts>
</Button>
<Button name="GameMenuButtonEditMode" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonOptions" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-20"/></Offset></Anchor>
</Anchors>
<Scripts><OnLoad>GameMenuButton_Pending(self, HUD_EDIT_MODE_MENU)</OnLoad></Scripts>
</Button>
<Button name="GameMenuButtonSupport" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonEditMode" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
</Anchors>
<Scripts><OnLoad>GameMenuButton_Pending(self, GAMEMENU_SUPPORT)</OnLoad></Scripts>
</Button>
<Button name="GameMenuButtonMacros" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonSupport" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
</Anchors>
<!-- LIVE since decision 0983 (MacroFrame.xml). The ref's own body
(GameMenuFrame.xml l.118-122): hide the menu, then ShowMacroFrame(). -->
<Scripts>
<OnLoad>self:SetText(MACROS)</OnLoad>
<OnClick>
PlaySound("igMainMenuOption")
HideUIPanel(getglobal("GameMenuFrame"))
ShowMacroFrame()
</OnClick>
</Scripts>
</Button>
<!-- The three that are live. The ref's OnShow on both Logout and Quit disables the
button while either logout dialog is already up (you cannot re-arm a running
countdown); it runs on the menu's own show, which is when a re-opened menu has to
re-read that state. -->
<Button name="GameMenuButtonLogout" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonMacros" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-20"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnLoad>self:SetText(LOGOUT)</OnLoad>
<OnShow>
if not StaticPopup_Visible("CAMP") and not StaticPopup_Visible("QUIT") then
self:Enable()
else
self:Disable()
end
</OnShow>
<OnClick>
PlaySound("igMainMenuLogout")
Logout()
HideUIPanel(GameMenuFrame)
</OnClick>
</Scripts>
</Button>
<Button name="GameMenuButtonQuit" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonLogout" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnLoad>self:SetText(EXIT_GAME)</OnLoad>
<OnShow>
if not StaticPopup_Visible("CAMP") and not StaticPopup_Visible("QUIT") then
self:Enable()
else
self:Disable()
end
</OnShow>
<OnClick>
PlaySound("igMainMenuQuit")
Quit()
HideUIPanel(GameMenuFrame)
</OnClick>
</Scripts>
</Button>
<Button name="GameMenuButtonContinue" inherits="GameMenuButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonQuit" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-20"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnLoad>self:SetText(RETURN_TO_GAME)</OnLoad>
<OnClick>
PlaySound("igMainMenuContinue")
HideUIPanel(GameMenuFrame)
</OnClick>
</Scripts>
</Button>
</Frames>
<!-- ref GameMenuFrame OnShow/OnHide, verbatim: the micro row's Main Menu button pushes in
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
without the action bar behind it. -->
<Scripts>
<OnLoad>GameMenuFrameTitle:SetText(MAIN_MENU)</OnLoad>
<OnShow>
-- The shared era-window scale first (ERA_WINDOW_SCALE, OptionsFrame.xml — loaded
-- before this file): the era menu has no scale of its own (GameMenuFrame.xml +
-- MainMenuFrameTemplates, grepped clean), it draws at UIParent's px-per-unit —
-- the SAME density as the era options window, whose checkFit caps at 1. The knob
-- is our stand-in for that UIParent scale; without it the menu drew 28% larger
-- relative to the options window than the era pair ("esc menu scale too big" —
-- director, 2026-08-04). `or 1` guards a load-order regression only. NOTE: this
-- lives INSIDE the existing OnShow — a second Scripts/OnShow block on the same
-- frame would silently REPLACE this one (SetScript semantics: last wins).
this:SetScale(ERA_WINDOW_SCALE or 1)
if UpdateMicroButtons then UpdateMicroButtons() end
if Disable_BagButtons then Disable_BagButtons() end
</OnShow>
<OnHide>
if UpdateMicroButtons then UpdateMicroButtons() end
if Enable_BagButtons then Enable_BagButtons() end
</OnHide>
</Scripts>
</Frame>
</Ui>