c7ff319ccc
PaperDollStatTooltip upper-cases UnitClass(unit)'s token, and a unit whose class byte has no ChrClasses row answers two nils (UnitClass, 0x518350): the server's demons do, so hovering the pet page's stats raised "bad argument #1 to strupper". Such a unit now gets the stock default line, in both styles. LEARNED_SPELL_IN_TAB's glow flashed where 1.12's hidden skill line tabs stood: it now sits on the book's own tabs, and choosing a tab stops it, as SpellBookSkillLineTab_OnClick does. Verified: harness probe (the pet tooltip shows the default strength line, no error; the tab 2 glow's center matches our tab 2's; choosing tab 2 hides it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1007 lines
33 KiB
Lua
1007 lines
33 KiB
Lua
-- After data/addon/ForeverUI/SpellBook.lua: camelot's spellbook (blizzard_playerspells) inside
|
|
-- 1.12's SpellBookFrame. SpellBookFrame keeps its open and close paths (ToggleSpellBook, the P
|
|
-- and Shift-P bindings, the micro button) and its close button, re-skinned; its art, tabs and
|
|
-- twelve spell buttons are hidden.
|
|
-- 1.12 casts from any button (CastSpell is not protected), so the cells are plain buttons and
|
|
-- the 3.3.5 port's secure controller goes. Clicks follow 1.12's SpellButton_OnClick: Shift
|
|
-- adds a /cast line to an open macro window or picks the spell up, right click toggles a pet
|
|
-- spell's autocast.
|
|
-- Differences with camelot, beyond the 3.3.5 port's (square icons, no upcoming spells):
|
|
-- * no flyout groups: 1.12 has no GetSpellInfo to name a group's spells by id;
|
|
-- * no search;
|
|
-- * "Show all spell ranks" is ours (1.12 has no ShowAllSpellRanks CVar) and on by default,
|
|
-- as 1.12's own book lists every rank.
|
|
|
|
if not MoonWellUI_IsForever() then
|
|
return
|
|
end
|
|
|
|
local L = ForeverUI.L
|
|
local B = {}
|
|
ForeverUI.SpellBook = B
|
|
|
|
-- Layout values from blizzard_playerspells: PlayerSpellsFrame, SpellBookFrame,
|
|
-- CategoryTabSystem, PagedSpellsFrame (PagedCondensedVerticalGrid), PagingControls.
|
|
local G = {
|
|
width = 1618, compactWidth = 809, height = 720, top = -116,
|
|
fitExtraW = 200, fitExtraH = 140, clampBottom = 140, clampTop = -10,
|
|
bookW = 1612, reducedBookW = 806, bookH = 702, bookBottom = 4,
|
|
tabsX = 70, tabsY = -26, tabW = 44, tabH = 32, tabGap = 1,
|
|
tabIconW = 34, tabIconH = 33,
|
|
pagesTop = -50, viewW = 680, viewH = 590, view1X = 85, viewY = -45, view2X = -50,
|
|
columns = 3, gapX = 15, gapY = 10, headerH = 51, spellH = 60, space = 20,
|
|
pagerX = -75, pagerY = 40, pagerGap = 8, arrowSide = 32,
|
|
buttonSide = 40, iconSide = 36, textX = 50,
|
|
cellsPerView = 24,
|
|
closeX = -2, closeY = 1, redSide = 24,
|
|
portraitX = -5, portraitY = 7, portraitSide = 62,
|
|
titleX1 = 58, titleX2 = -24, titleY = -1, titleH = 20,
|
|
settingsX = -30, settingsY = -27, settingsW = 15, settingsH = 16,
|
|
metalLevel = 20, portraitLevel = 19, titleLevel = 21, buttonLevel = 22,
|
|
backplateAlpha = 0.25, hoverAlpha = 0.35, pressedAlpha = 0.65,
|
|
}
|
|
G.cellW = (G.viewW - G.gapX * (G.columns - 1)) / G.columns
|
|
B.G = G
|
|
|
|
-- metal corners: PortraitFrameTemplate as camelot adjusts it
|
|
local METAL = {
|
|
{ key = "topLeft", name = "ui-frame-portraitmetal-cornertopleft", point = "TOPLEFT", x = -13, y = 16 },
|
|
{ key = "topRight", name = "ui-frame-metal-cornertopright", point = "TOPRIGHT", x = 2, y = 16 },
|
|
{ key = "bottomLeft", name = "ui-frame-metal-cornerbottomleft", point = "BOTTOMLEFT", x = -13, y = -8 },
|
|
{ key = "bottomRight", name = "ui-frame-metal-cornerbottomright", point = "BOTTOMRIGHT", x = 2, y = -8 },
|
|
}
|
|
|
|
local INK = { 0.18, 0.106, 0.059 } -- SPELLBOOK_FONT_COLOR
|
|
local TEXT = {
|
|
title = SPELLBOOK,
|
|
page = L.SPELLBOOK_PAGE,
|
|
passive = SPELL_PASSIVE,
|
|
hidePassives = L.SPELLBOOK_HIDE_PASSIVES,
|
|
allRanks = MOONWELLUI_TEXT.ALL_RANKS,
|
|
}
|
|
|
|
-- Settings menu (camelot's SetupSettingsDropdown, as DropDown.lua skins the client list):
|
|
-- rows of 20 at x 11 from 15 down, text 20 in, a ticked square of 12, the yellow check 15 x 14
|
|
-- at (2, 1); common-dropdown-bg-c60 nine-slice at 0.925; closes 2 s after the mouse leaves.
|
|
local MENU = {
|
|
rowH = 20, edge = 15, rowX = 11, textX = 20, extraWidth = 40, margin = 25,
|
|
checkbox = 12, checkMarkW = 15, checkMarkH = 14, checkMarkX = 2, checkMarkY = 1,
|
|
backgroundCorner = 18, backgroundMargins = { 9, 6, 9, 12 }, backgroundAlpha = 0.925, pending = 2,
|
|
}
|
|
local SETTINGS = {
|
|
{ key = "hidePassives", text = TEXT.hidePassives },
|
|
{ key = "allRanks", text = TEXT.allRanks },
|
|
}
|
|
|
|
local FILES = {
|
|
rock = "Interface\\ForeverUI\\framegeneral\\ui-background-rock",
|
|
arrows = "Interface\\Buttons\\UI-SpellbookIcon-",
|
|
squareHover = "Interface\\Buttons\\UI-Common-MouseHilight",
|
|
classIcon = "Interface\\ForeverUI\\icons\\classicon_",
|
|
-- the icon of camelot's General line (inv_misc_book_09), its round mask baked in
|
|
portrait = "Interface\\ForeverUI\\spellbook\\portrait",
|
|
rowHighlight = "Interface\\QuestFrame\\UI-QuestTitleHighlight",
|
|
petIcons = {
|
|
HUNTER = "Interface\\Icons\\Ability_Hunter_BeastTaming",
|
|
WARLOCK = "Interface\\Icons\\Spell_Shadow_SummonImp",
|
|
},
|
|
}
|
|
|
|
local function settings()
|
|
ForeverUIDB = ForeverUIDB or {}
|
|
ForeverUIDB.spellbook = ForeverUIDB.spellbook or {}
|
|
local s = ForeverUIDB.spellbook
|
|
if s.allRanks == nil then
|
|
s.allRanks = true
|
|
end
|
|
return s
|
|
end
|
|
|
|
local function font(fs, size, c)
|
|
fs:SetFont((GameFontNormal:GetFont()), size)
|
|
c = c or INK
|
|
fs:SetTextColor(c[1], c[2], c[3])
|
|
end
|
|
|
|
local function atlas(t, name, keep)
|
|
return ForeverUI.SetAtlas(t, name, keep)
|
|
end
|
|
|
|
-- Hides a client region or frame for good: SpellBookFrame_Update shows its tabs again.
|
|
local function suppress(f)
|
|
f:SetAlpha(0)
|
|
if f.EnableMouse then
|
|
f:EnableMouse(false)
|
|
end
|
|
f:Hide()
|
|
end
|
|
|
|
-- ---------------------------------------------------------------- Data
|
|
|
|
-- camelot's categories: one per spell tab (General with the class icon, then one per class
|
|
-- tree), plus the pet's (HasPetSpells: count and PET_TYPE_ token).
|
|
function B.categories()
|
|
local list = {}
|
|
for i = 1, GetNumSpellTabs() do
|
|
local name, icon, offset, count = GetSpellTabInfo(i)
|
|
if name then
|
|
if i == 1 then
|
|
local _, token = UnitClass("player")
|
|
icon = FILES.classIcon .. string.lower(token or "warrior")
|
|
end
|
|
table.insert(list, { name = name, icon = icon, offset = offset, count = count, book = BOOKTYPE_SPELL })
|
|
end
|
|
end
|
|
local count, token = HasPetSpells()
|
|
if count and count > 0 then
|
|
local _, class = UnitClass("player")
|
|
table.insert(list, { name = getglobal("PET_TYPE_" .. (token or "PET")) or PET_TYPE_PET,
|
|
icon = FILES.petIcons[class or ""] or FILES.petIcons.HUNTER,
|
|
offset = 0, count = count, book = BOOKTYPE_PET, pet = true })
|
|
end
|
|
return list
|
|
end
|
|
|
|
-- A category's spells. Without all ranks a spell keeps its highest rank, the last of its line;
|
|
-- hide passives drops IsSpellPassive's.
|
|
function B.spellsOf(cat)
|
|
local s = settings()
|
|
local spells, last = {}, {}
|
|
for slot = cat.offset + 1, cat.offset + cat.count do
|
|
local name, rank = GetSpellName(slot, cat.book)
|
|
local passive = name and IsSpellPassive(slot, cat.book) and true or false
|
|
if name and not (s.hidePassives and passive) then
|
|
local spell = { slot = slot, book = cat.book, name = name, rank = rank or "", passive = passive,
|
|
icon = GetSpellTexture(slot, cat.book), pet = cat.pet }
|
|
if not s.allRanks and last[name] then
|
|
spells[last[name]] = spell
|
|
else
|
|
table.insert(spells, spell)
|
|
last[name] = table.getn(spells)
|
|
end
|
|
end
|
|
end
|
|
return spells
|
|
end
|
|
|
|
-- PagedCondensedVerticalGrid: the header takes a row (again on each following view), then the
|
|
-- spells fill the columns one by one over ceil(remaining / 3) rows in the space left; a full
|
|
-- view opens another. Returns the views, each a list of { header or spell, column, y }.
|
|
function B.paginate(title, spells)
|
|
local views = {}
|
|
local view, busy
|
|
local step = G.spellH + G.gapY
|
|
local function newView()
|
|
view = {}
|
|
table.insert(views, view)
|
|
table.insert(view, { header = title, column = 1, y = 0 })
|
|
busy = G.headerH + G.gapY
|
|
end
|
|
newView()
|
|
local total = table.getn(spells)
|
|
local i = 1
|
|
while i <= total do
|
|
local available = math.floor((G.viewH - busy) / step)
|
|
if available < 1 then
|
|
newView()
|
|
available = math.floor((G.viewH - busy) / step)
|
|
end
|
|
local rows = math.min(math.ceil((total - i + 1) / G.columns), available)
|
|
for column = 1, G.columns do
|
|
for r = 1, rows do
|
|
if i <= total then
|
|
table.insert(view, { spell = spells[i], column = column, y = busy + (r - 1) * step })
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
busy = busy + rows * step
|
|
if i <= total then
|
|
newView()
|
|
end
|
|
end
|
|
return views
|
|
end
|
|
|
|
-- --------------------------------------------------------------- Cells
|
|
|
|
-- 1.12's SpellButton_OnClick on a cell's spell.
|
|
local function clickSpell(spell)
|
|
if IsShiftKeyDown() then
|
|
if MacroFrame and MacroFrame:IsVisible() then
|
|
if not spell.passive then
|
|
local line = SLASH_CAST1 .. " " .. spell.name
|
|
if spell.rank ~= "" then
|
|
line = line .. "(" .. spell.rank .. ")"
|
|
end
|
|
MacroFrame_AddMacroLine(line)
|
|
end
|
|
else
|
|
PickupSpell(spell.slot, spell.book)
|
|
end
|
|
elseif arg1 ~= "LeftButton" and spell.pet then
|
|
ToggleSpellAutocast(spell.slot, spell.book)
|
|
else
|
|
CastSpell(spell.slot, spell.book)
|
|
end
|
|
B.updateStates()
|
|
end
|
|
|
|
local function showTooltip(button)
|
|
local spell = button.cell.spell
|
|
if not spell then
|
|
return
|
|
end
|
|
GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
|
if GameTooltip:SetSpell(spell.slot, spell.book) then
|
|
button.updateTooltip = TOOLTIP_UPDATE_TIME
|
|
else
|
|
button.updateTooltip = nil
|
|
end
|
|
end
|
|
|
|
-- Spell cell k: a holder (backplate, texts) with the icon button inside.
|
|
local function createCell(view, k)
|
|
local c = CreateFrame("Frame", nil, view)
|
|
c:SetWidth(G.cellW)
|
|
c:SetHeight(G.spellH)
|
|
local background = c:CreateTexture(nil, "BACKGROUND")
|
|
atlas(background, "spellbook-item-backplate")
|
|
background:SetPoint("CENTER", c, "CENTER", 5, -5)
|
|
background:SetAlpha(G.backplateAlpha)
|
|
c.background = background
|
|
|
|
local name = "ForeverUISpellBookButton" .. k
|
|
local b = CreateFrame("Button", name, c)
|
|
b:SetWidth(G.buttonSide)
|
|
b:SetHeight(G.buttonSide)
|
|
b:SetPoint("LEFT", c, "LEFT", 0, 0)
|
|
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
b:RegisterForDrag("LeftButton")
|
|
b.cell = c
|
|
-- named: SetPortraitToTexture takes a texture's name
|
|
local icon = b:CreateTexture(name .. "Icon", "ARTWORK")
|
|
icon:SetWidth(G.iconSide)
|
|
icon:SetHeight(G.iconSide)
|
|
icon:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
local shadow = b:CreateTexture(nil, "ARTWORK")
|
|
atlas(shadow, "spellbook-item-iconframe-shadow", true)
|
|
shadow:SetPoint("TOPLEFT", b, "TOPLEFT", -12, 3)
|
|
shadow:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 2, -8)
|
|
local frame = b:CreateTexture(nil, "OVERLAY")
|
|
local hover = b:CreateTexture(nil, "OVERLAY")
|
|
hover:SetAllPoints(b)
|
|
hover:SetBlendMode("ADD")
|
|
hover:SetAlpha(G.hoverAlpha)
|
|
hover:Hide()
|
|
local auto = b:CreateTexture(nil, "OVERLAY")
|
|
atlas(auto, "spellbook-item-petautocast-corners", true)
|
|
auto:SetAllPoints(icon)
|
|
auto:Hide()
|
|
local cooldown = CreateFrame("Model", name .. "Cooldown", b, "CooldownFrameTemplate")
|
|
cooldown:SetPoint("TOPLEFT", icon, "TOPLEFT", 2, -2)
|
|
cooldown:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", -2, 2)
|
|
b.icon, b.iconName, b.shadow, b.frame, b.hover, b.auto, b.cooldown = icon, name .. "Icon", shadow, frame, hover, auto, cooldown
|
|
|
|
local title = c:CreateFontString(nil, "ARTWORK")
|
|
font(title, 16)
|
|
title:SetJustifyH("LEFT")
|
|
title:SetWidth(G.cellW - G.textX)
|
|
local sub = c:CreateFontString(nil, "ARTWORK")
|
|
font(sub, 12)
|
|
sub:SetJustifyH("LEFT")
|
|
sub:SetWidth(G.cellW - G.textX)
|
|
c.name, c.sub = title, sub
|
|
|
|
b:SetScript("OnEnter", function()
|
|
this.cell.background:SetAlpha(1)
|
|
this.hover:Show()
|
|
showTooltip(this)
|
|
end)
|
|
b:SetScript("OnLeave", function()
|
|
this.cell.background:SetAlpha(G.backplateAlpha)
|
|
this.hover:SetAlpha(G.hoverAlpha)
|
|
this.hover:Hide()
|
|
this.updateTooltip = nil
|
|
GameTooltip:Hide()
|
|
end)
|
|
b:SetScript("OnUpdate", function()
|
|
if not this.updateTooltip then
|
|
return
|
|
end
|
|
this.updateTooltip = this.updateTooltip - arg1
|
|
if this.updateTooltip > 0 then
|
|
return
|
|
end
|
|
if GameTooltip:IsOwned(this) then
|
|
showTooltip(this)
|
|
else
|
|
this.updateTooltip = nil
|
|
end
|
|
end)
|
|
b:SetScript("OnMouseDown", function() this.hover:SetAlpha(G.pressedAlpha) end)
|
|
b:SetScript("OnMouseUp", function() this.hover:SetAlpha(G.hoverAlpha) end)
|
|
b:SetScript("OnDragStart", function()
|
|
local spell = this.cell.spell
|
|
if spell then
|
|
PickupSpell(spell.slot, spell.book)
|
|
end
|
|
end)
|
|
b:SetScript("OnClick", function()
|
|
local spell = this.cell.spell
|
|
if spell then
|
|
clickSpell(spell)
|
|
end
|
|
end)
|
|
c.button = b
|
|
c:Hide()
|
|
return c
|
|
end
|
|
|
|
-- Square frame or round passive, texts, then cooldown and autocast.
|
|
local function fillCell(c, spell)
|
|
c.spell = spell
|
|
local b = c.button
|
|
if spell.passive then
|
|
SetPortraitToTexture(b.iconName, spell.icon or "")
|
|
atlas(b.frame, "talents-node-circle-gray", true)
|
|
b.frame:ClearAllPoints()
|
|
b.frame:SetAllPoints(b)
|
|
atlas(b.hover, "spellbook-item-iconframe-passive-hover", true)
|
|
b.shadow:Hide()
|
|
else
|
|
b.icon:SetTexture(spell.icon)
|
|
b.icon:SetTexCoord(0, 1, 0, 1)
|
|
atlas(b.frame, "spellbook-item-iconframe-c60", true)
|
|
b.frame:ClearAllPoints()
|
|
b.frame:SetPoint("TOPLEFT", b, "TOPLEFT", -11, 1)
|
|
b.frame:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 1, -7)
|
|
atlas(b.hover, "spellbook-item-iconframe-hover", true)
|
|
b.shadow:Show()
|
|
end
|
|
b.hover:SetAllPoints(b)
|
|
c.name:SetText(spell.name)
|
|
local subtitle = spell.rank
|
|
if subtitle == "" and spell.passive then
|
|
subtitle = TEXT.passive
|
|
end
|
|
c.sub:SetText(subtitle)
|
|
-- the text block centered on the cell at (50, -1)
|
|
local nameH = c.name:GetHeight() or 0
|
|
local subH = (subtitle ~= "" and (c.sub:GetHeight() or 0)) or 0
|
|
local total = nameH
|
|
if subH > 0 then
|
|
total = total + 2 + subH
|
|
end
|
|
c.name:ClearAllPoints()
|
|
c.name:SetPoint("TOPLEFT", c, "LEFT", G.textX, total / 2 - 1)
|
|
c.sub:ClearAllPoints()
|
|
c.sub:SetPoint("TOPLEFT", c.name, "BOTTOMLEFT", 0, -2)
|
|
if subtitle == "" then
|
|
c.sub:Hide()
|
|
else
|
|
c.sub:Show()
|
|
end
|
|
B.updateState(c)
|
|
end
|
|
|
|
-- Cooldown, autocast and the current cast (IsCurrentCast, 1.12's checked spell button).
|
|
function B.updateState(c)
|
|
local spell = c.spell
|
|
if not spell then
|
|
return
|
|
end
|
|
local b = c.button
|
|
local start, duration, enable = GetSpellCooldown(spell.slot, spell.book)
|
|
if start then
|
|
CooldownFrame_SetTimer(b.cooldown, start, duration, enable)
|
|
end
|
|
local _, lit = nil, nil
|
|
if spell.pet then
|
|
_, lit = GetSpellAutocast(spell.slot, spell.book)
|
|
end
|
|
if lit then
|
|
b.auto:Show()
|
|
else
|
|
b.auto:Hide()
|
|
end
|
|
if IsCurrentCast(spell.slot, spell.book) then
|
|
b.hover:Show()
|
|
elseif not MouseIsOver(b) then
|
|
b.hover:Hide()
|
|
end
|
|
end
|
|
|
|
-- category header (SpellBookHeaderTemplate)
|
|
local function createHeader(view)
|
|
local h = CreateFrame("Frame", nil, view)
|
|
h:SetWidth(G.viewW)
|
|
h:SetHeight(G.headerH)
|
|
local background = h:CreateTexture(nil, "BACKGROUND")
|
|
atlas(background, "spellbook-list-backplate", true)
|
|
background:SetWidth(416)
|
|
background:SetHeight(106)
|
|
background:SetPoint("LEFT", h, "LEFT", -85, 10)
|
|
background:SetAlpha(0.65)
|
|
local text = h:CreateFontString(nil, "ARTWORK")
|
|
font(text, 24)
|
|
text:SetJustifyH("LEFT")
|
|
text:SetPoint("TOPLEFT", h, "TOPLEFT", -8, 0)
|
|
text:SetPoint("BOTTOMRIGHT", h, "BOTTOMRIGHT", -60, 0)
|
|
local line = h:CreateTexture(nil, "ARTWORK")
|
|
atlas(line, "spellbook-divider", true)
|
|
line:SetHeight(11)
|
|
line:SetPoint("BOTTOMLEFT", h, "BOTTOMLEFT", -32, 0)
|
|
line:SetPoint("BOTTOMRIGHT", h, "BOTTOMRIGHT", -60, 0)
|
|
h.text = text
|
|
h:Hide()
|
|
return h
|
|
end
|
|
|
|
-- ------------------------------------------------------------ Frame
|
|
|
|
-- Red title bar button. normal, pressed: atlas names
|
|
local function redButton(parent, normal, pressed)
|
|
local b = CreateFrame("Button", nil, parent)
|
|
b:SetWidth(G.redSide)
|
|
b:SetHeight(G.redSide)
|
|
local e = ForeverUI.AtlasEntry(normal)
|
|
b:SetNormalTexture(e and e[1] or "")
|
|
atlas(b:GetNormalTexture(), normal, true)
|
|
b:SetPushedTexture(e and e[1] or "")
|
|
atlas(b:GetPushedTexture(), pressed, true)
|
|
b:SetHighlightTexture(e and e[1] or "")
|
|
atlas(b:GetHighlightTexture(), "redbutton-highlight", true)
|
|
b:GetHighlightTexture():SetBlendMode("ADD")
|
|
return b
|
|
end
|
|
|
|
-- The close button is the client's: its OnClick hides its parent, SpellBookFrame.
|
|
function B.placeCloseButton()
|
|
local close, book = SpellBookCloseButton, B.book
|
|
close:SetFrameLevel(book:GetFrameLevel() + G.buttonLevel)
|
|
close:SetWidth(G.redSide)
|
|
close:SetHeight(G.redSide)
|
|
close:ClearAllPoints()
|
|
close:SetPoint("TOPRIGHT", book, "TOPRIGHT", G.closeX, G.closeY)
|
|
if close.foreverSkinned then
|
|
return
|
|
end
|
|
close:SetHitRectInsets(0, 0, 0, 0)
|
|
for _, state in ipairs({ { "Normal", "redbutton-exit" }, { "Pushed", "redbutton-exit-pressed" },
|
|
{ "Highlight", "redbutton-highlight" } }) do
|
|
local t = close["Get" .. state[1] .. "Texture"](close)
|
|
if t then
|
|
atlas(t, state[2], true)
|
|
t:ClearAllPoints()
|
|
t:SetAllPoints(close)
|
|
end
|
|
end
|
|
close.foreverSkinned = true
|
|
end
|
|
|
|
-- Window chrome: rock, metal, portrait, title, the one/two page button.
|
|
local function buildFrame(book)
|
|
local rock = book:CreateTexture(nil, "BACKGROUND")
|
|
rock:SetTexture(FILES.rock)
|
|
rock:SetPoint("TOPLEFT", book, "TOPLEFT", 2, -21)
|
|
rock:SetPoint("BOTTOMRIGHT", book, "BOTTOMRIGHT", -2, 2)
|
|
|
|
local metal = CreateFrame("Frame", nil, book)
|
|
metal:SetAllPoints(book)
|
|
metal:SetFrameLevel(book:GetFrameLevel() + G.metalLevel)
|
|
local p = {}
|
|
for _, corner in ipairs(METAL) do
|
|
local t = metal:CreateTexture(nil, "OVERLAY")
|
|
atlas(t, corner.name)
|
|
t:SetPoint(corner.point, metal, corner.point, corner.x, corner.y)
|
|
p[corner.key] = t
|
|
end
|
|
local function edge(name, a1, c1, r1, a2, c2, r2)
|
|
local t = metal:CreateTexture(nil, "OVERLAY")
|
|
atlas(t, name)
|
|
t:SetPoint(a1, c1, r1, 0, 0)
|
|
t:SetPoint(a2, c2, r2, 0, 0)
|
|
end
|
|
edge("_ui-frame-metal-edgetop", "TOPLEFT", p.topLeft, "TOPRIGHT", "TOPRIGHT", p.topRight, "TOPLEFT")
|
|
edge("_ui-frame-metal-edgebottom", "BOTTOMLEFT", p.bottomLeft, "BOTTOMRIGHT", "BOTTOMRIGHT", p.bottomRight, "BOTTOMLEFT")
|
|
edge("!ui-frame-metal-edgeleft", "TOPLEFT", p.topLeft, "BOTTOMLEFT", "BOTTOMLEFT", p.bottomLeft, "TOPLEFT")
|
|
edge("!ui-frame-metal-edgeright", "TOPRIGHT", p.topRight, "BOTTOMRIGHT", "BOTTOMRIGHT", p.bottomRight, "TOPRIGHT")
|
|
|
|
local portraitFrame = CreateFrame("Frame", nil, book)
|
|
portraitFrame:SetAllPoints(book)
|
|
portraitFrame:SetFrameLevel(book:GetFrameLevel() + G.portraitLevel)
|
|
local portrait = portraitFrame:CreateTexture(nil, "OVERLAY")
|
|
portrait:SetWidth(G.portraitSide)
|
|
portrait:SetHeight(G.portraitSide)
|
|
portrait:SetPoint("TOPLEFT", book, "TOPLEFT", G.portraitX, G.portraitY)
|
|
portrait:SetTexture(FILES.portrait)
|
|
|
|
local banner = CreateFrame("Frame", nil, book)
|
|
banner:SetFrameLevel(book:GetFrameLevel() + G.titleLevel)
|
|
banner:SetHeight(G.titleH)
|
|
banner:SetPoint("TOPLEFT", book, "TOPLEFT", G.titleX1, G.titleY)
|
|
banner:SetPoint("TOPRIGHT", book, "TOPRIGHT", G.titleX2, G.titleY)
|
|
local title = banner:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
title:SetPoint("TOP", banner, "TOP", 0, -5)
|
|
title:SetText(TEXT.title)
|
|
book.title = title
|
|
|
|
-- maximize / minimize (MaximizeMinimizeButtonFrameTemplate), left of the close button
|
|
local size = redButton(book, "redbutton-condense", "redbutton-condense-pressed")
|
|
size:SetFrameLevel(book:GetFrameLevel() + G.buttonLevel)
|
|
size:SetPoint("TOPRIGHT", book, "TOPRIGHT", G.closeX - G.redSide, G.closeY)
|
|
size:SetScript("OnClick", function()
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
B.toggleSize()
|
|
end)
|
|
book.size = size
|
|
end
|
|
|
|
-- ------------------------------------------------------------ Settings
|
|
|
|
local function createSettings(pages)
|
|
local b = CreateFrame("Button", "ForeverUISpellBookSettingsButton", pages)
|
|
b:SetWidth(G.settingsW)
|
|
b:SetHeight(G.settingsH)
|
|
b:SetPoint("TOPRIGHT", pages, "TOPRIGHT", G.settingsX, G.settingsY)
|
|
local icon = b:CreateTexture(nil, "ARTWORK")
|
|
atlas(icon, "common-dropdown-a-button")
|
|
icon:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
local hover = b:CreateTexture(nil, "HIGHLIGHT")
|
|
atlas(hover, "common-dropdown-a-button")
|
|
hover:SetPoint("CENTER", icon, "CENTER", 0, 0)
|
|
hover:SetBlendMode("ADD")
|
|
hover:SetAlpha(0.4)
|
|
b:SetScript("OnMouseDown", function() icon:SetPoint("CENTER", b, "CENTER", 1, -1) end)
|
|
b:SetScript("OnMouseUp", function() icon:SetPoint("CENTER", b, "CENTER", 0, 0) end)
|
|
|
|
local list = CreateFrame("Frame", "ForeverUISpellBookSettingsList", pages)
|
|
list:SetFrameStrata("DIALOG")
|
|
list:EnableMouse(true)
|
|
list:SetPoint("TOPLEFT", b, "BOTTOMLEFT", 0, 0)
|
|
list:Hide()
|
|
local slices = ForeverUI.CreateNineSlice(list, "common-dropdown-bg-c60", MENU.backgroundCorner,
|
|
MENU.backgroundMargins, "BACKGROUND")
|
|
for _, t in ipairs(slices or {}) do
|
|
t:SetAlpha(MENU.backgroundAlpha)
|
|
end
|
|
list.rows = {}
|
|
local longest = 0
|
|
for i, r in ipairs(SETTINGS) do
|
|
local l = CreateFrame("Button", "ForeverUISpellBookSettingsEntry" .. i, list)
|
|
l:SetHeight(MENU.rowH)
|
|
l:SetPoint("TOPLEFT", list, "TOPLEFT", MENU.rowX, -MENU.edge - (i - 1) * MENU.rowH)
|
|
l:SetHighlightTexture(FILES.rowHighlight)
|
|
l:GetHighlightTexture():SetBlendMode("ADD")
|
|
local text = l:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
|
text:SetJustifyH("LEFT")
|
|
text:SetPoint("LEFT", l, "LEFT", MENU.textX, 0)
|
|
text:SetText(r.text)
|
|
longest = math.max(longest, text:GetStringWidth() or 0)
|
|
local checkbox = l:CreateTexture(nil, "BORDER")
|
|
atlas(checkbox, "common-dropdown-ticksquare", true)
|
|
checkbox:SetWidth(MENU.checkbox)
|
|
checkbox:SetHeight(MENU.checkbox)
|
|
checkbox:SetPoint("LEFT", l, "LEFT", 0, 0)
|
|
local checkMark = l:CreateTexture(nil, "ARTWORK")
|
|
atlas(checkMark, "common-dropdown-icon-checkmark-yellow", true)
|
|
checkMark:SetWidth(MENU.checkMarkW)
|
|
checkMark:SetHeight(MENU.checkMarkH)
|
|
checkMark:SetPoint("CENTER", checkbox, "CENTER", MENU.checkMarkX, MENU.checkMarkY)
|
|
l.checkMark, l.setting = checkMark, r
|
|
-- keepShownOnClick: the list stays open
|
|
l:SetScript("OnClick", function()
|
|
PlaySound("UChatScrollButton")
|
|
local s = settings()
|
|
s[this.setting.key] = not s[this.setting.key]
|
|
B.update()
|
|
end)
|
|
list.rows[i] = l
|
|
end
|
|
local width = longest + MENU.extraWidth + MENU.margin
|
|
list:SetWidth(width)
|
|
list:SetHeight(table.getn(SETTINGS) * MENU.rowH + 2 * MENU.edge)
|
|
for _, l in ipairs(list.rows) do
|
|
l:SetWidth(width - MENU.margin)
|
|
end
|
|
-- UIDROPDOWNMENU_SHOW_TIME: hidden 2 s after the mouse leaves the list and its arrow
|
|
list:SetScript("OnShow", function() this.away = 0 end)
|
|
list:SetScript("OnUpdate", function()
|
|
if MouseIsOver(this) or MouseIsOver(b) then
|
|
this.away = 0
|
|
return
|
|
end
|
|
this.away = (this.away or 0) + arg1
|
|
if this.away > MENU.pending then
|
|
this:Hide()
|
|
end
|
|
end)
|
|
b:SetScript("OnClick", function()
|
|
if list:IsShown() then
|
|
list:Hide()
|
|
else
|
|
list:Show()
|
|
end
|
|
end)
|
|
B.settingsList = list
|
|
end
|
|
|
|
local function checkSettings()
|
|
local s = settings()
|
|
for _, l in ipairs(B.settingsList.rows) do
|
|
if s[l.setting.key] then
|
|
l.checkMark:Show()
|
|
else
|
|
l.checkMark:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ Tabs
|
|
|
|
local function createTab(parent, n)
|
|
local b = CreateFrame("Button", "ForeverUISpellBookTab" .. n, parent)
|
|
b:SetID(n)
|
|
b:SetWidth(G.tabW)
|
|
b:SetHeight(G.tabH)
|
|
local icon = b:CreateTexture(nil, "ARTWORK")
|
|
icon:SetWidth(G.tabIconW)
|
|
icon:SetHeight(G.tabIconH)
|
|
icon:SetPoint("CENTER", b, "CENTER", -1, -1)
|
|
-- the frame above the icon (camelot: ARTWORK sublevel 1): a child frame
|
|
local over = CreateFrame("Frame", nil, b)
|
|
over:SetAllPoints(b)
|
|
over:SetFrameLevel(b:GetFrameLevel() + 1)
|
|
local frame = over:CreateTexture(nil, "ARTWORK")
|
|
atlas(frame, "spellbook-tab-frame-c60")
|
|
frame:SetPoint("BOTTOM", b, "BOTTOM", 0, 1)
|
|
local active = over:CreateTexture(nil, "ARTWORK")
|
|
atlas(active, "spellbook-tab-frame-glow-c60")
|
|
active:SetPoint("BOTTOM", b, "BOTTOM", 0, 1)
|
|
local glow = over:CreateTexture(nil, "OVERLAY")
|
|
atlas(glow, "spellbook-tab-frame-glow-gradient-c60")
|
|
glow:SetPoint("BOTTOM", b, "BOTTOM", 0, 0)
|
|
b.icon, b.frame, b.active, b.glow = icon, frame, active, glow
|
|
b:SetScript("OnClick", function()
|
|
PlaySound("igSpellBookOpen")
|
|
B.choose(this:GetID())
|
|
end)
|
|
b:SetScript("OnEnter", function()
|
|
GameTooltip:SetOwner(this, "ANCHOR_RIGHT", -12, -6)
|
|
GameTooltip:SetText(this.name)
|
|
GameTooltip:Show()
|
|
end)
|
|
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
return b
|
|
end
|
|
|
|
local function layoutTabs(cats, selected)
|
|
local tabs = B.tabs
|
|
for i, cat in ipairs(cats) do
|
|
local b = tabs.buttons[i]
|
|
if not b then
|
|
b = createTab(tabs, i)
|
|
tabs.buttons[i] = b
|
|
end
|
|
b.name = cat.name
|
|
b.icon:SetTexture(cat.icon)
|
|
b:ClearAllPoints()
|
|
b:SetPoint("TOPLEFT", tabs, "TOPLEFT", (i - 1) * (G.tabW + G.tabGap), 0)
|
|
b:Show()
|
|
-- LEARNED_SPELL_IN_TAB's glow (SpellBookSkillLineTab<i>Flash, 64 on a 32 tab) on our tab
|
|
local flash = getglobal("SpellBookSkillLineTab" .. i .. "Flash")
|
|
if flash and not cat.pet then
|
|
flash:ClearAllPoints()
|
|
flash:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
flash:SetWidth(G.tabW * 2)
|
|
flash:SetHeight(G.tabH * 2)
|
|
end
|
|
if i == selected then
|
|
b.frame:Hide()
|
|
b.active:Show()
|
|
b.glow:Show()
|
|
else
|
|
b.frame:Show()
|
|
b.active:Hide()
|
|
b.glow:Hide()
|
|
end
|
|
end
|
|
for i = table.getn(cats) + 1, table.getn(tabs.buttons) do
|
|
tabs.buttons[i]:Hide()
|
|
end
|
|
SpellBookTabFlashFrame:SetFrameLevel(tabs:GetFrameLevel() + 3)
|
|
end
|
|
|
|
-- ------------------------------------------------------------ Build
|
|
|
|
local function build()
|
|
SpellBookFrame:EnableMouse(false)
|
|
local book = CreateFrame("Frame", "ForeverUISpellBookFrame", SpellBookFrame)
|
|
book:SetHeight(G.height)
|
|
book:SetWidth(G.width)
|
|
book:EnableMouse(true)
|
|
B.book = book
|
|
buildFrame(book)
|
|
|
|
local pages = CreateFrame("Frame", "ForeverUISpellBookPages", book)
|
|
pages:SetPoint("BOTTOMLEFT", book, "BOTTOMLEFT", 0, G.bookBottom)
|
|
pages:SetHeight(G.bookH)
|
|
pages:SetWidth(G.bookW)
|
|
local left = pages:CreateTexture(nil, "BACKGROUND")
|
|
atlas(left, "spellbook-page-left-c60-2x", true)
|
|
left:SetPoint("TOPLEFT", pages, "TOPLEFT", 0, 0)
|
|
left:SetPoint("BOTTOMRIGHT", pages, "BOTTOM", 0, 0)
|
|
local right = pages:CreateTexture(nil, "BACKGROUND")
|
|
atlas(right, "spellbook-page-right-c60-2x", true)
|
|
right:SetPoint("TOPLEFT", pages, "TOP", 0, 0)
|
|
right:SetPoint("BOTTOMRIGHT", pages, "BOTTOMRIGHT", 0, 0)
|
|
local single = pages:CreateTexture(nil, "BACKGROUND")
|
|
atlas(single, "spellbook-page-right-c60-2x", true)
|
|
single:SetAllPoints(pages)
|
|
single:Hide()
|
|
pages.left, pages.right, pages.single = left, right, single
|
|
B.pages = pages
|
|
|
|
local tabs = CreateFrame("Frame", nil, pages)
|
|
tabs:SetPoint("TOPLEFT", pages, "TOPLEFT", G.tabsX, G.tabsY)
|
|
tabs:SetWidth(1)
|
|
tabs:SetHeight(G.tabH)
|
|
tabs.buttons = {}
|
|
B.tabs = tabs
|
|
|
|
local content = CreateFrame("Frame", "ForeverUISpellBookContent", pages)
|
|
content:SetPoint("TOPLEFT", pages, "TOPLEFT", 0, G.pagesTop)
|
|
content:SetPoint("BOTTOMRIGHT", pages, "BOTTOMRIGHT", 0, 0)
|
|
content:EnableMouseWheel(true)
|
|
content:SetScript("OnMouseWheel", function() B.rotate(-arg1) end)
|
|
B.views, B.cells = {}, {}
|
|
for v = 1, 2 do
|
|
local view = CreateFrame("Frame", "ForeverUISpellBookView" .. v, content)
|
|
view:SetWidth(G.viewW)
|
|
view:SetHeight(G.viewH)
|
|
if v == 1 then
|
|
view:SetPoint("TOPLEFT", content, "TOPLEFT", G.view1X, G.viewY)
|
|
else
|
|
view:SetPoint("TOPRIGHT", content, "TOPRIGHT", G.view2X, G.viewY)
|
|
end
|
|
view.cells = {}
|
|
for n = 1, G.cellsPerView do
|
|
local k = (v - 1) * G.cellsPerView + n
|
|
view.cells[n] = createCell(view, k)
|
|
B.cells[k] = view.cells[n]
|
|
end
|
|
view.header = createHeader(view)
|
|
B.views[v] = view
|
|
end
|
|
|
|
-- paging: "Page n/m", previous, next, right to left
|
|
local nextPage = CreateFrame("Button", "ForeverUISpellBookNextPage", content)
|
|
local prev = CreateFrame("Button", "ForeverUISpellBookPrevPage", content)
|
|
for _, f in ipairs({ { nextPage, "NextPage", 1 }, { prev, "PrevPage", -1 } }) do
|
|
local b = f[1]
|
|
b:SetWidth(G.arrowSide)
|
|
b:SetHeight(G.arrowSide)
|
|
b:SetNormalTexture(FILES.arrows .. f[2] .. "-Up")
|
|
b:SetPushedTexture(FILES.arrows .. f[2] .. "-Down")
|
|
b:SetDisabledTexture(FILES.arrows .. f[2] .. "-Disabled")
|
|
b:SetHighlightTexture(FILES.squareHover)
|
|
b:GetHighlightTexture():SetBlendMode("ADD")
|
|
b.direction = f[3]
|
|
b:SetScript("OnClick", function()
|
|
PlaySound("igAbiliityPageTurn")
|
|
B.rotate(this.direction)
|
|
end)
|
|
end
|
|
nextPage:SetPoint("BOTTOMRIGHT", content, "BOTTOMRIGHT", G.pagerX, G.pagerY)
|
|
prev:SetPoint("RIGHT", nextPage, "LEFT", -G.pagerGap, 0)
|
|
local text = content:CreateFontString(nil, "ARTWORK")
|
|
font(text, 14)
|
|
text:SetPoint("RIGHT", prev, "LEFT", -G.pagerGap, 0)
|
|
B.pager = { nextPage = nextPage, prev = prev, text = text }
|
|
|
|
createSettings(pages)
|
|
end
|
|
|
|
-- Hides 1.12's regions and frames in SpellBookFrame, except the book, the close button and
|
|
-- the tabs' flash, which UIFrameFlash shows on our tabs.
|
|
function B.suppressClient()
|
|
for _, region in ipairs({ SpellBookFrame:GetRegions() }) do
|
|
suppress(region)
|
|
end
|
|
for _, child in ipairs({ SpellBookFrame:GetChildren() }) do
|
|
if child ~= B.book and child ~= SpellBookCloseButton and child ~= SpellBookTabFlashFrame then
|
|
suppress(child)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- camelot's fit (blizzard_playerspellsregistration): SpellBookFrame scales down until the
|
|
-- book and its margins fit the screen; the book's top at -116, raised while its bottom would
|
|
-- come within 140 of the screen's, up to 10 below its top.
|
|
function B.fit()
|
|
local book = B.book
|
|
local k = math.min(1, UIParent:GetWidth() / (G.width + G.fitExtraW),
|
|
UIParent:GetHeight() / (G.height + G.fitExtraH))
|
|
if math.abs(SpellBookFrame:GetScale() - k) > 0.001 then
|
|
SpellBookFrame:SetScale(k)
|
|
end
|
|
local y = G.top
|
|
local bottom = UIParent:GetHeight() + y - G.height * k
|
|
if bottom < G.clampBottom then
|
|
y = y + G.clampBottom - bottom
|
|
end
|
|
y = math.min(y, G.clampTop)
|
|
book:ClearAllPoints()
|
|
book:SetPoint("TOP", UIParent, "TOP", 0, y / k)
|
|
end
|
|
|
|
-- ------------------------------------------------------------ Filling
|
|
|
|
B.state = { category = 1, page = 1 }
|
|
|
|
function B.choose(index)
|
|
local cats = B.categories()
|
|
local cat = cats[index]
|
|
if not cat then
|
|
return
|
|
end
|
|
B.state.category, B.state.page = index, 1
|
|
-- so P and Shift-P toggle as 1.12's book does
|
|
SpellBookFrame.bookType = cat.book
|
|
-- SpellBookSkillLineTab_OnClick: a chosen tab stops flashing
|
|
local flash = not cat.pet and getglobal("SpellBookSkillLineTab" .. index .. "Flash")
|
|
if flash then
|
|
flash:Hide()
|
|
end
|
|
B.update()
|
|
end
|
|
|
|
function B.rotate(direction)
|
|
local p = B.state.page + direction
|
|
if p >= 1 and p <= (B.state.pages or 1) then
|
|
B.state.page = p
|
|
B.update()
|
|
end
|
|
end
|
|
|
|
function B.toggleSize()
|
|
local s = settings()
|
|
if s.reduced then
|
|
s.reduced = nil
|
|
B.state.page = math.ceil(B.state.page / 2)
|
|
else
|
|
s.reduced = true
|
|
B.state.page = B.state.page * 2 - 1
|
|
end
|
|
B.update()
|
|
end
|
|
|
|
-- Two pages or one: widths, page art, the right view and the size button.
|
|
local function applySize(reduced)
|
|
local book, pages = B.book, B.pages
|
|
if reduced then
|
|
book:SetWidth(G.compactWidth)
|
|
pages:SetWidth(G.reducedBookW)
|
|
pages.left:Hide()
|
|
pages.right:Hide()
|
|
pages.single:Show()
|
|
B.views[2]:Hide()
|
|
atlas(book.size:GetNormalTexture(), "redbutton-expand", true)
|
|
atlas(book.size:GetPushedTexture(), "redbutton-expand-pressed", true)
|
|
else
|
|
book:SetWidth(G.width)
|
|
pages:SetWidth(G.bookW)
|
|
pages.left:Show()
|
|
pages.right:Show()
|
|
pages.single:Hide()
|
|
B.views[2]:Show()
|
|
atlas(book.size:GetNormalTexture(), "redbutton-condense", true)
|
|
atlas(book.size:GetPushedTexture(), "redbutton-condense-pressed", true)
|
|
end
|
|
end
|
|
|
|
function B.update()
|
|
if not SpellBookFrame:IsVisible() then
|
|
return
|
|
end
|
|
local e = B.state
|
|
local cats = B.categories()
|
|
if e.category > table.getn(cats) then
|
|
e.category, e.page = 1, 1
|
|
end
|
|
local reduced = settings().reduced and true or false
|
|
local perPage = reduced and 1 or 2
|
|
applySize(reduced)
|
|
checkSettings()
|
|
layoutTabs(cats, e.category)
|
|
|
|
local cat = cats[e.category]
|
|
local views = cat and B.paginate(cat.name, B.spellsOf(cat)) or {}
|
|
e.pages = math.max(1, math.ceil(table.getn(views) / perPage))
|
|
if e.page > e.pages then
|
|
e.page = e.pages
|
|
end
|
|
for slot, view in ipairs(B.views) do
|
|
local list = views[(e.page - 1) * perPage + slot] or {}
|
|
local n = 0
|
|
view.header:Hide()
|
|
for _, el in ipairs(list) do
|
|
if el.header then
|
|
view.header.text:SetText(el.header)
|
|
view.header:ClearAllPoints()
|
|
view.header:SetPoint("TOPLEFT", view, "TOPLEFT", 0, -el.y)
|
|
view.header:Show()
|
|
else
|
|
n = n + 1
|
|
local c = view.cells[n]
|
|
if c then
|
|
c:ClearAllPoints()
|
|
c:SetPoint("TOPLEFT", view, "TOPLEFT", (el.column - 1) * (G.cellW + G.gapX), -el.y)
|
|
fillCell(c, el.spell)
|
|
c:Show()
|
|
end
|
|
end
|
|
end
|
|
for i = n + 1, G.cellsPerView do
|
|
view.cells[i].spell = nil
|
|
view.cells[i]:Hide()
|
|
end
|
|
end
|
|
if e.page > 1 then B.pager.prev:Enable() else B.pager.prev:Disable() end
|
|
if e.page < e.pages then B.pager.nextPage:Enable() else B.pager.nextPage:Disable() end
|
|
B.pager.text:SetText(string.format(TEXT.page, e.page, e.pages))
|
|
end
|
|
|
|
-- Cooldowns, autocast and the current cast of the shown cells.
|
|
function B.updateStates()
|
|
for _, c in ipairs(B.cells) do
|
|
if c:IsShown() and c.spell then
|
|
B.updateState(c)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ Assembly
|
|
|
|
build()
|
|
|
|
-- On each show: the requested book (ToggleSpellBook sets bookType: the pet's or a spell tab).
|
|
ForeverUI.HookScript(SpellBookFrame, "OnShow", function()
|
|
B.suppressClient()
|
|
B.fit()
|
|
B.placeCloseButton()
|
|
local cats = B.categories()
|
|
local current = cats[B.state.category]
|
|
if SpellBookFrame.bookType == BOOKTYPE_PET then
|
|
for i, cat in ipairs(cats) do
|
|
if cat.pet then
|
|
B.state.category, B.state.page = i, 1
|
|
end
|
|
end
|
|
elseif current and current.pet then
|
|
B.state.category, B.state.page = 1, 1
|
|
end
|
|
B.update()
|
|
end)
|
|
ForeverUI.HookScript(SpellBookFrame, "OnHide", function()
|
|
B.settingsList:Hide()
|
|
end)
|
|
ForeverUI.HookGlobal("SpellBookFrame_Update", B.suppressClient)
|
|
|
|
local watcher = CreateFrame("Frame")
|
|
for _, name in ipairs({ "SPELLS_CHANGED", "LEARNED_SPELL_IN_TAB", "PET_BAR_UPDATE", "SPELL_UPDATE_COOLDOWN",
|
|
"CURRENT_SPELL_CAST_CHANGED", "TRADE_SKILL_SHOW", "TRADE_SKILL_CLOSE", "CRAFT_SHOW", "CRAFT_CLOSE" }) do
|
|
watcher:RegisterEvent(name)
|
|
end
|
|
watcher:SetScript("OnEvent", function()
|
|
if not SpellBookFrame:IsVisible() then
|
|
return
|
|
end
|
|
if event == "SPELLS_CHANGED" or event == "LEARNED_SPELL_IN_TAB" then
|
|
B.update()
|
|
else
|
|
B.updateStates()
|
|
end
|
|
end)
|