- the shine's stars size by the screen diagonal instead of a frozen 4:3 constant, so a widescreen window stops blobbing them - each button's shine wears its own authored geometry: the spell book's 36x36 model rect at 1.22 scale, not the pet bar's — and its autocast brackets reach the button's corners with the glow sharing their centre - one deliberate deviation, recorded as such: the spell book's shine borrows the pet button's rim ratio, because the reference's own washes out there - the perf HUD gains a pill that measures frame cost and its tail, and latches the spike that would otherwise scroll away Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
966 lines
59 KiB
XML
966 lines
59 KiB
XML
<Ui>
|
|
<!--
|
|
benilla's spellbook window (decision 0216 §8, slice 5 — the P-key window, the spell
|
|
SOURCE for the cursor-payload arc): the 384x512 book + the 12-spell page grid + the
|
|
right-edge skill-line tabs + the page-turn pair, dressed from the real 1.12
|
|
`SpellBookFrame.xml`/`.lua` — extracted from the MPQ chain to session scratch this
|
|
session (director-local reference artifacts, never committed — the 0068/0138 pattern;
|
|
line cites below are into that extraction's own `ref-SpellBookFrame.xml`/`.lua`).
|
|
|
|
Docks the left UIPanel slot exactly like Character/Merchant/Gossip/Quest/QuestLog
|
|
(`UiPanels.xml`'s `UIPanelWindows["SpellBookFrame"] = { area = "left", pushable =
|
|
0 }`, mirroring the ref's own `SpellBookFrame` row) — so it competes for/replaces those
|
|
windows, never stacks with them. `ToggleSpellBook(bookType)` (ref `SpellBookFrame.lua:
|
|
9-50`) is the show/hide entry point, and it is addon-facing: it wears the reference's bare
|
|
name for the same reason `ToggleCharacter`/`ToggleQuestLog` do. The app's 'P' binding calls
|
|
it with `BOOKTYPE_SPELL` (`ui_script/input.rs`, ref `Bindings.xml:582-583`).
|
|
|
|
Every frame this file defines wears the REFERENCE's name (`SpellBookFrame`, `SpellButton1`,
|
|
…), because addons address them by it — the `Benilla` prefix these carried until the
|
|
reference-naming pass is gone. A child with no counterpart in the 1.12 namespace keeps the
|
|
bare stripped name so `$parent`/`GetName()..` composition inside the family stays coherent.
|
|
|
|
The book MODEL (tabs = skill lines, the flat slot list, offsets) is built entirely by the
|
|
app from `PlayerActions.spells` through the `Spell.dbc`/`SkillLine.dbc` join
|
|
(`crate::ui_spellbook`) and pushed through `benilla_ui::script::spellbook`'s snapshot seam
|
|
— this file only ever reads it through `GetNumSpellTabs`/`GetSpellTabInfo`/`GetSpellName`/
|
|
`GetSpellTexture`/`IsSpellPassive`, exactly the ref's own Era API shape. `BOOKTYPE_SPELL`/
|
|
`BOOKTYPE_PET` are installed by the ENGINE (`spellbook.rs`'s `install()`), not this file's
|
|
own `<Script>` — the one deliberate exception to the ref's own home for them
|
|
(`SpellBookFrame.lua:5-6`), so the engine's OWN tests can exercise the pet-deferral path
|
|
without this XML (see that module's doc for the full reasoning). `SPELLS_PER_PAGE`/
|
|
`MAX_SKILLLINE_TABS`/`SPELLBOOK_PAGENUMBERS` stay here — genuine per-window UI state, the
|
|
ref's own home for them.
|
|
|
|
THE PET BOOK IS LIVE (decision 1032) — the second tab, its 12-slot page, the autocast
|
|
overlay + sparkle, the right-click autocast toggle, and the cast/pickup pair, all over
|
|
`crate::ui_pet_book`'s feed of `SMSG_PET_SPELLS`' own spell list. Two reference QUIRKS are
|
|
reproduced on purpose here and each carries a do-not-fix note at its site (the standing
|
|
rule from decision 1030): the pet page **ignores its page number**, and its page arrows
|
|
write the *spell* book's page counter. See `SpellBook_GetSpellID` and the two
|
|
page-turn handlers.
|
|
|
|
Named deferrals/OMITs (each re-cited at its own site below):
|
|
- `LEARNED_SPELL_IN_TAB`'s tab flash (`SpellBookTabFlashFrame`, `CheckButtonGlow`): no
|
|
such event exists yet (no "just learned a spell" signal split out of the general
|
|
`SPELLS_CHANGED` diff). The ref returns early on it for the pet book anyway.
|
|
- The CRAFT_SHOW/_CLOSE/TRADE_SKILL_SHOW/_CLOSE legs of the checked ring: the ring
|
|
itself is LIVE (`BenillaSpellButton_UpdateSelection`/`IsCurrentCast` over the
|
|
app-resolved slot verdict — the shapeshift arm makes Ghost Wolf's/a druid form's
|
|
slot glow while its form is up), but the trade-skill-window arm of the engine
|
|
predicate is unmodeled (the same named gap `ui_action`'s IsCurrentAction carries),
|
|
so those four events would re-read an arm that never fires — omitted with it.
|
|
- The `this.updateTooltip`/`OnUpdate` re-poll loop around the hover: `GameTooltip:SetSpell`
|
|
itself is LIVE (the engine channel, decision 0276's line law; it reads whichever book
|
|
`bookType` names — 1050), but its per-frame re-poll is dropped, since nothing in the
|
|
rendered lines changes per-frame the way a live cooldown would. The ref's own
|
|
`if ( GameTooltip:SetSpell(…) )` return value exists only to arm that loop.
|
|
- `maxLines="3"` on `$parentSpellName` (word-wrap line cap): no such FontString
|
|
attribute is modeled (grepped `benilla-ui/src/loader/widgets.rs`) — the name just
|
|
wraps unbounded inside its box width, a harmless cosmetic gap on the rare long name.
|
|
- `MultiActionBar_ShowAllGrids/_HideAllGrids()` (ref `SpellBookFrame_OnShow`/`_OnHide`):
|
|
no multi-bar grid-show mechanism exists in this engine yet — dropped, the same class of
|
|
gap CharacterFrame's own OnShow/OnHide already carry. Its neighbour in that pair,
|
|
`UpdateMicroButtons()`, is LIVE since the micro-menu slice (`MicroMenu.xml`) — nil-
|
|
guarded at the call sites only because several test harnesses load this window without
|
|
the action bar behind it.
|
|
|
|
Sounds (decision 0090): `igSpellBookOpen`/`igSpellBookClose` on show/hide (ref
|
|
`SpellBookFrame_Update`/`_OnHide`, VERIFIED present in the real `SoundEntries.dbc` this
|
|
session), `igAbiliityPageTurn` (the ref's own literal spelling — VERIFIED as the real
|
|
registered kit name, id 836, `Sound\interface\iAbilitiesTurnPage{A,B,C}.wav`; not a typo
|
|
to "fix") on both page-turn clicks.
|
|
-->
|
|
<Script><![CDATA[
|
|
-- ── GlobalStrings values this window uses (ref-GlobalStrings.lua, cited per line — the
|
|
-- `X = X or "..."` idiom matches CastingBar.xml/CharacterFrame.xml's own convention) ────
|
|
SPELLBOOK = SPELLBOOK or "Spellbook" -- :3820
|
|
PAGE_NUMBER = PAGE_NUMBER or "Page %d" -- :2981
|
|
-- The pet tab's label AND the window title while the pet book is up. Keyed, not chosen:
|
|
-- HasPetSpells()'s second return is ChrClasses.dbc field 4 ("PET"/"DEMON") and the ref
|
|
-- concatenates it (`getglobal("PET_TYPE_"..token)`, ref SpellBookFrame.lua:173).
|
|
PET_TYPE_PET = PET_TYPE_PET or "Pet" -- :3058
|
|
PET_TYPE_DEMON = PET_TYPE_DEMON or "Demon" -- :3057
|
|
|
|
-- ── This window's own constants (ref SpellBookFrame.lua:1-7, Benilla-prefixed where the
|
|
-- ref's own name would collide with the engine's BOOKTYPE_SPELL/BOOKTYPE_PET globals —
|
|
-- this file's header comment on that one deviation) ─────────────────────────────────────
|
|
SPELLS_PER_PAGE = 12
|
|
MAX_SKILLLINE_TABS = 8
|
|
SPELLBOOK_PAGENUMBERS = {}
|
|
|
|
-- ── The window: toggle (ref ToggleSpellBook, l.9-50) ─────────────────────────────────────
|
|
-- Kept BARE (not Benilla-prefixed) — the addon-facing entry point, matching this
|
|
-- codebase's own ToggleCharacter/ToggleQuestLog precedent. The ref's own DUPLICATED
|
|
-- prev/next enable/disable (once inside the `currentPage > maxPages` clamp branch, once
|
|
-- again unconditionally right after — both produce the identical end state) collapses to
|
|
-- the ONE SpellBook_UpdatePageArrows() call already shared by every other
|
|
-- page-turn site below — a redundant-code cleanup, not a behavior change.
|
|
function ToggleSpellBook(bookType)
|
|
-- ref l.11-14: asking for a pet book you haven't got does NOTHING — not even close a
|
|
-- spellbook that is already open. The TOGGLEPETBOOK key binding is the live caller.
|
|
if bookType == BOOKTYPE_PET and not HasPetSpells() then
|
|
return
|
|
end
|
|
local isVisible = SpellBookFrame:IsVisible()
|
|
HideUIPanel(SpellBookFrame)
|
|
if (not isVisible or (SpellBookFrame.bookType ~= bookType)) then
|
|
SpellBookFrame.bookType = bookType
|
|
ShowUIPanel(SpellBookFrame)
|
|
end
|
|
BenillaSpellBook_ClampPage()
|
|
SpellBook_UpdatePageArrows()
|
|
SpellBookPageText:SetText(format(PAGE_NUMBER, SpellBook_GetCurrentPage()))
|
|
end
|
|
|
|
-- Clamp the selected tab's page back onto range (ref's own inline logic inside
|
|
-- ToggleSpellBook, l.22-26) — split out so both ToggleSpellBook and a future re-entry
|
|
-- share it, rather than inlining it twice.
|
|
function BenillaSpellBook_ClampPage()
|
|
local currentPage, maxPages = SpellBook_GetCurrentPage()
|
|
if currentPage > maxPages then
|
|
SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] = maxPages
|
|
BenillaUpdateSpells()
|
|
end
|
|
end
|
|
|
|
function SpellBookFrame_OnLoad()
|
|
local frame = this
|
|
frame:RegisterEvent("SPELLS_CHANGED")
|
|
-- LEARNED_SPELL_IN_TAB OMITTED — this file's header comment.
|
|
frame.bookType = BOOKTYPE_SPELL
|
|
for i = 1, MAX_SKILLLINE_TABS do
|
|
SPELLBOOK_PAGENUMBERS[i] = 1
|
|
end
|
|
SPELLBOOK_PAGENUMBERS["pet"] = 1 -- ref l.66; read by GetCurrentPage, written by nothing
|
|
SpellBookSkillLineTab_OnClick(1)
|
|
end
|
|
|
|
-- ref SpellBookFrame_OnEvent (l.75-92), the SPELLS_CHANGED branch only (LEARNED_SPELL_IN_TAB
|
|
-- OMITTED, header comment).
|
|
function SpellBookFrame_OnEvent()
|
|
local frame = this
|
|
if event == "SPELLS_CHANGED" and frame:IsVisible() then
|
|
SpellBookFrame_Update()
|
|
SpellBook_UpdatePageArrows()
|
|
end
|
|
end
|
|
|
|
-- ref SpellBookFrame_OnShow (l.94-105): MultiActionBar_ShowAllGrids OMITTED (header
|
|
-- comment); the tab-flash UIFrameFlash call goes with LEARNED_SPELL_IN_TAB.
|
|
-- UpdateMicroButtons is LIVE as of the micro-menu slice (MicroMenu.xml).
|
|
function SpellBookFrame_OnShow()
|
|
if UpdateMicroButtons then UpdateMicroButtons() end
|
|
SpellBookFrame_Update(1)
|
|
end
|
|
|
|
-- ref SpellBookFrame_Update (l.107-164), whole. Three things happen here and they are
|
|
-- easy to conflate: the skill-line strip is gated on the book TYPE (the pet book has no
|
|
-- tabs at all — GetSpellTabInfo never sees it), the Spell/Pet toggle row is gated on
|
|
-- HasPetSpells(), and the title + open sound fork on which book is up.
|
|
function SpellBookFrame_Update(showing)
|
|
if showing then
|
|
SpellBookSkillLineTab_OnClick(SpellBookFrame.selectedSkillLine)
|
|
BenillaUpdateSpells()
|
|
end
|
|
local isPet = SpellBookFrame.bookType == BOOKTYPE_PET
|
|
local numSkillLineTabs = GetNumSpellTabs()
|
|
for i = 1, MAX_SKILLLINE_TABS do
|
|
local skillLineTab = getglobal("SpellBookSkillLineTab" .. i)
|
|
if i <= numSkillLineTabs and not isPet then
|
|
local name, texture = GetSpellTabInfo(i)
|
|
skillLineTab:SetNormalTexture(texture)
|
|
skillLineTab.tooltip = name
|
|
skillLineTab:Show()
|
|
skillLineTab:SetChecked(SpellBookFrame.selectedSkillLine == i)
|
|
else
|
|
skillLineTab:Hide()
|
|
end
|
|
end
|
|
|
|
-- ref l.108-111 + l.141-151: hide the row first, then raise exactly the tabs that
|
|
-- exist. Tab 3 never appears in 1.12 (no third book) and is hidden by the template's
|
|
-- own `hidden="true"`; it is kept so the anchor chain reads like the ref's.
|
|
SpellBookFrameTabButton1:Hide()
|
|
SpellBookFrameTabButton2:Hide()
|
|
local hasPetSpells, petToken = HasPetSpells()
|
|
SpellBookFrame.petTitle = nil
|
|
if hasPetSpells then
|
|
SpellBookFrame_SetTabType(SpellBookFrameTabButton1, BOOKTYPE_SPELL)
|
|
SpellBookFrame_SetTabType(SpellBookFrameTabButton2, BOOKTYPE_PET, petToken)
|
|
elseif isPet then
|
|
-- The pet died/was dismissed while its book was open: the ref closes the window
|
|
-- and reverts, rather than showing an empty pet page (l.147-151).
|
|
HideUIPanel(SpellBookFrame)
|
|
SpellBookFrame.bookType = BOOKTYPE_SPELL
|
|
isPet = false
|
|
end
|
|
|
|
if not isPet then
|
|
SpellBookTitleText:SetText(SPELLBOOK)
|
|
if showing then PlaySound("igSpellBookOpen") end
|
|
else
|
|
SpellBookTitleText:SetText(SpellBookFrame.petTitle)
|
|
-- ref l.161: the pet book opens on the ABILITY kit, not the spellbook one. Both
|
|
-- ship in the real SoundEntries.dbc.
|
|
if showing then PlaySound("igAbilityOpen") end
|
|
end
|
|
end
|
|
|
|
-- ref SpellBookFrame_SetTabType (l.166-183). `binding` is what the tab's tooltip appends
|
|
-- the bound key to (MicroButtonTooltipText); `petTitle` is set here as a side effect,
|
|
-- exactly as the ref does, because this is the only place the token is in hand.
|
|
function SpellBookFrame_SetTabType(tabButton, bookType, token)
|
|
if bookType == BOOKTYPE_SPELL then
|
|
tabButton.bookType = BOOKTYPE_SPELL
|
|
tabButton:SetText(SPELLBOOK)
|
|
tabButton.binding = "TOGGLESPELLBOOK"
|
|
else
|
|
tabButton.bookType = BOOKTYPE_PET
|
|
local label = getglobal("PET_TYPE_" .. (token or "PET")) or PET_TYPE_PET
|
|
tabButton:SetText(label)
|
|
tabButton.binding = "TOGGLEPETBOOK"
|
|
SpellBookFrame.petTitle = label
|
|
end
|
|
-- The tab for the book you are ON is disabled, which is also what draws it as the
|
|
-- selected (Tab1-Selected) plate — the ref uses <DisabledTexture> for the "current"
|
|
-- look rather than a checked state.
|
|
if SpellBookFrame.bookType == bookType then
|
|
tabButton:Disable()
|
|
else
|
|
tabButton:Enable()
|
|
end
|
|
tabButton:Show()
|
|
end
|
|
|
|
-- ref SpellBookFrame_OnHide (l.186-204): MultiActionBar_HideAllGrids and the tab-flash
|
|
-- cleanup OMITTED (header comment); always the spell-book close kit (no pet book to branch
|
|
-- on). UpdateMicroButtons is LIVE as of the micro-menu slice (MicroMenu.xml).
|
|
function SpellBookFrame_OnHide()
|
|
if UpdateMicroButtons then UpdateMicroButtons() end
|
|
if SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
PlaySound("igAbilityClose") -- ref l.191
|
|
else
|
|
PlaySound("igSpellBookClose")
|
|
end
|
|
end
|
|
|
|
-- UpdateSpells(): the ref's OWN global (`SpellBookFrame.lua:26/116/411/426/450` — never
|
|
-- DEFINED in this session's extraction, a base-UI/C-level helper outside this file)
|
|
-- transcribed here as BenillaUpdateSpells(): refresh every spell button on the current
|
|
-- page (this file's own convention: explicit button params, not ambient `this`).
|
|
function BenillaUpdateSpells()
|
|
for i = 1, SPELLS_PER_PAGE do
|
|
BenillaSpellButton_UpdateButton(getglobal("SpellButton" .. i))
|
|
end
|
|
end
|
|
|
|
-- ── The spell button (ref SpellButton_*, l.206-404) ──────────────────────────────────────
|
|
-- CRAFT_SHOW/_CLOSE/TRADE_SKILL_SHOW/_CLOSE are OMITTED (header comment: no craft or
|
|
-- trade-skill window arm); SPELLS_CHANGED and SPELL_UPDATE_COOLDOWN drive the full refresh
|
|
-- (the ref's own shared branch, l.221) and CURRENT_SPELL_CAST_CHANGED the checked ring.
|
|
-- PET_BAR_UPDATE is LIVE (ref l.214 + l.227-231) and it is the pet page's whole repaint
|
|
-- wire: the pet book's cooldowns, autocast bits and active ring all move without the BOOK
|
|
-- changing, so SPELLS_CHANGED alone would leave a stale page.
|
|
function SpellButton_OnLoad()
|
|
local button = this
|
|
button:RegisterEvent("SPELLS_CHANGED")
|
|
button:RegisterEvent("CURRENT_SPELL_CAST_CHANGED")
|
|
button:RegisterEvent("SPELL_UPDATE_COOLDOWN")
|
|
button:RegisterEvent("PET_BAR_UPDATE")
|
|
button:RegisterForDrag("LeftButton")
|
|
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
button.autocastable = getglobal(button:GetName() .. "AutoCastable")
|
|
-- The ref's `$parentAutoCast` is a <Model> playing UI-AutoCastButton.mdx; ours is
|
|
-- the native shine lane (decision 1383 — PetActionBar.xml's sparkle header has the
|
|
-- story, `autocast_shine` the numbers): $parentShine is the token marker, and
|
|
-- showing it is the whole enable.
|
|
button.shine = getglobal(button:GetName() .. "Shine")
|
|
BenillaSpellButton_UpdateButton(button)
|
|
end
|
|
|
|
function SpellButton_OnEvent(event)
|
|
local button = this
|
|
if event == "SPELLS_CHANGED" or event == "SPELL_UPDATE_COOLDOWN" then
|
|
BenillaSpellButton_UpdateButton(button)
|
|
elseif event == "CURRENT_SPELL_CAST_CHANGED" then
|
|
BenillaSpellButton_UpdateSelection(button)
|
|
elseif event == "PET_BAR_UPDATE" then
|
|
if SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
BenillaSpellButton_UpdateButton(button)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ref SpellButton_UpdateSelection (l.292-306): the checked ring — `IsCurrentCast` over
|
|
-- the app-resolved verdict (the ACTIVE shapeshift form's own spell — Ghost Wolf glows
|
|
-- while the shaman is the wolf, a druid form likewise; the engine predicate `0x4b3600`
|
|
-- deliberately has NO casting-now arm, so an ordinary cast never lights a book slot).
|
|
-- The ref's out-of-tab bounds fork collapses into the one SetChecked: IsCurrentCast
|
|
-- answers nil past the book's end already.
|
|
function BenillaSpellButton_UpdateSelection(button)
|
|
local id = SpellBook_GetSpellID(button:GetID())
|
|
button:SetChecked(IsCurrentCast(id, SpellBookFrame.bookType))
|
|
end
|
|
|
|
-- ref SpellButton_OnEnter (l.235-244): the engine's SetSpell — the byte-verified spell
|
|
-- line law (decision 0276: cost|range one line, casttime|cooldown one line, passives
|
|
-- omit it, the $-substituted gold description; no rank column from the book — the
|
|
-- verified showRank=0).
|
|
function BenillaSpellButton_OnEnter(button)
|
|
if not GameTooltip then return end -- engine tests load file subsets
|
|
local id = SpellBook_GetSpellID(button:GetID())
|
|
if not GetSpellName(id, SpellBookFrame.bookType) then
|
|
return
|
|
end
|
|
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
|
GameTooltip:SetSpell(id, SpellBookFrame.bookType)
|
|
end
|
|
|
|
-- ref SpellButton_OnClick (l.263-290): the MacroFrame branch and the right-click pet
|
|
-- autocast fork are both OMITTED (header comment) — shift-click always picks up (the
|
|
-- ref's own "no MacroFrame visible" fallthrough), every other click casts. The
|
|
-- `id > MAX_SPELLS` guard is dropped too: GetSpellName/CastSpell/PickupSpell already
|
|
-- answer nil/no-op for any id past the book's real length, so the extra guard checks
|
|
-- nothing a MAX_SPELLS constant would add here.
|
|
function SpellButton_OnClick(drag)
|
|
local button = this
|
|
-- The mouse button is the ambient `arg1`, exactly as the reference reads it (l.284) —
|
|
-- its XML passes nothing on OnClick and a bare `1` on the two drag slots. Only the
|
|
-- `drag` falsy arm below reaches it, so the drag slots never read a stale arg1.
|
|
local mouseButton = arg1
|
|
local id = SpellBook_GetSpellID(button:GetID())
|
|
button:SetChecked("false")
|
|
if drag then
|
|
PickupSpell(id, SpellBookFrame.bookType)
|
|
elseif not IsShiftKeyDown() and mouseButton and mouseButton ~= "LeftButton"
|
|
and SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
-- ref l.284-285: on the PET page a non-left click flips autocast instead of
|
|
-- casting. Shift still outranks it — the ref tests shift first, so a shift
|
|
-- right-click on a pet spell picks it up.
|
|
ToggleSpellAutocast(id, SpellBookFrame.bookType)
|
|
elseif IsShiftKeyDown() then
|
|
-- ref SpellButton_OnClick l.271-283 (LIVE since decision 0983): with the macro
|
|
-- editor open a shift-click APPENDS `/cast <name>[(<rank>)]` to the body instead of
|
|
-- picking the spell up — the behaviour MACRO_HELP_TEXT_LINE5 advertises ("Shift
|
|
-- click a spell in your spellbook with the macro UI open to add it to your macro").
|
|
-- The `/cast` alias comes from the shipped strings (SLASH_CAST1), never typed here.
|
|
--
|
|
-- DO NOT "FIX" THIS TO INSERT THE BARE NAME (B248, decision 1328). The whole
|
|
-- `/cast` line is what 1.12.1 writes; the bare-name-at-the-cursor insert people
|
|
-- remember is a LATER client's (`ChatEdit_InsertLink`). And the gate is SHIFT,
|
|
-- not the mouse button: a plain right click on this page casts, same as a left one
|
|
-- — pinned both ways in `ui_script::spellbook_tests`.
|
|
local macroFrame = getglobal("BenillaMacroFrame")
|
|
if macroFrame and macroFrame:IsVisible() then
|
|
local spellName, subSpellName = GetSpellName(id, SpellBookFrame.bookType)
|
|
if spellName and not IsSpellPassive(id, SpellBookFrame.bookType) then
|
|
local line = (SLASH_CAST1 or "/cast") .. " " .. spellName
|
|
if subSpellName and string.len(subSpellName) > 0 then
|
|
line = line .. "(" .. subSpellName .. ")"
|
|
end
|
|
BenillaMacroFrame_AddMacroLine(line)
|
|
end
|
|
else
|
|
PickupSpell(id, SpellBookFrame.bookType)
|
|
end
|
|
else
|
|
CastSpell(id, SpellBookFrame.bookType)
|
|
BenillaSpellButton_UpdateSelection(button) -- ref l.288: the ring re-reads at once
|
|
end
|
|
end
|
|
|
|
-- ref SpellButton_UpdateButton (l.307-404): the autocast overlay/model is OMITTED
|
|
-- (header comment); the cooldown sweep (l.359-365) and the checked-ring tail call are
|
|
-- LIVE. Passive gates CastSpell engine-side (spellbook.rs), not here — this only grays
|
|
-- the presentation.
|
|
function BenillaSpellButton_UpdateButton(button)
|
|
if not button:IsVisible() then
|
|
return
|
|
end
|
|
if GameTooltip:IsOwned(button) then
|
|
BenillaSpellButton_OnEnter(button)
|
|
end
|
|
if not SpellBookFrame.selectedSkillLine then
|
|
SpellBookFrame.selectedSkillLine = 1
|
|
end
|
|
local isPet = SpellBookFrame.bookType == BOOKTYPE_PET
|
|
local temp, tabTexture, offset, numSpells = GetSpellTabInfo(SpellBookFrame.selectedSkillLine)
|
|
offset = offset or 0
|
|
numSpells = numSpells or 0
|
|
SpellBookFrame.selectedSkillLineOffset = offset
|
|
local id = SpellBook_GetSpellID(button:GetID())
|
|
local name = button:GetName()
|
|
local iconTexture = getglobal(name .. "IconTexture")
|
|
local spellString = getglobal(name .. "SpellName")
|
|
local subSpellString = getglobal(name .. "SubSpellName")
|
|
local cooldown = getglobal(name .. "Cooldown")
|
|
local autocastable = getglobal(name .. "AutoCastable")
|
|
local highlightTexture = getglobal(name .. "Highlight")
|
|
local normalTexture = getglobal(name .. "NormalTexture")
|
|
|
|
-- TWO WAYS A SLOT COMES UP EMPTY, one dress for both. Past the end of the tab the
|
|
-- button also goes DEAD; a slot the book counts but has no icon for stays live and
|
|
-- only puts its highlight kit back to the square. Everything else the two do — the
|
|
-- five regions down, the autocast bit cleared, the ring unchecked, the button's own
|
|
-- ring back to plain white — is the same blanking, and it is written once here rather
|
|
-- than once per arm.
|
|
--
|
|
-- ref l.328: the out-of-tab test is `(bookType ~= BOOKTYPE_PET) and ...` — the pet
|
|
-- page has no tab to be out of, so a pet button past the end of the book falls to the
|
|
-- no-icon arm instead and stays ENABLED. Faithful, and harmless: an enabled button
|
|
-- with no spell behind it clicks into GetSpellName's nil and does nothing.
|
|
local outOfTab = (not isPet) and id > (offset + numSpells)
|
|
if outOfTab then
|
|
button:Disable()
|
|
else
|
|
button:Enable()
|
|
end
|
|
local texture
|
|
if not outOfTab then
|
|
texture = GetSpellTexture(id, SpellBookFrame.bookType)
|
|
end
|
|
if outOfTab or (not texture) or (texture == "") then
|
|
iconTexture:Hide()
|
|
spellString:Hide()
|
|
subSpellString:Hide()
|
|
cooldown:Hide()
|
|
autocastable:Hide()
|
|
button.shine:Hide()
|
|
if not outOfTab then
|
|
highlightTexture:SetTexture("Interface\\Buttons\\ButtonHilight-Square")
|
|
end
|
|
button:SetChecked(0)
|
|
normalTexture:SetVertexColor(1.0, 1.0, 1.0)
|
|
return
|
|
end
|
|
-- The cooldown sweep + the enable-keyed icon dim (ref l.359-365): enable == 0 is an
|
|
-- on-hold cooldown (Stealth/Feign Death parked until SMSG_COOLDOWN_EVENT) — the
|
|
-- widget stays hidden (CooldownFrame_SetTimer's own gate) and the icon reads 40%.
|
|
local start, duration, enable = GetSpellCooldown(id, SpellBookFrame.bookType)
|
|
CooldownFrame_SetTimer(cooldown, start, duration, enable)
|
|
local brightness = (enable == 1) and 1.0 or 0.4
|
|
iconTexture:SetVertexColor(brightness, brightness, brightness)
|
|
-- ref l.367-377: the autocast pair. `GetSpellAutocast` answers (nil, nil) for the
|
|
-- player book by the engine's own short-circuit, so this needs no isPet guard — the
|
|
-- overlay and the sparkle simply never come on outside the pet page. Showing the
|
|
-- shine marker IS the sparkle (decision 1383 — the native lane draws at it).
|
|
local autoCastAllowed, autoCastEnabled = GetSpellAutocast(id, SpellBookFrame.bookType)
|
|
if autoCastAllowed then autocastable:Show() else autocastable:Hide() end
|
|
if autoCastEnabled then button.shine:Show() else button.shine:Hide() end
|
|
local spellName, subSpellName = GetSpellName(id, SpellBookFrame.bookType)
|
|
local isPassive = IsSpellPassive(id, SpellBookFrame.bookType)
|
|
-- A passive slot wears a whole different dress — the button ring blacked right out,
|
|
-- the round passive highlight in place of the square one, and the name in the passive
|
|
-- grey. Three values that always travel together, so they are chosen once and applied
|
|
-- once instead of each verb appearing in both arms.
|
|
local ringLevel, highlightFile, nameColor
|
|
if isPassive then
|
|
ringLevel, highlightFile, nameColor =
|
|
0, "Interface\\Buttons\\UI-PassiveHighlight", PASSIVE_SPELL_FONT_COLOR
|
|
else
|
|
ringLevel, highlightFile, nameColor =
|
|
1.0, "Interface\\Buttons\\ButtonHilight-Square", NORMAL_FONT_COLOR
|
|
end
|
|
normalTexture:SetVertexColor(ringLevel, ringLevel, ringLevel)
|
|
highlightTexture:SetTexture(highlightFile)
|
|
spellString:SetTextColor(nameColor.r, nameColor.g, nameColor.b)
|
|
iconTexture:SetTexture(texture)
|
|
spellString:SetText(spellName)
|
|
subSpellString:SetText(subSpellName)
|
|
if subSpellName and subSpellName ~= "" then
|
|
spellString:SetPoint("LEFT", button, "RIGHT", 4, 4)
|
|
else
|
|
spellString:SetPoint("LEFT", button, "RIGHT", 4, 2)
|
|
end
|
|
iconTexture:Show()
|
|
spellString:Show()
|
|
subSpellString:Show()
|
|
BenillaSpellButton_UpdateSelection(button) -- ref l.403: every full refresh re-reads the ring
|
|
end
|
|
|
|
-- ── Page turn (ref PrevPageButton_OnClick/NextPageButton_OnClick, l.406-434) ─────────────
|
|
--
|
|
-- DO NOT "FIX" THE KEY (decision 1032, the standing rule from 1030). The reference writes
|
|
-- `SPELLBOOK_PAGENUMBERS[selectedSkillLine]` on BOTH books, while `SpellBook_GetCurrentPage`
|
|
-- reads `SPELLBOOK_PAGENUMBERS["pet"]` for the pet one — a key nothing writes. So on the
|
|
-- pet page the arrows turn nothing, the page text says a number the page does not honour,
|
|
-- and the *spell* book's page counter moves behind your back. All three are the reference's
|
|
-- and all three are reproduced; `SpellBook_GetSpellID`'s note is the other half.
|
|
function BenillaSpellBookPrevPageButton_OnClick()
|
|
local pageNum = SpellBook_GetCurrentPage() - 1
|
|
SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] = pageNum
|
|
SpellBook_UpdatePageArrows()
|
|
SpellBookPageText:SetText(format(PAGE_NUMBER, pageNum))
|
|
BenillaUpdateSpells()
|
|
-- ref l.414-417: the pet page re-asserts its own title, because the spell book's page
|
|
-- text handler is shared and the title is not.
|
|
if SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
SpellBookTitleText:SetText(SpellBookFrame.petTitle)
|
|
end
|
|
PlaySound("igAbiliityPageTurn")
|
|
end
|
|
|
|
function BenillaSpellBookNextPageButton_OnClick()
|
|
local pageNum = SpellBook_GetCurrentPage() + 1
|
|
SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] = pageNum
|
|
SpellBook_UpdatePageArrows()
|
|
SpellBookPageText:SetText(format(PAGE_NUMBER, pageNum))
|
|
BenillaUpdateSpells()
|
|
if SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
SpellBookTitleText:SetText(SpellBookFrame.petTitle)
|
|
end
|
|
PlaySound("igAbiliityPageTurn")
|
|
end
|
|
|
|
-- ── The skill-line tabs (ref SpellBookSkillLineTab_OnClick, l.436-457) ───────────────────
|
|
function SpellBookSkillLineTab_OnClick(id)
|
|
local update
|
|
if not id then
|
|
update = 1
|
|
id = this:GetID()
|
|
end
|
|
SpellBookFrame.selectedSkillLine = id
|
|
local name, texture, offset, numSpells = GetSpellTabInfo(id)
|
|
SpellBookFrame.selectedSkillLineOffset = offset or 0
|
|
SpellBookFrame.selectedSkillLineNumSpells = numSpells or 0
|
|
SpellBook_UpdatePageArrows()
|
|
SpellBookFrame_Update()
|
|
SpellBookPageText:SetText(format(PAGE_NUMBER, SpellBook_GetCurrentPage()))
|
|
if update then
|
|
BenillaUpdateSpells()
|
|
end
|
|
end
|
|
|
|
-- ref SpellBook_GetSpellID (l.459-465). This is the book id the engine's own byte-verified
|
|
-- seam expects verbatim (`benilla-ui/src/script/spellbook.rs`'s module doc).
|
|
--
|
|
-- DO NOT "FIX" THE PET ARM (decision 1032, the standing rule from 1030). The reference's
|
|
-- pet branch is a bare `return id` — no tab offset, and **no page term** — so the pet page
|
|
-- always shows book entries 1..12 no matter what page number the window is displaying. A
|
|
-- well-trained hunter pet can know more than twelve spells, so this is visible, and it is
|
|
-- still the reference's behaviour. Its sibling quirk is in the two page-turn handlers.
|
|
function SpellBook_GetSpellID(id)
|
|
if SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
return id
|
|
end
|
|
return id + (SpellBookFrame.selectedSkillLineOffset or 0)
|
|
+ (SPELLS_PER_PAGE * ((SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] or 1) - 1))
|
|
end
|
|
|
|
-- ref SpellBook_UpdatePageArrows (l.467-479). An arrow is live exactly while the page it
|
|
-- points at is a DIFFERENT page. Stated as an inequality rather than a range test on
|
|
-- purpose: the pet book's arrows write a counter its own page ignores (the do-not-fix
|
|
-- notes above), so a page number can sit outside 1..maxPages, and when it does BOTH arrows
|
|
-- stay live — which is the reference's answer, not an accident of this spelling.
|
|
function SpellBook_UpdatePageArrows()
|
|
local currentPage, maxPages = SpellBook_GetCurrentPage()
|
|
if currentPage ~= 1 then SpellBookPrevPageButton:Enable() else SpellBookPrevPageButton:Disable() end
|
|
if currentPage ~= maxPages then SpellBookNextPageButton:Enable() else SpellBookNextPageButton:Disable() end
|
|
end
|
|
|
|
-- ref SpellBook_GetCurrentPage (l.481-493), both branches. `maxPages` is clamped to at
|
|
-- least 1 (a defensive addition this file's own — an empty/not-yet-fed book must still
|
|
-- show ONE (empty) page rather than disabling both page buttons into a currentPage=1 >
|
|
-- maxPages=0 dead state).
|
|
--
|
|
-- The pet branch reads `SPELLBOOK_PAGENUMBERS["pet"]`, which is the counter NOTHING ever
|
|
-- writes — see the page-turn handlers. So it is always 1, and with it `maxPages > 1` the
|
|
-- Next arrow stays enabled forever on a big pet book. Reference behaviour; see the
|
|
-- do-not-fix note on `SpellBook_GetSpellID`.
|
|
function SpellBook_GetCurrentPage()
|
|
local numPetSpells = HasPetSpells()
|
|
if numPetSpells and SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
return SPELLBOOK_PAGENUMBERS["pet"] or 1,
|
|
max(ceil(numPetSpells / SPELLS_PER_PAGE), 1)
|
|
end
|
|
local currentPage = SPELLBOOK_PAGENUMBERS[SpellBookFrame.selectedSkillLine] or 1
|
|
local temp, texture, offset, numSpells = GetSpellTabInfo(SpellBookFrame.selectedSkillLine)
|
|
local maxPages = max(ceil((numSpells or 0) / SPELLS_PER_PAGE), 1)
|
|
return currentPage, maxPages
|
|
end
|
|
]]></Script>
|
|
|
|
<!--
|
|
The skill-line tab (ref SpellBookSkillLineTabTemplate, l.4-39): 32x32, the
|
|
SpellBook-SkillLineTab 64x64 backdrop offset (-3,11), an empty NormalTexture placeholder
|
|
(filled at runtime by SetNormalTexture — SetNormalTexture creates the region lazily on
|
|
first call, `benilla-ui/src/script/button.rs`'s `ensure_slot`, verified this session), the
|
|
ADD highlight + CheckedTexture ring for the SELECTED tab.
|
|
-->
|
|
<CheckButton name="BenillaSpellBookSkillLineTabTemplate" virtual="true">
|
|
<Size><AbsDimension x="32" y="32"/></Size>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<Texture file="Interface\SpellBook\SpellBook-SkillLineTab">
|
|
<Size><AbsDimension x="64" y="64"/></Size>
|
|
<Anchors>
|
|
<Anchor point="TOPLEFT"><Offset><AbsDimension x="-3" y="11"/></Offset></Anchor>
|
|
</Anchors>
|
|
</Texture>
|
|
</Layer>
|
|
</Layers>
|
|
<NormalTexture/>
|
|
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
|
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
|
<Scripts>
|
|
<OnClick>SpellBookSkillLineTab_OnClick()</OnClick>
|
|
<OnEnter>
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
if self.tooltip then
|
|
GameTooltip:SetText(self.tooltip)
|
|
GameTooltip:Show()
|
|
end
|
|
</OnEnter>
|
|
<OnLeave>GameTooltip:Hide()</OnLeave>
|
|
</Scripts>
|
|
</CheckButton>
|
|
|
|
<!--
|
|
The spell button (ref SpellButtonTemplate, l.74-201): 37x37, the UI-Spellbook-SpellBackground
|
|
64x64 backdrop offset (-3,3), the icon (setAllPoints, hidden until fed), the name/rank
|
|
FontStrings anchored off the button's own RIGHT edge, the UI-Quickslot2 ring + Depress push +
|
|
ADD highlight + the CheckedTexture ring (`IsCurrentCast`'s glow), and the Cooldown child
|
|
(ref l.136: $parentCooldown inherits CooldownFrameTemplate — ours is the native Cooldown
|
|
widget at the template's own 36x36 CENTER (0,-1), the ActionBar/BagFrame transcription).
|
|
The AutoCast overlay/model is OMITTED (this file's header comment — pet-only autocast).
|
|
-->
|
|
<CheckButton name="BenillaSpellButtonTemplate" virtual="true">
|
|
<Size><AbsDimension x="37" y="37"/></Size>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<Texture name="$parentBackground" file="Interface\Spellbook\UI-Spellbook-SpellBackground">
|
|
<Size><AbsDimension x="64" y="64"/></Size>
|
|
<Anchors>
|
|
<Anchor point="TOPLEFT"><Offset><AbsDimension x="-3" y="3"/></Offset></Anchor>
|
|
</Anchors>
|
|
</Texture>
|
|
</Layer>
|
|
<Layer level="OVERLAY">
|
|
<!-- The corner brackets that say a pet spell CAN autocast. The art fills only the
|
|
middle 33/64 = 0.5156 of UI-AutoCastableOverlay.blp, so where the brackets land
|
|
is set entirely by how big the texture is drawn:
|
|
|
|
pet button ref 58 -> 58 x 0.5156 = 29.9 on a 30 button. Dead in the corners.
|
|
spell book ref 60 -> 60 x 0.5156 = 30.9 on a 37 button. THREE UNITS INSIDE
|
|
each edge, floating — the ref barely grew the overlay (58->60)
|
|
while the button grew 30->37.
|
|
|
|
DEVIATION 2 of 3 in this widget (decision 1393, extending 1392). 71.53 is the
|
|
pet button's own ratio carried over — 37 x 58/30 — so the bracket square lands
|
|
on this button's corners exactly as it does on that one. Write 60 to go back to
|
|
the reference. -->
|
|
<Texture name="$parentAutoCastable" file="Interface\Buttons\UI-AutoCastableOverlay" hidden="true">
|
|
<Size><AbsDimension x="71.53" y="71.53"/></Size>
|
|
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Texture>
|
|
<!-- The animated sibling: the ref's $parentAutoCast <Model>, which on this
|
|
template carries its own 36x36 CENTER (1,1) rect at scale="1.22".
|
|
|
|
DEVIATION 3 of 3 (decision 1393, extending 1392), and both halves are the same
|
|
idea — borrow the pet button's proportions so this button reads like that one:
|
|
|
|
* rect 36 CENTER (1,1) -> 37 CENTER (0,0). The ref's +1,+1 puts the glow a
|
|
unit up-and-right of the brackets, which sit dead centre; measured on the
|
|
director's capture, the glow's centre really was ~1 unit right of the
|
|
button's. Concentric now, so top/right stop reading loose.
|
|
* scale 1.22 -> 1.48. 0.02 x 1280 x 1.48 = 37.888 = 1.024 x 37 — the same
|
|
1.024 rim/viewport ratio the ref writes on the pet button, which is what
|
|
puts the rim ON the viewport edge so the widget's own scissor halves every
|
|
star (1387). At the ref's 0.87x the rim floats clear and nothing clips it.
|
|
|
|
To go back to the reference exactly: 36x36, CENTER (1,1), and 1.22. -->
|
|
<Texture name="$parentShine" file="benilla:autocast-shine:1.48" hidden="true">
|
|
<Size><AbsDimension x="37" y="37"/></Size>
|
|
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
|
|
</Texture>
|
|
</Layer>
|
|
<Layer level="BORDER">
|
|
<Texture name="$parentIconTexture" setAllPoints="true" hidden="true"/>
|
|
<!-- maxLines="3" unmodeled (this file's header comment) — wraps unbounded instead. -->
|
|
<FontString name="$parentSpellName" inherits="GameFontNormal" hidden="true" justifyH="LEFT">
|
|
<Size><AbsDimension x="103" y="0"/></Size>
|
|
<Anchors>
|
|
<Anchor point="LEFT" relativePoint="RIGHT"><Offset><AbsDimension x="4" y="0"/></Offset></Anchor>
|
|
</Anchors>
|
|
</FontString>
|
|
<FontString name="$parentSubSpellName" inherits="SubSpellFont" hidden="true" justifyH="LEFT">
|
|
<Size><AbsDimension x="79" y="18"/></Size>
|
|
<Anchors>
|
|
<Anchor point="TOPLEFT" relativeTo="$parentSpellName" relativePoint="BOTTOMLEFT">
|
|
<Offset><AbsDimension x="0" y="4"/></Offset>
|
|
</Anchor>
|
|
</Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Frames>
|
|
<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>
|
|
<Scripts>
|
|
<OnLoad>SpellButton_OnLoad()</OnLoad>
|
|
<OnEvent>SpellButton_OnEvent(event)</OnEvent>
|
|
<OnClick>SpellButton_OnClick()</OnClick>
|
|
<OnShow>BenillaSpellButton_UpdateButton(self)</OnShow>
|
|
<!-- The reference routes both drag entries to the plain click path with drag=1
|
|
(SpellButtonTemplate l.169-174) — the bag/doll/action slots' own precedent. -->
|
|
<OnDragStart>SpellButton_OnClick(1)</OnDragStart>
|
|
<OnReceiveDrag>SpellButton_OnClick(1)</OnReceiveDrag>
|
|
<OnEnter>BenillaSpellButton_OnEnter(self)</OnEnter>
|
|
<OnLeave>GameTooltip:Hide()</OnLeave>
|
|
</Scripts>
|
|
<NormalTexture name="$parentNormalTexture" file="Interface\Buttons\UI-Quickslot2">
|
|
<Size><AbsDimension x="64" y="64"/></Size>
|
|
<Anchors><Anchor point="CENTER"/></Anchors>
|
|
</NormalTexture>
|
|
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
|
|
<HighlightTexture name="$parentHighlight" file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
|
|
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
|
|
</CheckButton>
|
|
|
|
<!--
|
|
The Spell/Pet toggle tab (ref SpellBookFrameTabButtonTemplate, l.40-71): a 128x64 plate
|
|
that hangs off the window's bottom-left, drawn UNSELECTED normally and swapping to the
|
|
selected plate through its <DisabledTexture> — the ref uses Disable() for "this is the
|
|
book you are on", not a checked state, which is why this is a plain Button and not a
|
|
CheckButton. Hidden by default; SpellBookFrame_Update raises exactly the ones that exist.
|
|
-->
|
|
<Button name="BenillaSpellBookFrameTabButtonTemplate" virtual="true" hidden="true">
|
|
<Size><AbsDimension x="128" y="64"/></Size>
|
|
<HitRectInsets><AbsInset left="15" right="14" top="13" bottom="15"/></HitRectInsets>
|
|
<Scripts>
|
|
<OnClick>ToggleSpellBook(self.bookType)</OnClick>
|
|
<OnEnter>
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
-- ref l.53: the label plus its bound key. MicroButtonTooltipText is MicroMenu.xml's
|
|
-- (loaded before this file); nil-guarded like every other cross-file call here.
|
|
if MicroButtonTooltipText then
|
|
GameTooltip:SetText(MicroButtonTooltipText(self:GetText(), self.binding), 1.0, 1.0, 1.0)
|
|
else
|
|
GameTooltip:SetText(self:GetText(), 1.0, 1.0, 1.0)
|
|
end
|
|
GameTooltip:Show()
|
|
</OnEnter>
|
|
<OnLeave>GameTooltip:Hide()</OnLeave>
|
|
</Scripts>
|
|
<ButtonText>
|
|
<Anchors><Anchor point="CENTER"><Offset><AbsDimension x="0" y="3"/></Offset></Anchor></Anchors>
|
|
</ButtonText>
|
|
<NormalFont inherits="GameFontNormalSmall"/>
|
|
<HighlightFont inherits="GameFontHighlightSmall"/>
|
|
<DisabledFont inherits="GameFontHighlightSmall"/>
|
|
<NormalTexture file="Interface\SpellBook\UI-SpellBook-Tab-Unselected"/>
|
|
<HighlightTexture file="Interface\SpellBook\UI-SpellbookPanel-Tab-Highlight" alphaMode="ADD"/>
|
|
</Button>
|
|
|
|
<Frame name="SpellBookFrame" hidden="true">
|
|
<!-- The real 384x512 window (ref l.202-205). No <Anchors> — ShowUIPanel/SetLeftFrame
|
|
SetPoints this to the left slot on open (UiPanels.xml's own convention). -->
|
|
<Size><AbsDimension x="384" y="512"/></Size>
|
|
<!-- HitRectInsets: transcribed for fidelity; no loader wiring exists yet (CharacterFrame's
|
|
own precedent note) — a harmless no-op today. -->
|
|
<HitRectInsets><AbsInset left="0" right="30" top="0" bottom="70"/></HitRectInsets>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<Texture file="Interface\Spellbook\Spellbook-Icon">
|
|
<Size><AbsDimension x="58" y="58"/></Size>
|
|
<Anchors>
|
|
<Anchor point="TOPLEFT"><Offset><AbsDimension x="10" y="-8"/></Offset></Anchor>
|
|
</Anchors>
|
|
</Texture>
|
|
</Layer>
|
|
<Layer level="ARTWORK">
|
|
<!-- The four quadrant plates, anchored off the frame's own corners exactly like
|
|
the ref (l.231-263) — simpler than CharacterFrame's TOPLEFT-offset scheme
|
|
since the ref itself uses the corner anchors directly here. -->
|
|
<Texture file="Interface\Spellbook\UI-SpellbookPanel-TopLeft">
|
|
<Size><AbsDimension x="256" y="256"/></Size>
|
|
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
|
</Texture>
|
|
<Texture file="Interface\Spellbook\UI-SpellbookPanel-TopRight">
|
|
<Size><AbsDimension x="128" y="256"/></Size>
|
|
<Anchors><Anchor point="TOPRIGHT"/></Anchors>
|
|
</Texture>
|
|
<Texture file="Interface\Spellbook\UI-SpellbookPanel-BotLeft">
|
|
<Size><AbsDimension x="256" y="256"/></Size>
|
|
<Anchors><Anchor point="BOTTOMLEFT"/></Anchors>
|
|
</Texture>
|
|
<Texture file="Interface\Spellbook\UI-SpellbookPanel-BotRight">
|
|
<Size><AbsDimension x="128" y="256"/></Size>
|
|
<Anchors><Anchor point="BOTTOMRIGHT"/></Anchors>
|
|
</Texture>
|
|
<FontString name="SpellBookTitleText" inherits="GameFontNormal" text="SPELLBOOK">
|
|
<Anchors>
|
|
<Anchor point="CENTER"><Offset><AbsDimension x="6" y="230"/></Offset></Anchor>
|
|
</Anchors>
|
|
</FontString>
|
|
<FontString name="SpellBookPageText" inherits="GameFontNormal">
|
|
<Size><AbsDimension x="102" y="0"/></Size>
|
|
<Anchors>
|
|
<Anchor point="BOTTOM"><Offset><AbsDimension x="-14" y="96"/></Offset></Anchor>
|
|
</Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Frames>
|
|
<!-- Close: the house minimize-button art (no UIPanelCloseButton template ships —
|
|
Gossip/Bag/Merchant/CharacterFrame's own precedent), the same TOPRIGHT(-44,-25)
|
|
position as every other window's close button. -->
|
|
<Button name="SpellBookFrameCloseButton">
|
|
<Size><AbsDimension x="32" y="32"/></Size>
|
|
<Anchors><Anchor point="CENTER" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-44" y="-25"/></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>HideUIPanel(SpellBookFrame)</OnClick>
|
|
</Scripts>
|
|
</Button>
|
|
|
|
<!-- ref l.288-317. Tab 3 exists in the ref's own XML and is never raised in 1.12
|
|
(there is no third book); kept so the anchor chain reads like the ref's. -->
|
|
<Button name="SpellBookFrameTabButton1" inherits="BenillaSpellBookFrameTabButtonTemplate">
|
|
<Anchors>
|
|
<Anchor point="CENTER" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="79" y="61"/></Offset></Anchor>
|
|
</Anchors>
|
|
<DisabledTexture file="Interface\SpellBook\UI-SpellBook-Tab1-Selected"/>
|
|
</Button>
|
|
<Button name="SpellBookFrameTabButton2" inherits="BenillaSpellBookFrameTabButtonTemplate">
|
|
<Anchors>
|
|
<Anchor point="LEFT" relativeTo="SpellBookFrameTabButton1" relativePoint="RIGHT">
|
|
<Offset><AbsDimension x="-20" y="0"/></Offset>
|
|
</Anchor>
|
|
</Anchors>
|
|
<DisabledTexture file="Interface\SpellBook\UI-SpellBook-Tab1-Selected"/>
|
|
</Button>
|
|
<Button name="SpellBookFrameTabButton3" inherits="BenillaSpellBookFrameTabButtonTemplate">
|
|
<Anchors>
|
|
<Anchor point="LEFT" relativeTo="SpellBookFrameTabButton2" relativePoint="RIGHT">
|
|
<Offset><AbsDimension x="-20" y="0"/></Offset>
|
|
</Anchor>
|
|
</Anchors>
|
|
<DisabledTexture file="Interface\SpellBook\UI-SpellBook-Tab3-Selected"/>
|
|
</Button>
|
|
|
|
<Button name="SpellBookPrevPageButton">
|
|
<Size><AbsDimension x="32" y="32"/></Size>
|
|
<Anchors>
|
|
<Anchor point="CENTER" relativeTo="SpellBookFrame" relativePoint="BOTTOMLEFT">
|
|
<Offset><AbsDimension x="50" y="105"/></Offset>
|
|
</Anchor>
|
|
</Anchors>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<FontString inherits="GameFontNormal" justifyH="LEFT" text="PREV">
|
|
<Anchors><Anchor point="LEFT" relativeTo="SpellBookPrevPageButton" relativePoint="RIGHT"/></Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Scripts><OnClick>BenillaSpellBookPrevPageButton_OnClick()</OnClick></Scripts>
|
|
<NormalTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Up"/>
|
|
<PushedTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Down"/>
|
|
<DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-PrevPage-Disabled"/>
|
|
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD"/>
|
|
</Button>
|
|
<Button name="SpellBookNextPageButton">
|
|
<Size><AbsDimension x="32" y="32"/></Size>
|
|
<Anchors>
|
|
<Anchor point="CENTER" relativeTo="SpellBookFrame" relativePoint="BOTTOMLEFT">
|
|
<Offset><AbsDimension x="314" y="105"/></Offset>
|
|
</Anchor>
|
|
</Anchors>
|
|
<Layers>
|
|
<Layer level="BACKGROUND">
|
|
<FontString inherits="GameFontNormal" justifyH="RIGHT" text="NEXT">
|
|
<Anchors><Anchor point="RIGHT" relativeTo="SpellBookNextPageButton" relativePoint="LEFT"/></Anchors>
|
|
</FontString>
|
|
</Layer>
|
|
</Layers>
|
|
<Scripts><OnClick>BenillaSpellBookNextPageButton_OnClick()</OnClick></Scripts>
|
|
<NormalTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Up"/>
|
|
<PushedTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Down"/>
|
|
<DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Disabled"/>
|
|
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD"/>
|
|
</Button>
|
|
|
|
<!-- The 12-spell page grid (ref l.387-494): 2 columns x 6 rows, ids assigned the
|
|
ref's own column-major pattern (col1 ids 1-6, col2 ids 7-12) — SpellBook_GetSpellID
|
|
reads a button's `id=` as its within-page/within-tab 1-based position, not its
|
|
screen order. -->
|
|
<CheckButton name="SpellButton1" inherits="BenillaSpellButtonTemplate" id="1">
|
|
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="34" y="-85"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton2" inherits="BenillaSpellButtonTemplate" id="7">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton1"><Offset><AbsDimension x="157" y="0"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton3" inherits="BenillaSpellButtonTemplate" id="2">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-14"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton4" inherits="BenillaSpellButtonTemplate" id="8">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton3"><Offset><AbsDimension x="157" y="0"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton5" inherits="BenillaSpellButtonTemplate" id="3">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-14"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton6" inherits="BenillaSpellButtonTemplate" id="9">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton5"><Offset><AbsDimension x="157" y="0"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton7" inherits="BenillaSpellButtonTemplate" id="4">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-14"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton8" inherits="BenillaSpellButtonTemplate" id="10">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton7"><Offset><AbsDimension x="157" y="0"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton9" inherits="BenillaSpellButtonTemplate" id="5">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-14"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton10" inherits="BenillaSpellButtonTemplate" id="11">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton9"><Offset><AbsDimension x="157" y="0"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton11" inherits="BenillaSpellButtonTemplate" id="6">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-14"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellButton12" inherits="BenillaSpellButtonTemplate" id="12">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellButton11"><Offset><AbsDimension x="157" y="0"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
|
|
<!-- The right-edge skill-line tabs, up to MAX_SKILLLINE_TABS (8) — ref l.495-566. -->
|
|
<CheckButton name="SpellBookSkillLineTab1" inherits="BenillaSpellBookSkillLineTabTemplate" id="1">
|
|
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-32" y="-65"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab2" inherits="BenillaSpellBookSkillLineTabTemplate" id="2">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab3" inherits="BenillaSpellBookSkillLineTabTemplate" id="3">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab4" inherits="BenillaSpellBookSkillLineTabTemplate" id="4">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab5" inherits="BenillaSpellBookSkillLineTabTemplate" id="5">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab6" inherits="BenillaSpellBookSkillLineTabTemplate" id="6">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab7" inherits="BenillaSpellBookSkillLineTabTemplate" id="7">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
<CheckButton name="SpellBookSkillLineTab8" inherits="BenillaSpellBookSkillLineTabTemplate" id="8">
|
|
<Anchors><Anchor point="TOPLEFT" relativeTo="SpellBookSkillLineTab7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-17"/></Offset></Anchor></Anchors>
|
|
</CheckButton>
|
|
</Frames>
|
|
<Scripts>
|
|
<OnLoad>SpellBookFrame_OnLoad()</OnLoad>
|
|
<OnEvent>SpellBookFrame_OnEvent()</OnEvent>
|
|
<OnShow>SpellBookFrame_OnShow()</OnShow>
|
|
<OnHide>SpellBookFrame_OnHide()</OnHide>
|
|
</Scripts>
|
|
</Frame>
|
|
</Ui>
|