- the four extra action bars become per-character options, off by default, on a new Action Bars options page — the toggles ride the server's own byte (`CMSG_SET_ACTIONBAR_TOGGLES` into `PLAYER_FIELD_BYTES`), so a fresh character's zero is the default for free; turning the bottom-left bar off gives the stance bar its previously unbuilt unraised look, end-caps and 64×64 rings - bag windows stop drawing straight through a raised bottom bar: the bottom band has ONE owner — the manage pass — the bag stack joins it through a listener seam, and a guard test walks all eight raisable-bar combinations across 24 bar/tenant pairs and refuses overlap - the item-push card takes the reference's real geometry, closing the gap 0887 measured - resizable addon windows stop at their bounds instead of pinning and walking across the screen: four per-frame f32s with 0.0 the disable sentinel, the clamp on the interactive drag only with the residual rebated out of the drag delta, `<ResizeBounds>` in XML honoured — and `SetFontString`'s three raises land exactly as the bytes have them Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2219 lines
141 KiB
XML
2219 lines
141 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's bag windows (decision 0068 T2), RE-SKINNED to the real 1.12 ContainerFrame
|
||
(dressing arc, decision 0084; whole-space generalization, decision 0216 slice 2): the
|
||
geometry and art below are QUOTED from the real `ContainerFrame.xml`/`ContainerFrame.lua`
|
||
(scratchpad `ref-framexml/ContainerFrame.xml`, `ContainerFrame.lua`; line citations inline),
|
||
turned onto our own container feed/intents. FIVE windows now — the backpack (bag id 0, 16
|
||
slots, its own hand-authored block below, unchanged in shape) plus the four equipped bags
|
||
(ids 1..4, `BenillaBagWindowTemplate`, up to 20 slots each) — the ContainerFrameTemplate
|
||
generalization this file's header always said was coming.
|
||
|
||
Every window shares the same handler functions, deriving its bag id from
|
||
`button:GetParent():GetID()`/`frame:GetID()` (the ref's own `this:GetParent():GetID()`
|
||
pattern, ContainerFrame.lua:88 &c.) rather than a hardcoded global — the XML `id=` attribute
|
||
is applied (SetID) before any child's OnLoad fires (the loader's bottom-up materialize order,
|
||
`loader/mod.rs` step 5 before step 7), so a slot button's OnLoad can already read its
|
||
parent's id. All state arrives through the container snapshot
|
||
(GetContainerNumSlots/GetContainerItemInfo) and refreshes on BAG_UPDATE/ITEM_LOCK_CHANGED.
|
||
LEFT-click drives the cursor drag (PickupContainerItem → pick up / place / swap, the app's
|
||
move drain → CMSG_SWAP_INV_ITEM/CMSG_SWAP_ITEM); RIGHT-click cancels a held cursor, else uses
|
||
the slot (UseContainerItem → CMSG_USE_ITEM / auto-equip, or a merchant sell); SHIFT+left-click
|
||
opens the stack-split spinner (the reference fork, ContainerFrame.lua:567-577).
|
||
|
||
REAL-CLIENT DIVERGENCES (noted, not bugs):
|
||
- The real client scales the whole frame to CONTAINER_SCALE=0.90 (ContainerFrame.lua l.13);
|
||
we don't do frame scale, so every window renders ~11% larger. Scaling is uniform over the
|
||
frame + its children + the background art, so the slot buttons still seat in the painted
|
||
wells — only the on-screen size differs.
|
||
- The bag portrait is the C-side SetBagPortaitTexture (ContainerFrame.lua l.422): the backpack
|
||
shows the static `Interface\Buttons\Button-Backpack-Up` art, an equipped bag its own item
|
||
icon (BenillaBagWindow_Update reads inv slot 19+bagId).
|
||
- Bags 1..4 SNUG-FIT to their real row count (BenillaBagWindow_FitBackground): the background
|
||
is stitched from the real client's `UI-Bag-Components` top/middle/bottom pieces sized to
|
||
ceil(size/4) rows (ContainerFrame.lua ContainerFrame_GenerateFrame, id~=0 branch), so a
|
||
6-slot pouch is a 2-row window, not the backpack's 5-row slab. The backpack (id 0) keeps its
|
||
own single `UI-BackpackBackground` slab (the id==0 branch), unchanged.
|
||
MONEY: reuses the shared BenillaMoney_Set/_Clear purse helpers (they live in MerchantFrame.xml
|
||
— decision 0084's reusable money display; the same reuse the loot window makes). At runtime
|
||
every FrameXML file is loaded before any event fires, so the helper is defined by the time
|
||
BenillaBagWindow_Update first runs; a unit test that loads this file in isolation must also
|
||
load MerchantFrame.xml (as the loot tests do). Money is BACKPACK ONLY (ContainerFrame.lua
|
||
l.314 shows the MoneyFrame only for id==0) — every other window hides it.
|
||
|
||
The title inherits GameFontHighlight and the counts NumberFontNormal — both live in the
|
||
shipped Fonts.xml (the font-object slice already landed), so they render in the real fonts.
|
||
-->
|
||
<Script><![CDATA[
|
||
-- The five windows' shared slot count cap: the backpack is always exactly 16
|
||
-- (GetContainerNumSlots(0) never varies — PACK_SLOTS is a wire constant); the
|
||
-- equipped-bag windows show up to this many (5 rows × 4 columns — the reference template's
|
||
-- true max is 36, but 20 is vanilla's largest actual equippable bag, and building out to 36
|
||
-- slot buttons per window for content that can never exist would be pure waste. Hides the
|
||
-- unused tail via BenillaBagSlot_Update's physIndex-past-size branch, same as the backpack.
|
||
BENILLA_BAG_WINDOW_MAX_SLOTS = 20
|
||
|
||
-- The keyring's container id (ref MainMenuBarBagButtons.lua:1) — decision 0765. It is an
|
||
-- ordinary container in every respect the seam cares about: the app feeds it like any other
|
||
-- bag (its slots are the player descriptor's own 81.., no container object), and every
|
||
-- container verb, the cursor, the pending-op lock and the wire drains take it unchanged.
|
||
-- What makes it special is only what the reference makes special: the window's art, its
|
||
-- open/close sound, and the fact that its capacity is not a wire field.
|
||
KEYRING_CONTAINER = -2
|
||
|
||
-- The keyring's usable slot count (ref GetKeyRingSize, ContainerFrame.lua:773). The
|
||
-- reference recomputes a level ladder in Lua (4 / 8 at 40 / 12 at 50 / 16 above 60) that the
|
||
-- server enforces identically (Player::GetMaxKeyringSize); benilla computes it once app-side
|
||
-- and feeds it as the container's own size, so this reads it back rather than keeping a
|
||
-- second copy of the ladder that could drift from the one the feed uses.
|
||
function GetKeyRingSize()
|
||
return GetContainerNumSlots(KEYRING_CONTAINER)
|
||
end
|
||
|
||
-- BenillaBagSlot_OnLoad(button, physIndex): physIndex is the button's CHAIN position (1 =
|
||
-- bottom-right, growing up-and-left — the anchor order below), not the game slot. The ref's
|
||
-- own formula (index = size - j + 1, ContainerFrame.lua:426/446) maps chain position → game
|
||
-- slot dynamically in BenillaBagSlot_Update, so slot 1 always reads top-left regardless of
|
||
-- how many of the window's slots are actually occupied — recomputed every Update (the ref
|
||
-- only computes it once, at window generation; recomputing is a strict robustness win for
|
||
-- the rare live bag-swap case, not a behavior change for a size that never moves).
|
||
function BenillaBagSlot_OnLoad(button, physIndex)
|
||
button.physIndex = physIndex
|
||
button.icon = getglobal(button:GetName() .. "Icon")
|
||
button.count = getglobal(button:GetName() .. "Count")
|
||
-- Both buttons must reach OnClick (the default set is LeftButtonUp only): LEFT-click is the
|
||
-- pickup gesture (PickupContainerItem — pick up / place / swap on the cursor); RIGHT-click
|
||
-- cancels a held cursor, else uses the slot (the C side sells it when a merchant is open —
|
||
-- our container drain forks).
|
||
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
-- The drag trio (decision 0216 §3): click-carry and drag are ONE code path in the
|
||
-- reference (ContainerFrame.xml:40-55 routes OnDragStart/OnReceiveDrag to the same
|
||
-- OnClick("LeftButton", ignoreModifiers=1) the plain click uses) — see
|
||
-- BenillaBagSlot_OnClick below for the identical routing (its own `ignoreModifiers`
|
||
-- suppresses the shift-split fork, the reference's own contract for drag/receive).
|
||
button:RegisterForDrag("LeftButton")
|
||
BenillaBagSlot_Update(button)
|
||
end
|
||
|
||
function BenillaBagSlot_OnClick(button, mouseButton, ignoreModifiers)
|
||
if button.slot == nil then return end -- a hidden button (physIndex past the bag's size)
|
||
local bagId = button:GetParent():GetID()
|
||
if mouseButton == "LeftButton" then
|
||
-- The reference's own five returns (ContainerFrame.lua:241) — decision 1199
|
||
-- put this binding back on its 1.12 shape.
|
||
local texture, itemCount, locked, quality, readable =
|
||
GetContainerItemInfo(bagId, button.slot)
|
||
-- The modifier fork, the reference's own order (ContainerFrame.lua:563-579;
|
||
-- BankFrame.lua:141-152 for a bank slot, which is this same handler at container
|
||
-- -1). `ignoreModifiers` (the drag-trio calls, both true) suppresses it whole —
|
||
-- the reference's drag/receive contract.
|
||
--
|
||
-- CTRL: preview the item on your own character in the dressing room (decision 1060).
|
||
if IsControlKeyDown() and not ignoreModifiers then
|
||
DressUpItemLink(GetContainerItemLink(bagId, button.slot))
|
||
return
|
||
end
|
||
-- SHIFT: post the item's link into the chat edit box if it's open, ELSE split the
|
||
-- stack. The ref's own `else` (l.567-577) — and note it gates on `IsShown()` here
|
||
-- where its siblings use `IsVisible()`; ours are the same thing (the edit box's only
|
||
-- parent is UIParent), so the ref's own word is quoted at each site.
|
||
if IsShiftKeyDown() and not ignoreModifiers then
|
||
-- The visibility test is the REF'S fork, not the helper's: with chat open this
|
||
-- arm never splits, even in the one benilla state where nothing can be posted
|
||
-- (an unresolved template — `BenillaChatEdit_InsertLink`'s own note).
|
||
if ChatFrameEditBox and ChatFrameEditBox:IsShown() then
|
||
BenillaChatEdit_InsertLink(GetContainerItemLink(bagId, button.slot))
|
||
return
|
||
end
|
||
if texture ~= nil and not locked and (itemCount or 1) >= 2 then
|
||
button.SplitStack = function(btn, n)
|
||
SplitContainerItem(bagId, btn.slot, n)
|
||
BenillaBagWindow_Repaint(btn:GetParent())
|
||
end
|
||
-- Ref ContainerFrameItemButton_OnLoad/_OnClick (ContainerFrame.lua:558-560,
|
||
-- 573-576): the owner's own SplitStack closure carries the bag/slot so
|
||
-- StackSplitFrameOkay_Click's generic `owner.SplitStack(owner, split)` call
|
||
-- needs no window-specific knowledge. SplitContainerItem lives in cursor.rs
|
||
-- rather than container.rs — it is the one container-named verb whose
|
||
-- payload is the cursor's, not a bag's — but like every container verb it is
|
||
-- a plain top-level global (decision 1198).
|
||
OpenStackSplitFrame(itemCount, button, "BOTTOMRIGHT", "TOPRIGHT")
|
||
end
|
||
return
|
||
end
|
||
-- A plain click hides any open split frame (ref ContainerFrame.lua:581) before the
|
||
-- ordinary pickup/place proceeds.
|
||
local split = getglobal("StackSplitFrame")
|
||
if split then split:Hide() end
|
||
-- PickupContainerItem is the single drag entry point (real client): an empty cursor
|
||
-- picks this slot up; a held cursor places/swaps into it (same slot = cancel). Hide the
|
||
-- hover tooltip (the item just left the slot for the cursor) and repaint so the picked
|
||
-- slot dims / un-dims immediately — the swap itself settles when the server answers.
|
||
PickupContainerItem(bagId, button.slot)
|
||
GameTooltip:Hide()
|
||
BenillaBagWindow_Repaint(button:GetParent())
|
||
elseif mouseButton == "RightButton" then
|
||
-- A held cursor cancels (client-side, nothing sent); otherwise use/equip/sell the slot.
|
||
if CursorHasItem() then
|
||
ClearCursor()
|
||
BenillaBagWindow_Repaint(button:GetParent())
|
||
else
|
||
UseContainerItem(bagId, button.slot)
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Hover: the era-true GameTooltip:SetBagItem(bag, slot) — the ENGINE renders the full
|
||
-- item tooltip from the template store and owns the sell-price money law (real instance
|
||
-- + merchant open + repair off ⇒ OnTooltipAddMoney(SellPrice × stack), or the
|
||
-- ITEM_UNSELLABLE line — wow-re ui/scratch/tooltip-money.md's byte-verified gate,
|
||
-- decision 0274 P1). The durability-adjusted damaged price is deferred until durability
|
||
-- damage reaches the feed (a pristine item reduces to SellPrice × stack, the case we
|
||
-- ship). Nothing shows while the template is in flight — the OnUpdate re-enter fills it.
|
||
function BenillaBagSlot_OnEnter(button)
|
||
if button.slot == nil then return end
|
||
local bagId = button:GetParent():GetID()
|
||
local texture, itemCount, locked, quality, readable =
|
||
GetContainerItemInfo(bagId, button.slot)
|
||
-- An emptied slot drops its tooltip (ref ContainerFrame_Update's texture-nil branch,
|
||
-- ContainerFrame.lua:281-283) — without this the OnUpdate re-enter below would leave
|
||
-- a stale tooltip up after the item is sold or moved out from under the hover.
|
||
if not texture then
|
||
if GameTooltip:IsOwned(button) then GameTooltip:Hide() end
|
||
return
|
||
end
|
||
-- Ref ContainerFrameItemButton_OnEnter (ContainerFrame.lua:602-612) verbatim: a slot
|
||
-- in the RIGHT half of the screen hangs its tooltip LEFT, so it never runs off the
|
||
-- edge (the bag lives at the bottom-right — this is the ref's own screen-edge answer,
|
||
-- a side-pick, not a clamp).
|
||
if (button:GetRight() or 0) >= (GetScreenWidth() / 2) then
|
||
GameTooltip:SetOwner(button, "ANCHOR_LEFT")
|
||
else
|
||
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
||
end
|
||
GameTooltip:SetBagItem(bagId, button.slot)
|
||
-- The pouch/magnifier cursor (ref ContainerFrameItemButton_OnEnter tail,
|
||
-- ContainerFrame.lua l.636-642): merchant open on the MERCHANT tab and not repair
|
||
-- mode → the sell cursor over this slot; else a readable item (a mail letter copy —
|
||
-- right-click opens the reader) → the Inspect magnifier; anything else restores the
|
||
-- base cursor. The OnUpdate re-enter keeps it current while hovering (the ref's own
|
||
-- loop). The ref's `IsControlKeyDown() and hasItem` magnifier arm (l.638) is the
|
||
-- dress-up preview's own cursor tell — it landed with the dressing room (decision
|
||
-- 1060); `info` is non-nil above, which is the ref's `hasItem`.
|
||
if MerchantFrame and MerchantFrame:IsShown()
|
||
and MerchantFrame.selectedTab == 1 and not InRepairMode() then
|
||
ShowContainerSellCursor(bagId, button.slot)
|
||
elseif readable or IsControlKeyDown() then
|
||
ShowInspectCursor()
|
||
else
|
||
ResetCursor()
|
||
end
|
||
GameTooltip:Show()
|
||
end
|
||
|
||
function BenillaBagSlot_OnLeave(button)
|
||
GameTooltip:Hide()
|
||
-- Ref ItemButton OnLeave (ContainerFrame.xml): the hover's sell cursor drops with it.
|
||
ResetCursor()
|
||
end
|
||
|
||
-- Ref ContainerFrameItemButton_OnUpdate (ContainerFrame.lua:645-660): while the tooltip
|
||
-- is ours, re-run OnEnter every frame — the ref ships this loop UNTHROTTLED (its
|
||
-- updateTooltip throttle is commented out in 1.12). It is the real client's own refresh
|
||
-- mechanism: a tooltip set while the item template was still in flight fills itself in
|
||
-- the moment the answer lands, no re-hover.
|
||
function BenillaBagSlot_OnUpdate(button)
|
||
if GameTooltip:IsOwned(button) then
|
||
BenillaBagSlot_OnEnter(button)
|
||
end
|
||
end
|
||
|
||
-- The item's use-cooldown sweep (ref ContainerFrame_UpdateCooldown,
|
||
-- ContainerFrame.lua:295-299, verbatim shape over our container dialect).
|
||
function BenillaBagSlot_UpdateCooldown(button, bagId)
|
||
local cooldown = getglobal(button:GetName() .. "Cooldown")
|
||
local start, duration, enable = GetContainerItemCooldown(bagId, button.slot)
|
||
CooldownFrame_SetTimer(cooldown, start, duration, enable)
|
||
end
|
||
|
||
-- The physIndex → game-slot resolution (the module doc above) + the paint (ref
|
||
-- ContainerFrame_Update, ContainerFrame.lua:234-293). Shared by every window's slot
|
||
-- buttons. The occupied/empty fork drives the cooldown exactly as the ref does
|
||
-- (l.248-253: occupied → UpdateCooldown, empty → Cooldown:Hide()).
|
||
function BenillaBagSlot_Update(button)
|
||
local bagId = button:GetParent():GetID()
|
||
local size = GetContainerNumSlots(bagId)
|
||
if button.physIndex > size then
|
||
button.slot = nil
|
||
button:Hide()
|
||
return
|
||
end
|
||
button.slot = size - button.physIndex + 1
|
||
button:Show()
|
||
local texture, itemCount, locked = GetContainerItemInfo(bagId, button.slot)
|
||
if texture ~= nil or itemCount ~= nil then
|
||
BenillaBagSlot_UpdateCooldown(button, bagId)
|
||
button.icon:SetTexture(texture or BENILLA_FALLBACK_ICON)
|
||
-- A locked slot (its item is up on the cursor, or a send is still pending
|
||
-- server-side, decision 0216 §4/0218 §3) dims, the real client's drag feedback.
|
||
if locked then
|
||
button.icon:SetVertexColor(0.4, 0.4, 0.4)
|
||
else
|
||
button.icon:SetVertexColor(1, 1, 1)
|
||
end
|
||
if (itemCount or 1) > 1 then
|
||
button.count:SetText(itemCount)
|
||
else
|
||
button.count:SetText("")
|
||
end
|
||
else
|
||
button.icon:SetTexture(nil)
|
||
button.count:SetText("")
|
||
getglobal(button:GetName() .. "Cooldown"):Hide()
|
||
end
|
||
end
|
||
|
||
-- The generic per-window repaint (decision 0216 slice 2): every slot up to this window's
|
||
-- cap, the title (GetBagName — dynamic since a live bag swap changes it), and the money
|
||
-- purse (backpack only, ContainerFrame.lua l.314). BenillaBagFrame_Update (below) is the
|
||
-- backpack's zero-arg convenience alias, kept for existing callers (UiPanels.xml's
|
||
-- OpenBackpack/CloseBackpack, and the tests that patch it directly).
|
||
function BenillaBagWindow_Update(frame)
|
||
local bagId = frame:GetID()
|
||
local maxSlots = (bagId == 0) and 16 or BENILLA_BAG_WINDOW_MAX_SLOTS
|
||
-- The backpack predates the $parent-prefixed slot naming (BenillaBagSlot1..16, not
|
||
-- BenillaBagFrameSlot1..16 — its buttons are hand-authored, not $parent-templated) and
|
||
-- several existing tests reference that exact name directly; every other window's slots
|
||
-- DO follow frame:GetName().."Slot"..i (the virtual template's $parentSlotN).
|
||
local slotPrefix = (bagId == 0) and "BenillaBagSlot" or (frame:GetName() .. "Slot")
|
||
for i = 1, maxSlots do
|
||
local button = getglobal(slotPrefix .. i)
|
||
if button then BenillaBagSlot_Update(button) end
|
||
end
|
||
local title = getglobal(frame:GetName() .. "Name")
|
||
if title then
|
||
-- The keyring is titled from the localized KEYRING string, not GetBagName — it has
|
||
-- no bag ITEM to be named after (ref ContainerFrame.lua l.418).
|
||
if bagId == KEYRING_CONTAINER then
|
||
title:SetText(KEYRING)
|
||
else
|
||
title:SetText(GetBagName(bagId) or "")
|
||
end
|
||
end
|
||
if bagId == 0 then
|
||
BenillaMoney_Set("BenillaBagMoney", GetMoney())
|
||
elseif bagId == KEYRING_CONTAINER then
|
||
-- Fixed art, again because there is no bag item: the keyring's own portrait
|
||
-- (ref ContainerFrame.lua l.419) and its own background variant, snug-fitted to the
|
||
-- level-gated slot count exactly like an equipped bag.
|
||
-- The GLOBAL form, which is the reference's own (ContainerFrame.lua l.419
|
||
-- writes exactly this call) — 1.12 has no such Texture method.
|
||
SetPortraitToTexture(frame:GetName() .. "Portrait",
|
||
"Interface\\ContainerFrame\\KeyRing-Bag-Icon")
|
||
local size = GetContainerNumSlots(bagId)
|
||
if size > 0 then BenillaBagWindow_FitBackground(frame, size) end
|
||
else
|
||
-- The window's portrait is the bag's OWN item icon (the real client's
|
||
-- C-side SetBagPortaitTexture), not the default backpack art. An equipped bag
|
||
-- (1..4) reads its doll slot (19+bagId, Bag0Slot..Bag3Slot); a bank bag (5..10,
|
||
-- decision 0604) reads the app-resolved bank-bag feed instead — the doll array
|
||
-- stops at the equipped bags, so GetInventoryItemTexture can't reach the vault's.
|
||
-- Falls back to the backpack icon while the item template's icon is in flight.
|
||
local portrait = getglobal(frame:GetName() .. "Portrait")
|
||
if portrait then
|
||
local icon
|
||
if bagId >= 5 then
|
||
icon = BenillaGetBankBagTexture(bagId - 4)
|
||
else
|
||
icon = GetInventoryItemTexture("player", 19 + bagId)
|
||
end
|
||
if icon then
|
||
-- The circular crop (the real SetBagPortaitTexture is C-side and masks the
|
||
-- icon to the ring's inscribed circle): a raw square icon pokes its corners
|
||
-- past the round rim — the director's bank-bag popout artifact.
|
||
SetPortraitToTexture(frame:GetName() .. "Portrait", icon)
|
||
else
|
||
-- The backpack fallback art is authored round — no crop to apply.
|
||
portrait:SetTexture("Interface\\Buttons\\Button-Backpack-Up")
|
||
end
|
||
end
|
||
-- Equipped bags snug-fit their stitched background to the live row count.
|
||
local size = GetContainerNumSlots(bagId)
|
||
if size > 0 then BenillaBagWindow_FitBackground(frame, size) end
|
||
end
|
||
end
|
||
|
||
-- Fit an equipped-bag window's stitched background (BgTop/BgMiddle/BgBottom, authored in the
|
||
-- template above) and its OWN height to the bag's actual row count. This is a transcription of
|
||
-- the real client's ContainerFrame_GenerateFrame (the id~=0 branch) as shipped in the 1.12.1
|
||
-- MPQ (Interface\FrameXML\ContainerFrame.lua) — every constant below is the reference's, not a
|
||
-- measured approximation. rows = ceil(size/4). The TOP piece carries the header + the first
|
||
-- well row; the MIDDLE tiles the remaining rows; the BOTTOM is the frame's bottom rim. The
|
||
-- slot buttons anchor UP from the frame's BOTTOMRIGHT (first at -12,9) and hide past `size`
|
||
-- (BenillaBagSlot_Update), so nothing here touches them — only the art + the frame height.
|
||
-- Which UI-Bag-Components variant a window is stitched from — the ref's own `bagTextureSuffix`
|
||
-- (ContainerFrame_GenerateFrame, ContainerFrame.lua l.326-334): the bank bags get the
|
||
-- tinted "-Bank" plate, the keyring the "-Keyring" one, an equipped bag the plain sheet.
|
||
-- All three atlases are 256x512 with the same band layout, so FitBackground's tex-coords
|
||
-- are shared verbatim and only the file differs. (Ours ALSO applies the "-Bank" arm, which
|
||
-- benilla had been quietly skipping — the bank popouts have been drawing ordinary bag art
|
||
-- since decision 0604.)
|
||
function BenillaBagWindow_BgTexture(bagId)
|
||
local suffix = ""
|
||
if bagId >= 5 then
|
||
suffix = "-Bank"
|
||
elseif bagId == KEYRING_CONTAINER then
|
||
suffix = "-Keyring"
|
||
end
|
||
return "Interface\\ContainerFrame\\UI-Bag-Components" .. suffix
|
||
end
|
||
|
||
function BenillaBagWindow_FitBackground(frame, size)
|
||
local name = frame:GetName()
|
||
local top = getglobal(name .. "BgTop")
|
||
local middle = getglobal(name .. "BgMiddle")
|
||
local bottom = getglobal(name .. "BgBottom")
|
||
if not (top and middle and bottom) then return end
|
||
-- Re-set every fit, as the ref does at every generate: the template authors the plain
|
||
-- sheet, and a window's kind is only known from its id.
|
||
local bg = BenillaBagWindow_BgTexture(frame:GetID())
|
||
top:SetTexture(bg)
|
||
middle:SetTexture(bg)
|
||
bottom:SetTexture(bg)
|
||
local rowH = 41 -- rowHeight
|
||
local rows = math.ceil(size / 4)
|
||
if rows < 1 then rows = 1 end
|
||
-- isPlusTwoBag: a size leaving a remainder of 2 (6/10/14/18) has a 2-well top row, and the
|
||
-- texture carries a whole separate top band for it.
|
||
local plusTwo = (size - math.floor(size / 4) * 4) == 2
|
||
local topH
|
||
if plusTwo then
|
||
topH = 72
|
||
top:SetTexCoord(0, 1, 0.189453125, 0.330078125)
|
||
elseif rows == 1 then
|
||
topH = 86 -- one row only: chop the bottom of the texture
|
||
top:SetTexCoord(0, 1, 0.00390625, 0.16796875)
|
||
else
|
||
topH = 94
|
||
top:SetTexCoord(0, 1, 0.00390625, 0.18359375)
|
||
end
|
||
top:SetHeight(topH)
|
||
-- The top piece already carries one row, so the middle tiles `rows - 1` more. Its height is
|
||
-- one row short of a clean multiple: the reference's firstRowPixelOffset = 9 accounts for
|
||
-- the 9px the BOTTOM rim itself contributes to the final row's frame. Getting this wrong
|
||
-- pushes the rim a row-fraction too low and bleeds the NEXT row's wells in above it.
|
||
local middleH = 0
|
||
bottom:ClearAllPoints()
|
||
if rows > 1 then
|
||
-- A single middle piece spans at most ROWS_IN_BG_TEXTURE (6) rows; the reference
|
||
-- cycles up to MAX_BG_TEXTURES for windows taller than that. Our largest window is a
|
||
-- 20-slot bag (4 middle rows) and the keyring caps at 16 (3), so one always suffices.
|
||
middleH = (rows - 1) * rowH - 9
|
||
middle:SetHeight(middleH)
|
||
middle:SetTexCoord(0, 1, 0.353515625, middleH / 512 + 0.353515625)
|
||
middle:Show()
|
||
bottom:SetPoint("TOPRIGHT", middle, "BOTTOMRIGHT", 0, 0)
|
||
else
|
||
-- One row: the rim seats straight under the top piece. (The reference anchors it to the
|
||
-- hidden middle's TOP, which is the same point — the middle hangs off the top's bottom.)
|
||
middle:Hide()
|
||
bottom:SetPoint("TOPRIGHT", top, "BOTTOMRIGHT", 0, 0)
|
||
end
|
||
-- The bottom rim is a FIXED 10px band at texture v 0.330078125..0.349609375 — the strip
|
||
-- immediately below the plus-two top band, and the only true outer bottom border in the
|
||
-- texture. The reference never rescales or re-coords it; it is authored once in XML.
|
||
local bottomH = 10
|
||
bottom:SetHeight(bottomH)
|
||
bottom:SetTexCoord(0, 1, 0.330078125, 0.349609375)
|
||
frame:SetHeight(topH + middleH + bottomH)
|
||
-- A live size change (a bag swap while the stack is open) shifts every window stacked above
|
||
-- this one; re-run the stack layout so they re-seat against the new height.
|
||
if frame:IsShown() then BenillaBagStack_Relayout() end
|
||
end
|
||
|
||
function BenillaBagFrame_Update()
|
||
BenillaBagWindow_Update(BenillaBagFrame)
|
||
end
|
||
|
||
-- Routes a repaint through the backpack's own zero-arg BenillaBagFrame_Update alias when
|
||
-- `frame` IS the backpack — preserving that global's observability (existing tests patch it
|
||
-- directly to count backpack repaints, e.g. delete_item_tests.rs's stuck-darkening
|
||
-- regression check) — and BenillaBagWindow_Update generically for every other window. Every
|
||
-- runtime repaint trigger (a slot click, an event, OpenAllBags' pre-show paint) goes
|
||
-- through this (BenillaBagBarSlot_OnClick reaches it through the ToggleBag global too).
|
||
function BenillaBagWindow_Repaint(frame)
|
||
if frame:GetID() == 0 then
|
||
BenillaBagFrame_Update()
|
||
else
|
||
BenillaBagWindow_Update(frame)
|
||
end
|
||
end
|
||
|
||
-- OnLoad/OnEvent (generic, shared by all five windows — each already receives `frame`, so
|
||
-- deriving bagId from `frame:GetID()` needs no per-window body).
|
||
function BenillaBagFrame_OnLoad(frame)
|
||
frame:RegisterEvent("BAG_UPDATE")
|
||
-- The engine fires ITEM_LOCK_CHANGED(bag, slot) on every cursor pickup/clear AND every
|
||
-- pending-op send/resolve (decisions 0216 §4/0218 §3) — including clears the bag never
|
||
-- clicked through (the delete popup's No, ESC; a server failure), which the click-time
|
||
-- repaint can't see. The reference ContainerFrame repaints on exactly this event.
|
||
frame:RegisterEvent("ITEM_LOCK_CHANGED")
|
||
-- Item cooldown starts/ends (ref ContainerFrame_OnLoad, ContainerFrame.lua:21 —
|
||
-- BAG_UPDATE_COOLDOWN carries no bag argument; every open window refreshes).
|
||
frame:RegisterEvent("BAG_UPDATE_COOLDOWN")
|
||
-- The real backpack MoneyFrame refreshes on PLAYER_MONEY (SmallMoneyFrame's own OnEvent);
|
||
-- keep the purse live while the window is open. Backpack only — the other windows never
|
||
-- show a purse, so there's nothing for them to refresh.
|
||
if frame:GetID() == 0 then
|
||
frame:RegisterEvent("PLAYER_MONEY")
|
||
end
|
||
end
|
||
|
||
function BenillaBagFrame_OnEvent(frame)
|
||
if event == "PLAYER_MONEY" then
|
||
BenillaMoney_Set("BenillaBagMoney", GetMoney())
|
||
return
|
||
end
|
||
-- The cooldown-only refresh (ref ContainerFrame_UpdateCooldowns via OnEvent,
|
||
-- ContainerFrame.lua:243-253's loop shape): no bag argument — sweep every shown
|
||
-- slot of THIS window, no full repaint.
|
||
if event == "BAG_UPDATE_COOLDOWN" then
|
||
local bagId = frame:GetID()
|
||
local maxSlots = (bagId == 0) and 16 or BENILLA_BAG_WINDOW_MAX_SLOTS
|
||
local slotPrefix = (bagId == 0) and "BenillaBagSlot" or (frame:GetName() .. "Slot")
|
||
for i = 1, maxSlots do
|
||
local button = getglobal(slotPrefix .. i)
|
||
if button and button.slot then
|
||
BenillaBagSlot_UpdateCooldown(button, bagId)
|
||
end
|
||
end
|
||
return
|
||
end
|
||
-- BAG_UPDATE / ITEM_LOCK_CHANGED name their bag in arg1; only THIS window's own bag
|
||
-- repaints (ref ContainerFrame_OnEvent, ContainerFrame.lua:26-44: `this:GetID() == arg1`).
|
||
if (event == "BAG_UPDATE" or event == "ITEM_LOCK_CHANGED") and arg1 ~= frame:GetID() then
|
||
return
|
||
end
|
||
BenillaBagWindow_Repaint(frame)
|
||
end
|
||
|
||
-- ToggleBag / ToggleBackpack / OpenAllBags (ref ContainerFrame.lua l.46-82, l.662-700) —
|
||
-- TWO DISTINCT KNOBS, and benilla ran them as one until 1494. The reference's split, which
|
||
-- is now ours:
|
||
--
|
||
-- B / F12 TOGGLEBACKPACK -> ToggleBackpack() — the BACKPACK's toggle. Closed: opens
|
||
-- bag 0 ALONE. Already open: hides every container window there is. The
|
||
-- asymmetry is the reference's own — one bag out, all bags in.
|
||
-- SHIFT-B OPENALLBAGS -> OpenAllBags() — the ALL-bags toggle: everything open
|
||
-- already closes the lot, anything else opens the lot.
|
||
-- F8..F11 TOGGLEBAG1..4 -> ToggleBag(4..1) — one equipped bag each (note the
|
||
-- reference's REVERSED numbering: TOGGLEBAG1 is bag 4).
|
||
--
|
||
-- "All bags" = the backpack (bag 0, which always exists) plus each equipped-bag slot 1..4
|
||
-- that actually holds a bag (GetContainerNumSlots > 0); an empty slot has no window to
|
||
-- show. The five windows, indexed by bag id (BENILLA_BAG_WINDOWS[bagId+1]) — one code path
|
||
-- over all of them. The keyring is a seventh window with its own ToggleKeyRing: swept by
|
||
-- the two close arms below (the ref's sweeps are over ALL ContainerFrames, which is what
|
||
-- its keyring lives in), never counted as an open bag and never opened by them.
|
||
BENILLA_BAG_WINDOWS = { "BenillaBagFrame", "BenillaBagFrame1", "BenillaBagFrame2", "BenillaBagFrame3", "BenillaBagFrame4" }
|
||
|
||
-- THE REFERENCE'S NAMES ARE THE REAL ENTRY POINTS, and our own UI calls THEM.
|
||
--
|
||
-- This is how a 1.12 addon customises anything: it replaces a global and expects the
|
||
-- client to call its replacement. `Bagnon_Core/core/Overrides.lua` is the canonical shape —
|
||
-- local bToggleBackpack = ToggleBackpack
|
||
-- ToggleBackpack = function() ... end
|
||
-- and until now that override was INERT here, because the bag bindings and the bag button
|
||
-- called `BenillaBagToggle_OnClick` directly and nothing ever looked up `ToggleBackpack`.
|
||
-- Bagnon loaded, appeared in the AddOns list, replaced the globals, and the player still
|
||
-- got the stock bags. The director saw that; no instrument here could, because the corpus
|
||
-- survey loads addons and fires events but never CLICKS anything.
|
||
--
|
||
-- The class is far wider than one addon: every "hook a global to change behaviour" addon is
|
||
-- silently inert wherever our UI calls a benilla-named equivalent instead of the
|
||
-- reference's name. `CloseAllBags`/`OpenBackpack`/`CloseBackpack` already lived under the
|
||
-- ref's names in UiPanels.xml for exactly this reason; these are the three that did not.
|
||
--
|
||
-- `OpenAllBags(forceOpen)` is the ref's SHIFT-B body (ContainerFrame.lua l.662-700) and it
|
||
-- is a TOGGLE, not a plain open: one pass hides every open window while counting them
|
||
-- against how many CAN be open, and if everything already was, that pass IS the close and
|
||
-- it returns. `forceOpen` (the ref's own argument, used by callers that mean "open") skips
|
||
-- the close arm. The open arm calls the GLOBALS `ToggleBackpack()`/`ToggleBag(1..4)` on a
|
||
-- now-closed set — the ref's exact tail, so a bag addon holding either name gets both.
|
||
function OpenAllBags(forceOpen)
|
||
if UIParent and not UIParent:IsVisible() then return end
|
||
local totalBags = 1 -- the backpack always counts
|
||
for bagId = 1, 4 do
|
||
if GetContainerNumSlots(bagId) > 0 then totalBags = totalBags + 1 end
|
||
end
|
||
local bagsOpen = 0
|
||
for _, name in ipairs(BENILLA_BAG_WINDOWS) do
|
||
local frame = getglobal(name)
|
||
if frame and frame:IsShown() then
|
||
frame:Hide()
|
||
bagsOpen = bagsOpen + 1
|
||
end
|
||
end
|
||
-- Swept with the rest, but never counted (ref: `if GetID() ~= KEYRING_CONTAINER`).
|
||
local keyring = getglobal("BenillaKeyRingFrame")
|
||
if keyring and keyring:IsShown() then keyring:Hide() end
|
||
if bagsOpen >= totalBags and not forceOpen then return end
|
||
ToggleBackpack()
|
||
ToggleBag(1)
|
||
ToggleBag(2)
|
||
ToggleBag(3)
|
||
ToggleBag(4)
|
||
end
|
||
|
||
-- `ToggleBag(id)` — the ref's per-bag toggle (ContainerFrame.lua l.46-65), and the other
|
||
-- global Bagnon replaces. Ours drives the same window the all-bags path does.
|
||
--
|
||
-- The ref's `if size > 0` gate is load-bearing here and was missing until 1494: it is what
|
||
-- keeps `OpenAllBags`' blind `ToggleBag(1..4)` tail from showing an empty slot's window.
|
||
-- Bag 0 is exempt for the same reason `OpenBag` exempts it (it always exists even when the
|
||
-- feed has not told us its size yet) — the ref gets that for free from its own always-16
|
||
-- backpack.
|
||
function ToggleBag(id)
|
||
id = id or 0
|
||
if id ~= 0 and GetContainerNumSlots(id) <= 0 then return end
|
||
local frame = getglobal(BENILLA_BAG_WINDOWS[id + 1])
|
||
if not frame then return end
|
||
if frame:IsShown() then
|
||
frame:Hide()
|
||
else
|
||
BenillaBagWindow_Repaint(frame)
|
||
frame:Show()
|
||
end
|
||
end
|
||
|
||
-- `OpenBag(id)` / `CloseBag(id)` / `IsBagOpen(id)` — ToggleBag's three siblings from the
|
||
-- same reference file (ContainerFrame.lua l.144-185), and the last of that family that was
|
||
-- still missing here. `Bagnon_Core/core/Overrides.lua` l.42/51 captures BOTH of the first
|
||
-- two and calls the capture back for any bag Bagnon does not control — a nil call, on the
|
||
-- ordinary path, for an addon that only *partly* takes the bags over.
|
||
--
|
||
-- The reference's `OpenBag` opens a bag only when `GetContainerNumSlots(id) > 0`; ours keeps
|
||
-- that gate for 1..4 and exempts bag 0, which always exists (the same rule `OpenAllBags`
|
||
-- above already applies, for the same reason).
|
||
function OpenBag(id)
|
||
id = id or 0
|
||
if id ~= 0 and GetContainerNumSlots(id) <= 0 then return end
|
||
local frame = getglobal(BENILLA_BAG_WINDOWS[id + 1])
|
||
if frame and not frame:IsShown() then
|
||
BenillaBagWindow_Repaint(frame)
|
||
frame:Show()
|
||
end
|
||
end
|
||
|
||
function CloseBag(id)
|
||
local frame = getglobal(BENILLA_BAG_WINDOWS[(id or 0) + 1])
|
||
if frame and frame:IsShown() then frame:Hide() end
|
||
end
|
||
|
||
-- ONE STATED DIVERGENCE. The reference returns the INDEX of the ContainerFrame showing that
|
||
-- bag (1..NUM_CONTAINER_FRAMES) so its own code can `getglobal("ContainerFrame"..i)`; we
|
||
-- ship no such pool (each bag has one fixed window), so there is no index to name and this
|
||
-- answers 1 / nil. Every corpus caller — and the reference's own `ToggleBackpack` — uses it
|
||
-- as a boolean; a caller that indexed the result would already be reaching for frames that
|
||
-- do not exist here.
|
||
function IsBagOpen(id)
|
||
local frame = getglobal(BENILLA_BAG_WINDOWS[(id or 0) + 1])
|
||
if frame and frame:IsShown() then return 1 end
|
||
return nil
|
||
end
|
||
|
||
-- `ToggleBackpack()` — ref ContainerFrame.lua l.67-82, and NOT the all-bags toggle it was
|
||
-- here until 1494:
|
||
--
|
||
-- if ( IsBagOpen(0) ) then <hide every ContainerFrame> else ToggleBag(0) end
|
||
--
|
||
-- Open arm: `ToggleBag(0)`, the backpack ALONE (through the global, so a bag addon holding
|
||
-- `ToggleBag` gets it). Close arm: the ref's own frame sweep — every window, keyring
|
||
-- included — and NOT a `CloseAllBags()` call, because the reference does not make one here
|
||
-- and an addon holding that name would fire on a path the real client never runs it on.
|
||
-- The condition reads bag 0 SPECIFICALLY: with only bag 2 open, B opens the backpack
|
||
-- beside it rather than closing anything.
|
||
function ToggleBackpack()
|
||
if IsBagOpen(0) then
|
||
for _, name in ipairs(BENILLA_BAG_WINDOWS) do
|
||
local frame = getglobal(name)
|
||
if frame and frame:IsShown() then frame:Hide() end
|
||
end
|
||
local keyring = getglobal("BenillaKeyRingFrame")
|
||
if keyring and keyring:IsShown() then keyring:Hide() end
|
||
else
|
||
ToggleBag(0)
|
||
end
|
||
end
|
||
|
||
-- The backpack button (MainMenuBarBackpackButton): if any bag window is open, close them
|
||
-- all; otherwise open every existing bag (ref ToggleBackpack — "if numOpen > 0 then
|
||
-- CloseAllBags() else OpenAllBags()").
|
||
--
|
||
-- ONE STATED DIVERGENCE from ref BackpackButton_OnClick (MainMenuBarBagButtons.lua
|
||
-- l.55-69). The ref's tail re-derives the checked state from a scan of its NATIVE
|
||
-- ContainerFrames — and OnShow/OnHide dispatch is SYNCHRONOUS in the reference (wow-re
|
||
-- `onshow-onhide-dispatch-order.md`: Show binder 0x775750 → transition 0x76ae10 → notify
|
||
-- 0x76b260 → lua_pcall, every hop a direct call), so when an addon owns the bags its
|
||
-- OnShow's `SetChecked(1)` (Bagnon.lua l.33) lands FIRST and the ref tail stomps it: on
|
||
-- the real client the backpack button ends UNLIT after clicking it with Bagnon, and
|
||
-- lights only via the key binding (whose body is the bare `ToggleBackpack()`, no tail).
|
||
-- That click-path outcome contradicts the addon's evident intent and the director's call,
|
||
-- so ours swaps the scan for the auto-toggle UNDO below: checked belongs to the WINDOWS'
|
||
-- OnShow/OnHide writes — ours (BenillaBagFrame_OnShow/_OnHide) and any addon's alike —
|
||
-- and this handler only repairs what the CheckButton widget flipped before it ran. Every
|
||
-- stock outcome is identical to the ref's (the transition writes land inside
|
||
-- ToggleBackpack and are the last word); the addon case ends lit instead of stomped.
|
||
-- The widget-flip UNDO itself lives in the button's XML <OnClick> wrapper — the one seat
|
||
-- where the CheckButton auto-toggle has just happened — so every DIRECT caller of this
|
||
-- function (the tests, a macro) gets pure toggle semantics with no checked bookkeeping
|
||
-- to corrupt.
|
||
function BenillaBagToggle_OnClick()
|
||
-- Through the GLOBAL, so an addon that replaced `ToggleBackpack` gets the click.
|
||
ToggleBackpack()
|
||
end
|
||
|
||
-- The window's bar button (ref ContainerFrame_OnShow/OnHide: bag 0 →
|
||
-- MainMenuBarBackpackButton, bags 1..4 → CharacterBag(N-1)Slot).
|
||
function BenillaBagWindow_BarButton(frame)
|
||
local name = frame:GetName()
|
||
if name == "BenillaKeyRingFrame" then return getglobal("KeyRingButton") end
|
||
for bagId = 0, 4 do
|
||
if name == BENILLA_BAG_WINDOWS[bagId + 1] then
|
||
if bagId == 0 then return getglobal("MainMenuBarBackpackButton") end
|
||
return getglobal("CharacterBag" .. (bagId - 1) .. "Slot")
|
||
end
|
||
end
|
||
end
|
||
|
||
-- Open/close sounds — the window-sound convention (decision 0090), wrapper form: a named
|
||
-- Benilla<Window>Frame_OnShow/_OnHide fn (used when the handler is more than the bare
|
||
-- PlaySound, or — as here — to carry the cite). Kits quoted from the real ContainerFrame.lua
|
||
-- ContainerFrame_OnShow/OnHide (l.124-142 / l.100-122), reused VERBATIM by every window
|
||
-- (backpack included), INCLUDING the real fn's keyring fork: the keyring has its own
|
||
-- jingling KeyRingOpen/KeyRingClose pair (both real SoundEntries kits), every other window
|
||
-- the plain igBackPackOpen/igBackPackClose. Fired on every visibility transition (a Show/Hide
|
||
-- from a toggle button, a bag binding, a close button, or ESC), never at load (every window
|
||
-- is authored hidden="true", so none ever transitions on startup).
|
||
--
|
||
-- The `this` legacy global (RF-0025, script/event.rs) names the window that just
|
||
-- shown/hidden — used here for the open-window STACK the layout law below reads, rather
|
||
-- than a per-window OnShow/OnHide body (which would defeat the whole point of sharing one
|
||
-- handler across five windows).
|
||
function BenillaBagFrame_OnShow()
|
||
if this:GetID() == KEYRING_CONTAINER then
|
||
PlaySound("KeyRingOpen")
|
||
else
|
||
PlaySound("igBackPackOpen")
|
||
end
|
||
-- The bar lights the open bag's button (ref ContainerFrame_OnShow l.124-131,
|
||
-- SetChecked(1)) — the window side is the source of truth, so a bag opened by any
|
||
-- path (the B key, a bar click, open-all at a vendor) lights its button.
|
||
local barButton = BenillaBagWindow_BarButton(this)
|
||
if barButton then barButton:SetChecked(1) end
|
||
BenillaBagStack_Open(this)
|
||
end
|
||
|
||
function BenillaBagFrame_OnHide()
|
||
if this:GetID() == KEYRING_CONTAINER then
|
||
PlaySound("KeyRingClose")
|
||
else
|
||
PlaySound("igBackPackClose")
|
||
end
|
||
-- ...and clears it on any close (ref ContainerFrame_OnHide l.84-95, SetChecked(0)).
|
||
local barButton = BenillaBagWindow_BarButton(this)
|
||
if barButton then barButton:SetChecked(0) end
|
||
BenillaBagStack_Close(this)
|
||
end
|
||
|
||
-- ── The open-bag stack + layout law (ref ContainerFrame1.bags +
|
||
-- updateContainerFrameAnchors, ContainerFrame.lua:472-552, transcribed shape) ─────────────
|
||
-- Open windows stack bottom-right UPWARD in show order: the first at the bottom-right
|
||
-- CLEARANCE CORNER, each next one anchored above the previous (TOPRIGHT → BOTTOMRIGHT,
|
||
-- CONTAINER_SPACING=0 gap); when a stack would run off the top of the screen, the NEXT
|
||
-- window starts a fresh column one CONTAINER_WIDTH further left.
|
||
-- Out of scope (nothing here ever needs it): the ref's UI-scale/BankFrame-collision shrink
|
||
-- branch (l.505-539) — benilla has no uiScale CVar and no bank window yet.
|
||
--
|
||
-- The corner is `CONTAINER_OFFSET_X`/`CONTAINER_OFFSET_Y` — the two GLOBALS
|
||
-- `UIParent_ManageFramePositions()` recomputes every time the bottom of the screen fills up
|
||
-- or empties (UIParent.xml's var rows). Reading them live is the whole point and it is
|
||
-- load-bearing, not tidiness: this file used to keep its own `local
|
||
-- BENILLA_CONTAINER_OFFSET_X/Y = 0/70` shadow pair, which meant the stack sat at the
|
||
-- no-bars-raised corner FOREVER — with a bottom multibar up, the lowest bag window drew
|
||
-- straight through the bar's buttons (director-caught, decision 1499). A shadow copy of a
|
||
-- managed value cannot be kept in sync by anyone; the fix is to have no copy.
|
||
-- `BenillaBagStack_Relayout` is registered as a managed-position LISTENER at the end of this
|
||
-- file, so a bar raised while bags are open re-seats them on the same pass that moves the
|
||
-- cast bar and the chat frames.
|
||
BENILLA_BAG_STACK = {}
|
||
local BENILLA_CONTAINER_WIDTH = 192
|
||
local BENILLA_CONTAINER_SPACING = 0
|
||
local BENILLA_VISIBLE_CONTAINER_SPACING = 3
|
||
|
||
function BenillaBagStack_Open(frame)
|
||
table.insert(BENILLA_BAG_STACK, frame)
|
||
BenillaBagStack_Relayout()
|
||
end
|
||
|
||
function BenillaBagStack_Close(frame)
|
||
for i = 1, table.getn(BENILLA_BAG_STACK) do
|
||
if BENILLA_BAG_STACK[i] == frame then
|
||
table.remove(BENILLA_BAG_STACK, i)
|
||
break
|
||
end
|
||
end
|
||
BenillaBagStack_Relayout()
|
||
end
|
||
|
||
function BenillaBagStack_Relayout()
|
||
-- Read the clearance corner FRESH on every pass — never cached in a local that outlives
|
||
-- the call (see the law above). The `or` fallbacks cover the per-window test harnesses
|
||
-- that load this file without UIParent.xml: with no manage pass in the VM the globals
|
||
-- are nil, and the no-bars-raised corner is the right answer there by construction.
|
||
local offsetX = CONTAINER_OFFSET_X or 0
|
||
local offsetY = CONTAINER_OFFSET_Y or 70
|
||
local screenHeight = GetScreenHeight()
|
||
local freeHeight = screenHeight - offsetY
|
||
local column = 0
|
||
for i = 1, table.getn(BENILLA_BAG_STACK) do
|
||
local frame = BENILLA_BAG_STACK[i]
|
||
if i == 1 then
|
||
frame:SetPoint("BOTTOMRIGHT", -offsetX, offsetY)
|
||
elseif freeHeight < frame:GetHeight() then
|
||
column = column + 1
|
||
freeHeight = screenHeight - offsetY
|
||
frame:SetPoint("BOTTOMRIGHT",
|
||
-(column * BENILLA_CONTAINER_WIDTH) - offsetX,
|
||
offsetY)
|
||
else
|
||
frame:SetPoint("BOTTOMRIGHT", BENILLA_BAG_STACK[i - 1], "TOPRIGHT", 0, BENILLA_CONTAINER_SPACING)
|
||
end
|
||
freeHeight = freeHeight - frame:GetHeight() - BENILLA_VISIBLE_CONTAINER_SPACING
|
||
end
|
||
end
|
||
|
||
-- The stack is a CONSUMER of two managed vars, so it joins the pass's listener list: the
|
||
-- pass writes CONTAINER_OFFSET_X/Y and then calls everything registered here, which is how
|
||
-- an open bag stack gets out of the way of a bar raised underneath it. (The reference does
|
||
-- the same thing by hard-calling `updateContainerFrameAnchors()` from the end of its own
|
||
-- pass — UIParent.lua:1774; ours is that call generalized so the next var consumer does not
|
||
-- have to edit UIParent.xml to be noticed. Decision 1499.) Existence-guarded for the
|
||
-- harnesses that load this file alone.
|
||
if UIParent_RegisterManagedPositionListener then
|
||
UIParent_RegisterManagedPositionListener(BenillaBagStack_Relayout)
|
||
end
|
||
|
||
-- ── The bag bar (decision 0216 slice 2) — four 30×30 buttons left of MainMenuBarBackpackButton,
|
||
-- mirroring the reference main-bar bag buttons (CharacterBag0..3Slot). No exact reference
|
||
-- XML was available to transcribe (not in the session's extracted set) — size (30×30) and
|
||
-- placement (left of the backpack button) are per the brief; inter-button spacing is an
|
||
-- authored assumption (2px), FLAGGED for the director's look. Each button shows the
|
||
-- equipped bag's own icon (GetInventoryItemTexture, inv slots 20..23 — Bag0Slot..Bag3Slot,
|
||
-- PaperDollItemFrame.dbc-verified, decision 0216 slice 2's char-feed extension) or the
|
||
-- empty-slot art when no bag is equipped there. Click toggles that bag's window — NAMED
|
||
-- DEFERRAL: no drag-to-equip a bag onto the bar yet (that's the paper-doll drag arc, slice
|
||
-- 3's scope, not this one).
|
||
-- The bag bar (and the backpack toggle) are RELOCATED onto the action bar — anchored into
|
||
-- MainMenuBarArtFrame's bottom-right — which means they need seating one frame level
|
||
-- above the bar art or it paints over their icons. That lever lives with the frame it's
|
||
-- about: BenillaActionBarArt_SeatAbove (ActionBar.xml, loaded before this file), which
|
||
-- carries the full explanation; the micro-button row is its second caller. Called
|
||
-- nil-GUARDED here: the shipped load order always has the bar first, but ~25 bag/bank/
|
||
-- escape/merchant test harnesses load THIS file alone — and with no bar loaded there is by
|
||
-- definition no bar art to seat above, so the guard's no-op is the right answer, not a
|
||
-- swallowed failure.
|
||
|
||
-- Bag0Slot..Bag3Slot = live inv ids 20..23 (char_stats.rs SLOT_INFO, DBC-verified); OUR bag
|
||
-- ids 1..4 map the same way (bagId N ⇒ inv slot 19+N), the id PickupInventoryItem/
|
||
-- GetInventoryItemTexture speak.
|
||
function BenillaBagBarSlot_InvSlot(button) return 19 + button.bagId end
|
||
|
||
function BenillaBagBarSlot_OnLoad(button, bagId)
|
||
button.bagId = bagId
|
||
-- The button's ID is the REFERENCE's: its 1-based inventory slot, 20..23 (the real
|
||
-- client gets there through PaperDollItemSlotButton_OnLoad, which resolves
|
||
-- "CharacterBag0Slot" → "Bag0Slot" → GetInventorySlotInfo → 20). Nothing of ours reads
|
||
-- it — every body here goes through `button.bagId` — but every ADDON does:
|
||
-- `Bagnon.lua:104` computes its highlight target as `this:GetID() - 19`, and against
|
||
-- an unset id that is -19, so Bagnon highlighted the wrong bag (silently, with no
|
||
-- raise) on every bag-slot hover. `isBag` is the same story from the same template
|
||
-- (ref BagSlotButtonTemplate OnLoad l.33), read by KeyRingItemButton_OnClick.
|
||
button:SetID(19 + bagId)
|
||
button.isBag = 1
|
||
button.icon = getglobal(button:GetName() .. "IconTexture")
|
||
if BenillaActionBarArt_SeatAbove then BenillaActionBarArt_SeatAbove(button) end
|
||
-- Both buttons (ref BagSlotButtonTemplate inherits PaperDollItemSlotButtonTemplate, and
|
||
-- its OnLoad calls PaperDollItemSlotButton_OnLoad — PaperDollFrame.lua:86 — so a bag-bar
|
||
-- slot registers the pair like every doll slot; MainMenuBarBagButtons.xml:78 does the
|
||
-- same for the backpack). BagSlotButton_OnClick reads no button: right-click opens the
|
||
-- bag, exactly as left does.
|
||
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
-- Drag-to-equip (decision 0208 phase 1b's deferred bag-icon arm, now landed): the bar
|
||
-- slot is a paper-doll equipment slot for bags. LEFT drag picks the equipped bag up;
|
||
-- a drag/receive drops a carried bag in to equip it (PickupInventoryItem — the exact
|
||
-- doll-slot transition, the app maps id 20..23 onto wire bag slots 19..22).
|
||
button:RegisterForDrag("LeftButton")
|
||
button:RegisterEvent("UNIT_INVENTORY_CHANGED")
|
||
button:RegisterEvent("BAG_UPDATE")
|
||
button:RegisterEvent("ITEM_LOCK_CHANGED")
|
||
BenillaBagBarSlot_Update(button)
|
||
end
|
||
|
||
-- Placing/equipping a carried bag (or picking the equipped one up) rides PickupInventoryItem,
|
||
-- exactly like a paper-doll slot; the empty-cursor plain click just toggles the bag's window.
|
||
function BenillaBagBarSlot_Place(button)
|
||
PickupInventoryItem(BenillaBagBarSlot_InvSlot(button))
|
||
BenillaBagBarSlot_Update(button)
|
||
end
|
||
|
||
-- ref BagSlotButton_OnClick (MainMenuBarBagButtons.lua l.3-21): the cursor arm first (the
|
||
-- ref's PutItemInBag; ours is the equip/swap PickupInventoryItem arm, decision 0208 1b),
|
||
-- otherwise the toggle goes THROUGH THE GLOBAL `ToggleBag` — the exact name
|
||
-- Bagnon_Core/Overrides.lua replaces — with the ref's own button sound on that arm only.
|
||
-- Toggling the window directly here (what this did before) made every bag addon's override
|
||
-- silently inert for the four slot buttons while the backpack button honoured it: the
|
||
-- 517-line rule above ("the reference's names are the real entry points") applied to only
|
||
-- one of the five buttons, and the director met the other four.
|
||
function BenillaBagBarSlot_OnClick(button)
|
||
if CursorHasItem() then
|
||
BenillaBagBarSlot_Place(button) -- drop/equip the carried bag onto this slot
|
||
else
|
||
ToggleBag(button.bagId)
|
||
PlaySound("BAGMENUBUTTONPRESS")
|
||
end
|
||
-- The click's own CheckButton auto-toggle is provisional — re-derive from the NATIVE
|
||
-- window on every branch, the ref's exact tail (BagSlotButton_OnClick l.12-20 scans
|
||
-- ContainerFrame1..N: SetChecked(isVisible) whether the click toggled, placed a bag,
|
||
-- or did nothing). Reading the WINDOW rather than what ToggleBag did is load-bearing
|
||
-- both ways: stock, the flag is already set when the tail runs; with an addon holding
|
||
-- the bags, the native stays hidden and the slot button stays unlit — the reference's
|
||
-- own behaviour (its scan is equally blind to addon frames).
|
||
local frame = getglobal("BenillaBagFrame" .. button.bagId)
|
||
button:SetChecked(frame and frame:IsShown())
|
||
end
|
||
|
||
function BenillaBagBarSlot_OnEvent(button)
|
||
if event == "UNIT_INVENTORY_CHANGED" and arg1 ~= "player" then return end
|
||
-- ITEM_LOCK_CHANGED names its slot in arg1/arg2; the bar's slots are the EQUIPMENT_BAG
|
||
-- space, so a bag-window lock event (a real bag id in arg1) never concerns the icon —
|
||
-- repainting anyway is idempotent (the lock read below is slot-specific). BAG_UPDATE
|
||
-- fires per-bag-CONTENTS change, not per-icon change (the icon is the bag ITEM's own
|
||
-- texture) — repainting on it too covers the freshly-equipped-bag-template-in-flight frame.
|
||
BenillaBagBarSlot_Update(button)
|
||
end
|
||
|
||
-- ── The bar buttons' hovers ───────────────────────────────────────────────────────────
|
||
-- ref GlobalStrings.lua l.132 / l.1458 (enUS), fallback form: the real localized
|
||
-- GlobalStrings.lua runs before this file at runtime (ui_script/mod.rs), so these only
|
||
-- fill in for the harnesses that load no patch chain.
|
||
BACKPACK_TOOLTIP = BACKPACK_TOOLTIP or "Backpack"
|
||
EQUIP_CONTAINER = EQUIP_CONTAINER or "Equip Container"
|
||
-- ref GlobalStrings.lua l.2472 / l.2810 — the keyring's window title + button tooltip, and
|
||
-- the full-keyring refusal.
|
||
KEYRING = KEYRING or "Keyring"
|
||
NO_EMPTY_KEYRING_SLOTS_ERROR = NO_EMPTY_KEYRING_SLOTS_ERROR or "Your keyring is full."
|
||
|
||
-- Both are PLAIN tooltips — the reference calls GameTooltip:SetText here, not
|
||
-- GameTooltip_AddNewbieTip, so unlike the micro buttons next door (0661) there is no second
|
||
-- explanation line to be missing. They also anchor beside the button (ANCHOR_LEFT, so the
|
||
-- plate opens toward screen center off a bottom-right button), NOT at the default corner.
|
||
--
|
||
-- ref MainMenuBarBackpackButton OnEnter (ref-MainMenuBarBagButtons.xml l.91-99). The ref
|
||
-- appends the live binding key with GameTooltip:AppendText; ours concatenates the same
|
||
-- suffix from a LIVE GetBindingKey read since 0997, rendered through the Key Bindings
|
||
-- window's display law when it is loaded. Unbound: the bare label, the ref's own read.
|
||
-- The command is TOGGLEBACKPACK — the ref's own read here, and since 1494 ours too: it is
|
||
-- the key that runs what a plain click on this button runs.
|
||
function BenillaBagToggle_OnEnter(button)
|
||
if not GameTooltip then return end -- engine tests load file subsets
|
||
GameTooltip:SetOwner(button, "ANCHOR_LEFT")
|
||
local text = BACKPACK_TOOLTIP
|
||
local key = GetBindingKey("TOGGLEBACKPACK")
|
||
if key then
|
||
if KeyBindings_KeyText then key = KeyBindings_KeyText(key) end
|
||
text = text .. " " .. NORMAL_FONT_COLOR_CODE .. "(" .. key .. ")" .. FONT_COLOR_CODE_CLOSE
|
||
end
|
||
GameTooltip:SetText(text, 1.0, 1.0, 1.0)
|
||
end
|
||
|
||
-- ref BagSlotButton_OnEnter (ref-MainMenuBarBagButtons.lua l.86-96): the equipped bag's own
|
||
-- item tooltip, or "Equip Container" for an empty slot. The ref's "(F8)".."(F11)" suffix
|
||
-- needed GetBindingKey AND the TOGGLEBAG1..4 bindings; those bind as of 1494, so the ONE
|
||
-- thing still missing is `GameTooltip:AppendText` — our tooltip has SetText/AddLine and no
|
||
-- append verb, and the ref's suffix lands on a plate SetInventoryItem already wrote. That
|
||
-- verb's byte semantics (which line does it extend?) are unverified, so the suffix waits
|
||
-- rather than guessing; this is where it goes, over `GetBindingKey("TOGGLEBAG"..(5 -
|
||
-- button.bagId))` — the ref's index is REVERSED against the bar, so the slot nearest the
|
||
-- backpack (bagId 1) is TOGGLEBAG4/F11 and the farthest (bagId 4) is TOGGLEBAG1/F8.
|
||
function BenillaBagBarSlot_OnEnter(button)
|
||
if not GameTooltip then return end
|
||
GameTooltip:SetOwner(button, "ANCHOR_LEFT")
|
||
if not GameTooltip:SetInventoryItem("player", BenillaBagBarSlot_InvSlot(button)) then
|
||
GameTooltip:SetText(EQUIP_CONTAINER, 1.0, 1.0, 1.0)
|
||
end
|
||
end
|
||
|
||
-- `BagSlotButton_OnEnter()` — THE REFERENCE'S NAME for the hover above, and the entry point
|
||
-- the four `CharacterBag<N>Slot` buttons actually call (their XML below). Published for the
|
||
-- same standing reason `ToggleBackpack` is: an addon replaces the client's global and
|
||
-- expects the client to call the replacement.
|
||
--
|
||
-- `Bagnon.lua:67` is the exact shape, and it is a hover-frequency call, not a rare one:
|
||
-- bBagSlotButton_OnEnter = BagSlotButton_OnEnter -- capture ours
|
||
-- BagSlotButton_OnEnter = BagnonBlizBag_OnEnter -- replace the global
|
||
-- Bagnon's replacement highlights the matching slots in its own window and then calls the
|
||
-- capture. With the global absent that capture was nil, and — because nothing here ever
|
||
-- looked the global up — the replacement was never reached to raise on it: Bagnon's
|
||
-- highlight was simply, silently inert. Corpus demand is exactly one addon (this one) at
|
||
-- two sites; its siblings `BagSlotButton_OnClick`/`_OnDrag`/`_OnShiftClick`/
|
||
-- `BackpackButton_OnClick` score ZERO and are deliberately not published (1210).
|
||
--
|
||
-- The reference's body takes no argument and reads `this`; so does this one.
|
||
function BagSlotButton_OnEnter()
|
||
BenillaBagBarSlot_OnEnter(this)
|
||
end
|
||
|
||
-- ref OnLeave for both (l.100-102 / the template's own): a plain Hide, no fade — the item
|
||
-- half of the split BenillaUnitFrame_OnLeave's comment describes.
|
||
function BenillaBagBarButton_OnLeave()
|
||
if GameTooltip then GameTooltip:Hide() end
|
||
end
|
||
|
||
-- ── The keyring (decision 0765) ──────────────────────────────────────────────────────────
|
||
-- ref ToggleKeyRing (ContainerFrame.lua:757-771). The reference generates the window on
|
||
-- demand from a pool of generic ContainerFrames sized to GetKeyRingSize(); ours is a fixed
|
||
-- window like the other six, so the toggle is the bag bar's own show/hide shape and the
|
||
-- size arrives through the feed. The ref's IsOptionFrameOpen() guard has no analogue here
|
||
-- (our bag-bar buttons carry none either — the game menu greys the row instead, 0674), and
|
||
-- its SetButtonPulse stop is moot with no pulse to stop (0304).
|
||
function ToggleKeyRing()
|
||
local frame = getglobal("BenillaKeyRingFrame")
|
||
if not frame then return end
|
||
if frame:IsShown() then
|
||
frame:Hide()
|
||
else
|
||
BenillaBagWindow_Update(frame)
|
||
frame:Show()
|
||
end
|
||
end
|
||
|
||
-- ref PutKeyInKeyRing (ContainerFrame.lua:740-755) — dropping a held key onto the keyring
|
||
-- BUTTON files it in the first free slot. "Pick up" from an empty slot IS the place gesture
|
||
-- (PickupContainerItem is the one entry point: empty cursor picks up, a held cursor places),
|
||
-- which is why the reference's own line reads as a pickup.
|
||
--
|
||
-- One deliberate un-quirking: the ref passes `NO_EMPTY_KEYRING_SLOTS`, but GlobalStrings
|
||
-- only ever defined `NO_EMPTY_KEYRING_SLOTS_ERROR` — so the real client silently prints
|
||
-- nothing when your keyring is full. We print the string that exists.
|
||
function PutKeyInKeyRing()
|
||
for i = 1, GetKeyRingSize() do
|
||
-- Occupancy is `texture or itemCount`, not `texture` alone. The reference tests
|
||
-- the texture (ContainerFrame_Update) because ITS client always has the icon by
|
||
-- the time a slot is populated; ours can hold an item whose icon has not resolved
|
||
-- yet, and reading that as an empty slot would file the key on top of it
|
||
-- (decision 1199 — the transient our five-value shape exposed).
|
||
local texture, itemCount = GetContainerItemInfo(KEYRING_CONTAINER, i)
|
||
if texture == nil and itemCount == nil then
|
||
PickupContainerItem(KEYRING_CONTAINER, i)
|
||
return
|
||
end
|
||
end
|
||
if UIErrorsFrame then
|
||
UIErrorsFrame:AddMessage(NO_EMPTY_KEYRING_SLOTS_ERROR, 1.0, 0.1, 0.1)
|
||
end
|
||
end
|
||
|
||
-- ref KeyRingButton's OnLoad/OnClick/OnReceiveDrag (MainMenuBarBagButtons.xml l.142-199).
|
||
-- The button is authored HIDDEN and only ever revealed by MainMenuBar_UpdateKeyRing
|
||
-- (ActionBar.xml), which is where the whole show/hide law and its divergence note live.
|
||
function BenillaKeyRingButton_OnLoad(button)
|
||
button:SetID(KEYRING_CONTAINER)
|
||
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
button:RegisterForDrag("LeftButton")
|
||
-- The ref watches PLAYER_ENTERING_WORLD / VARIABLES_LOADED / BAG_UPDATE on the bar's art
|
||
-- frame; with no saved variable there is nothing for VARIABLES_LOADED to restore, and
|
||
-- BAG_UPDATE is what actually carries "a key just arrived".
|
||
button:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||
button:RegisterEvent("BAG_UPDATE")
|
||
if BenillaActionBarArt_SeatAbove then BenillaActionBarArt_SeatAbove(button) end
|
||
BenillaKeyRingButton_OnEvent()
|
||
end
|
||
|
||
function BenillaKeyRingButton_OnEvent()
|
||
if MainMenuBar_UpdateKeyRing then MainMenuBar_UpdateKeyRing() end
|
||
end
|
||
|
||
function BenillaKeyRingButton_OnClick(button)
|
||
-- Holding something ⇒ file it; empty-handed ⇒ open/close the keyring (ref l.166-173).
|
||
if CursorHasItem() then
|
||
PutKeyInKeyRing()
|
||
else
|
||
ToggleKeyRing()
|
||
end
|
||
-- Re-derive the lit ring from the window, the same provisional-toggle tail every other
|
||
-- bag-bar button uses.
|
||
local frame = getglobal("BenillaKeyRingFrame")
|
||
button:SetChecked(frame and frame:IsShown())
|
||
end
|
||
|
||
-- ref l.180-184: the plain KEYRING title plus the ref's own empty AddLine (which reserves
|
||
-- the second row the binding key would print into — we ship no TOGGLEKEYRING binding, the
|
||
-- same gap the bag slots' "(F1)".."(F4)" suffixes have).
|
||
function BenillaKeyRingButton_OnEnter(button)
|
||
if not GameTooltip then return end
|
||
GameTooltip:SetOwner(button, "ANCHOR_LEFT")
|
||
GameTooltip:SetText(KEYRING, 1.0, 1.0, 1.0)
|
||
end
|
||
|
||
function BenillaBagBarSlot_Update(button)
|
||
local invSlot = BenillaBagBarSlot_InvSlot(button)
|
||
local texture = GetInventoryItemTexture("player", invSlot)
|
||
button.icon:SetTexture(texture or "Interface\\PaperDoll\\UI-PaperDoll-Slot-Bag")
|
||
-- Dim while the bag is up on the cursor or a pending equip is in flight (the doll's own
|
||
-- drag feedback, IsInventoryItemLocked — the bag-slot twin of BenillaBagSlot_Update).
|
||
if IsInventoryItemLocked(invSlot) then
|
||
button.icon:SetVertexColor(0.4, 0.4, 0.4)
|
||
elseif button:IsEnabled() then
|
||
button.icon:SetVertexColor(1, 1, 1)
|
||
else
|
||
-- Disabled by Disable_BagButtons below: keep the grey. The reference needs no such
|
||
-- arm — its desaturation is a shader flag on the texture, untouched by an Update
|
||
-- that only re-sets the image — but ours IS a vertex colour (UiPanels.xml
|
||
-- SetDesaturation), so a bag update behind the open game menu would otherwise
|
||
-- repaint the icon bright under a button that stayed dead.
|
||
button.icon:SetVertexColor(0.5, 0.5, 0.5)
|
||
end
|
||
end
|
||
|
||
-- ── The item-push drop animation (decision 0887) ─────────────────────────────────────────
|
||
-- An item lands in a bag: its icon pops in above the bag bar, hangs there, then falls into
|
||
-- the button that took it and shrinks away. ref ItemAnim (MainMenuBarBagButtons.xml l.4-16 +
|
||
-- .lua l.68-80, .lua l.92-94): each bag button owns a hidden child that, on ITEM_PUSH
|
||
-- naming its own container, swaps in the pushed item's icon, rewinds to sequence time 0 and
|
||
-- shows itself; OnAnimFinished hides it again. A second push on the same button RESTARTS it
|
||
-- (SetSequenceTime(0,0)); pushes into different bags run independently. That is exactly the
|
||
-- machine below, with the reference's ITEM_PUSH `arg1` translated from its inventory-slot
|
||
-- vocabulary (20..23) into ours (bagId 1..4) app-side — ui_loot.rs `push_container` carries
|
||
-- the byte-verified selector.
|
||
--
|
||
-- The reference's is a <Model> playing Interface\ItemAnimations\ForcedBackpackItem.mdx — a
|
||
-- single 4-vertex quad on one animated bone, i.e. a 2D icon card with keyframed scale, alpha
|
||
-- and offset. benilla has no Model widget (decision 0137's Cooldown took the same posture:
|
||
-- model the mechanism, let our own renderer draw it), so it is a Texture driven by the
|
||
-- model's OWN tracks, read out of the shipped .m2 with `benilla-extract m2anim`/`m2bones`:
|
||
--
|
||
-- sequence 0, CLAMP (plays once), duration 1.000 s
|
||
-- texture-weight (alpha) 0.000→0.0 0.133→1.0 0.267→1.0 1.000→0.0 linear
|
||
-- bone 0 scale 0.000→1.0 0.133→1.2 0.267→1.0 1.000→0.014 linear
|
||
-- bone 0 translation 0.000→(0,0) 0.500→(0,0) 1.000→(+0.010,-0.040)
|
||
-- the quad itself: 0.03 x 0.03 model units, blend Alpha, unlit, no depth write
|
||
--
|
||
-- So: fade in over the first 133 ms while swelling to 1.2x; settle back to full size by
|
||
-- 267 ms; from there dwindle and fade continuously for the remaining 733 ms — while the
|
||
-- POSITION holds until the half-second and only then falls. The three tracks deliberately
|
||
-- do not share a schedule: the card is already down to ~0.69 size and ~0.68 alpha when it
|
||
-- starts moving, so the drop reads as the icon being drawn into the bag rather than as a
|
||
-- solid tile sliding. Those numbers are the file's, not ours.
|
||
--
|
||
-- THE MODEL-UNIT → PIXEL SCALE is no longer ours to calibrate: the <Model> widget's
|
||
-- projection is RE-recorded now (wow-re `system/ui/scratch/modelframe-animation-clock.md`,
|
||
-- dispatched over the pet bar's B228 and folded back with it). The ortho leg gives
|
||
--
|
||
-- px per model unit = (5/3) * modelScale * layoutScale * screenHeightPx
|
||
--
|
||
-- which in FrameXML units is **1280 * modelScale * layoutScale**, aspect- and
|
||
-- resolution-independent, with the model ORIGIN at the frame rect's bottom-left. The ref's
|
||
-- `ItemAnimTemplate` (MainMenuBarBagButtons.xml:4) carries **no `scale` attribute**, so
|
||
-- modelScale is 1 and the constant is a flat 1280. Decision 0887's named gap is closed.
|
||
--
|
||
-- This REPLACES a back-fit, and the back-fit is worth naming because it looked like
|
||
-- evidence. The old 1200 came from assuming CooldownFrameTemplate's 0.04-unit sweep
|
||
-- *exactly* covers a 36 px action button at its scale="0.75" (⇒ K = 1200). The assumption
|
||
-- is the error: at the real projection that sweep is 0.04 · 1280 · 0.75 = **38.4 px**, so
|
||
-- it overhangs its button by 6.7% rather than fitting it — exactly as the autocast shine's
|
||
-- 30.72 px square overhangs its 30 px button. Solving against a wrong premise produced a
|
||
-- number that then "cross-checked" against a second model derived the same wrong way, and
|
||
-- both files cited the agreement as the reason to trust it.
|
||
--
|
||
-- Everything below is the model's own ratios times this constant, so the correction lands
|
||
-- in one place and the animation stays in proportion.
|
||
BENILLA_ITEM_PUSH_PX_PER_UNIT = 1280
|
||
BENILLA_ITEM_PUSH_DURATION = 1.0
|
||
|
||
-- ── The widget rect, and why the card is not placed against the button ─────────────────
|
||
-- A `<Model>` with no `<Size>` and no `setAllPoints` takes its rect from the **M2 header
|
||
-- bounding box** (`MD20+0xB4`, max−min per axis), consumed RAW as layout units — unlike
|
||
-- CSimpleTexture's texel fallback, there is no AbsDimension conversion. So the ref's
|
||
-- ItemAnim widget is **42.41 x 124.72**, nothing like the 36-square everyone assumes from
|
||
-- looking at the XML, and **model-space (0,0,0) lands on that rect's BOTTOM-LEFT corner**.
|
||
-- (wow-re `system/ui/scratch/modelframe-implicit-size-law.md`, §5-cross-checked: vtable
|
||
-- 0x81c5d8 +0x1c/+0x20 -> 0x76d080/0x76d0d0, bbox source 0x713640 at `713661 add esi,0xb4`.
|
||
-- The one worker who read `MD20+0xD0` — the VertexBox — got an all-zero box and concluded
|
||
-- the widget was degenerate; that wrong premise is exactly what the pair round exists to
|
||
-- catch, and it is why this looked unresolvable in 0887.)
|
||
--
|
||
-- That rect is the whole reason this animation reads the way it does: it stands 124.72 tall
|
||
-- off the button's own bottom edge, so the card's travel band reaches **54 px above the
|
||
-- button's top**. Decision 0887 could not know that and placed the card against the
|
||
-- button's CENTER instead, which is what put it in the wrong place in x and gave it no
|
||
-- horizontal drift at all.
|
||
BENILLA_ITEM_PUSH_FRAME_W = 42.41
|
||
BENILLA_ITEM_PUSH_FRAME_H = 124.72
|
||
-- Where that rect hangs off the button: the ref anchors the widget's BOTTOMRIGHT to the
|
||
-- button's, 10 in from the right for the five bag buttons and flush (0) for the keyring —
|
||
-- MainMenuBarBagButtons.xml l.19-27 (BagSlotButtonTemplate) and l.152-160 (KeyRingButton).
|
||
-- Per-button, so it is an OnLoad argument, not a constant.
|
||
BENILLA_ITEM_PUSH_ANCHOR_X = -10
|
||
|
||
-- ── The model's own numbers, unrounded ────────────────────────────────────────────────
|
||
-- Every one of these was rounded in 0887 and every rounding moved the card. The quad span
|
||
-- read as 0.03 (it is 0.0288 — a 4% size error), and the translation as (0.010, -0.040)
|
||
-- (which alone accounts for half a pixel of the landing point).
|
||
--
|
||
-- The bone transform is `v' = pivot + T(t) + S(t) * (v - pivot)` — three wow-re workers
|
||
-- derived that independently in three matrix conventions and agreed. The pivot
|
||
-- (M2CompBone+0x60) is NOT the quad's centre: it sits 0.23 px right and 0.07 px above it,
|
||
-- so the card shrinks *almost* in place and drifts a fifth of a pixel doing it. Keeping
|
||
-- the pivot as its own term rather than folding it into the centre is what makes this
|
||
-- reproduce the reference exactly at all three sampled times instead of nearly.
|
||
-- Bone 0's ROTATION track is empty (nKeys = 0), so there is no roll to model.
|
||
BENILLA_ITEM_PUSH_PIVOT_X = 0.017580900341272354
|
||
BENILLA_ITEM_PUSH_PIVOT_Y = 0.053958501666784286
|
||
BENILLA_ITEM_PUSH_QUAD_X = 0.017400000942870975
|
||
BENILLA_ITEM_PUSH_QUAD_Y = 0.053900001570582390
|
||
BENILLA_ITEM_PUSH_QUAD_SPAN = 0.028800001833587885
|
||
|
||
-- {time, value} keyframes, linear between (M2 track interpolation 1) — the file's own keys,
|
||
-- at full precision. The three tracks keep DIFFERENT schedules and that is the whole feel:
|
||
-- the card fades up while swelling to 1.2x over 133 ms, settles back to full size at
|
||
-- 267 ms, then dwindles and fades *continuously* for the remaining 733 ms — while its
|
||
-- position holds until the half second and only then falls. So it is already at ~0.69 size
|
||
-- and ~0.68 alpha when it starts to move, and it is invisible by the time it lands.
|
||
BENILLA_ITEM_PUSH_ALPHA = { {0.000, 0.0}, {0.133, 1.0}, {0.267, 1.0}, {1.000, 0.0} }
|
||
BENILLA_ITEM_PUSH_SCALE = { {0.000, 1.0}, {0.133, 1.2000000476837158}, {0.267, 1.0}, {1.000, 0.01441549975425005} }
|
||
-- Translation is per-AXIS: the card falls 51.4 px and drifts 13.3 px RIGHT, so one shared
|
||
-- 0..1 "drop" curve (0887's shape) cannot express it — the old code had no horizontal term
|
||
-- at all and moved the card the wrong way in x when it inferred one.
|
||
BENILLA_ITEM_PUSH_TRANS_X = { {0.000, 0.0}, {0.500, 0.0}, {1.000, 0.010394600220024586} }
|
||
BENILLA_ITEM_PUSH_TRANS_Y = { {0.000, 0.0}, {0.500, 0.0}, {1.000, -0.040167398750782013} }
|
||
|
||
-- Sample a {time, value} keyframe list at `t`, linear between keys, clamped at both ends
|
||
-- (the M2 sampler's own shape for a CLAMP sequence).
|
||
function BenillaItemPushAnim_Sample(track, t)
|
||
local last = table.getn(track)
|
||
if t <= track[1][1] then return track[1][2] end
|
||
for i = 2, last do
|
||
local key = track[i]
|
||
if t <= key[1] then
|
||
local prev = track[i - 1]
|
||
local span = key[1] - prev[1]
|
||
if span <= 0 then return key[2] end
|
||
return prev[2] + (key[2] - prev[2]) * (t - prev[1]) / span
|
||
end
|
||
end
|
||
return track[last][2]
|
||
end
|
||
|
||
-- Place/size/fade the card for the current clock, from the model's own transform.
|
||
--
|
||
-- The card's centre in MODEL space is `pivot + T(t) + S(t)*(quadCentre - pivot)`; times the
|
||
-- projection constant that is its offset in layout units from the model origin, which is
|
||
-- the widget rect's bottom-left corner. The rect's own BOTTOMRIGHT hangs off the button's,
|
||
-- so the card is placed against the BUTTON'S BOTTOMRIGHT — never its centre — and the
|
||
-- frame width is what converts between the two.
|
||
--
|
||
-- On screen: a button-sized card appears with its bottom edge ~13.6 px ABOVE the button's
|
||
-- top, pops to 1.2x and back while fading in, hangs there through the first half second,
|
||
-- then falls down-and-right INTO the button, shrinking to a half-pixel point at its centre
|
||
-- as it fades out. Reproduces the reference at t = 0, 0.133 and 1.0 to the hundredth of a
|
||
-- pixel (`modelframe-implicit-size-law.md` §3's table).
|
||
--
|
||
-- NOT modelled, deliberately, and both are named in the record: the reference's widget
|
||
-- CLIPS the card to its own rect, which shaves 1.94 px off the right edge at the 1.2x peak
|
||
-- **at 4:3 only** (16:10 and 16:9 clear it); and the widget clears the depth buffer inside
|
||
-- that 124.72-tall rect every paint. benilla draws this as a Texture, not a Model, so it
|
||
-- inherits neither — reproducing an aspect-conditional sliver would be hard-coding a
|
||
-- rendering artefact rather than modelling the mechanism that causes it.
|
||
function BenillaItemPushAnim_Paint(anim)
|
||
local t = anim.elapsed
|
||
local k = BENILLA_ITEM_PUSH_PX_PER_UNIT
|
||
local scale = BenillaItemPushAnim_Sample(BENILLA_ITEM_PUSH_SCALE, t)
|
||
local size = BENILLA_ITEM_PUSH_QUAD_SPAN * scale * k
|
||
local cx = (BENILLA_ITEM_PUSH_PIVOT_X
|
||
+ BenillaItemPushAnim_Sample(BENILLA_ITEM_PUSH_TRANS_X, t)
|
||
+ scale * (BENILLA_ITEM_PUSH_QUAD_X - BENILLA_ITEM_PUSH_PIVOT_X)) * k
|
||
local cy = (BENILLA_ITEM_PUSH_PIVOT_Y
|
||
+ BenillaItemPushAnim_Sample(BENILLA_ITEM_PUSH_TRANS_Y, t)
|
||
+ scale * (BENILLA_ITEM_PUSH_QUAD_Y - BENILLA_ITEM_PUSH_PIVOT_Y)) * k
|
||
anim:SetWidth(size)
|
||
anim:SetHeight(size)
|
||
anim:SetPoint("CENTER", anim:GetParent(), "BOTTOMRIGHT",
|
||
anim.anchorX - BENILLA_ITEM_PUSH_FRAME_W + cx, cy)
|
||
anim:SetAlpha(BenillaItemPushAnim_Sample(BENILLA_ITEM_PUSH_ALPHA, t))
|
||
end
|
||
|
||
-- ref ItemAnim_OnLoad (l.68-70): the card listens for ITEM_PUSH and nothing else. It is
|
||
-- authored hidden, so it costs no OnUpdate until a push shows it (events reach hidden
|
||
-- frames; OnUpdate does not — the reference's own split).
|
||
function BenillaItemPushAnim_OnLoad(anim, containerId, anchorX)
|
||
anim.containerId = containerId
|
||
-- The widget's own offset from the button's BOTTOMRIGHT: -10 for the five bag buttons,
|
||
-- flush 0 for the keyring (the ref's two different anchors — see the constant block).
|
||
anim.anchorX = anchorX or BENILLA_ITEM_PUSH_ANCHOR_X
|
||
anim.icon = getglobal(anim:GetName() .. "Icon")
|
||
anim.elapsed = 0
|
||
anim:RegisterEvent("ITEM_PUSH")
|
||
end
|
||
|
||
-- ref ItemAnim_OnEvent (l.72-80): `if this:GetParent():GetID() == arg1`, then
|
||
-- ReplaceIconTexture(arg2) / SetSequence(0) / SetSequenceTime(0,0) / Show. A push into a bag
|
||
-- with no button (a bank bag) matches nothing and animates nowhere, there and here.
|
||
function BenillaItemPushAnim_OnEvent(anim)
|
||
if arg1 ~= anim.containerId then return end
|
||
anim.icon:SetTexture(arg2)
|
||
anim.elapsed = 0
|
||
-- Seat the card above its button rather than at load: the bag bar's own level is set in
|
||
-- the BUTTON's OnLoad (BenillaActionBarArt_SeatAbove), which the loader may run after
|
||
-- this child exists. Re-deriving it per push is one call and can never read it stale.
|
||
anim:SetFrameLevel(anim:GetParent():GetFrameLevel() + 1)
|
||
BenillaItemPushAnim_Paint(anim)
|
||
anim:Show()
|
||
end
|
||
|
||
-- The CLAMP sequence's end is the ref's OnAnimFinished → this:Hide() (l.92-94).
|
||
function BenillaItemPushAnim_OnUpdate(anim, elapsed)
|
||
anim.elapsed = anim.elapsed + (elapsed or 0)
|
||
if anim.elapsed >= BENILLA_ITEM_PUSH_DURATION then
|
||
anim:Hide()
|
||
return
|
||
end
|
||
BenillaItemPushAnim_Paint(anim)
|
||
end
|
||
|
||
-- The bag BAR's five buttons (the backpack toggle + the four equipped-bag slots) — the row
|
||
-- Disable_/Enable_BagButtons greys as a unit. Distinct from UiPanels.xml's BAG_WINDOWS,
|
||
-- which is the five bag *windows* those buttons open.
|
||
BENILLA_BAG_BUTTONS = { "MainMenuBarBackpackButton", "CharacterBag0Slot", "CharacterBag1Slot",
|
||
"CharacterBag2Slot", "CharacterBag3Slot" }
|
||
|
||
-- Disable_BagButtons / Enable_BagButtons — ref MainMenuBarBagButtons.lua l.102-128, called
|
||
-- by GameMenuFrame's OnShow/OnHide (decision 0674) and by nothing else: while the game menu
|
||
-- holds the screen, the whole bag row greys out. That is the *visible* half of a rule the
|
||
-- panel manager already enforces (ShowUIPanel's native-center gate refuses every window
|
||
-- while the menu is up — UiPanels.xml `CanOpenPanels`); without it the bags would look
|
||
-- clickable and simply do nothing.
|
||
--
|
||
-- Mapping onto benilla's row: the ref's MainMenuBarBackpackButton is MainMenuBarBackpackButton and
|
||
-- CharacterBag0..3Slot are CharacterBag0Slot..4 — and in BOTH cases the greying goes onto
|
||
-- the button's `$parentIcon` LAYER texture, never onto a state texture. That is the
|
||
-- reference's own structure and it is load-bearing here: a disabled button draws its
|
||
-- DisabledTexture, and with none set it draws no state texture at all
|
||
-- (`ButtonState::region_visible`), so greying a NormalTexture would grey something already
|
||
-- gone. The four slots' UI-Quickslot2 rings ARE state textures and do vanish while
|
||
-- disabled unless the slot states one explicitly — so what you should see is the
|
||
-- ring stay put and the bag icon grey — which is why each slot repeats its ring as
|
||
-- DisabledTexture (see the slot instances below).
|
||
function Disable_BagButtons()
|
||
for _, button in ipairs(BENILLA_BAG_BUTTONS) do
|
||
local b = getglobal(button)
|
||
b:Disable()
|
||
SetDesaturation(b.icon, 1)
|
||
end
|
||
end
|
||
|
||
function Enable_BagButtons()
|
||
for _, button in ipairs(BENILLA_BAG_BUTTONS) do
|
||
local b = getglobal(button)
|
||
b:Enable()
|
||
SetDesaturation(b.icon, nil)
|
||
end
|
||
-- The four slots' own paint decides their restored colour: an item locked on the cursor
|
||
-- wants its 0.4 grey back, which the un-desaturate above does not restore (it clears
|
||
-- the greyscale flag, not the tint).
|
||
for i = 1, 4 do
|
||
BenillaBagBarSlot_Update(getglobal("CharacterBag" .. (i - 1) .. "Slot"))
|
||
end
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
One bag slot (ref ItemButtonTemplate, scratchpad `ref-ItemButtonTemplate.xml` l.4-45): a 37×37
|
||
button (l.5-7); the icon fills the button (l.10, no size/anchors → owner-sized); the "xN" count
|
||
is NumberFontNormal, right-justified, at BOTTOMRIGHT (-5,2) (l.11-19); the NormalTexture is the
|
||
64×64 UI-Quickslot2 ring centered at (0,-1) (l.31-42); PushedTexture UI-Quickslot-Depress
|
||
(l.43); HighlightTexture ButtonHilight-Square ADD (l.44). Shared by every window (backpack +
|
||
the four equipped bags) — physIndex-driven, see BenillaBagSlot_OnLoad's own comment.
|
||
-->
|
||
<Button name="BenillaBagSlotTemplate" virtual="true">
|
||
<Size><AbsDimension x="37" y="37"/></Size>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentIcon"/>
|
||
</Layer>
|
||
<Layer level="OVERLAY">
|
||
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="-5" y="2"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- The item's use-cooldown sweep (ref ContainerFrame.xml:13 — $parentCooldown
|
||
inherits CooldownFrameTemplate; ours is the native Cooldown widget, same as the
|
||
action buttons'). Driven by BenillaBagSlot_Update / BAG_UPDATE_COOLDOWN via
|
||
GetContainerItemCooldown + CooldownFrame_SetTimer (ActionBar.xml's transcription,
|
||
loaded before this file). -->
|
||
<Cooldown name="$parentCooldown" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Cooldown>
|
||
</Frames>
|
||
<NormalTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="64" y="64"/></Size>
|
||
<Anchors>
|
||
<Anchor point="CENTER" relativePoint="CENTER"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
|
||
</Anchors>
|
||
</NormalTexture>
|
||
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnClick>BenillaBagSlot_OnClick(self, arg1)</OnClick>
|
||
<OnEnter>BenillaBagSlot_OnEnter(self)</OnEnter>
|
||
<OnLeave>BenillaBagSlot_OnLeave(self)</OnLeave>
|
||
<OnUpdate>BenillaBagSlot_OnUpdate(self)</OnUpdate>
|
||
<!-- The drag trio (decision 0216 §3): both route to the SAME left-click path the
|
||
reference uses for both gestures (ContainerFrame.xml:40-55) — "LeftButton" hardcoded,
|
||
exactly as the reference calls it, since RegisterForDrag above only ever arms Left —
|
||
`true` (ignoreModifiers) suppresses the shift-split fork, matching the ref's own
|
||
ignoreModifiers contract for a drag/receive. -->
|
||
<OnDragStart>BenillaBagSlot_OnClick(self, "LeftButton", true)</OnDragStart>
|
||
<OnReceiveDrag>BenillaBagSlot_OnClick(self, "LeftButton", true)</OnReceiveDrag>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<Frame name="BenillaBagFrame" id="0" hidden="true">
|
||
<!-- The real backpack frame: 192 wide (CONTAINER_WIDTH, ContainerFrame.lua l.8,412) × 240 tall
|
||
(l.325), anchored to UIParent BOTTOMRIGHT with CONTAINER_OFFSET_X=0 / CONTAINER_OFFSET_Y=70
|
||
(l.11-12) — the STACK's own anchor once shown (BenillaBagStack_Relayout); this static
|
||
anchor is only the pre-first-show placeholder. -->
|
||
<Size><AbsDimension x="192" y="240"/></Size>
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT">
|
||
<Offset><AbsDimension x="0" y="70"/></Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<!-- The bag portrait: 40×40 at the frame TOPLEFT (7,-5) (ref-ContainerFrame.xml l.67-78).
|
||
BACKGROUND (below the ARTWORK background art) so it shows through the background's
|
||
portrait-ring cut-out — the same layering the loot-frame skull uses. Static
|
||
Button-Backpack-Up (the backpack portrait art; the real client's C-side
|
||
SetBagPortaitTexture). -->
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="BenillaBagPortrait" file="Interface\Buttons\Button-Backpack-Up">
|
||
<Size><AbsDimension x="40" y="40"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="7" y="-5"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="ARTWORK">
|
||
<!-- The single backpack background slab (ContainerFrame.lua l.316-318, the id==0
|
||
branch): UI-BackpackBackground, 256×256, full TexCoords (0,1,0,1), anchored TOPRIGHT
|
||
of the frame (ref-ContainerFrame.xml l.86). Wider/taller than the 192×240 frame — it
|
||
overhangs left and down, exactly as the real art does; the painted slot wells assume
|
||
this TOPRIGHT anchoring. The middle/bottom strips are hidden for the backpack
|
||
(l.321-324), so this one texture is the whole window art. -->
|
||
<Texture name="BenillaBagBackground" file="Interface\ContainerFrame\UI-BackpackBackground">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<TexCoords left="0" right="1" top="0" bottom="1"/>
|
||
</Texture>
|
||
<!-- Title: the bag name, GameFontHighlight, 112×12 at the frame TOPLEFT (47,-10)
|
||
(ref-ContainerFrame.xml l.120-131). BenillaBagWindow_Update keeps it current via
|
||
GetBagName(0), which always answers "Backpack" — the authored text is just the
|
||
pre-first-Update placeholder. -->
|
||
<FontString name="BenillaBagFrameName" inherits="GameFontHighlight" text="Backpack">
|
||
<Size><AbsDimension x="112" y="12"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="47" y="-10"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!--
|
||
The item grid (ContainerFrame.lua l.425-444). Authored verbatim from the real backpack
|
||
anchor chain: Item1 at the frame BOTTOMRIGHT (-12,30) (the id==0 first-button offset,
|
||
l.433); each new row (j-1 divisible by NUM_CONTAINER_COLUMNS=4) anchors BOTTOMRIGHT to
|
||
Item(j-4)'s TOPRIGHT (0,4) (l.440), and every other button BOTTOMRIGHT to Item(j-1)'s
|
||
BOTTOMLEFT (-5,0) (l.442). So button 1 is bottom-right and the chain fills up-and-left.
|
||
Slot1 (self, 1) is CHAIN POSITION 1 (physIndex), not the game slot — BenillaBagSlot_Update
|
||
resolves the game slot dynamically (size - physIndex + 1 = 16 - physIndex + 1 for the
|
||
backpack's fixed 16), so slot 1 renders TOP-LEFT and slot 16 BOTTOM-RIGHT, matching the
|
||
ref's own visual order.
|
||
-->
|
||
<Button name="BenillaBagSlot1" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="-12" y="30"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 1)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot2" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 2)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot3" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 3)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot4" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 4)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot5" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot1" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 5)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot6" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 6)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot7" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 7)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot8" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 8)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot9" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot5" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 9)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot10" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 10)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot11" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot10" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 11)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot12" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot11" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 12)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot13" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot9" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 13)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot14" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot13" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 14)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot15" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot14" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 15)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="BenillaBagSlot16" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="BenillaBagSlot15" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 16)</OnLoad></Scripts>
|
||
</Button>
|
||
|
||
<!-- The money purse (ContainerFrame.lua l.314 shows the MoneyFrame for the backpack; ref
|
||
SmallMoneyFrame anchored TOPRIGHT (-2,-216), ref-ContainerFrame.xml l.135-143). The
|
||
template pads 13px right of the copper coin (its content chains from x=-13 inside
|
||
the frame — same pad as the merchant purse), so the COIN edge the ref frame anchor
|
||
implies is -2-13 = -15. Three position-slots chained right-to-left with the real 4px
|
||
spacing (Coin1 rightmost, copper), filled copper-first and shrunk to content by
|
||
BenillaMoney_Set("BenillaBagMoney", GetMoney()); Coin2/3 chain to its left. -->
|
||
<Frame name="BenillaBagMoneyCoin1">
|
||
<Size><AbsDimension x="13" y="13"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-15" y="-216"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" file="Interface\MoneyFrame\UI-MoneyIcons">
|
||
<Size><AbsDimension x="13" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"/></Anchors>
|
||
<TexCoords left="0.5" right="0.75" top="0" bottom="1"/>
|
||
</Texture>
|
||
<FontString name="$parentNum" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Size><AbsDimension x="20" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<Frame name="BenillaBagMoneyCoin2">
|
||
<Size><AbsDimension x="13" y="13"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="BenillaBagMoneyCoin1" relativePoint="LEFT"><Offset><AbsDimension x="-4" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" file="Interface\MoneyFrame\UI-MoneyIcons">
|
||
<Size><AbsDimension x="13" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"/></Anchors>
|
||
<TexCoords left="0.25" right="0.5" top="0" bottom="1"/>
|
||
</Texture>
|
||
<FontString name="$parentNum" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Size><AbsDimension x="20" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
<Frame name="BenillaBagMoneyCoin3">
|
||
<Size><AbsDimension x="13" y="13"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="BenillaBagMoneyCoin2" relativePoint="LEFT"><Offset><AbsDimension x="-4" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" file="Interface\MoneyFrame\UI-MoneyIcons">
|
||
<Size><AbsDimension x="13" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"/></Anchors>
|
||
<TexCoords left="0" right="0.25" top="0" bottom="1"/>
|
||
</Texture>
|
||
<FontString name="$parentNum" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Size><AbsDimension x="20" y="13"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
|
||
<!-- Close: the real ContainerFrame close button position, TOPRIGHT (0,-1)
|
||
(ref-ContainerFrame.xml l.217-224), on the minimize-button art UIPanelCloseButton
|
||
itself uses (ref-UIPanelTemplates.xml l.100-102 — the same art merchant/loot draw; our
|
||
engine ships no UIPanelCloseButton template, so we draw it, matching the house style).
|
||
A close hides the window (the standalone-addon equivalent of ToggleBag). -->
|
||
<Button name="BenillaBagCloseButton">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
|
||
</Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnClick>getglobal("BenillaBagFrame"):Hide()</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>BenillaBagFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaBagFrame_OnEvent(self)</OnEvent>
|
||
<OnShow>BenillaBagFrame_OnShow()</OnShow>
|
||
<OnHide>BenillaBagFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!--
|
||
The generalized equipped-bag window (decision 0216 slice 2): the same portrait + slot template
|
||
as the backpack, but a stitched UI-Bag-Components background that SNUG-FITS the bag's row count
|
||
(BenillaBagWindow_FitBackground) rather than the backpack's fixed slab. The authored 260 height
|
||
is only a placeholder — FitBackground sets the live height on every repaint (before Show). No
|
||
money frame; first slot at the ref's non-backpack offset (-12,9 vs the backpack's -12,30 —
|
||
ContainerFrame.lua l.435 vs l.433, the id==0 fork). Carries NO <Scripts> block — each of the
|
||
four concrete windows below supplies its own (so the template/instance merge never has to
|
||
reconcile two OnLoad bodies; see `framexml.rs::merge`'s doc — a template with no Scripts child
|
||
can't collide with the instance's).
|
||
-->
|
||
<Frame name="BenillaBagWindowTemplate" virtual="true" hidden="true">
|
||
<Size><AbsDimension x="192" y="260"/></Size>
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT">
|
||
<Offset><AbsDimension x="0" y="70"/></Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentPortrait" file="Interface\Buttons\Button-Backpack-Up">
|
||
<Size><AbsDimension x="40" y="40"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="7" y="-5"/></Offset></Anchor>
|
||
</Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="ARTWORK">
|
||
<!-- The snug-fit background, STITCHED from the real client's UI-Bag-Components (256×512;
|
||
ContainerFrame.lua ContainerFrame_GenerateFrame, the id~=0 branch), so an equipped
|
||
bag's window is exactly its row count tall instead of the backpack's fixed 5-row
|
||
slab (decision 0216's flagged divergence, now closed). Three right-anchored 256-wide
|
||
pieces, all sized/tex-coorded per-bag by BenillaBagWindow_FitBackground (below): the
|
||
TOP carries the title bar + portrait ring + the top well row (a full 4-well row, or
|
||
a partial 2-well row for a size%4==2 bag — the reference's isPlusTwoBag fork); the
|
||
MIDDLE tiles the remaining full well rows (41px each, the button row stride, from
|
||
texture v 0.353515625 = the grid's top edge); the BOTTOM is the frame's bottom rim.
|
||
Authored values are a 2-row full-bag placeholder — every Show repaints through
|
||
FitBackground first, so the live geometry always wins. -->
|
||
<Texture name="$parentBgTop" file="Interface\ContainerFrame\UI-Bag-Components">
|
||
<Size><AbsDimension x="256" y="94"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<TexCoords left="0" right="1" top="0.00390625" bottom="0.18359375"/>
|
||
</Texture>
|
||
<Texture name="$parentBgMiddle" file="Interface\ContainerFrame\UI-Bag-Components">
|
||
<Size><AbsDimension x="256" y="32"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativeTo="$parentBgTop" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<TexCoords left="0" right="1" top="0.353515625" bottom="0.416015625"/>
|
||
</Texture>
|
||
<Texture name="$parentBgBottom" file="Interface\ContainerFrame\UI-Bag-Components">
|
||
<Size><AbsDimension x="256" y="10"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativeTo="$parentBgMiddle" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<TexCoords left="0" right="1" top="0.330078125" bottom="0.349609375"/>
|
||
</Texture>
|
||
<FontString name="$parentName" inherits="GameFontHighlight">
|
||
<Size><AbsDimension x="112" y="12"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="47" y="-10"/></Offset></Anchor>
|
||
</Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- 20 slots, 5 rows × 4 columns, chain-anchored exactly like the backpack's own 16 (see
|
||
that block's comment) but from the non-backpack first-button offset (-12,9). -->
|
||
<!-- First slot at (-12, 9) — the reference's id~=0 first-button offset (the backpack's is
|
||
-12,30). The grid then seats itself on the baked wells for free, because the background
|
||
is built bottom-up from the same 41px stride: the rim is 10px, the button's bottom edge
|
||
sits 9px up, and every row above is +41. -->
|
||
<Button name="$parentSlot1" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="-12" y="9"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 1)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot2" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 2)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot3" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 3)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot4" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 4)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot5" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot1" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 5)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot6" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 6)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot7" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 7)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot8" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 8)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot9" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot5" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 9)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot10" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 10)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot11" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot10" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 11)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot12" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot11" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 12)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot13" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot9" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 13)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot14" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot13" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 14)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot15" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot14" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 15)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot16" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot15" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 16)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot17" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot13" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="4"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 17)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot18" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot17" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 18)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot19" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot18" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 19)</OnLoad></Scripts>
|
||
</Button>
|
||
<Button name="$parentSlot20" inherits="BenillaBagSlotTemplate">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentSlot19" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-5" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>BenillaBagSlot_OnLoad(self, 20)</OnLoad></Scripts>
|
||
</Button>
|
||
|
||
<!-- Close: same art/position as the backpack's, but resolves ITS OWN parent via `this`
|
||
(the button, legacy global) rather than a hardcoded name — one body, five windows. -->
|
||
<Button name="$parentCloseButton">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor>
|
||
</Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnClick>this:GetParent():Hide()</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
</Frames>
|
||
</Frame>
|
||
|
||
<!-- The four equipped-bag windows: id=1..4 (SetID applied before any child's OnLoad — the
|
||
loader's bottom-up materialize order), each supplying its OWN Scripts block (the template
|
||
above carries none, so there is nothing to merge/collide with). -->
|
||
<Frame name="BenillaBagFrame1" id="1" inherits="BenillaBagWindowTemplate">
|
||
<Scripts>
|
||
<OnLoad>BenillaBagFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaBagFrame_OnEvent(self)</OnEvent>
|
||
<OnShow>BenillaBagFrame_OnShow()</OnShow>
|
||
<OnHide>BenillaBagFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="BenillaBagFrame2" id="2" inherits="BenillaBagWindowTemplate">
|
||
<Scripts>
|
||
<OnLoad>BenillaBagFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaBagFrame_OnEvent(self)</OnEvent>
|
||
<OnShow>BenillaBagFrame_OnShow()</OnShow>
|
||
<OnHide>BenillaBagFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="BenillaBagFrame3" id="3" inherits="BenillaBagWindowTemplate">
|
||
<Scripts>
|
||
<OnLoad>BenillaBagFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaBagFrame_OnEvent(self)</OnEvent>
|
||
<OnShow>BenillaBagFrame_OnShow()</OnShow>
|
||
<OnHide>BenillaBagFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
<Frame name="BenillaBagFrame4" id="4" inherits="BenillaBagWindowTemplate">
|
||
<Scripts>
|
||
<OnLoad>BenillaBagFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaBagFrame_OnEvent(self)</OnEvent>
|
||
<OnShow>BenillaBagFrame_OnShow()</OnShow>
|
||
<OnHide>BenillaBagFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!--
|
||
The keyring window (decision 0765) — id = KEYRING_CONTAINER. Structurally just a seventh
|
||
container window on the SAME template as the four equipped bags and the six bank popouts;
|
||
everything that makes it a keyring (the "-Keyring" plate, the KeyRing-Bag-Icon portrait, the
|
||
KEYRING title, the jingling open/close pair) is the id-keyed fork inside the shared handlers,
|
||
exactly as ContainerFrame.lua does it. Its 20 template buttons cover the keyring's 16-slot
|
||
ceiling; the level-gated remainder hides through the ordinary physIndex-past-size branch.
|
||
|
||
It is deliberately NOT in BENILLA_BAG_WINDOWS: the keyring is not one of "your bags", so no
|
||
bag toggle ever OPENS it and a vendor's auto-open never touches it — the reference's own
|
||
arrangement (OpenAllBags' open arm is ToggleBackpack + ToggleBag(1..4), and its count
|
||
explicitly excludes KEYRING_CONTAINER). It is still SWEPT by the two close arms, which the
|
||
ref runs over every ContainerFrame — the keyring lives in one there, so 1494 sweeps ours by
|
||
name alongside the list. ESC closes it too — UiPanels.xml's CloseAllWindows hides every open
|
||
container, the ref's own loop.
|
||
-->
|
||
<Frame name="BenillaKeyRingFrame" id="-2" inherits="BenillaBagWindowTemplate">
|
||
<Scripts>
|
||
<OnLoad>BenillaBagFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaBagFrame_OnEvent(self)</OnEvent>
|
||
<OnShow>BenillaBagFrame_OnShow()</OnShow>
|
||
<OnHide>BenillaBagFrame_OnHide()</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!--
|
||
The backpack toggle, RELOCATED onto the main action bar's right side so the bar reads whole
|
||
(the real client's MainMenuBarBackpackButton, ref-MainMenuBarBagButtons.xml l.54-64): a 37x37
|
||
button parented/anchored to the bar art frame at BOTTOMRIGHT (-6,2). Its behavior (toggle the
|
||
backpack window) is unchanged; only its seat moved from the free-floating screen corner onto
|
||
the bar. (MainMenuBarArtFrame is defined in ActionBar.xml, which the loader loads before
|
||
this file; the anchor resolves by name.)
|
||
-->
|
||
<CheckButton name="MainMenuBarBackpackButton">
|
||
<Size><AbsDimension x="37" y="37"/></Size>
|
||
<Anchors>
|
||
<Anchor point="BOTTOMRIGHT" relativeTo="MainMenuBarArtFrame" relativePoint="BOTTOMRIGHT">
|
||
<Offset><AbsDimension x="-6" y="2"/></Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
<!-- The backpack art is a LAYER texture, not the NormalTexture — the reference's own
|
||
structure (MainMenuBarBackpackButton inherits ItemButtonTemplate and sets
|
||
`MainMenuBarBackpackButtonIconTexture` in its OnLoad; the state textures are the
|
||
template's ring). It matters because `Disable_BagButtons` (decision 0674) disables this
|
||
button while the game menu is up, and a *state* texture with no DisabledTexture beside
|
||
it is not drawn in the disabled state (`ButtonState::region_visible` — the byte rule at
|
||
`SetState 0x779790`), so the backpack icon vanished outright instead of greying
|
||
(director-reported). As a layer it is untouched by button state, exactly like the four
|
||
bag-bar slots' own `$parentIcon`, and the greying is the vertex tint on it. -->
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentIconTexture" file="Interface\Buttons\Button-Backpack-Up"/>
|
||
</Layer>
|
||
</Layers>
|
||
<!-- The item-push drop card (decision 0887, BenillaItemPushAnim_* above) — the ref's
|
||
$parentItemAnim, one per bag button, container id 0 = the backpack. -->
|
||
<Frames>
|
||
<Frame name="$parentItemAnim" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaItemPushAnim_OnLoad(self, 0)</OnLoad>
|
||
<OnEvent>BenillaItemPushAnim_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaItemPushAnim_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<!-- The lit ring while the backpack window is open (ref MainMenuBarBackpackButton
|
||
l.104) — a CheckButton like the ref's; OnShow/OnHide of the window drive it. -->
|
||
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<!-- Seat the backpack icon above the bar art too (same reason as the bag-bar slots —
|
||
BenillaActionBarArt_SeatAbove's comment). -->
|
||
<OnLoad>
|
||
self.icon = getglobal("MainMenuBarBackpackButtonIconTexture")
|
||
if BenillaActionBarArt_SeatAbove then BenillaActionBarArt_SeatAbove(self) end
|
||
</OnLoad>
|
||
<!-- The undo repairs the CheckButton widget's own pre-handler flip; from there the
|
||
checked state belongs to the windows' OnShow/OnHide writes (ours and any
|
||
addon's) — the stated divergence at BenillaBagToggle_OnClick's comment.
|
||
The shift fork is the ref's own (MainMenuBarBagButtons.xml l.81-87): the button
|
||
carries the SAME pair of knobs the B / SHIFT-B keys do (1494), so a shift-click
|
||
opens all bags and a plain one toggles the backpack. -->
|
||
<OnClick>
|
||
self:SetChecked(not self:GetChecked())
|
||
if IsShiftKeyDown() then
|
||
OpenAllBags()
|
||
else
|
||
BenillaBagToggle_OnClick()
|
||
end
|
||
</OnClick>
|
||
<OnEnter>BenillaBagToggle_OnEnter(self)</OnEnter>
|
||
<OnLeave>BenillaBagBarButton_OnLeave()</OnLeave>
|
||
</Scripts>
|
||
</CheckButton>
|
||
|
||
<!--
|
||
The bag bar (decision 0216 slice 2, BenillaBagBarSlot_* above): four 36×36 buttons to the
|
||
LEFT of MainMenuBarBackpackButton, mirroring the reference CharacterBag0..3Slot row. Bar slot N (1..4)
|
||
sits at chain position N counting away from the backpack button — CharacterBag0Slot (bagId
|
||
1, Bag0Slot) is CLOSEST to the backpack, CharacterBag3Slot (bagId 4, Bag3Slot) FARTHEST —
|
||
the real bar's own left-to-right order. Sized to MATCH the action buttons (36×36 icon in a
|
||
66×66 UI-Quickslot2 ring, 6px chain gap = the 42px stride), so the bag icons fill their slots
|
||
exactly like the spell icons instead of floating undersized (the earlier 30×30 guess).
|
||
-->
|
||
<CheckButton name="CharacterBag0Slot">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="MainMenuBarBackpackButton" relativePoint="LEFT"><Offset><AbsDimension x="-6" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers><Layer level="BACKGROUND"><Texture name="$parentIconTexture"/></Layer></Layers>
|
||
<!-- The item-push drop card (decision 0887, BenillaItemPushAnim_* above) — the ref's
|
||
$parentItemAnim, one per bag button; container id 1. -->
|
||
<Frames>
|
||
<Frame name="$parentItemAnim" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaItemPushAnim_OnLoad(self, 1)</OnLoad>
|
||
<OnEvent>BenillaItemPushAnim_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaItemPushAnim_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<NormalTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</NormalTexture>
|
||
<!-- The same ring again as the DISABLED art, so the slot keeps its frame while
|
||
Disable_BagButtons has the row greyed under the game menu (decision 0674). A button
|
||
with no DisabledTexture draws NO state texture when disabled
|
||
(`ButtonState::region_visible`) — the ring would blink out of the bar entirely. The
|
||
reference needs no such line because its widget keeps the previously shown texture up
|
||
when the new state's slot is empty (`SetState 0x779790`'s gated hide); ours states it
|
||
instead of relying on that. -->
|
||
<DisabledTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</DisabledTexture>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<!-- The lit ring while this bag's window is open (ref BagSlotButtonTemplate l.52). -->
|
||
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>BenillaBagBarSlot_OnLoad(self, 1)</OnLoad>
|
||
<OnClick>BenillaBagBarSlot_OnClick(self)</OnClick>
|
||
<OnEvent>BenillaBagBarSlot_OnEvent(self)</OnEvent>
|
||
<OnEnter>BagSlotButton_OnEnter()</OnEnter>
|
||
<OnLeave>BenillaBagBarButton_OnLeave()</OnLeave>
|
||
<!-- The drag trio: OnDragStart picks the equipped bag up, OnReceiveDrag drops a carried
|
||
bag in — both the same PickupInventoryItem transition (empty cursor picks up, a held
|
||
bag places), mirroring the paper-doll/bag-slot drag routing. -->
|
||
<OnDragStart>BenillaBagBarSlot_Place(self)</OnDragStart>
|
||
<OnReceiveDrag>BenillaBagBarSlot_Place(self)</OnReceiveDrag>
|
||
</Scripts>
|
||
</CheckButton>
|
||
<CheckButton name="CharacterBag1Slot">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="CharacterBag0Slot" relativePoint="LEFT"><Offset><AbsDimension x="-6" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers><Layer level="BACKGROUND"><Texture name="$parentIconTexture"/></Layer></Layers>
|
||
<!-- The item-push drop card (decision 0887, BenillaItemPushAnim_* above) — the ref's
|
||
$parentItemAnim, one per bag button; container id 2. -->
|
||
<Frames>
|
||
<Frame name="$parentItemAnim" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaItemPushAnim_OnLoad(self, 2)</OnLoad>
|
||
<OnEvent>BenillaItemPushAnim_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaItemPushAnim_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<NormalTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</NormalTexture>
|
||
<!-- The same ring again as the DISABLED art, so the slot keeps its frame while
|
||
Disable_BagButtons has the row greyed under the game menu (decision 0674). A button
|
||
with no DisabledTexture draws NO state texture when disabled
|
||
(`ButtonState::region_visible`) — the ring would blink out of the bar entirely. The
|
||
reference needs no such line because its widget keeps the previously shown texture up
|
||
when the new state's slot is empty (`SetState 0x779790`'s gated hide); ours states it
|
||
instead of relying on that. -->
|
||
<DisabledTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</DisabledTexture>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>BenillaBagBarSlot_OnLoad(self, 2)</OnLoad>
|
||
<OnClick>BenillaBagBarSlot_OnClick(self)</OnClick>
|
||
<OnEvent>BenillaBagBarSlot_OnEvent(self)</OnEvent>
|
||
<OnEnter>BagSlotButton_OnEnter()</OnEnter>
|
||
<OnLeave>BenillaBagBarButton_OnLeave()</OnLeave>
|
||
<!-- The drag trio: OnDragStart picks the equipped bag up, OnReceiveDrag drops a carried
|
||
bag in — both the same PickupInventoryItem transition (empty cursor picks up, a held
|
||
bag places), mirroring the paper-doll/bag-slot drag routing. -->
|
||
<OnDragStart>BenillaBagBarSlot_Place(self)</OnDragStart>
|
||
<OnReceiveDrag>BenillaBagBarSlot_Place(self)</OnReceiveDrag>
|
||
</Scripts>
|
||
</CheckButton>
|
||
<CheckButton name="CharacterBag2Slot">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="CharacterBag1Slot" relativePoint="LEFT"><Offset><AbsDimension x="-6" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers><Layer level="BACKGROUND"><Texture name="$parentIconTexture"/></Layer></Layers>
|
||
<!-- The item-push drop card (decision 0887, BenillaItemPushAnim_* above) — the ref's
|
||
$parentItemAnim, one per bag button; container id 3. -->
|
||
<Frames>
|
||
<Frame name="$parentItemAnim" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaItemPushAnim_OnLoad(self, 3)</OnLoad>
|
||
<OnEvent>BenillaItemPushAnim_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaItemPushAnim_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<NormalTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</NormalTexture>
|
||
<!-- The same ring again as the DISABLED art, so the slot keeps its frame while
|
||
Disable_BagButtons has the row greyed under the game menu (decision 0674). A button
|
||
with no DisabledTexture draws NO state texture when disabled
|
||
(`ButtonState::region_visible`) — the ring would blink out of the bar entirely. The
|
||
reference needs no such line because its widget keeps the previously shown texture up
|
||
when the new state's slot is empty (`SetState 0x779790`'s gated hide); ours states it
|
||
instead of relying on that. -->
|
||
<DisabledTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</DisabledTexture>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>BenillaBagBarSlot_OnLoad(self, 3)</OnLoad>
|
||
<OnClick>BenillaBagBarSlot_OnClick(self)</OnClick>
|
||
<OnEvent>BenillaBagBarSlot_OnEvent(self)</OnEvent>
|
||
<OnEnter>BagSlotButton_OnEnter()</OnEnter>
|
||
<OnLeave>BenillaBagBarButton_OnLeave()</OnLeave>
|
||
<!-- The drag trio: OnDragStart picks the equipped bag up, OnReceiveDrag drops a carried
|
||
bag in — both the same PickupInventoryItem transition (empty cursor picks up, a held
|
||
bag places), mirroring the paper-doll/bag-slot drag routing. -->
|
||
<OnDragStart>BenillaBagBarSlot_Place(self)</OnDragStart>
|
||
<OnReceiveDrag>BenillaBagBarSlot_Place(self)</OnReceiveDrag>
|
||
</Scripts>
|
||
</CheckButton>
|
||
<CheckButton name="CharacterBag3Slot">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="CharacterBag2Slot" relativePoint="LEFT"><Offset><AbsDimension x="-6" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<Layers><Layer level="BACKGROUND"><Texture name="$parentIconTexture"/></Layer></Layers>
|
||
<!-- The item-push drop card (decision 0887, BenillaItemPushAnim_* above) — the ref's
|
||
$parentItemAnim, one per bag button; container id 4. -->
|
||
<Frames>
|
||
<Frame name="$parentItemAnim" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaItemPushAnim_OnLoad(self, 4)</OnLoad>
|
||
<OnEvent>BenillaItemPushAnim_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaItemPushAnim_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<NormalTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</NormalTexture>
|
||
<!-- The same ring again as the DISABLED art, so the slot keeps its frame while
|
||
Disable_BagButtons has the row greyed under the game menu (decision 0674). A button
|
||
with no DisabledTexture draws NO state texture when disabled
|
||
(`ButtonState::region_visible`) — the ring would blink out of the bar entirely. The
|
||
reference needs no such line because its widget keeps the previously shown texture up
|
||
when the new state's slot is empty (`SetState 0x779790`'s gated hide); ours states it
|
||
instead of relying on that. -->
|
||
<DisabledTexture file="Interface\Buttons\UI-Quickslot2">
|
||
<Size><AbsDimension x="66" y="66"/></Size>
|
||
<Anchors><Anchor point="CENTER" relativePoint="CENTER"/></Anchors>
|
||
</DisabledTexture>
|
||
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
||
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>BenillaBagBarSlot_OnLoad(self, 4)</OnLoad>
|
||
<OnClick>BenillaBagBarSlot_OnClick(self)</OnClick>
|
||
<OnEvent>BenillaBagBarSlot_OnEvent(self)</OnEvent>
|
||
<OnEnter>BagSlotButton_OnEnter()</OnEnter>
|
||
<OnLeave>BenillaBagBarButton_OnLeave()</OnLeave>
|
||
<!-- The drag trio: OnDragStart picks the equipped bag up, OnReceiveDrag drops a carried
|
||
bag in — both the same PickupInventoryItem transition (empty cursor picks up, a held
|
||
bag places), mirroring the paper-doll/bag-slot drag routing. -->
|
||
<OnDragStart>BenillaBagBarSlot_Place(self)</OnDragStart>
|
||
<OnReceiveDrag>BenillaBagBarSlot_Place(self)</OnReceiveDrag>
|
||
</Scripts>
|
||
</CheckButton>
|
||
|
||
<!--
|
||
The keyring button (decision 0765) — ref KeyRingButton, MainMenuBarBagButtons.xml l.142-199.
|
||
Sits at the FAR left of the bag row, past CharacterBag3Slot (the ref's CharacterBag3Slot),
|
||
and is authored HIDDEN: nothing reveals it but MainMenuBar_UpdateKeyRing, and only
|
||
while HasKey() — the point being that a character with no key has no keyring at all, and the
|
||
bar's plate has no socket for one.
|
||
|
||
18x39 and the TexCoords are the ref's exactly, and they are not arbitrary: the three state
|
||
atlases are 32x64 holding one 18x39 button, so 18/32 = 0.5625 and 39/64 = 0.609375 crop it
|
||
1:1. The chain gap is OUR row's -6 rather than the ref's -5, so the button seats evenly
|
||
against the 36px slots this bar scaled its own row to.
|
||
|
||
Unlike the five bag buttons it is NOT in BENILLA_BAG_BUTTONS: its art is a state texture, not
|
||
an $parentIcon layer, so Disable_BagButtons' SetDesaturation(b.icon) has nothing to grey —
|
||
and the ref leaves it out of its own Disable_BagButtons for the same reason.
|
||
-->
|
||
<CheckButton name="KeyRingButton" hidden="true">
|
||
<Size><AbsDimension x="18" y="39"/></Size>
|
||
<Anchors>
|
||
<Anchor point="RIGHT" relativeTo="CharacterBag3Slot" relativePoint="LEFT"><Offset><AbsDimension x="-6" y="0"/></Offset></Anchor>
|
||
</Anchors>
|
||
<!-- The item-push drop card (decision 0887, BenillaItemPushAnim_* above) — the ref's
|
||
$parentItemAnim, one per bag button; container id -2 (KEYRING_CONTAINER). The ref gives
|
||
the keyring one too (MainMenuBarBagButtons.xml l.152-160), and the byte selector really
|
||
does reach it: a push landing in player-array slots 81..112 resolves to -2, not 0. -->
|
||
<Frames>
|
||
<Frame name="$parentItemAnim" hidden="true">
|
||
<Size><AbsDimension x="36" y="36"/></Size>
|
||
<Anchors><Anchor point="CENTER"/></Anchors>
|
||
<Layers>
|
||
<Layer level="OVERLAY">
|
||
<Texture name="$parentIcon" setAllPoints="true"/>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaItemPushAnim_OnLoad(self, -2, 0)</OnLoad>
|
||
<OnEvent>BenillaItemPushAnim_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaItemPushAnim_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
<NormalTexture file="Interface\Buttons\UI-Button-KeyRing">
|
||
<TexCoords left="0" right="0.5625" top="0" bottom="0.609375"/>
|
||
</NormalTexture>
|
||
<PushedTexture file="Interface\Buttons\UI-Button-KeyRing-Down">
|
||
<TexCoords left="0" right="0.5625" top="0" bottom="0.609375"/>
|
||
</PushedTexture>
|
||
<HighlightTexture file="Interface\Buttons\UI-Button-KeyRing-Highlight" alphaMode="ADD">
|
||
<TexCoords left="0" right="0.5625" top="0" bottom="0.609375"/>
|
||
</HighlightTexture>
|
||
<!-- The lit ring while the keyring window is open — the bag row's own convention
|
||
(the ref drives the same state through UpdateMicroButtons' SetButtonState). -->
|
||
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
||
<Scripts>
|
||
<OnLoad>BenillaKeyRingButton_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaKeyRingButton_OnEvent()</OnEvent>
|
||
<OnClick>BenillaKeyRingButton_OnClick(self)</OnClick>
|
||
<OnEnter>BenillaKeyRingButton_OnEnter(self)</OnEnter>
|
||
<OnLeave>BenillaBagBarButton_OnLeave()</OnLeave>
|
||
<!-- A key dragged onto the button files itself, the ref's own OnReceiveDrag (l.174-178). -->
|
||
<OnReceiveDrag>PutKeyInKeyRing()</OnReceiveDrag>
|
||
</Scripts>
|
||
</CheckButton>
|
||
</Ui>
|