- spells shake the camera: `SpellEffectCameraShakes.dbc` loads beside `CameraShakes.dbc` as the group table, `SpellVisualKit` field 14 is the shake column (58 of 1772 kits carry one — War Stomp, Thunder Clap, Kodo Stomp, the ~50 Knockdown/Slam/Charge impacts, every summon, Sapper Charge, Earthquake, Sapphiron's death), and the kit shake fires exactly once per play from the first effect node's one-time arm pass (`0x620e11`), the same leg that plays the kit sound one field over — the older "fires only if nothing else did" reading would have silenced every kit with a populated effect slot; `$SHK` markers fire from GameObject and DynamicObject hosts only (the titan chest, the bomb wagon); one deliberate deviation — the reference reads a bone-attached node's position twelve instructions before it is written, so 26 of its 58 shake kits shake at the world origin and are culled by the 80 yd cut, which is an uninitialised field, not a design; 21 of 24 presets now have a live producer, up from 6 - the sound keeps playing when the window loses focus, if you want it to: 1.12 mutes everything on `WM_ACTIVATE` and offers no way out, so benilla ships that as the default (`Sound_EnableSoundWhenGameIsInBG` "0") and puts an Audio-page checkbox on it — a gate appended LAST in the main-track chain, downstream of every tap, so an unattended capture still records; wow-re's round settled that music is not exempt and that it is a mute, not a pause - a building's far side no longer draws through its own walls: the camera-inside leg has three passes and we had one and a half — Pass 2 admits an exterior-shell group only against a frustum clipped to ONE deferred window (we marked every such group visible against the full view, under a comment calling it a benign over-draw), and Pass 3, which we had none of, draws the 24 `0x10000` groups (14 in Stormwind, 6 across Dire Maul, Razorfen's four 450–520 yd shells) from anywhere, frustum-tested on both legs by byte-identical setup; there is no antiportal branch in 5875 and no such flag in its data (815/815 roots and 5220/5220 groups censused, no bit above 18 ever set) - the macro window is the reference's own `Blizzard_MacroUI`, and `GlobalStrings.lua` — line 1 of the reference's own toc — was missing from our manifest entirely (the app loaded it out of band at startup, so the client was right and every harness that loaded the manifest was not); exactly one `<OnLoad>` runs, the most-derived, because `SetScript` releases the slot before it looks at the new body — which is why the reference re-states the template's width line in tab 1 and not tab 2 Co-Authored-By: Claude Fable 5.1 <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("MacroFrame")
|
|
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
|
|
MacroFrame_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" enableMouse="true" toplevel="true" parent="UIParent" 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>
|