Files
benilla-octo/crates/benilla-app/assets/ui/GameMenuFrame.xml
T
SamandClaude Fable 5.1 9e528e6f86 the video options window goes stock, and water collision returns whole
- the reference's own video options window loads hidden, so pfUI's video skin and any addon reaching for its sliders and check buttons by name finds real frames; our own options window is BenillaOptionsFrame now, and ESC still opens it (2177)
- GetScreenResolutions, GetCurrentResolution, SetScreenResolution, GetRefreshRates, GetVideoCaps, RestartGx and RestoreVideoDefaults answer off the monitor's own modes, so CT_Viewport loads clean (2177)
- three of those verbs were corrected against a second read of the binary: GetRefreshRates answers nothing on a device with no rates, GetVideoCaps always gives a number for triple buffering, and RestoreVideoDefaults writes the ten rows the verb writes (2177)
- the camera's water collision is back with both halves: the boom stops at a water surface, and a swimmer's camera keeps a constant 2/9 yd clearance over the waterline whatever the body underneath does (2179)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 21:04:35 +07:00

400 lines
26 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 (our since-retired 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 carried on each button's own
`text=` attribute — which this engine resolves as a global-string lookup exactly as
the reference does (decision 0995, `loader/widgets.rs`'s `resolve_text`).
· **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 (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`.
NAMES are the reference's, unprefixed (`GameMenuFrame`, `GameMenuButton*`) — the same call
our retired 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`), the loader honours
`toplevel="true"`, and the frame below carries it — so the Esc menu does come to the
front over any other DIALOG-strata frame it overlaps.
-->
<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 retired MicroMenu.xml's 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 THREE STOCK CONSUMERS THAT ASK "IS AN OPTIONS WINDOW OPEN?" (decision 2177) ══
-- All three are the reference's own, off the chain, and all three name the reference's
-- three windows literally. Two of those names are now REAL hidden stock frames
-- (`SoundOptionsFrame` since 2147, `UIOptionsFrame` since 2115) and the third,
-- `OptionsFrame`, became one when the stock VIDEO window joined the manifest — so the
-- whole chain now reads "no", always, while the window the player actually opens is up.
-- Until then `OptionsFrame` WAS our window and every one of them answered by accident.
--
-- **Wrappers, not replacements.** Each stock function keeps running and keeps deciding;
-- ours adds the one term the reference could not know about. A rewrite would be thirty
-- lines of the reference's ladder copied into our tree to drift.
--
-- **HERE, not in `OptionsFrame.xml`, because of load order.** `UpdateMicroButtons` is
-- defined by `MainMenuBarMicroButtons.xml`, manifest l.576 — AFTER our options window at
-- l.522, where a wrapper would capture a nil. This file is the manifest's LAST row
-- (l.1273), so all three exist. It is also the right home on the merits: this is the ESC
-- menu, and these three are exactly "the ESC ladder and the micro button know about our
-- options window".
local Ref_IsOptionFrameOpen = IsOptionFrameOpen
local Ref_ToggleGameMenu = ToggleGameMenu
local Ref_UpdateMicroButtons = UpdateMicroButtons
-- The one term all three add. Existence-guarded because these three wrappers stand in a
-- file that can be seated without the options window: in the client `BenillaOptionsFrame`
-- is manifest row 38 and this file is the last row, so it is always real — but a test kit
-- that seats the game menu alone must get "no options window is open", not a raise inside
-- the ESC handler.
local function BenillaOptions_IsOpen()
return BenillaOptionsFrame and BenillaOptionsFrame:IsVisible()
end
-- `UIParent.lua:996`. One caller: `CloseAllWindows_WithExceptions`, which passes
-- `ignoreCenter = 1` when an options window is up so the ESC sweep does not close the
-- centre panel out from under it. Ours IS the centre panel (`UIPanelWindows` row,
-- `area = "center"`), so answering "no" would have ESC close it through the sweep instead
-- of through its own rung, discarding pending edits with no Cancel semantics.
function IsOptionFrameOpen()
if BenillaOptions_IsOpen() then
return 1
end
return Ref_IsOptionFrameOpen()
end
-- `UIParent.lua:1465-1497`. The ESC ladder, and the rung matters as much as the answer:
-- the reference tries the static popup FIRST, then an open options window, then the game
-- menu. So this runs that first rung itself and returns if it fired — `StaticPopup_Escape -- Pressed` is a pure scan when nothing is shown (`StaticPopup.lua:1879-1893`), so the
-- delegate below re-running it costs nothing and changes nothing — then takes the options
-- rung, then hands the rest of the ladder back untouched.
--
-- The close is our own Close button's click, which is the same discard-and-hide the
-- reference reaches through `OptionsFrameCancel:Click()`: our `<OnHide>` drops the pending
-- page. (That alias is retired — `OptionsFrameCancel` is the stock video window's own
-- button now, and ours loading later would have clobbered it.)
function ToggleGameMenu(clicked)
if clicked then
-- The reference's `clicked` arm closes an open options window and then goes on to
-- toggle the game menu, rather than returning. Same here.
if BenillaOptions_IsOpen() then
BenillaOptionsFrameCloseButton:Click()
end
return Ref_ToggleGameMenu(clicked)
end
if StaticPopup_EscapePressed() then
return
end
if BenillaOptions_IsOpen() then
BenillaOptionsFrameCloseButton:Click()
return
end
return Ref_ToggleGameMenu(clicked)
end
-- `MainMenuBarMicroButtons.lua:47-58`. A POST-hook that can only ever push the button, never
-- release it: the reference has already decided from the six frames it knows, and this adds
-- the seventh. Written this way round so it cannot fight that decision — a wrapper that also
-- set NORMAL would be a second copy of the reference's whole `or` chain.
--
-- **Existence-guarded, and only here.** The shipped manifest always carries
-- `MainMenuBarMicroButtons.xml`, so in the client `Ref_UpdateMicroButtons` and
-- `MainMenuMicroButton` are always real. A partial test kit that seats this file and not
-- the micro bar is the case the guards are for, and a guard is the honest answer there:
-- there is no micro button to push, so there is nothing to do — as against a raise inside
-- an unrelated window's OnShow, which is what an unguarded wrapper turns that into.
function UpdateMicroButtons()
if Ref_UpdateMicroButtons then
Ref_UpdateMicroButtons()
end
if MainMenuMicroButton and BenillaOptions_IsOpen() then
MainMenuMicroButton:SetButtonState("PUSHED", 1)
end
end
-- 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.
]]></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" text="MAIN_MENU">
<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, BenillaOptionsFrame 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" text="Options">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="28" y="-32"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnClick>
PlaySound("igMainMenuOption")
HideUIPanel(GameMenuFrame)
ShowUIPanel(BenillaOptionsFrame)
</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" text="MACROS">
<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>
<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" text="LOGOUT">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonMacros" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-20"/></Offset></Anchor>
</Anchors>
<Scripts>
<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" text="EXIT_GAME">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonLogout" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
</Anchors>
<Scripts>
<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" text="RETURN_TO_GAME">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GameMenuButtonQuit" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-20"/></Offset></Anchor>
</Anchors>
<Scripts>
<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, in
the `CloseMenus and CloseMenus()` posture our retired panel file used: a headless test
loads this file without the action bar behind it. -->
<Scripts>
<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>