- the raid and reputation panes are the reference's own files: two manifest lines replace our `RaidFrame.xml` (83 of 84 frame names were already the reference's; the tear-off pullouts arrive) and one replaces our `ReputationFrame.xml`; the raid swap surfaced a loader defect (a font object inherited one level down was the 26 unexplained warnings), rehomed `RaidFrame_LoadUI` and two popup dialogs, and reproduces one reference DEFECT: an emptied lockout list keeps its last row painted (1874); the reputation swap moved the WATCH BAR out of `ActionBar.xml`, where it would have shadowed the chain's own, and exposed an ENGINE gap: `CollapseFactionHeader`/`ExpandFactionHeader` fire `UPDATE_FACTION` (`0x4d5dab`) and ours fired nothing, so with the stock pane repainting on that event alone, a fold painted nothing and the header kept its minus — invisible while our own file repainted itself (1875) - a wanted poster is a questgiver on the wire as a creature is, and benilla never asked about one; the RE round came back in two halves: the reference DOES send `CMSG_QUESTGIVER_STATUS_QUERY` for a GameObject, gated on `GAMEOBJECT_FLAGS` bit 2, seen in 20 of 62 sniffed sessions — and it can never render the answer (the status handler's typemask excludes a GameObject, its status slot lies past the object's end, and no poster, sign or plaque carries attachment 18); vmangos DOES answer, so the sweep gains a GameObject arm on the reference's own gate and the apply side refuses a non-unit guid, without which a gold `!` would hang over a poster no 1.12 client draws; two shipped claims fall with it (`0x5eb3c0` is the FULL re-query sweep; a status never suppresses a GameObject's minimap dot), and `WOW_PROBE_GOQUEST` at the Goldshire wanted poster reads the server's 1 then 5, both refused (1872) - the money entry comes off the chain: Trade, Mail and Auction switch to the reference's `MoneyInputFrameTemplate` and its verbs, and our `BenillaMoneyInput_*` kit retires — it was the exact answer while benilla fired `OnTextChanged` synchronously inside `SetText`, and the engine now raises it deferred and coalesced, matching `0x77d3e0` (1831), so the reference's `expectChanges` guard works and our bracket flag was a duplicate; most of the 430 deleted lines are verbatim art — all three windows carried an inline copy of the template's three edit boxes, AuctionFrame a whole second copy; one visible change: TradeFrame now makes the reference's own `MoneyInputFrame_SetMode(this, "compact")` call, which tightens the trade money boxes (Gold 58→56 wide, Silver's offset 26→22, Copper's 16→11), and two stale claims in the kit's comments are corrected, and a verb nothing called goes (1882) - the `UIFrameFlash` family is transcribed — six FrameXML names from `UIParent.lua`, which we do not load — unblocking SpellBookFrame and HelpFrame, which called it into silence; re-arming a flashing frame is a RETURN and `-1` flashes forever (1879); UIParent is recounted — `UpdateNameplates` and the `*_Show`/`*_Hide` family around it are FrameXML, not engine, missed by a survey that skipped the LoadOnDemand addons — so its engine surface is four verbs, not a wall: `GetLocale` answers `enUS`, `IsMacClient` answers nil (the whole verb on the PC build), and `CheckReadyCheckTime` and `RequestBattlefieldPositions` are the two it waits on (1880); and `BasicControls.xml` comes off the chain by pure deletion — ours differed by nothing but line-wrapping and one comment — with `FailedAddOnLoad` and `UIParentLoadAddOn` moving to `UIParent.xml`, their reference home, below their four callers (1881) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
718 lines
40 KiB
XML
718 lines
40 KiB
XML
<Ui>
|
|
<!--
|
|
THE MONEY FRAME KIT — `MoneyFrameTemplate` / `SmallMoneyFrameTemplate`, the `MoneyTypeInfo`
|
|
table and the `MoneyFrame_*` API that drives them.
|
|
|
|
This is **our implementation** of that kit. The specification it implements is the extracted
|
|
1.12 `Interface\FrameXML\MoneyFrame.lua` (356 lines) and `MoneyFrame.xml` (297), cited below
|
|
as `ref l.N`: the names, the published field names, the constants and every branch of the
|
|
collapse rule are the specification's, because addons call this by name and a compatible kit
|
|
has no freedom in any of that. How it is written — the structure, the helpers, the local
|
|
names, the comments — is ours.
|
|
|
|
WHY IT IS HERE: it is FrameXML's surface, not Rust's (decision 1190 — a name the shipped 1.12
|
|
UI defines belongs in a UI file, never hardcoded), and the addon corpus asks for it by name.
|
|
`MoneyFrame_SetType` is wanted by 11 addons, `MoneyFrame_Update` by 9, `SmallMoneyFrame_OnLoad`
|
|
by 9, and 13 declare a frame `inherits="SmallMoneyFrameTemplate"`. `MoneyTypeInfo` was one of
|
|
the top runtime walls the frame rename left standing.
|
|
|
|
── THE OTHER COIN KIT, and why there are still two ──────────────────────────────────────────
|
|
Eight of our windows (merchant, bank, trade, mail, quest, quest log, taxi, trainer) do NOT use
|
|
this file. They render coins through `BenillaMoney_Set`/`_Clear`/`_SetColor`, which live
|
|
below in this same file (they were in MerchantFrame.xml until 1751 took that window to the
|
|
stock chain): a three-SLOT chain (`<prefix>Coin1..3`) that fills only the non-zero
|
|
denominations in display order and re-flows, rather than three fixed GoldButton/SilverButton/
|
|
CopperButton frames that hide themselves. That kit takes its coin TexCoords, its collapse and
|
|
its shrink from the same specification as this one, and its layout is the one the director has
|
|
signed off across those eight windows.
|
|
|
|
The auction house is the exception, and the reason the reconciliation started there rather
|
|
than anywhere else: the three-slot kit has no notion of a money TYPE, so it cannot express
|
|
`showSmallerCoins` or `fixedWidth` — and those two flags ARE the auction house's price column
|
|
(`MoneyTypeInfo["AUCTION"]`, declared below and, until AuctionFrame.xml moved, used by
|
|
nothing). On the three-slot kit "1g" showed as one lone gold coin where the reference shows
|
|
`1g 0s 0c`, and a column of prices packed tight instead of lining up. That is not a layout
|
|
preference to re-approve, it is the kit being the wrong kit. See decision 1522.
|
|
|
|
So the two still coexist, and the split is now by KIT CAPABILITY as much as by audience:
|
|
· `BenillaMoney_*` + `<prefix>Coin1..3` — the eight windows whose look is signed off and
|
|
whose money is all plain collapsing STATIC amounts, which that kit renders correctly.
|
|
· `MoneyFrame_*` + `MoneyTypeInfo` here — the names and structure an addon writes against,
|
|
what an addon's `inherits="SmallMoneyFrameTemplate"` resolves to, and what the auction
|
|
house is laid out on.
|
|
Finishing the migration — moving those eight onto `SmallMoneyFrameTemplate` and retiring
|
|
`BenillaMoney_*` — is still the right end state; it is a re-layout of hand-authored art in
|
|
eight files (an approved look), so it stays named here rather than done in passing.
|
|
|
|
── WHAT IS NOT CARRIED, and why (each is guarded at its own site below) ─────────────────────
|
|
· THE COIN PICKUP. `OpenCoinPickupFrame`/`UpdateCoinPickupFrame`/`CoinPickupFrame` belong to
|
|
CoinPickupFrame.lua/.xml, which we do not ship — and the engine verbs underneath them
|
|
(`PickupPlayerMoney`, `DropCursorMoney`, `PickupTradeMoney`, `AddTradeMoney`) are not built
|
|
either, so a picked-up coin would have nowhere to go. The coin buttons still take the mouse
|
|
for a `canPickup` type (that is the specified state) and the click is guarded, so it does
|
|
nothing.
|
|
· `GetCursorMoney` (PLAYER's amount, ref l.17) — the engine verb for coins held on the cursor.
|
|
With no coin pickup there is no cursor money, so its term is not approximated away: it is
|
|
structurally zero. Stated at the spot.
|
|
· `GetSendMailMoney` / `GetSendMailCOD` (ref l.73, l.90) — 1.12 engine verbs we have not
|
|
built. We ship their SETTERS (`SetSendMailMoney`/`SetSendMailCOD`, which MailFrame.xml
|
|
drives); nothing reads the amount back yet, so those two types read 0.
|
|
· `message()` (ref l.145, l.173, l.181) — the one-line StaticPopup shim, which belongs to
|
|
BasicControls.xml, a file family we have not built. Guarded, so a misuse of the API stays
|
|
silent instead of erroring on the diagnostic.
|
|
· `Button:GetTextWidth()` (ref l.202 etc.) — BUILT, and called here, exactly as the
|
|
specification calls it. It forwards to the label FontString's `GetStringWidth`, which the
|
|
engine now answers inside the tick that asked (`script::measure`).
|
|
· The four `Pickup*`/`Add*` mail verbs the pickup closures name are not in 1.12's `_G` either
|
|
(they are absent from reference/1.12-globals.tsv) — so those closures are as unreachable
|
|
here as they are there. They exist because the table's shape is the contract.
|
|
-->
|
|
<Script><![CDATA[
|
|
-- ══ THE THREE-SLOT COIN KIT (`BenillaMoney_*`), rehomed from MerchantFrame.xml ═══════════
|
|
--
|
|
-- The OTHER kit — see this file's header for why there are two and what the split is. It
|
|
-- lives beside `MoneyFrame_*` rather than inside a window because eight windows share it:
|
|
-- merchant, bank, trade, mail, quest, quest log, taxi and trainer. Nothing about the kit
|
|
-- changed in the move; the `SmallMoneyFrameTemplate` migration the header names is still
|
|
-- outstanding and still the director's call.
|
|
-- The coin display, quoted from the real SmallMoneyFrame (ref MoneyFrame.xml/lua): a copper
|
|
-- amount renders as a number + a 13px coin icon per NONZERO denomination, cut from the one
|
|
-- shared texture Interface\MoneyFrame\UI-MoneyIcons by TexCoord (gold 0..0.25, silver
|
|
-- 0.25..0.5, copper 0.5..0.75 — ref l.115/74/33), the real collapse that hides zero coins
|
|
-- (MoneyFrame.lua l.221-267). Each money display owns three position-"slots"; the XML chains
|
|
-- them either left-to-right (row prices + the quest reward: Coin1 leftmost, gold first) or
|
|
-- right-to-left (the purses: Coin1 rightmost, copper first). BenillaMoney_Set fills the
|
|
-- visible denominations into slots 1.. in DISPLAY order (highestFirst=true for the
|
|
-- left-aligned chains) and — the real shrink, MoneyFrame.lua l.202/269 — sizes each slot to
|
|
-- exactly its number + its 13px coin (`SetWidth(GetTextWidth() + iconWidth)` there; the
|
|
-- same read here, off the number FontString the slot already owns). The static ±4px
|
|
-- chain-anchor offsets are the real MONEY_BUTTON_SPACING gap, so a shrunk group packs tight,
|
|
-- left-flush in the ltr chains and right-flush in the rtl ones. BenillaMoney_Clear hides
|
|
-- all three slots (the real collapse hides, see the helper).
|
|
--
|
|
-- NOTE (for the loot window's fold): the reusable helpers are
|
|
-- BenillaMoney_Set(prefix, copper) and BenillaMoney_Clear(prefix)
|
|
-- where `prefix` names the slot frames `<prefix>Coin1..3` (each with a `<prefix>CoinNIcon`
|
|
-- texture + `<prefix>CoinNNum` fontstring child). They live in this file.
|
|
--
|
|
-- They lived in MerchantFrame.xml until 1751 came for that window: the stock
|
|
-- `MerchantFrame.xml` off the player's chain has no room for eight other windows'
|
|
-- shared helpers, and this file is where the reference keeps money code anyway. A pure
|
|
-- move — not the `SmallMoneyFrameTemplate` migration named at the top of this file,
|
|
-- which is a re-layout of an approved look and is the director's to call.
|
|
BENILLA_COIN_TC = {
|
|
{ 0.0, 0.25 }, -- [1] gold
|
|
{ 0.25, 0.5 }, -- [2] silver
|
|
{ 0.5, 0.75 }, -- [3] copper
|
|
}
|
|
|
|
-- Unused slots HIDE (the real collapse — MoneyFrame.lua l.230/247 goldButton:Hide()), never
|
|
-- SetWidth(0): a 0 width means "derive from opposing anchors" to the layout (the client's
|
|
-- own G+0x50 convention), not "zero px". Fills are contiguous from Coin1, so a chain never
|
|
-- anchors THROUGH a hidden slot.
|
|
function BenillaMoney_Clear(prefix)
|
|
for i = 1, 3 do
|
|
getglobal(prefix .. "Coin" .. i):Hide()
|
|
end
|
|
end
|
|
|
|
function BenillaMoney_Set(prefix, copper, highestFirst)
|
|
copper = copper or 0
|
|
local vals = {
|
|
math.floor(copper / 10000), -- gold
|
|
math.floor((copper % 10000) / 100), -- silver
|
|
copper % 100, -- copper
|
|
}
|
|
-- Fill slots 1.. in display order (see the module comment); a zero denomination is
|
|
-- skipped (the real collapse), except copper always shows when the whole amount is
|
|
-- zero so a free item / empty purse isn't blank.
|
|
local first, last, step = 3, 1, -1
|
|
if highestFirst then first, last, step = 1, 3, 1 end
|
|
local slot = 0
|
|
for d = first, last, step do
|
|
if vals[d] > 0 or (d == 3 and vals[1] == 0 and vals[2] == 0) then
|
|
slot = slot + 1
|
|
-- The real shrink: this slot is exactly its number + its 13px coin, and the
|
|
-- XML anchor chain re-flows off the new width.
|
|
-- Text first, then measure it: the engine answers a width read inside the
|
|
-- tick that set the text, so the number IS this number and not the last one.
|
|
local num = getglobal(prefix .. "Coin" .. slot .. "Num")
|
|
num:SetText(vals[d])
|
|
local numW = num:GetStringWidth()
|
|
local slotFrame = getglobal(prefix .. "Coin" .. slot)
|
|
slotFrame:SetWidth(numW + 13)
|
|
slotFrame:Show()
|
|
local icon = getglobal(prefix .. "Coin" .. slot .. "Icon")
|
|
icon:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
|
|
icon:SetTexCoord(BENILLA_COIN_TC[d][1], BENILLA_COIN_TC[d][2], 0, 1)
|
|
num:SetWidth(numW)
|
|
end
|
|
end
|
|
for i = slot + 1, 3 do
|
|
getglobal(prefix .. "Coin" .. i):Hide()
|
|
end
|
|
end
|
|
|
|
-- Recolor the coin *numbers* (the ref's SetMoneyFrameColor — the digits redden, the coin icons
|
|
-- keep their own texture). The trainer detail cost calls this white when affordable / red
|
|
-- (1.0, 0.1, 0.1) when not; a plain purse never calls it, so its coins stay default. Applies to
|
|
-- all 3 slots (hidden ones are harmless) and must be re-called after each BenillaMoney_Set,
|
|
-- which fills the numbers but does not reset their color.
|
|
function BenillaMoney_SetColor(prefix, r, g, b)
|
|
for i = 1, 3 do
|
|
getglobal(prefix .. "Coin" .. i .. "Num"):SetTextColor(r, g, b)
|
|
end
|
|
end
|
|
|
|
-- ── What a coin is worth ─────────────────────────────────────────────────────────────────
|
|
-- Published globals: an addon that formats a price does the same split we do below, and
|
|
-- reads these rather than spelling 100 twice.
|
|
COPPER_PER_SILVER = 100
|
|
SILVER_PER_GOLD = 100
|
|
COPPER_PER_GOLD = COPPER_PER_SILVER * SILVER_PER_GOLD
|
|
|
|
-- ── How wide a coin draws ────────────────────────────────────────────────────────────────
|
|
-- One coin icon's width at each of the two sizes the templates below come in, and the gap
|
|
-- between two coin buttons — NEGATIVE, because the three deliberately bite into each other
|
|
-- so a group reads as one number rather than as three. `COIN_BUTTON_WIDTH` is the fixed slot
|
|
-- a `fixedWidth` type pads its smaller coins out to, so a column of prices lines up.
|
|
-- The values are the specification's (ref l.2-12): measurements of the shipped coin art, not
|
|
-- ours to re-derive.
|
|
MONEY_ICON_WIDTH = 19
|
|
MONEY_ICON_WIDTH_SMALL = 13
|
|
MONEY_BUTTON_SPACING = -4
|
|
MONEY_BUTTON_SPACING_SMALL = -4
|
|
COIN_BUTTON_WIDTH = 32
|
|
|
|
-- ── The money types (ref l.14-103) ───────────────────────────────────────────────────────
|
|
--
|
|
-- A money frame carries no amount of its own: it carries a TYPE, and the type says where the
|
|
-- number comes from and how the coins behave. An entry has three parts:
|
|
--
|
|
-- · `UpdateFunc()` returns the amount, in copper. It is called with the global `this` bound
|
|
-- to the frame being painted, so a type may read the frame as well as the engine.
|
|
-- · `PickupFunc(amount)` / `DropFunc()` are the cursor verbs a click-to-pick-up type drives.
|
|
-- · the display flags `MoneyFrame_Update` reads: `collapse` (drop leading zero
|
|
-- denominations), `showSmallerCoins` (keep the trailing ones on even at zero; the value
|
|
-- "Backpack" additionally keeps copper on by itself), `canPickup` (the coins take the
|
|
-- mouse), `fixedWidth` (pad the smaller coins to COIN_BUTTON_WIDTH), `truncateSmallCoins`
|
|
-- (drop copper once there is gold).
|
|
--
|
|
-- Nothing else is consulted. That is why those field names and the two function signatures
|
|
-- are the published contract and not an implementation detail: addons register types of their
|
|
-- own into this table and expect exactly these parts to be honoured.
|
|
MoneyTypeInfo = { }
|
|
|
|
-- Read an amount through an engine verb that may not be built here yet: absent, it reads 0
|
|
-- rather than calling into nil. Two of the seven types below need it — see the header.
|
|
local function AmountFrom(verbName)
|
|
local verb = getglobal(verbName)
|
|
if verb then
|
|
return verb()
|
|
end
|
|
return 0
|
|
end
|
|
|
|
-- The purse. The specification subtracts a third term here (ref l.17,
|
|
-- `GetMoney() - GetCursorMoney() - GetPlayerTradeMoney()`): coins lifted onto the cursor by
|
|
-- the coin-pickup frame. benilla ships neither that frame nor the `PickupPlayerMoney` verb
|
|
-- behind it, so the term is structurally 0 rather than approximated away — it comes back the
|
|
-- moment either lands.
|
|
MoneyTypeInfo["PLAYER"] = {
|
|
UpdateFunc = function() return GetMoney() - GetPlayerTradeMoney() end,
|
|
PickupFunc = function(amount) PickupPlayerMoney(amount) end,
|
|
DropFunc = function() DropCursorMoney() end,
|
|
collapse = 1,
|
|
canPickup = 1,
|
|
showSmallerCoins = "Backpack",
|
|
}
|
|
|
|
-- A number the owner parked on the frame itself — what `MoneyFrame_Update(name, amount)`
|
|
-- leaves behind, and how an addon shows a price it worked out for itself.
|
|
MoneyTypeInfo["STATIC"] = {
|
|
UpdateFunc = function() return this.staticMoney end,
|
|
collapse = 1,
|
|
}
|
|
|
|
-- The auction house's price column: the same source as STATIC, but the smaller coins pad out
|
|
-- to a fixed slot and stay on at zero, so a stack of prices reads as a column of digits.
|
|
MoneyTypeInfo["AUCTION"] = {
|
|
UpdateFunc = function() return this.staticMoney end,
|
|
collapse = 1,
|
|
showSmallerCoins = "Backpack",
|
|
fixedWidth = 1,
|
|
truncateSmallCoins = nil,
|
|
}
|
|
|
|
-- Our side of an open trade, and the other party's. Only ours is click-to-pick-up.
|
|
MoneyTypeInfo["PLAYER_TRADE"] = {
|
|
UpdateFunc = function() return GetPlayerTradeMoney() end,
|
|
PickupFunc = function(amount) PickupTradeMoney(amount) end,
|
|
DropFunc = function() AddTradeMoney() end,
|
|
collapse = 1,
|
|
canPickup = 1,
|
|
}
|
|
|
|
MoneyTypeInfo["TARGET_TRADE"] = {
|
|
UpdateFunc = function() return GetTargetTradeMoney() end,
|
|
collapse = 1,
|
|
}
|
|
|
|
-- Mail postage and cash-on-delivery. Postage explicitly does NOT collapse (ref l.84): the
|
|
-- send-mail frame wants all three coins standing whatever the amount, because you are typing
|
|
-- into them. Both read 0 until their engine getters exist — see the header.
|
|
MoneyTypeInfo["SEND_MAIL"] = {
|
|
UpdateFunc = function() return AmountFrom("GetSendMailMoney") end,
|
|
PickupFunc = function(amount) PickupSendMailMoney(amount) end,
|
|
DropFunc = function() AddSendMailMoney() end,
|
|
collapse = nil,
|
|
canPickup = 1,
|
|
showSmallerCoins = "Backpack",
|
|
}
|
|
|
|
MoneyTypeInfo["SEND_MAIL_COD"] = {
|
|
UpdateFunc = function() return AmountFrom("GetSendMailCOD") end,
|
|
PickupFunc = function(amount) PickupSendMailCOD(amount) end,
|
|
DropFunc = function() AddSendMailCOD() end,
|
|
collapse = 1,
|
|
canPickup = 1,
|
|
}
|
|
|
|
-- ── Hearing about a change (ref l.105-140) ───────────────────────────────────────────────
|
|
--
|
|
-- Every money frame registers all five money events; each then decides whether the one that
|
|
-- arrived is about the number IT is showing. That pairing is data, not control flow, so it is
|
|
-- written as data: one row per event, in the order the templates register them, naming the
|
|
-- money types that event can change.
|
|
local MONEY_EVENTS = {
|
|
{ "PLAYER_MONEY", { PLAYER = 1 } },
|
|
{ "PLAYER_TRADE_MONEY", { PLAYER = 1, PLAYER_TRADE = 1 } },
|
|
{ "TRADE_MONEY_CHANGED", { TARGET_TRADE = 1 } },
|
|
{ "SEND_MAIL_MONEY_CHANGED", { PLAYER = 1, SEND_MAIL = 1 } },
|
|
{ "SEND_MAIL_COD_CHANGED", { PLAYER = 1, SEND_MAIL_COD = 1 } },
|
|
}
|
|
|
|
-- The same rows keyed by event name, built once, so the handler below is a lookup.
|
|
local moneyEventTypes = { }
|
|
for _, row in ipairs(MONEY_EVENTS) do
|
|
moneyEventTypes[row[1]] = row[2]
|
|
end
|
|
|
|
local function MoneyFrameListen(frame)
|
|
for _, row in ipairs(MONEY_EVENTS) do
|
|
frame:RegisterEvent(row[1])
|
|
end
|
|
end
|
|
|
|
-- The two OnLoads differ in exactly one thing: `small`, which is what picks the 13px coin and
|
|
-- its tighter spacing over the 19px one in MoneyFrame_Update below. Both then take type
|
|
-- PLAYER, so a frame nobody tells otherwise shows the purse.
|
|
function MoneyFrame_OnLoad()
|
|
MoneyFrameListen(this)
|
|
MoneyFrame_SetType("PLAYER")
|
|
end
|
|
|
|
function SmallMoneyFrame_OnLoad()
|
|
MoneyFrameListen(this)
|
|
this.small = 1
|
|
MoneyFrame_SetType("PLAYER")
|
|
end
|
|
|
|
function MoneyFrame_OnEvent()
|
|
if not this.info or not this:IsVisible() then
|
|
return
|
|
end
|
|
local affected = moneyEventTypes[event]
|
|
if affected and affected[this.moneyType] then
|
|
MoneyFrame_UpdateMoney()
|
|
end
|
|
end
|
|
|
|
-- ── Painting ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
-- A money frame's three coin buttons, biggest first. Every verb below addresses them as a
|
|
-- trio, so this is the one place their `$parent<Denomination>Button` names are spelled.
|
|
local function MoneyFrameCoins(frameName)
|
|
return getglobal(frameName .. "GoldButton"),
|
|
getglobal(frameName .. "SilverButton"),
|
|
getglobal(frameName .. "CopperButton")
|
|
end
|
|
|
|
-- Point a frame at a money type (ref l.142-162): remember it, wire the mouse to match, and
|
|
-- repaint. Reads `this` rather than taking a frame — that is the convention the eleven corpus
|
|
-- callers write against.
|
|
function MoneyFrame_SetType(type)
|
|
local info = MoneyTypeInfo[type]
|
|
if not info then
|
|
-- ref l.145 diagnoses this with `message()`, which we DO have: it comes off the
|
|
-- chain in `Interface\FrameXML\BasicControls.xml` (1881 migrated that file; before
|
|
-- it, our own copy carried the same function). The `if` is therefore belt-and-braces
|
|
-- for a harness that loads this file without BasicControls, not a missing verb.
|
|
if message then
|
|
message("Invalid money type: " .. type)
|
|
end
|
|
return
|
|
end
|
|
this.info = info
|
|
this.moneyType = type
|
|
-- Only a click-to-pick-up type wants the mouse; on the rest a click falls through to
|
|
-- whatever is behind the coins.
|
|
local gold, silver, copper = MoneyFrameCoins(this:GetName())
|
|
local pickable = info.canPickup and true or false
|
|
gold:EnableMouse(pickable)
|
|
silver:EnableMouse(pickable)
|
|
copper:EnableMouse(pickable)
|
|
MoneyFrame_UpdateMoney()
|
|
end
|
|
|
|
-- Re-read the amount from the type and repaint (ref l.164-175). `this` again.
|
|
function MoneyFrame_UpdateMoney()
|
|
if not this.info then
|
|
if message then
|
|
message("Error moneyType not set")
|
|
end
|
|
return
|
|
end
|
|
local money = this.info.UpdateFunc()
|
|
MoneyFrame_Update(this:GetName(), money)
|
|
-- ref l.169-171 also feeds the coin-pickup frame while one is open. `hasPickup` is set
|
|
-- only by the coin click, which is guarded off (see the header), so this is unreachable
|
|
-- today rather than removed.
|
|
if this.hasPickup == 1 and UpdateCoinPickupFrame then
|
|
UpdateCoinPickupFrame(money)
|
|
end
|
|
end
|
|
|
|
-- Lay one denomination out: its digits, and the width those digits plus the coin icon need.
|
|
--
|
|
-- `Button:GetTextWidth()` right after `SetText`, which is what the specification writes
|
|
-- (ref l.202 and kin) and what the real client answers synchronously off its inline font
|
|
-- engine, so the coin is the right width on the frame that set its text.
|
|
--
|
|
-- This read used to return 0 — our measure landed at extract, a frame after the tick — and
|
|
-- left all three coins at exactly one bare icon width with their digits overlapping: the
|
|
-- director's "gold numbers are all cramped up when I first open the bags; close and open
|
|
-- again and it looks good", the reopen being the first open's cached measure. It was served
|
|
-- for a while by a digits-only advance table, since a number's width is a pure sum of
|
|
-- per-glyph advances. The engine answers the general question now (`script::measure`), so
|
|
-- this asks it the way the specification does.
|
|
local function ShowCoin(coin, coinName, amount, iconWidth)
|
|
coin:SetText(amount)
|
|
coin:SetWidth(coin:GetTextWidth() + iconWidth)
|
|
coin:Show()
|
|
end
|
|
|
|
-- Chain the next-bigger coin onto `coin`, and report what `coin` contributes to the group's
|
|
-- width.
|
|
--
|
|
-- Showing: the bigger coin hangs off this one's LEFT edge by `spacing` (negative — they
|
|
-- overlap), and the group grows by this coin's width less that overlap, but only when the
|
|
-- bigger coin is actually on screen to overlap with. Not showing: this coin hides and the
|
|
-- bigger one collapses onto its RIGHT edge, contributing nothing. `padToSlot` is the
|
|
-- `fixedWidth` exception, which sizes the coin to the fixed column slot first.
|
|
local function ChainCoin(bigger, coin, coinName, showing, padToSlot, spacing)
|
|
if not showing then
|
|
coin:Hide()
|
|
bigger:SetPoint("RIGHT", coinName, "RIGHT", 0, 0)
|
|
return 0
|
|
end
|
|
if padToSlot then
|
|
coin:SetWidth(COIN_BUTTON_WIDTH)
|
|
end
|
|
local grown = coin:GetWidth()
|
|
bigger:SetPoint("RIGHT", coinName, "LEFT", spacing, 0)
|
|
if bigger:IsVisible() then
|
|
grown = grown - spacing
|
|
end
|
|
return grown
|
|
end
|
|
|
|
-- THE PAINTER (ref l.177-270). Split a copper amount into the three denominations, size each
|
|
-- coin to its own digits plus its icon, and then — if the type collapses — drop the leading
|
|
-- zeros, re-chain what is left so the group packs tight, and report the frame's true width.
|
|
--
|
|
-- This one takes a frame NAME, not `this`: it is the only entry point in the family an owner
|
|
-- can call about a frame other than the one currently dispatching, which is how an addon
|
|
-- paints a STATIC frame it has just filled.
|
|
function MoneyFrame_Update(frameName, money)
|
|
local frame = getglobal(frameName)
|
|
local info = frame.info
|
|
if not info then
|
|
-- ref l.181 diagnoses and, notably, does NOT return: the coins below are still laid
|
|
-- out, and the collapse read further down is what actually stops it. Kept as-is.
|
|
if message then
|
|
message("Error moneyType not set")
|
|
end
|
|
end
|
|
|
|
-- Copper is the low two digits, silver the next two, gold everything above. Silver comes
|
|
-- out by subtracting the gold back off rather than by a second `mod`: `mod` here is 1.12's
|
|
-- `math.mod`, which truncates towards zero, so `mod(-1, 100)` is -1 and not 99 — the two
|
|
-- forms part company the moment `money` goes negative (which `GetMoney()` minus a trade
|
|
-- offer can), and this one is the specified answer.
|
|
-- A STATIC/AUCTION frame's amount is whatever its owner last parked on it, and on the
|
|
-- very first paint — `MoneyFrame_SetType`'s own repaint, in OnLoad, before any owner has
|
|
-- filled it — that is nil. The specification divides straight into it and throws there;
|
|
-- we answer 0, because the throw would take the whole `<OnLoad>`/`<OnShow>` chain down
|
|
-- with it and an empty price column is the honest reading of "nothing set yet".
|
|
money = money or 0
|
|
local gold = floor(money / COPPER_PER_GOLD)
|
|
local silver = floor((money - gold * COPPER_PER_GOLD) / COPPER_PER_SILVER)
|
|
local copper = mod(money, COPPER_PER_SILVER)
|
|
|
|
local goldCoin, silverCoin, copperCoin = MoneyFrameCoins(frameName)
|
|
local iconWidth, spacing = MONEY_ICON_WIDTH, MONEY_BUTTON_SPACING
|
|
if frame.small then
|
|
iconWidth, spacing = MONEY_ICON_WIDTH_SMALL, MONEY_BUTTON_SPACING_SMALL
|
|
end
|
|
|
|
ShowCoin(goldCoin, frameName .. "GoldButton", gold, iconWidth)
|
|
ShowCoin(silverCoin, frameName .. "SilverButton", silver, iconWidth)
|
|
ShowCoin(copperCoin, frameName .. "CopperButton", copper, iconWidth)
|
|
|
|
-- Remember what the frame is displaying — STATIC's own reader reads it back.
|
|
frame.staticMoney = money
|
|
|
|
-- A type that does not collapse is finished: all three coins stand, at the width their
|
|
-- digits asked for, and the frame keeps whatever width it was given.
|
|
if not info.collapse then
|
|
return
|
|
end
|
|
|
|
-- Gold leads. Present, it stays and sets the terms for the two below it; absent, it goes.
|
|
-- The running width starts at one icon's worth of frame padding.
|
|
local width = iconWidth
|
|
local keepSmaller, dropCopper
|
|
if gold > 0 then
|
|
width = width + goldCoin:GetWidth()
|
|
keepSmaller = info.showSmallerCoins and 1 or nil
|
|
dropCopper = info.truncateSmallCoins and 1 or nil
|
|
else
|
|
goldCoin:Hide()
|
|
end
|
|
|
|
-- Silver, then copper: each either shows — padded, chained and counted — or hides and lets
|
|
-- the coin above it collapse onto its edge. Silver showing under a `showSmallerCoins` type
|
|
-- is what carries the exemption down to copper; copper also survives at zero for a
|
|
-- "Backpack" type, and dies whatever it is once gold truncated it.
|
|
local showSilver = silver > 0 or keepSmaller
|
|
width = width + ChainCoin(goldCoin, silverCoin, frameName .. "SilverButton",
|
|
showSilver, keepSmaller and info.fixedWidth, spacing)
|
|
if showSilver and info.showSmallerCoins then
|
|
keepSmaller = 1
|
|
end
|
|
|
|
local showCopper = (copper > 0 or keepSmaller or info.showSmallerCoins == "Backpack")
|
|
and not dropCopper
|
|
width = width + ChainCoin(silverCoin, copperCoin, frameName .. "CopperButton",
|
|
showCopper, keepSmaller and info.fixedWidth, spacing)
|
|
|
|
frame:SetWidth(width)
|
|
end
|
|
|
|
-- A NO-OP, deliberately. The specification's whole body for this one sits inside a `--[[ ]]`
|
|
-- block (ref l.272-346) — an earlier painter that MoneyFrame_Update replaced. The name is in
|
|
-- the shipped client's `_G`, and an addon that calls it there gets exactly this: nothing.
|
|
function RefreshMoneyFrame(frameName, money, small, collapse, showSmallerCoins)
|
|
end
|
|
|
|
-- Recolour the DIGITS; the coin icons keep their own texture (ref l.348-356). This is how a
|
|
-- price you cannot afford turns red.
|
|
function SetMoneyFrameColor(frameName, r, g, b)
|
|
local gold, silver, copper = MoneyFrameCoins(frameName)
|
|
gold:SetTextColor(r, g, b)
|
|
silver:SetTextColor(r, g, b)
|
|
copper:SetTextColor(r, g, b)
|
|
end
|
|
|
|
-- A click on a coin opens the pickup frame on that denomination, seeded with what the frame is
|
|
-- currently showing; `denomination` is one coin's worth in copper, which is the unit the
|
|
-- pickup frame counts in.
|
|
--
|
|
-- Guarded, because we ship no coin pickup (see the header) — so today the click does nothing,
|
|
-- and the mouse-enabled state a `canPickup` type gives the coins is all that is observable.
|
|
-- Note the amount is read by calling the type's own `UpdateFunc` while `this` is still the
|
|
-- BUTTON rather than the frame, which is what the specification's own coin `<OnClick>` does
|
|
-- (ref MoneyFrame.xml l.20-23) and what a frame-reading type would see through.
|
|
function BenillaMoneyFrameCoin_OnClick(coin, denomination)
|
|
if not OpenCoinPickupFrame then
|
|
return
|
|
end
|
|
local frame = coin:GetParent()
|
|
OpenCoinPickupFrame(denomination, MoneyTypeInfo[frame.moneyType].UpdateFunc(), frame)
|
|
frame.hasPickup = 1
|
|
end
|
|
|
|
-- Closing a money frame takes any pickup it opened down with it.
|
|
function BenillaMoneyFrame_OnHide()
|
|
if this.hasPickup == 1 and CoinPickupFrame then
|
|
CoinPickupFrame:Hide()
|
|
this.hasPickup = 0
|
|
end
|
|
end
|
|
]]></Script>
|
|
|
|
<!--
|
|
MoneyFrameTemplate (ref MoneyFrame.xml l.3-149) — the LARGE kit: 192x28, 19px coins, the
|
|
NumberFontNormalLarge digits. The three buttons chain RIGHT-to-LEFT from the copper end, which
|
|
is what lets MoneyFrame_Update above re-point them past a hidden denomination.
|
|
|
|
`<PushedTextOffset>` is carried for provenance; our loader does not model it and ignores it.
|
|
-->
|
|
<Frame name="MoneyFrameTemplate" virtual="true">
|
|
<Size><AbsDimension x="192" y="28"/></Size>
|
|
<Frames>
|
|
<Button name="$parentCopperButton">
|
|
<Size><AbsDimension x="47" y="19"/></Size>
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts>
|
|
<OnClick>BenillaMoneyFrameCoin_OnClick(this, 1)</OnClick>
|
|
</Scripts>
|
|
<NormalTexture file="Interface\MoneyFrame\UI-MoneyIcons">
|
|
<Size><AbsDimension x="19" y="19"/></Size>
|
|
<Anchors><Anchor point="RIGHT"/></Anchors>
|
|
<TexCoords left="0.5" right="0.75" top="0" bottom="1"/>
|
|
</NormalTexture>
|
|
<ButtonText name="$parentText">
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-19" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="NumberFontNormalLarge" justifyH="RIGHT"/>
|
|
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
|
|
</Button>
|
|
<Button name="$parentSilverButton">
|
|
<Size><AbsDimension x="47" y="19"/></Size>
|
|
<Anchors>
|
|
<Anchor point="RIGHT" relativeTo="$parentCopperButton" relativePoint="LEFT"><Offset><AbsDimension x="-4" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts>
|
|
<OnClick>BenillaMoneyFrameCoin_OnClick(this, COPPER_PER_SILVER)</OnClick>
|
|
</Scripts>
|
|
<NormalTexture file="Interface\MoneyFrame\UI-MoneyIcons">
|
|
<Size><AbsDimension x="19" y="19"/></Size>
|
|
<Anchors><Anchor point="RIGHT"/></Anchors>
|
|
<TexCoords left="0.25" right="0.5" top="0" bottom="1"/>
|
|
</NormalTexture>
|
|
<ButtonText name="$parentText">
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-19" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="NumberFontNormalLarge" justifyH="RIGHT"/>
|
|
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
|
|
</Button>
|
|
<Button name="$parentGoldButton">
|
|
<Size><AbsDimension x="47" y="19"/></Size>
|
|
<Anchors>
|
|
<Anchor point="RIGHT" relativeTo="$parentSilverButton" relativePoint="LEFT"><Offset><AbsDimension x="-4" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts>
|
|
<OnClick>BenillaMoneyFrameCoin_OnClick(this, COPPER_PER_GOLD)</OnClick>
|
|
</Scripts>
|
|
<NormalTexture file="Interface\MoneyFrame\UI-MoneyIcons">
|
|
<Size><AbsDimension x="19" y="19"/></Size>
|
|
<Anchors><Anchor point="RIGHT"/></Anchors>
|
|
<TexCoords left="0" right="0.25" top="0" bottom="1"/>
|
|
</NormalTexture>
|
|
<ButtonText name="$parentText">
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-19" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="NumberFontNormalLarge" justifyH="RIGHT"/>
|
|
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
|
|
</Button>
|
|
</Frames>
|
|
<Scripts>
|
|
<OnLoad>MoneyFrame_OnLoad()</OnLoad>
|
|
<OnEvent>MoneyFrame_OnEvent()</OnEvent>
|
|
<OnShow>MoneyFrame_UpdateMoney()</OnShow>
|
|
<OnHide>BenillaMoneyFrame_OnHide()</OnHide>
|
|
</Scripts>
|
|
</Frame>
|
|
|
|
<!--
|
|
SmallMoneyFrameTemplate (ref MoneyFrame.xml l.150-296) — the same kit at 128x13 with 13px
|
|
coins and NumberFontNormal digits, and `SmallMoneyFrame_OnLoad` in place of `MoneyFrame_OnLoad`
|
|
so `this.small` is set. This is the one the shipped UI uses nearly everywhere (merchant prices,
|
|
the purse, mail postage, trade offers) and the one 13 corpus addons inherit.
|
|
-->
|
|
<Frame name="SmallMoneyFrameTemplate" virtual="true">
|
|
<Size><AbsDimension x="128" y="13"/></Size>
|
|
<Frames>
|
|
<Button name="$parentCopperButton">
|
|
<Size><AbsDimension x="32" y="13"/></Size>
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts>
|
|
<OnClick>BenillaMoneyFrameCoin_OnClick(this, 1)</OnClick>
|
|
</Scripts>
|
|
<NormalTexture file="Interface\MoneyFrame\UI-MoneyIcons">
|
|
<Size><AbsDimension x="13" y="13"/></Size>
|
|
<Anchors><Anchor point="RIGHT"/></Anchors>
|
|
<TexCoords left="0.5" right="0.75" top="0" bottom="1"/>
|
|
</NormalTexture>
|
|
<ButtonText name="$parentText">
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="NumberFontNormal" justifyH="RIGHT"/>
|
|
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
|
|
</Button>
|
|
<Button name="$parentSilverButton">
|
|
<Size><AbsDimension x="32" y="13"/></Size>
|
|
<Anchors>
|
|
<Anchor point="RIGHT" relativeTo="$parentCopperButton" relativePoint="LEFT"><Offset><AbsDimension x="-4" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts>
|
|
<OnClick>BenillaMoneyFrameCoin_OnClick(this, COPPER_PER_SILVER)</OnClick>
|
|
</Scripts>
|
|
<NormalTexture file="Interface\MoneyFrame\UI-MoneyIcons">
|
|
<Size><AbsDimension x="13" y="13"/></Size>
|
|
<Anchors><Anchor point="RIGHT"/></Anchors>
|
|
<TexCoords left="0.25" right="0.5" top="0" bottom="1"/>
|
|
</NormalTexture>
|
|
<ButtonText name="$parentText">
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="NumberFontNormal" justifyH="RIGHT"/>
|
|
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
|
|
</Button>
|
|
<Button name="$parentGoldButton">
|
|
<Size><AbsDimension x="32" y="13"/></Size>
|
|
<Anchors>
|
|
<Anchor point="RIGHT" relativeTo="$parentSilverButton" relativePoint="LEFT"><Offset><AbsDimension x="-4" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
<Scripts>
|
|
<OnClick>BenillaMoneyFrameCoin_OnClick(this, COPPER_PER_GOLD)</OnClick>
|
|
</Scripts>
|
|
<NormalTexture file="Interface\MoneyFrame\UI-MoneyIcons">
|
|
<Size><AbsDimension x="13" y="13"/></Size>
|
|
<Anchors><Anchor point="RIGHT"/></Anchors>
|
|
<TexCoords left="0" right="0.25" top="0" bottom="1"/>
|
|
</NormalTexture>
|
|
<ButtonText name="$parentText">
|
|
<Anchors>
|
|
<Anchor point="RIGHT"><Offset><AbsDimension x="-13" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="NumberFontNormal" justifyH="RIGHT"/>
|
|
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
|
|
</Button>
|
|
</Frames>
|
|
<Scripts>
|
|
<OnLoad>SmallMoneyFrame_OnLoad()</OnLoad>
|
|
<OnEvent>MoneyFrame_OnEvent()</OnEvent>
|
|
<OnShow>MoneyFrame_UpdateMoney()</OnShow>
|
|
<OnHide>BenillaMoneyFrame_OnHide()</OnHide>
|
|
</Scripts>
|
|
</Frame>
|
|
</Ui>
|