ae87393c0c
Le nom du résultat et les outils débordaient de la fiche (largeur de 800 de la fiche camelot normale) : ils suivent la règle de la fiche réduite de camelot, 250 de large sur plusieurs lignes, et ce qui suit descend sous eux quand ils dépassent sa place. Les composants passent au pas de 163 pour que la deuxième colonne reste dans la fiche de 360. Écart noté dans NOTES.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1380 lines
51 KiB
Lua
1380 lines
51 KiB
Lua
-- ForeverUI: the profession crafting page (TradeSkillFrame, from Blizzard_TradeSkillUI) with
|
|
-- Camelot's ProfessionsFrame layout; the overview page and side tabs are in ProfessionsBook.lua.
|
|
-- The client's TradeSkillFrame stays the host (panel, events, selection): its widgets are hidden
|
|
-- and mouse-less, and our list, schematic, rank bar and buttons run on its data. Favorites,
|
|
-- tracking, qualities, concentration and orders do not exist in 3.3.5 and are left out.
|
|
|
|
local ForeverUI = ForeverUI or {}
|
|
_G.ForeverUI = ForeverUI
|
|
|
|
local Tpl = ForeverUI.Templates
|
|
local L = ForeverUI.L
|
|
|
|
local M = {}
|
|
ForeverUI.Professions = M
|
|
|
|
local SEP = string.char(92)
|
|
local FONT = "Fonts" .. SEP .. "FRIZQT__.TTF"
|
|
local NUMBER_FONT = "Fonts" .. SEP .. "ARIALN.TTF"
|
|
local BUTTONS = "Interface" .. SEP .. "Buttons" .. SEP
|
|
|
|
local N = {
|
|
window = { 673, 594 },
|
|
portrait = { side = 48, x = 1, y = 1.5 },
|
|
background = { 2, -21, -2, 2 }, -- Bg of PortraitFrameTemplate
|
|
page = { 3, -21 }, -- Profession-Background-Template2
|
|
list = { 5, -72, 304, down = 5 },
|
|
filter = { -8, -9, 18 },
|
|
search = { 13, -8, 20, gap = -4 },
|
|
zone = { 8, -35, -20, 5 },
|
|
tree = { indent = 10, top = 5, down = 5, right = 5, space = 1, hovered = 1, below = 10 },
|
|
category = { h = 25, text = 8, button = 20, buttonX = -6 },
|
|
recipe = { h = 20, progress = { 26, 15, -9 }, nameX = 4, margin = 10 },
|
|
none = { 0, -60, 200 },
|
|
step = 21, -- one wheel step: one recipe
|
|
rank = { 110, -40, 453, 18, background = { 451, 29 }, filled = { 441, 18, 5, -3 }, mask = 1,
|
|
flare = { 53, 16 }, text = -3 },
|
|
link = { -2, -4, 23, background = 34, icon = 25 },
|
|
card = { 2, 0, 360, 484 },
|
|
result = { 28, -28, 47, icon = 53, outline = 68, glow = 66, count = { -4, 1 } },
|
|
name = { 14, 17 },
|
|
tools = { 0, -4 },
|
|
textWidth = 250, -- name and tools: camelot's minimized schematic, wrapped
|
|
organizer = { -1, -12, 4 },
|
|
cooldown = 400, description = 305,
|
|
-- slot 158 wide (camelot 180): the schematic is 360 wide (camelot 493), the second column
|
|
-- has to stay inside it
|
|
reagents = { 0, -20, tag = { 180, 20 }, slot = { 158, 50 }, start = { 1, -20 },
|
|
gap = { 5, 5 }, column = 4, button = 39, nameX = 46, nameSize = { 108, 36 } },
|
|
create = { -9, 7, 80, 28, margin = 30 },
|
|
createAll = { -362, 7 },
|
|
counter = { -185, 11, 31, 20, arrow = { 23, 22 }, minusGap = -6 },
|
|
levels = { page = 1, list = 2, rows = 3, card = 2, rank = 5, closeButton = 22 },
|
|
}
|
|
|
|
-- Camelot's GlobalColor
|
|
local COLORS = {
|
|
recipe = { 0.8863, 0.8627, 0.8392 }, -- PROFESSION_RECIPE_COLOR
|
|
missingReagent = { 0.6275, 0.6275, 0.6275 }, -- DISABLED_REAGENT_COLOR
|
|
}
|
|
|
|
local PROGRESS = {
|
|
optimal = { "professions-icon-skill-high", 1, L.TRADESKILL_SKILL_UP_OPTIMAL },
|
|
medium = { "professions-icon-skill-medium", 0, L.TRADESKILL_SKILL_UP_MEDIUM },
|
|
easy = { "professions-icon-skill-low", 0, L.TRADESKILL_SKILL_UP_EASY },
|
|
}
|
|
|
|
-- Profession, found by its spell icon (3.3.5 Spell.dbc), the same in every language: background
|
|
-- card, rank fill and flare (c60 variant when Camelot has one). Jewelcrafting and inscription have
|
|
-- no card in Camelot: Professions-Recipe-Background is used.
|
|
local PROFESSIONS = {
|
|
["trade_alchemy"] = { map = "profession-background-card-alchemy", rank = "alchemy_c60" },
|
|
["trade_blacksmithing"] = { map = "profession-background-card-blacksmithing", rank = "blacksmithing" },
|
|
["trade_engraving"] = { map = "profession-background-card-enchanting", rank = "enchanting_c60" },
|
|
["trade_engineering"] = { map = "profession-background-card-engineering", rank = "engineering" },
|
|
["inv_inscription_tradeskill01"] = { rank = "inscription" },
|
|
["inv_misc_gem_01"] = { rank = "jewelcrafting" },
|
|
["inv_misc_gem_02"] = { rank = "jewelcrafting" },
|
|
["inv_misc_armorkit_17"] = { map = "profession-background-card-leatherworking", rank = "leatherworking" },
|
|
["trade_tailoring"] = { map = "profession-background-card-tailoring", rank = "tailoring" },
|
|
["inv_misc_food_15"] = { map = "profession-background-card-cooking", rank = "cooking" },
|
|
["spell_holy_sealofsacrifice"] = { map = "profession-background-card-firstaid", rank = "firstaid_c60" },
|
|
["trade_mining"] = { map = "profession-background-card-mining", rank = "mining" },
|
|
}
|
|
|
|
-- AUCTION_HOUSE_ITEM_QUALITY_ICON_BORDER_ATLASES / PROFESSIONS_ITEM_QUALITY_-
|
|
-- ICON_BORDER_ATLASES (blizzard_colors)
|
|
local RESULT_OUTLINE = { [0] = "gray", [1] = "white", [2] = "green", [3] = "blue", [4] = "purple",
|
|
[5] = "orange", [6] = "artifact", [7] = "account" }
|
|
local REAGENT_OUTLINE = { [1] = "professions-slot-frame", [2] = "professions-slot-frame-green",
|
|
[3] = "professions-slot-frame-blue", [4] = "professions-slot-frame-epic", [5] = "professions-slot-frame-legendary" }
|
|
|
|
local function place(r, ...)
|
|
r:ClearAllPoints()
|
|
r:SetPoint(...)
|
|
end
|
|
|
|
local function atlas(t, name, size)
|
|
return ForeverUI.SetAtlas(t, name, not size)
|
|
end
|
|
|
|
-- Camelot fonts missing in 3.3.5
|
|
local function font(name, path, size, outline, shadow, r, g, b)
|
|
local p = _G[name] or CreateFont(name)
|
|
p:SetFont(path, size, outline or "")
|
|
if shadow then
|
|
p:SetShadowOffset(1, -1)
|
|
p:SetShadowColor(0, 0, 0, 1)
|
|
else
|
|
p:SetShadowOffset(0, 0)
|
|
p:SetShadowColor(0, 0, 0, 0)
|
|
end
|
|
p:SetTextColor(r or 1, g or 1, b or 1)
|
|
return p
|
|
end
|
|
local FONTS = {
|
|
row = font("ForeverUIFontHighlightNoShadow12", FONT, 12), -- GameFontHighlight_NoShadow
|
|
category = font("ForeverUIFontGame15Shadow", FONT, 15, nil, true), -- Game15Font_Shadow
|
|
med2 = font("ForeverUIFontHighlightMed2", FONT, 14, nil, true), -- GameFontHighlightMed2
|
|
small2 = font("ForeverUIFontHighlightSmall2", FONT, 11), -- GameFontHighlightSmall2
|
|
rank = font("ForeverUIFontNumber12Outline", NUMBER_FONT, 12, "OUTLINE"), -- Number12FontOutline
|
|
}
|
|
|
|
local function truthy(v)
|
|
return v and v ~= 0 and true or false
|
|
end
|
|
|
|
-- ------------------------------------------------------------ profession
|
|
|
|
-- Current profession's PROFESSIONS entry, and its spell icon
|
|
local function profession()
|
|
local name = GetTradeSkillLine()
|
|
local icon = name and GetSpellTexture(name)
|
|
local key = icon and string.lower(string.match(icon, "([^" .. SEP .. SEP .. "/]+)$") or "")
|
|
return key and PROFESSIONS[key], icon
|
|
end
|
|
|
|
-- ------------------------------------------------------------ recipe list
|
|
|
|
-- Header background: common-button-list-collapseExpand, 18-wide ends and a middle
|
|
-- (28 texels of 64) laid tile by tile (see QuestLog.lua)
|
|
local HEADER_SLICE = { side = 18, image = 64 }
|
|
local function headerBackground(b, layer, mode, alpha)
|
|
local e = ForeverUI.AtlasEntry("common-button-list-collapseexpand")
|
|
if not e then return {} end
|
|
local du = (e[3] - e[2]) / HEADER_SLICE.image
|
|
local side = HEADER_SLICE.side
|
|
local middle = HEADER_SLICE.image - 2 * side
|
|
local pieces = {}
|
|
local function piece(u1, u2)
|
|
local t = b:CreateTexture(nil, layer)
|
|
t:SetTexture(e[1])
|
|
t:SetTexCoord(u1, u2, e[4], e[5])
|
|
if mode then t:SetBlendMode(mode) end
|
|
if alpha then t:SetAlpha(alpha) end
|
|
pieces[#pieces + 1] = t
|
|
return t
|
|
end
|
|
local left = piece(e[2], e[2] + side * du)
|
|
left:SetWidth(side)
|
|
left:SetPoint("TOPLEFT", b, "TOPLEFT", 0, 0)
|
|
left:SetPoint("BOTTOMLEFT", b, "BOTTOMLEFT", 0, 0)
|
|
local right = piece(e[3] - side * du, e[3])
|
|
right:SetWidth(side)
|
|
right:SetPoint("TOPRIGHT", b, "TOPRIGHT", 0, 0)
|
|
right:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 0, 0)
|
|
b.foreverTiles = b.foreverTiles or {}
|
|
b.foreverTiles[layer] = { left = left, du = du, e = e, middle = middle, side = side, pieces = {}, mode = mode, alpha = alpha }
|
|
return pieces
|
|
end
|
|
|
|
-- Middle tiles, to the row width
|
|
local function tileHeader(b, width)
|
|
for layer, T in pairs(b.foreverTiles or {}) do
|
|
for _, t in ipairs(T.pieces) do t:Hide() end
|
|
local rest, x, n = width - 2 * T.side, 0, 0
|
|
while rest > 0 do
|
|
n = n + 1
|
|
local t = T.pieces[n]
|
|
if not t then
|
|
t = b:CreateTexture(nil, layer)
|
|
t:SetTexture(T.e[1])
|
|
if T.mode then t:SetBlendMode(T.mode) end
|
|
if T.alpha then t:SetAlpha(T.alpha) end
|
|
T.pieces[n] = t
|
|
end
|
|
local l = math.min(T.middle, rest)
|
|
local u1 = T.e[2] + T.side * T.du
|
|
t:SetTexCoord(u1, u1 + l * T.du, T.e[4], T.e[5])
|
|
t:SetWidth(l)
|
|
place(t, "TOPLEFT", T.left, "TOPRIGHT", x, 0)
|
|
t:SetPoint("BOTTOMLEFT", T.left, "BOTTOMRIGHT", x, 0)
|
|
t:Show()
|
|
x = x + l
|
|
rest = rest - l
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function createCategory(n)
|
|
local h = M.skin
|
|
local C = N.category
|
|
local b = CreateFrame("Button", "ForeverUITradeSkillCategory" .. n, h.child)
|
|
b:SetHeight(C.h)
|
|
b:RegisterForClicks("LeftButtonUp")
|
|
headerBackground(b, "BACKGROUND")
|
|
headerBackground(b, "HIGHLIGHT", "ADD", 0.4)
|
|
local plus = CreateFrame("Frame", nil, b)
|
|
plus:SetWidth(C.button)
|
|
plus:SetHeight(C.button)
|
|
plus:SetPoint("RIGHT", b, "RIGHT", C.buttonX, 0)
|
|
plus.Icon = plus:CreateTexture(nil, "ARTWORK")
|
|
plus.Icon:SetPoint("CENTER", plus, "CENTER", 0, 0)
|
|
b.plus = plus
|
|
local text = b:CreateFontString(nil, "OVERLAY")
|
|
text:SetFontObject(FONTS.category)
|
|
text:SetJustifyH("LEFT")
|
|
text:SetPoint("LEFT", b, "LEFT", C.text, 0)
|
|
text:SetPoint("RIGHT", plus, "LEFT", -4, 0)
|
|
b.text = text
|
|
local n_ = NORMAL_FONT_COLOR
|
|
text:SetTextColor(n_.r, n_.g, n_.b)
|
|
b:SetScript("OnEnter", function(self) self.text:SetTextColor(1, 1, 1) end)
|
|
b:SetScript("OnLeave", function(self) self.text:SetTextColor(n_.r, n_.g, n_.b) end)
|
|
b:SetScript("OnMouseDown", function(self)
|
|
place(self.text, "LEFT", self, "LEFT", C.text + 1, -1)
|
|
self.text:SetPoint("RIGHT", self.plus, "LEFT", -4, 0)
|
|
place(self.plus.Icon, "CENTER", self.plus, "CENTER", 1, -1)
|
|
end)
|
|
b:SetScript("OnMouseUp", function(self)
|
|
place(self.text, "LEFT", self, "LEFT", C.text, 0)
|
|
self.text:SetPoint("RIGHT", self.plus, "LEFT", -4, 0)
|
|
place(self.plus.Icon, "CENTER", self.plus, "CENTER", 0, 0)
|
|
end)
|
|
b:SetScript("OnClick", function(self)
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
if self.expanded then
|
|
CollapseTradeSkillSubClass(self:GetID())
|
|
else
|
|
ExpandTradeSkillSubClass(self:GetID())
|
|
end
|
|
end)
|
|
return b
|
|
end
|
|
|
|
local function createRecipe(n)
|
|
local h = M.skin
|
|
local R = N.recipe
|
|
local b = CreateFrame("Button", "ForeverUITradeSkillRecipe" .. n, h.child)
|
|
b:SetHeight(R.h)
|
|
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
local progress = CreateFrame("Frame", nil, b)
|
|
progress:SetWidth(R.progress[1])
|
|
progress:SetHeight(R.progress[2])
|
|
progress:SetPoint("LEFT", b, "LEFT", R.progress[3], 0)
|
|
progress:EnableMouse(true)
|
|
progress.Icon = progress:CreateTexture(nil, "OVERLAY")
|
|
progress.Icon:SetPoint("RIGHT", progress, "RIGHT", 0, -1)
|
|
b.progress = progress
|
|
local name = b:CreateFontString(nil, "OVERLAY")
|
|
name:SetFontObject(FONTS.row)
|
|
name:SetJustifyH("LEFT")
|
|
name:SetHeight(12)
|
|
name:SetPoint("LEFT", progress, "RIGHT", R.nameX, 0)
|
|
b.name = name
|
|
local count = b:CreateFontString(nil, "OVERLAY")
|
|
count:SetFontObject(FONTS.row)
|
|
count:SetJustifyH("LEFT")
|
|
count:SetHeight(12)
|
|
count:SetPoint("LEFT", name, "RIGHT", 0, 0)
|
|
b.count = count
|
|
-- Selected (above the name) and hover (HIGHLIGHT layer)
|
|
local choice = CreateFrame("Frame", nil, b)
|
|
choice:SetAllPoints(b)
|
|
choice:SetFrameLevel(b:GetFrameLevel() + 1)
|
|
choice:EnableMouse(false)
|
|
local selectedItem = choice:CreateTexture(nil, "OVERLAY")
|
|
atlas(selectedItem, "professions_recipe_active", true)
|
|
selectedItem:SetPoint("CENTER", b, "CENTER", 0, -1)
|
|
selectedItem:Hide()
|
|
b.selectedItem = selectedItem
|
|
local hover = b:CreateTexture(nil, "HIGHLIGHT")
|
|
atlas(hover, "professions_recipe_hover", true)
|
|
hover:SetPoint("CENTER", b, "CENTER", 0, -1)
|
|
hover:SetAlpha(0.5)
|
|
b.hover = hover
|
|
local function colors(self, white)
|
|
local c = white and { 1, 1, 1 } or COLORS.recipe
|
|
self.name:SetTextColor(c[1], c[2], c[3])
|
|
self.count:SetTextColor(c[1], c[2], c[3])
|
|
end
|
|
b.colors = colors
|
|
local function onEnter(self)
|
|
colors(b, true)
|
|
if b.isTruncated then
|
|
-- 3.3.5 takes only a frame as owner: the row, with the tooltip where ANCHOR_RIGHT
|
|
-- puts it on the name
|
|
GameTooltip:SetOwner(b, "ANCHOR_NONE")
|
|
GameTooltip:ClearAllPoints()
|
|
GameTooltip:SetPoint("BOTTOMLEFT", b.name, "TOPRIGHT")
|
|
GameTooltip:AddLine(b.fullName, 1, 1, 1, false)
|
|
GameTooltip:Show()
|
|
end
|
|
end
|
|
local function exit()
|
|
colors(b, false)
|
|
GameTooltip:Hide()
|
|
end
|
|
b:SetScript("OnEnter", onEnter)
|
|
b:SetScript("OnLeave", exit)
|
|
progress:SetScript("OnLeave", exit)
|
|
progress:SetScript("OnMouseUp", function(_, button) b:Click(button) end)
|
|
b:SetScript("OnClick", function(self, button)
|
|
if button ~= "LeftButton" then return end
|
|
if IsModifiedClick() then
|
|
HandleModifiedItemClick(GetTradeSkillRecipeLink(self:GetID()))
|
|
return
|
|
end
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
TradeSkillFrame_SetSelection(self:GetID())
|
|
TradeSkillFrame_Update()
|
|
end)
|
|
return b
|
|
end
|
|
|
|
-- List elements in order: the 3.3.5 flat list made into a tree (a header, its recipes);
|
|
-- the "Has skill up" filter, missing in 3.3.5, drops trivial recipes
|
|
function M.Elements()
|
|
local elements = {}
|
|
local category
|
|
local queued = {}
|
|
local function close()
|
|
if category then
|
|
local recipes = category.recipes
|
|
if category.expanded and #recipes > 0 then
|
|
elements[#elements + 1] = { space = N.tree.hovered }
|
|
for _, r in ipairs(recipes) do elements[#elements + 1] = r end
|
|
elements[#elements + 1] = { space = N.tree.below }
|
|
end
|
|
end
|
|
end
|
|
for i = 1, GetNumTradeSkills() or 0 do
|
|
local name, kind, numCraftable, expanded = GetTradeSkillInfo(i)
|
|
if name then
|
|
if kind == "header" then
|
|
close()
|
|
category = { index = i, name = name, expanded = expanded and true or false, recipes = {}, category = true }
|
|
queued[#queued + 1] = category
|
|
elements[#elements + 1] = category
|
|
elseif not (M.skillUpsOnly and kind == "trivial") then
|
|
local r = { index = i, name = name, kind = kind, numCraftable = numCraftable or 0, indent = category and true or false }
|
|
if category then
|
|
table.insert(category.recipes, r)
|
|
else
|
|
elements[#elements + 1] = r
|
|
end
|
|
end
|
|
end
|
|
end
|
|
close()
|
|
-- A category emptied by the filter disappears (camelot filters before building the tree);
|
|
-- a collapsed category keeps its header
|
|
if M.skillUpsOnly then
|
|
local keep = {}
|
|
for _, e in ipairs(elements) do
|
|
if not (e.category and e.expanded and #e.recipes == 0) then keep[#keep + 1] = e end
|
|
end
|
|
elements = keep
|
|
end
|
|
return elements
|
|
end
|
|
|
|
local function placeBar(hasBar)
|
|
local h = M.skin
|
|
local Z = N.zone
|
|
h.zone:ClearAllPoints()
|
|
h.zone:SetPoint("TOPLEFT", h.list, "TOPLEFT", Z[1], Z[2])
|
|
-- Without a bar: the same margin on the right as on the left
|
|
h.zone:SetPoint("BOTTOMRIGHT", h.list, "BOTTOMRIGHT", hasBar and Z[3] or -Z[1], Z[4])
|
|
end
|
|
|
|
function M.UpdateList()
|
|
local h = M.skin
|
|
if not h then return end
|
|
local A = N.tree
|
|
local elements = M.Elements()
|
|
-- Content height decides whether the bar is needed
|
|
local height = A.top + A.down
|
|
for i, e in ipairs(elements) do
|
|
height = height + (e.category and N.category.h or e.space or N.recipe.h) + (i > 1 and A.space or 0)
|
|
end
|
|
local view = h.zone:GetHeight()
|
|
if not view or view <= 0 then view = N.window[2] + N.list[2] - N.list.down + N.zone[2] - N.zone[4] end
|
|
local hasBar = height > view
|
|
if hasBar ~= h.hasBar then
|
|
h.hasBar = hasBar
|
|
placeBar(hasBar)
|
|
end
|
|
local width = N.list[3] - N.zone[1] + (hasBar and N.zone[3] or -N.zone[1])
|
|
h.child:SetWidth(width)
|
|
h.child:SetHeight(math.max(height, 1))
|
|
-- Scroll position first: only the elements in view get a row. A profession has hundreds of
|
|
-- recipes, and every shown row is laid out again each frame the window moves.
|
|
local total = math.ceil(height / N.step)
|
|
local visibleCount = math.floor(view / N.step)
|
|
h.offset = math.max(0, math.min(h.offset or 0, total - visibleCount))
|
|
local scroll = math.min(h.offset * N.step, math.max(0, height - view))
|
|
local selected = GetTradeSkillSelectionIndex()
|
|
local y, nc, nr = A.top, 0, 0
|
|
for i, e in ipairs(elements) do
|
|
if i > 1 then y = y + A.space end
|
|
local size = e.category and N.category.h or e.space or N.recipe.h
|
|
local inView = y + size > scroll and y < scroll + view
|
|
if e.category and inView then
|
|
nc = nc + 1
|
|
local b = h.categories[nc] or createCategory(nc)
|
|
h.categories[nc] = b
|
|
b:SetID(e.index)
|
|
b.expanded = e.expanded
|
|
b.text:SetText(e.name)
|
|
local ic = e.expanded and "common-button-list-minus" or "common-button-list-plus"
|
|
atlas(b.plus.Icon, ic, true)
|
|
local l = width - A.right
|
|
b:SetWidth(l)
|
|
tileHeader(b, l)
|
|
place(b, "TOPLEFT", h.child, "TOPLEFT", 0, -y)
|
|
b:Show()
|
|
elseif not e.category and not e.space and inView then
|
|
nr = nr + 1
|
|
local b = h.recipes[nr] or createRecipe(nr)
|
|
h.recipes[nr] = b
|
|
b:SetID(e.index)
|
|
local indent = e.indent and A.indent or 0
|
|
local l = width - A.right - indent
|
|
b:SetWidth(l)
|
|
place(b, "TOPLEFT", h.child, "TOPLEFT", indent, -y)
|
|
M.FillRecipe(b, e, l, selected == e.index)
|
|
b:Show()
|
|
end
|
|
y = y + size
|
|
end
|
|
for i = nc + 1, #h.categories do h.categories[i]:Hide() end
|
|
for i = nr + 1, #h.recipes do h.recipes[i]:Hide() end
|
|
Tpl.SetShown(h.none, #elements == 0)
|
|
h.bar:Configure(total, visibleCount, h.offset)
|
|
h.zone:SetVerticalScroll(scroll)
|
|
end
|
|
|
|
-- Name width. A row is reused for several recipes: its name keeps the previous width, and the
|
|
-- client measures the text within that width (GetStringWidth returns the shown width), so a
|
|
-- longer name would be cut. We measure on a separate, unbounded, invisible font string.
|
|
local function nameWidth(text)
|
|
local m = M.measure
|
|
if not m then
|
|
m = M.skin.child:CreateFontString(nil, "OVERLAY")
|
|
m:SetFontObject(FONTS.row)
|
|
m:SetPoint("TOPLEFT", M.skin.child, "TOPLEFT", 0, 0)
|
|
m:SetAlpha(0)
|
|
M.measure = m
|
|
end
|
|
m:SetText(text)
|
|
return m:GetStringWidth()
|
|
end
|
|
|
|
function M.FillRecipe(b, e, width, selectedItem)
|
|
local R = N.recipe
|
|
b.fullName = e.name
|
|
b.name:SetText(e.name)
|
|
b.colors(b, false)
|
|
local P = PROGRESS[e.kind]
|
|
if P then
|
|
atlas(b.progress.Icon, P[1], true)
|
|
place(b.progress, "LEFT", b, "LEFT", R.progress[3], P[2])
|
|
b.progress:Show()
|
|
b.progress:SetScript("OnEnter", function()
|
|
b.colors(b, true)
|
|
GameTooltip:SetOwner(b.progress, "ANCHOR_RIGHT")
|
|
local t = P[3]
|
|
local n_ = NORMAL_FONT_COLOR
|
|
-- 3.3.5 does not give the skill points gained: 1 is shown
|
|
GameTooltip:AddLine(string.format(t, 1), n_.r, n_.g, n_.b, true)
|
|
GameTooltip:Show()
|
|
end)
|
|
else
|
|
b.progress:Hide()
|
|
end
|
|
local hasCount = (e.numCraftable or 0) > 0
|
|
if hasCount then
|
|
b.count:SetFormattedText(" [%d] ", e.numCraftable)
|
|
b.count:Show()
|
|
else
|
|
b.count:SetText("")
|
|
b.count:Hide()
|
|
end
|
|
-- Room for the name: the row minus the count, the margin and the progress frame
|
|
local position = width - ((hasCount and b.count:GetStringWidth() or 0) + R.margin + R.progress[1])
|
|
local full = nameWidth(e.name)
|
|
b.name:SetWidth(math.max(1, math.min(position, full)))
|
|
b.isTruncated = full > position
|
|
Tpl.SetShown(b.selectedItem, selectedItem)
|
|
Tpl.SetShown(b.hover, not selectedItem)
|
|
end
|
|
|
|
-- ------------------------------------------------------------ rank bar
|
|
|
|
function M.UpdateRank()
|
|
local h = M.skin
|
|
local r = h.rank
|
|
local name, rank, maxValue, bonus = GetTradeSkillLine()
|
|
if not name or not maxValue or maxValue <= 0 then
|
|
r:Hide()
|
|
return
|
|
end
|
|
r:Show()
|
|
if bonus and bonus > 0 then
|
|
r.text:SetFormattedText(L.TRADESKILL_NAME_RANK_MODIFIER, name, rank, bonus, maxValue)
|
|
else
|
|
r.text:SetFormattedText(L.TRADESKILL_NAME_RANK, name, rank, maxValue)
|
|
end
|
|
local M_ = profession()
|
|
local strip = M_ and ("skillbar_fill_flipbook_" .. M_.rank) or "skillbar_fill_flipbook_defaultblue"
|
|
local e = ForeverUI.AtlasEntry(strip) or ForeverUI.AtlasEntry("skillbar_fill_flipbook_defaultblue")
|
|
local flare = M_ and ForeverUI.AtlasEntry("skillbar_flare_" .. M_.rank)
|
|
local R = N.rank
|
|
local part = math.min(rank / maxValue, 1)
|
|
-- Mask: from 1 after the fill start, over 453 x the ratio; the fill (441) shows only below it.
|
|
-- Camelot's fill is a 60-frame flipbook 1712 wide that 3.3.5 cannot show: the first frame is used.
|
|
local found = math.min(R.filled[1] - R.mask, R[3] * part)
|
|
if e and found >= 1 then
|
|
r.filled:SetTexture(e[1])
|
|
local du = (e[3] - e[2]) / R.filled[1]
|
|
r.filled:SetTexCoord(e[2] + du * R.mask, e[2] + du * (R.mask + found), e[4], e[5])
|
|
r.filled:SetWidth(found)
|
|
r.filled:Show()
|
|
else
|
|
r.filled:Hide()
|
|
end
|
|
-- Camelot masks the flare too (MaskedTexture Flare): it shows only over the mask width, from the
|
|
-- fill start. 3.3.5 has no mask, so we keep the flare's right part, cut to the visible width;
|
|
-- otherwise it overhangs the bar on the left at low rank.
|
|
local mask = R[3] * part
|
|
if flare and mask >= 1 then
|
|
local l = math.min(R.flare[1], mask)
|
|
local du = (flare[3] - flare[2]) / R.flare[1]
|
|
r.flare:SetTexture(flare[1])
|
|
r.flare:SetTexCoord(flare[3] - du * l, flare[3], flare[4], flare[5])
|
|
r.flare:SetWidth(l)
|
|
place(r.flare, "RIGHT", r, "TOPLEFT", R.filled[3] + R.mask + mask, R.filled[4] - R.filled[2] / 2)
|
|
r.flare:SetAlpha(rank >= maxValue and 0 or 1)
|
|
r.flare:Show()
|
|
else
|
|
r.flare:Hide()
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ schematic
|
|
|
|
-- Sizes fs to its text at maxValue wide: on several lines (multiline), otherwise one line as
|
|
-- wide as the text (camelot SetTextToFit)
|
|
local function fitText(fs, text, maxValue, multiline)
|
|
fs:SetHeight(200)
|
|
fs:SetText(text)
|
|
fs:SetWidth(maxValue)
|
|
if not multiline then fs:SetWidth(fs:GetStringWidth()) end
|
|
fs:SetHeight(fs:GetStringHeight())
|
|
end
|
|
|
|
-- Quality and name of an item link; 0 and nil for anything else
|
|
local function quality(link)
|
|
if link and string.find(link, "|Hitem:", 1, true) then
|
|
local name, _, q = GetItemInfo(link)
|
|
return q or 0, name
|
|
end
|
|
return 0, nil
|
|
end
|
|
|
|
local function createReagent(n)
|
|
local h = M.skin
|
|
local Rg = N.reagents
|
|
local s = CreateFrame("Frame", nil, h.reagents)
|
|
s:SetWidth(Rg.slot[1])
|
|
s:SetHeight(Rg.slot[2])
|
|
local b = CreateFrame("Button", "ForeverUITradeSkillReagent" .. n, s)
|
|
b:SetWidth(Rg.button)
|
|
b:SetHeight(Rg.button)
|
|
b:SetPoint("LEFT", s, "LEFT", 0, 0)
|
|
local background = b:CreateTexture(nil, "BACKGROUND")
|
|
atlas(background, "professions-slot-bg", true)
|
|
background:SetAllPoints(b)
|
|
local icon = b:CreateTexture(nil, "ARTWORK")
|
|
icon:SetAllPoints(b)
|
|
local outline = b:CreateTexture(nil, "OVERLAY")
|
|
outline:SetPoint("TOPLEFT", icon, "TOPLEFT", -5, 4)
|
|
outline:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", 4, -5)
|
|
-- UI-Quickslot2 (SetModifyingRequired(false)), BORDER layer, on the button
|
|
b:SetNormalTexture(BUTTONS .. "UI-Quickslot2")
|
|
local frame = b:GetNormalTexture()
|
|
frame:SetDrawLayer("BORDER")
|
|
frame:ClearAllPoints()
|
|
frame:SetAllPoints(b)
|
|
b.icon, b.outline = icon, outline
|
|
local name = s:CreateFontString(nil, "BORDER")
|
|
name:SetFontObject(FONTS.row)
|
|
name:SetJustifyH("LEFT")
|
|
name:SetWidth(Rg.nameSize[1])
|
|
name:SetHeight(Rg.nameSize[2])
|
|
name:SetPoint("LEFT", s, "LEFT", Rg.nameX, 0)
|
|
s.button, s.name = b, name
|
|
b:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetTradeSkillItem(M.selected, self:GetID())
|
|
GameTooltip:Show()
|
|
end)
|
|
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
b:SetScript("OnClick", function(self)
|
|
if IsModifiedClick() then
|
|
HandleModifiedItemClick(GetTradeSkillReagentItemLink(M.selected, self:GetID()))
|
|
end
|
|
end)
|
|
return s
|
|
end
|
|
|
|
-- After TradeSkillFrame_SetSelection: the selected recipe's schematic
|
|
function M.UpdateCard()
|
|
local h = M.skin
|
|
if not h then return end
|
|
local id = GetTradeSkillSelectionIndex()
|
|
local name, kind, numCraftable, _, verb = GetTradeSkillInfo(id)
|
|
local F = h.card
|
|
-- Profession card
|
|
local M_ = profession()
|
|
local map = (M_ and M_.map and ForeverUI.AtlasEntry(M_.map)) and M_.map or "professions-recipe-background"
|
|
atlas(F.map, map, true)
|
|
if not name or kind == "header" then
|
|
M.selected = nil
|
|
F.content:Hide()
|
|
M.UpdateButtons(nil)
|
|
return
|
|
end
|
|
M.selected = id
|
|
F.content:Show()
|
|
-- Result
|
|
local link = GetTradeSkillItemLink(id)
|
|
local q, itemName = quality(link)
|
|
SetPortraitToTexture(F.icon, GetTradeSkillIcon(id))
|
|
local outline = RESULT_OUTLINE[q]
|
|
if outline then
|
|
atlas(F.outline, "auctionhouse-itemicon-border-" .. outline)
|
|
F.outline:Show()
|
|
else
|
|
F.outline:Hide()
|
|
end
|
|
local minValue, maxValue = GetTradeSkillNumMade(id)
|
|
if maxValue and maxValue > 1 then
|
|
if minValue == maxValue then F.count:SetText(minValue) else F.count:SetFormattedText("%d-%d", minValue, maxValue) end
|
|
if F.count:GetWidth() > 39 then F.count:SetFormattedText("~%d", math.floor((minValue + maxValue) / 2)) end
|
|
F.shadow:Show()
|
|
else
|
|
F.count:SetText("")
|
|
F.shadow:Hide()
|
|
end
|
|
local nameText
|
|
if itemName then
|
|
local c = ITEM_QUALITY_COLORS[q]
|
|
local hex = c and (c.hex or string.format("|cff%02x%02x%02x", math.floor(c.r * 255 + 0.5), math.floor(c.g * 255 + 0.5), math.floor(c.b * 255 + 0.5)))
|
|
nameText = hex and (hex .. itemName .. "|r") or itemName
|
|
else
|
|
nameText = NORMAL_FONT_COLOR_CODE .. name .. "|r"
|
|
end
|
|
fitText(F.name, nameText, N.textWidth, true)
|
|
-- Tools
|
|
local tools = BuildColoredListString(GetTradeSkillTools(id))
|
|
if tools then
|
|
fitText(F.tools, NORMAL_FONT_COLOR_CODE .. REQUIRES_LABEL .. "|r " .. tools, N.textWidth, true)
|
|
F.tools:Show()
|
|
else
|
|
F.tools:SetText("")
|
|
F.tools:Hide()
|
|
end
|
|
-- Cooldown, then description (vertical layout)
|
|
local O = N.organizer
|
|
-- Wrapped, the name and tools may reach below the place of what follows (12 under the
|
|
-- result): it then starts 4 under the text. Heights from the result's centre, the name 17
|
|
-- above it.
|
|
local textBottom = N.name[2] - F.name:GetHeight() / 2
|
|
if tools then textBottom = textBottom + N.tools[2] - F.tools:GetHeight() end
|
|
local shift = math.min(0, textBottom - O[3] - (O[2] - N.result[3] / 2))
|
|
local cooldown = GetTradeSkillCooldown(id)
|
|
local previous
|
|
if cooldown then
|
|
F.cooldown:SetText(COOLDOWN_REMAINING .. " " .. SecondsToTime(cooldown))
|
|
place(F.cooldown, "TOPLEFT", F.result, "BOTTOMLEFT", O[1], O[2] + shift)
|
|
F.cooldown:Show()
|
|
previous = F.cooldown
|
|
else
|
|
F.cooldown:Hide()
|
|
end
|
|
local description = GetTradeSkillDescription(id)
|
|
F.description:SetWidth(N.description)
|
|
F.description:SetHeight(600)
|
|
F.description:SetText(description or "")
|
|
F.description:SetHeight((description and description ~= "") and (F.description:GetStringHeight() + 1) or 1)
|
|
if previous then
|
|
place(F.description, "TOPLEFT", previous, "BOTTOMLEFT", 0, -(O[3] + 5))
|
|
else
|
|
place(F.description, "TOPLEFT", F.result, "BOTTOMLEFT", O[1], O[2] + shift)
|
|
end
|
|
-- Reagents
|
|
local Rg = N.reagents
|
|
local n = GetTradeSkillNumReagents(id) or 0
|
|
Tpl.SetShown(h.reagents, n > 0)
|
|
place(h.reagents, "TOPLEFT", F.description, "BOTTOMLEFT", Rg[1], Rg[2])
|
|
local shownItems, possible = 0, true
|
|
for i = 1, n do
|
|
local rName, rIcon, required, owned = GetTradeSkillReagentInfo(id, i)
|
|
local enough = (owned or 0) >= (required or 0)
|
|
if not enough then possible = false end
|
|
if rName and rIcon then
|
|
shownItems = shownItems + 1
|
|
local s = h.slots[shownItems] or createReagent(shownItems)
|
|
h.slots[shownItems] = s
|
|
s.button:SetID(i)
|
|
s.button.icon:SetTexture(rIcon)
|
|
local rq = quality(GetTradeSkillReagentItemLink(id, i))
|
|
local ct = REAGENT_OUTLINE[rq]
|
|
if ct then
|
|
atlas(s.button.outline, ct, true)
|
|
s.button.outline:Show()
|
|
else
|
|
s.button.outline:Hide()
|
|
end
|
|
local c = enough and { 1, 1, 1 } or COLORS.missingReagent
|
|
s.name:SetFormattedText(L.TRADESKILL_REAGENT_COUNT .. " %s", tostring(owned or 0), required or 0, rName)
|
|
s.name:SetTextColor(c[1], c[2], c[3])
|
|
local column = math.floor((shownItems - 1) / Rg.column)
|
|
local rowLine = (shownItems - 1) % Rg.column
|
|
place(s, "TOPLEFT", h.reagents, "TOPLEFT", Rg.start[1] + column * (Rg.slot[1] + Rg.gap[1]),
|
|
Rg.start[2] - rowLine * (Rg.slot[2] + Rg.gap[2]))
|
|
s:Show()
|
|
end
|
|
end
|
|
for i = shownItems + 1, #h.slots do h.slots[i]:Hide() end
|
|
M.UpdateButtons(id, name, verb, numCraftable, possible)
|
|
end
|
|
|
|
-- ------------------------------------------------------------ buttons
|
|
|
|
-- Sets the button text and widens it to fit (never narrower)
|
|
local function fitButtonText(b, text)
|
|
b:SetText(text)
|
|
local fs = b:GetFontString()
|
|
local width = (fs and fs:GetStringWidth() or 0) + N.create.margin
|
|
b:SetWidth(math.max(b:GetWidth(), width))
|
|
end
|
|
|
|
-- possible: every reagent is there (UpdateCard's reagent loop)
|
|
function M.UpdateButtons(id, name, verb, numCraftable, possible)
|
|
local h = M.skin
|
|
local B = h.buttons
|
|
if not id or truthy(IsTradeSkillLinked()) then
|
|
B.create:Hide()
|
|
B.all:Hide()
|
|
B.counter:Hide()
|
|
return
|
|
end
|
|
-- Create is enabled when the reagents are there (the 3.3.5 rule); Create All and the counter
|
|
-- do not exist for a spell with a verb (enchanting), as in 3.3.5
|
|
local maxValue = math.abs(numCraftable or 0)
|
|
B.create:Show()
|
|
fitButtonText(B.create, verb or CREATE)
|
|
if possible then B.create:Enable() else B.create:Disable() end
|
|
local multiple = not verb
|
|
Tpl.SetShown(B.all, multiple)
|
|
Tpl.SetShown(B.counter, multiple)
|
|
if multiple then
|
|
fitButtonText(B.all, string.format(L.TRADESKILL_CREATE_ALL_FORMAT, CREATE_ALL, maxValue))
|
|
if possible and maxValue > 0 then B.all:Enable() else B.all:Disable() end
|
|
B.counter.maxValue = maxValue
|
|
if maxValue > 0 then
|
|
B.counter:SetNumber(math.max(1, math.min(GetTradeskillRepeatCount() or 1, maxValue)))
|
|
B.counter:EnableMouse(true)
|
|
B.counter.active = true
|
|
else
|
|
B.counter:SetNumber(0)
|
|
B.counter:EnableMouse(false)
|
|
B.counter.active = false
|
|
end
|
|
M.UpdateArrows()
|
|
end
|
|
end
|
|
|
|
function M.UpdateArrows()
|
|
local c = M.skin.buttons.counter
|
|
local v = c:GetNumber()
|
|
local function state(b, yes) if yes then b:Enable() else b:Disable() end end
|
|
state(c.plus, c.active and v < (c.maxValue or 0))
|
|
state(c.minus, c.active and v > 1)
|
|
end
|
|
|
|
local function changeCounter(step)
|
|
local c = M.skin.buttons.counter
|
|
if not c.active then return end
|
|
c:SetNumber(math.max(1, math.min((c:GetNumber() or 1) + step, c.maxValue or 1)))
|
|
M.UpdateArrows()
|
|
end
|
|
|
|
local function createButtons(page)
|
|
local h = M.skin
|
|
local C, T, K = N.create, N.createAll, N.counter
|
|
local fonts = { GameFontNormal, GameFontHighlight, GameFontDisable }
|
|
local function button(name)
|
|
local b = CreateFrame("Button", name, page)
|
|
b:SetWidth(C[3])
|
|
b:SetHeight(C[4])
|
|
local fs = b:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
b:SetFontString(fs)
|
|
Tpl.ThreeSliceButton(b, "128-redbutton", fonts)
|
|
return b
|
|
end
|
|
local create = button("ForeverUITradeSkillCreateButton")
|
|
create:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", C[1], C[2])
|
|
create:SetScript("OnClick", function()
|
|
if not M.selected then return end
|
|
-- A spell with a verb (enchanting) has no counter, and the hidden one keeps the previous
|
|
-- recipe's number (0 when it could not be made): one cast, as 3.3.5's hidden input box
|
|
-- reset to GetTradeskillRepeatCount gives
|
|
local c = h.buttons.counter
|
|
DoTradeSkill(M.selected, c:IsShown() and c:GetNumber() or 1)
|
|
end)
|
|
local all = button("ForeverUITradeSkillCreateAllButton")
|
|
all:SetPoint("BOTTOMLEFT", page, "BOTTOMRIGHT", T[1], T[2])
|
|
all:SetScript("OnClick", function()
|
|
local c = h.buttons.counter
|
|
if M.selected and (c.maxValue or 0) > 0 then
|
|
c:SetNumber(c.maxValue)
|
|
DoTradeSkill(M.selected, c.maxValue)
|
|
end
|
|
end)
|
|
-- Counter (NumericInputSpinnerTemplate < InputBoxTemplate)
|
|
local c = CreateFrame("EditBox", "ForeverUITradeSkillInputBox", page)
|
|
c:SetWidth(K[3])
|
|
c:SetHeight(K[4])
|
|
c:SetPoint("BOTTOMLEFT", page, "BOTTOMRIGHT", K[1], K[2])
|
|
c:SetAutoFocus(false)
|
|
c:SetNumeric(true)
|
|
c:SetMaxLetters(3)
|
|
c:SetFontObject(ChatFontNormal)
|
|
c:SetJustifyH("CENTER")
|
|
local edge = "Interface" .. SEP .. "Common" .. SEP .. "Common-Input-Border"
|
|
local g = c:CreateTexture(nil, "BACKGROUND")
|
|
g:SetTexture(edge) g:SetTexCoord(0, 0.0625, 0, 0.625)
|
|
g:SetWidth(8) g:SetHeight(20)
|
|
g:SetPoint("LEFT", c, "LEFT", -5, 0)
|
|
local d = c:CreateTexture(nil, "BACKGROUND")
|
|
d:SetTexture(edge) d:SetTexCoord(0.9375, 1, 0, 0.625)
|
|
d:SetWidth(8) d:SetHeight(20)
|
|
d:SetPoint("RIGHT", c, "RIGHT", 0, 0)
|
|
local m = c:CreateTexture(nil, "BACKGROUND")
|
|
m:SetTexture(edge) m:SetTexCoord(0.0625, 0.9375, 0, 0.625)
|
|
m:SetHeight(20)
|
|
m:SetPoint("LEFT", g, "RIGHT", 0, 0)
|
|
m:SetPoint("RIGHT", d, "LEFT", 0, 0)
|
|
c:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
|
c:SetScript("OnEnterPressed", function(self) self:ClearFocus() end)
|
|
c:SetScript("OnEditFocusLost", function() changeCounter(0) end)
|
|
c:SetScript("OnTextChanged", function() M.UpdateArrows() end)
|
|
local function arrow(name, file)
|
|
local f = CreateFrame("Button", name, c)
|
|
f:SetWidth(K.arrow[1])
|
|
f:SetHeight(K.arrow[2])
|
|
f:SetNormalTexture(BUTTONS .. file .. "-Up")
|
|
f:SetPushedTexture(BUTTONS .. file .. "-Down")
|
|
f:SetDisabledTexture(BUTTONS .. file .. "-Disabled")
|
|
f:SetHighlightTexture(BUTTONS .. "UI-Common-MouseHilight")
|
|
f:GetHighlightTexture():SetBlendMode("ADD")
|
|
return f
|
|
end
|
|
local plus = arrow("ForeverUITradeSkillIncrementButton", "UI-SpellbookIcon-NextPage")
|
|
plus:SetPoint("LEFT", c, "RIGHT", 0, 0)
|
|
plus:SetScript("OnClick", function()
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
changeCounter(1)
|
|
end)
|
|
local minus = arrow("ForeverUITradeSkillDecrementButton", "UI-SpellbookIcon-PrevPage")
|
|
minus:SetPoint("RIGHT", c, "LEFT", K.minusGap, 0)
|
|
minus:SetScript("OnClick", function()
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
changeCounter(-1)
|
|
end)
|
|
c.plus, c.minus = plus, minus
|
|
local wheel = CreateFrame("Frame", nil, c)
|
|
wheel:SetPoint("TOPLEFT", minus, "TOPLEFT")
|
|
wheel:SetPoint("BOTTOMRIGHT", plus, "BOTTOMRIGHT")
|
|
wheel:EnableMouseWheel(true)
|
|
wheel:SetScript("OnMouseWheel", function(_, direction)
|
|
changeCounter((IsShiftKeyDown() and 10 or 1) * (direction > 0 and 1 or -1))
|
|
c:ClearFocus()
|
|
end)
|
|
h.buttons = { create = create, all = all, counter = c }
|
|
end
|
|
|
|
-- ------------------------------------------------------------ filter
|
|
|
|
-- 3.3.5 calls it with (frame, level) (UIDropDownMenu.lua);
|
|
-- ToggleDropDownMenu also sets UIDROPDOWNMENU_MENU_LEVEL
|
|
local function initFilter(_, level)
|
|
level = level or UIDROPDOWNMENU_MENU_LEVEL or 1
|
|
if level == 1 then
|
|
local info = UIDropDownMenu_CreateInfo()
|
|
info.text = L.TRADESKILL_FILTER_SKILL_UP
|
|
info.checked = M.skillUpsOnly
|
|
info.keepShownOnClick = 1
|
|
info.func = function()
|
|
M.skillUpsOnly = not M.skillUpsOnly
|
|
M.UpdateList()
|
|
end
|
|
UIDropDownMenu_AddButton(info, level)
|
|
info = UIDropDownMenu_CreateInfo()
|
|
info.text = CRAFT_IS_MAKEABLE
|
|
info.checked = truthy(TradeSkillFrameAvailableFilterCheckButton:GetChecked())
|
|
info.keepShownOnClick = 1
|
|
info.func = function()
|
|
local yes = not truthy(TradeSkillFrameAvailableFilterCheckButton:GetChecked())
|
|
TradeSkillFrameAvailableFilterCheckButton:SetChecked(yes)
|
|
TradeSkillOnlyShowMakeable(yes)
|
|
end
|
|
UIDropDownMenu_AddButton(info, level)
|
|
info = UIDropDownMenu_CreateInfo()
|
|
info.text = L.TRADESKILL_FILTER_SLOTS
|
|
info.hasArrow = 1
|
|
info.notCheckable = 1
|
|
info.value = "slots"
|
|
UIDropDownMenu_AddButton(info, level)
|
|
elseif UIDROPDOWNMENU_MENU_VALUE == "slots" then
|
|
local info = UIDropDownMenu_CreateInfo()
|
|
info.text = L.TRADESKILL_CHECK_ALL
|
|
info.notCheckable = 1
|
|
info.func = function()
|
|
SetTradeSkillInvSlotFilter(0, 1, 1)
|
|
CloseDropDownMenus()
|
|
end
|
|
UIDropDownMenu_AddButton(info, level)
|
|
info = UIDropDownMenu_CreateInfo()
|
|
info.text = L.TRADESKILL_UNCHECK_ALL
|
|
info.notCheckable = 1
|
|
info.func = function()
|
|
for i = 1, select("#", GetTradeSkillInvSlots()) do SetTradeSkillInvSlotFilter(i, 0, 0) end
|
|
CloseDropDownMenus()
|
|
end
|
|
UIDropDownMenu_AddButton(info, level)
|
|
local all = truthy(GetTradeSkillInvSlotFilter(0))
|
|
for i = 1, select("#", GetTradeSkillInvSlots()) do
|
|
info = UIDropDownMenu_CreateInfo()
|
|
info.text = select(i, GetTradeSkillInvSlots())
|
|
info.checked = all or truthy(GetTradeSkillInvSlotFilter(i))
|
|
info.keepShownOnClick = 1
|
|
local index = i
|
|
info.func = function(self)
|
|
local checkMark = truthy(GetTradeSkillInvSlotFilter(0)) or truthy(GetTradeSkillInvSlotFilter(index))
|
|
SetTradeSkillInvSlotFilter(index, checkMark and 0 or 1, 0)
|
|
end
|
|
UIDropDownMenu_AddButton(info, level)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------ window
|
|
|
|
-- The client's frame: invisible and mouse-less; it stays the host
|
|
local function suppress(f)
|
|
for _, r in ipairs({ f:GetRegions() }) do
|
|
if r:GetObjectType() == "Texture" then r:SetAlpha(0) end
|
|
end
|
|
TradeSkillFrameTitleText:SetAlpha(0)
|
|
TradeSkillFrameDummyString:SetAlpha(0)
|
|
for i = 1, TRADE_SKILLS_DISPLAYED or 8 do
|
|
local b = _G["TradeSkillSkill" .. i]
|
|
if b then b:SetAlpha(0) b:EnableMouse(false) end
|
|
end
|
|
for _, name in ipairs({ "TradeSkillListScrollFrame", "TradeSkillDetailScrollFrame", "TradeSkillHighlightFrame" }) do
|
|
local fx = _G[name]
|
|
if fx then
|
|
fx:SetAlpha(0)
|
|
fx:EnableMouse(false)
|
|
if fx.EnableMouseWheel then fx:EnableMouseWheel(false) end
|
|
for _, s in ipairs({ "ScrollBar", "ScrollBarScrollUpButton", "ScrollBarScrollDownButton" }) do
|
|
local c = _G[name .. s]
|
|
if c then c:EnableMouse(false) end
|
|
end
|
|
end
|
|
end
|
|
for i = 1, MAX_TRADE_SKILL_REAGENTS or 8 do
|
|
local r = _G["TradeSkillReagent" .. i]
|
|
if r then r:EnableMouse(false) end
|
|
end
|
|
if TradeSkillSkillIcon then TradeSkillSkillIcon:EnableMouse(false) end
|
|
for _, c in ipairs({ TradeSkillLinkButton, TradeSkillFrameAvailableFilterCheckButton, TradeSkillRankFrame,
|
|
TradeSkillFrameEditBox, TradeSkillExpandButtonFrame, TradeSkillInvSlotDropDown, TradeSkillSubClassDropDown,
|
|
TradeSkillCreateButton, TradeSkillCreateAllButton, TradeSkillDecrementButton, TradeSkillInputBox,
|
|
TradeSkillIncrementButton, TradeSkillCancelButton }) do
|
|
if c then ForeverUI.Suppress(c) end
|
|
end
|
|
end
|
|
|
|
-- After TradeSkillFrame_Update: title, portrait, rank, list. Below 75 skill (unless linked),
|
|
-- TradeSkillFrame_Update clears the name filter on each update, so the search box is hidden
|
|
-- as in 3.3.5 (forcing it would update forever).
|
|
function M.Update()
|
|
local f = TradeSkillFrame
|
|
local h = f and f.foreverSkin
|
|
if not h then return end
|
|
local name = GetTradeSkillLine()
|
|
local linked, player = IsTradeSkillLinked()
|
|
if truthy(linked) and player then
|
|
h.title:SetText(string.format("%s %s[%s]|r", string.format(TRADE_SKILL_TITLE, name or ""), HIGHLIGHT_FONT_COLOR_CODE, player))
|
|
else
|
|
h.title:SetText(string.format(TRADE_SKILL_TITLE, name or ""))
|
|
end
|
|
local _, icon = profession()
|
|
if icon then
|
|
SetPortraitToTexture(h.portrait, icon)
|
|
else
|
|
SetPortraitTexture(h.portrait, "player")
|
|
end
|
|
M.UpdateRank()
|
|
Tpl.SetShown(h.link, not truthy(linked) and GetTradeSkillListLink() ~= nil)
|
|
local _, rank = GetTradeSkillLine()
|
|
local search = truthy(linked) or (rank or 0) >= 75
|
|
Tpl.SetShown(h.search, search)
|
|
if not search and h.search:GetText() ~= "" then h.search:SetText("") end
|
|
M.UpdateList()
|
|
M.UpdateCard()
|
|
end
|
|
|
|
-- While a profession's items load, the client sends TRADE_SKILL_UPDATE once per item received,
|
|
-- often many in one frame, and each one runs TradeSkillFrame_SetSelection and
|
|
-- TradeSkillFrame_Update. The first call of a frame refreshes the page at once; the calls after
|
|
-- it in that frame give a single refresh on the next frame.
|
|
local refresher = CreateFrame("Frame")
|
|
M.refresher = refresher
|
|
local function onNextFrame(self)
|
|
self:SetScript("OnUpdate", nil)
|
|
M.busy = nil
|
|
if M.pending then
|
|
M.pending = nil
|
|
M.Refresh()
|
|
end
|
|
end
|
|
function M.Refresh()
|
|
if M.busy then
|
|
M.pending = true
|
|
return
|
|
end
|
|
M.busy = true
|
|
refresher:SetScript("OnUpdate", onNextFrame)
|
|
M.Update()
|
|
end
|
|
|
|
function M.Skin()
|
|
local f = TradeSkillFrame
|
|
if not f or f.foreverSkin then return end
|
|
suppress(f)
|
|
f:SetWidth(N.window[1])
|
|
f:SetHeight(N.window[2])
|
|
f:SetHitRectInsets(0, 0, 0, 0)
|
|
local skin = Tpl.PortraitWindow(f, {
|
|
portraitSide = N.portrait.side, portraitX = N.portrait.x, portraitY = N.portrait.y,
|
|
})
|
|
f.foreverSkin = skin
|
|
M.skin = skin
|
|
-- OverrideArt: Profession-Background-Overview instead of the rock, no stripes
|
|
if skin.rock.SetHorizTile then
|
|
skin.rock:SetHorizTile(false)
|
|
skin.rock:SetVertTile(false)
|
|
end
|
|
atlas(skin.rock, "profession-background-overview", true)
|
|
skin.stripes:Hide()
|
|
local base = f:GetFrameLevel()
|
|
local NV = N.levels
|
|
-- Crafting page
|
|
local page = CreateFrame("Frame", "ForeverUITradeSkillPage", f)
|
|
page:SetAllPoints(f)
|
|
page:SetFrameLevel(base + NV.page)
|
|
skin.page = page
|
|
local pageBackground = page:CreateTexture(nil, "BACKGROUND")
|
|
atlas(pageBackground, "profession-background-template2", true)
|
|
pageBackground:SetPoint("TOPLEFT", f, "TOPLEFT", N.page[1], N.page[2])
|
|
skin.pageBackground = pageBackground
|
|
-- Recipe list
|
|
local Li = N.list
|
|
local list = CreateFrame("Frame", "ForeverUITradeSkillRecipeList", page)
|
|
list:SetWidth(Li[3])
|
|
list:SetPoint("TOPLEFT", page, "TOPLEFT", Li[1], Li[2])
|
|
list:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", Li[1], Li.down)
|
|
list:SetFrameLevel(base + NV.list)
|
|
skin.list = list
|
|
local listBackground = list:CreateTexture(nil, "BACKGROUND")
|
|
atlas(listBackground, "professions-background-summarylist", true)
|
|
listBackground:SetAllPoints(list)
|
|
local none = list:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
|
none:SetWidth(N.none[3])
|
|
none:SetPoint("TOP", list, "TOP", N.none[1], N.none[2])
|
|
none:SetText(L.TRADESKILL_NO_RESULTS)
|
|
none:Hide()
|
|
skin.none = none
|
|
-- Filter
|
|
local Fi = N.filter
|
|
local dd = CreateFrame("Frame", "ForeverUITradeSkillFilter", list, "UIDropDownMenuTemplate")
|
|
UIDropDownMenu_Initialize(dd, initFilter)
|
|
UIDropDownMenu_SetText(dd, FILTER)
|
|
Tpl.FilterMenu(dd, Fi[3])
|
|
-- The menu list is at least the button width, wider if its entries need it
|
|
-- (camelot SetMinimumWidth)
|
|
dd.foreverFloor = true
|
|
place(dd, "TOPRIGHT", list, "TOPRIGHT", Fi[1], Fi[2])
|
|
skin.filter = dd
|
|
-- Search (SearchBoxTemplate, as in the quest log)
|
|
local Sr = N.search
|
|
local r = CreateFrame("EditBox", "ForeverUITradeSkillSearchBox", list)
|
|
r:SetHeight(Sr[3])
|
|
r:SetPoint("TOPLEFT", list, "TOPLEFT", Sr[1], Sr[2])
|
|
r:SetPoint("RIGHT", dd, "LEFT", Sr.gap, 0)
|
|
r:SetAutoFocus(false)
|
|
r:SetMaxLetters(60)
|
|
r:SetFontObject("GameFontHighlightSmall")
|
|
r:SetTextInsets(16, 20, 0, 0)
|
|
local function edge(prefix)
|
|
local g = r:CreateTexture(nil, "BACKGROUND")
|
|
atlas(g, prefix .. "-left", true)
|
|
g:SetWidth(8) g:SetHeight(20)
|
|
g:SetPoint("LEFT", r, "LEFT", -5, 0)
|
|
local d = r:CreateTexture(nil, "BACKGROUND")
|
|
atlas(d, prefix .. "-right", true)
|
|
d:SetWidth(8) d:SetHeight(20)
|
|
d:SetPoint("RIGHT", r, "RIGHT", 0, 0)
|
|
local m = r:CreateTexture(nil, "BACKGROUND")
|
|
atlas(m, prefix .. "-middle", true)
|
|
m:SetPoint("TOPLEFT", g, "TOPRIGHT")
|
|
m:SetPoint("BOTTOMRIGHT", d, "BOTTOMLEFT")
|
|
end
|
|
edge("common-search-border")
|
|
local magnifier = r:CreateTexture(nil, "OVERLAY")
|
|
atlas(magnifier, "common-search-magnifyingglass", true)
|
|
magnifier:SetWidth(10) magnifier:SetHeight(10)
|
|
magnifier:SetPoint("LEFT", r, "LEFT", 1, -1)
|
|
local instruction = r:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
|
|
instruction:SetPoint("TOPLEFT", r, "TOPLEFT", 16, 0)
|
|
instruction:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", -20, 0)
|
|
instruction:SetJustifyH("LEFT")
|
|
instruction:SetTextColor(0.35, 0.35, 0.35)
|
|
instruction:SetText(SEARCH)
|
|
local clear = CreateFrame("Button", nil, r)
|
|
clear:SetWidth(17) clear:SetHeight(17)
|
|
clear:SetPoint("RIGHT", r, "RIGHT", -3, 0)
|
|
local closeButton = clear:CreateTexture(nil, "ARTWORK")
|
|
atlas(closeButton, "common-search-clearbutton", true)
|
|
closeButton:SetWidth(10) closeButton:SetHeight(10)
|
|
closeButton:SetPoint("CENTER", clear, "CENTER", 0, 0)
|
|
closeButton:SetAlpha(0.5)
|
|
clear:SetScript("OnEnter", function() closeButton:SetAlpha(1) end)
|
|
clear:SetScript("OnLeave", function() closeButton:SetAlpha(0.5) end)
|
|
clear:SetScript("OnClick", function()
|
|
r:SetText("")
|
|
r:ClearFocus()
|
|
end)
|
|
clear:Hide()
|
|
r:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
|
r:SetScript("OnEnterPressed", function(self) self:ClearFocus() end)
|
|
r:SetScript("OnEditFocusGained", function() instruction:Hide() end)
|
|
r:SetScript("OnEditFocusLost", function(self)
|
|
if self:GetText() == "" then instruction:Show() end
|
|
end)
|
|
r:SetScript("OnTextChanged", function(self)
|
|
local t = self:GetText()
|
|
if t == "" then clear:Hide() else clear:Show() instruction:Hide() end
|
|
SetTradeSkillItemNameFilter(t)
|
|
end)
|
|
skin.search = r
|
|
-- Scrolling list area
|
|
local zone = CreateFrame("ScrollFrame", "ForeverUITradeSkillListScroll", list)
|
|
skin.zone = zone
|
|
placeBar(false)
|
|
skin.hasBar = false
|
|
local child = CreateFrame("Frame", nil, zone)
|
|
child:SetWidth(1)
|
|
child:SetHeight(1)
|
|
zone:SetScrollChild(child)
|
|
child:SetFrameLevel(base + NV.rows)
|
|
skin.child = child
|
|
skin.categories, skin.recipes, skin.offset = {}, {}, 0
|
|
local bar = ForeverUI.CreateScrollBar("ForeverUITradeSkillScrollBar", list, zone)
|
|
bar:ClearAllPoints()
|
|
bar:SetPoint("TOPLEFT", zone, "TOPRIGHT", 0, 0)
|
|
bar:SetPoint("BOTTOMLEFT", zone, "BOTTOMRIGHT", 0, 0)
|
|
bar.onScroll = function(step)
|
|
skin.offset = step
|
|
M.UpdateList()
|
|
end
|
|
skin.bar = bar
|
|
zone:EnableMouseWheel(true)
|
|
zone:SetScript("OnMouseWheel", function(_, direction)
|
|
if bar:IsShown() then bar:MoveTo(bar.offset - direction * 3) end
|
|
end)
|
|
-- Rank bar
|
|
local R = N.rank
|
|
local rank = CreateFrame("Frame", "ForeverUITradeSkillRankBar", page)
|
|
rank:SetWidth(R[3])
|
|
rank:SetHeight(R[4])
|
|
rank:SetPoint("TOPLEFT", page, "TOPLEFT", R[1], R[2])
|
|
rank:SetFrameLevel(base + NV.rank)
|
|
local rankBackground = rank:CreateTexture(nil, "BACKGROUND")
|
|
atlas(rankBackground, "professions-skillbar-bg", true)
|
|
rankBackground:SetWidth(R.background[1]) rankBackground:SetHeight(R.background[2])
|
|
rankBackground:SetPoint("TOPLEFT", rank, "TOPLEFT", 0, 0)
|
|
local filled = rank:CreateTexture(nil, "BORDER")
|
|
filled:SetHeight(R.filled[2])
|
|
filled:SetPoint("TOPLEFT", rank, "TOPLEFT", R.filled[3] + R.mask, R.filled[4])
|
|
local flare = rank:CreateTexture(nil, "ARTWORK")
|
|
flare:SetWidth(R.flare[1]) flare:SetHeight(R.flare[2])
|
|
flare:SetBlendMode("ADD")
|
|
local rankFrame = rank:CreateTexture(nil, "OVERLAY")
|
|
atlas(rankFrame, "professions-skillbar-frame", true)
|
|
rankFrame:SetWidth(R.background[1]) rankFrame:SetHeight(R.background[2])
|
|
rankFrame:SetPoint("TOPLEFT", rank, "TOPLEFT", 0, 0)
|
|
local rankText = CreateFrame("Frame", nil, rank)
|
|
rankText:SetHeight(R[4])
|
|
rankText:SetPoint("LEFT", rank, "LEFT", 0, R.text)
|
|
rankText:SetPoint("RIGHT", rank, "RIGHT", 0, R.text)
|
|
rankText:SetFrameLevel(rank:GetFrameLevel() + 1)
|
|
local t = rankText:CreateFontString(nil, "ARTWORK")
|
|
t:SetFontObject(FONTS.rank)
|
|
t:SetPoint("CENTER", rankText, "CENTER", 0, 0)
|
|
rank.filled, rank.flare, rank.text = filled, flare, t
|
|
skin.rank = rank
|
|
-- Link button
|
|
local Ln = N.link
|
|
local link = CreateFrame("Button", "ForeverUITradeSkillLinkButton", page)
|
|
link:SetWidth(Ln[3]) link:SetHeight(Ln[3])
|
|
link:SetPoint("LEFT", rank, "RIGHT", Ln[1], Ln[2])
|
|
link:SetFrameLevel(base + NV.rank)
|
|
local linkBackground = link:CreateTexture(nil, "BACKGROUND")
|
|
linkBackground:SetWidth(Ln.background) linkBackground:SetHeight(Ln.background)
|
|
linkBackground:SetPoint("CENTER", link, "CENTER", 0, 0)
|
|
local linkIcon = link:CreateTexture(nil, "ARTWORK")
|
|
atlas(linkIcon, "common-icon-chatlink", true)
|
|
linkIcon:SetWidth(Ln.icon) linkIcon:SetHeight(Ln.icon)
|
|
linkIcon:SetPoint("CENTER", link, "CENTER", 0, 0)
|
|
local function applyLinkState(state) atlas(linkBackground, "common-button-tertiary-square-" .. state, true) end
|
|
applyLinkState("normal")
|
|
link:SetScript("OnEnter", function(self)
|
|
applyLinkState("hover")
|
|
GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
|
|
GameTooltip:SetText(LINK_TRADESKILL_TOOLTIP, nil, nil, nil, nil, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
link:SetScript("OnLeave", function()
|
|
applyLinkState("normal")
|
|
GameTooltip:Hide()
|
|
end)
|
|
link:SetScript("OnMouseDown", function() applyLinkState("pressed") end)
|
|
link:SetScript("OnMouseUp", function(self) applyLinkState(self:IsMouseOver() and "hover" or "normal") end)
|
|
link:SetScript("OnClick", function()
|
|
local l = GetTradeSkillListLink()
|
|
if l and not ChatEdit_InsertLink(l) then
|
|
ChatEdit_GetLastActiveWindow():Show()
|
|
ChatEdit_InsertLink(l)
|
|
end
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
end)
|
|
skin.link = link
|
|
-- Schematic
|
|
local Cd = N.card
|
|
local card = CreateFrame("Frame", "ForeverUITradeSkillSchematic", page)
|
|
card:SetWidth(Cd[3])
|
|
card:SetHeight(Cd[4])
|
|
card:SetPoint("TOPLEFT", list, "TOPRIGHT", Cd[1], Cd[2])
|
|
card:SetFrameLevel(base + NV.card)
|
|
local F = { frame = card }
|
|
F.map = card:CreateTexture(nil, "BACKGROUND")
|
|
F.map:SetAllPoints(card)
|
|
local cardEdge = Tpl.StretchedAtlas(card, "common-insideframe", "BORDER")
|
|
cardEdge.rect:SetAllPoints(card)
|
|
-- Recipe content (hidden without a recipe)
|
|
local content = CreateFrame("Frame", nil, card)
|
|
content:SetAllPoints(card)
|
|
F.content = content
|
|
local Rs = N.result
|
|
local result = CreateFrame("Button", "ForeverUITradeSkillOutputIcon", content)
|
|
result:SetWidth(Rs[3]) result:SetHeight(Rs[3])
|
|
result:SetPoint("TOPLEFT", card, "TOPLEFT", Rs[1], Rs[2])
|
|
result:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
F.result = result
|
|
F.icon = result:CreateTexture(nil, "BORDER")
|
|
F.icon:SetWidth(Rs.icon) F.icon:SetHeight(Rs.icon)
|
|
F.icon:SetPoint("CENTER", result, "CENTER", 0, 0)
|
|
F.outline = result:CreateTexture(nil, "OVERLAY")
|
|
F.outline:SetWidth(Rs.outline) F.outline:SetHeight(Rs.outline)
|
|
F.outline:SetPoint("CENTER", result, "CENTER", 0, 0)
|
|
local glow = result:CreateTexture(nil, "HIGHLIGHT")
|
|
atlas(glow, "auctionhouse-itemicon-border-white", true)
|
|
glow:SetWidth(Rs.glow) glow:SetHeight(Rs.glow)
|
|
glow:SetPoint("CENTER", result, "CENTER", 0, 0)
|
|
glow:SetBlendMode("ADD")
|
|
glow:SetAlpha(0.2)
|
|
local resultOverlay = CreateFrame("Frame", nil, result)
|
|
resultOverlay:SetAllPoints(result)
|
|
resultOverlay:SetFrameLevel(result:GetFrameLevel() + 1)
|
|
F.count = resultOverlay:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge")
|
|
F.count:SetJustifyH("RIGHT")
|
|
F.count:SetPoint("BOTTOM", result, "BOTTOMRIGHT", Rs.count[1], Rs.count[2])
|
|
F.shadow = resultOverlay:CreateTexture(nil, "ARTWORK")
|
|
atlas(F.shadow, "battlebar-swappetshadow", true)
|
|
F.shadow:SetAlpha(0.8)
|
|
F.shadow:SetPoint("TOPLEFT", F.count, "TOPLEFT", -10, 10)
|
|
F.shadow:SetPoint("BOTTOMRIGHT", F.count, "BOTTOMRIGHT", 10, -10)
|
|
F.shadow:Hide()
|
|
result:SetScript("OnEnter", function(self)
|
|
if not M.selected then return end
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
GameTooltip:SetTradeSkillItem(M.selected)
|
|
GameTooltip:Show()
|
|
end)
|
|
result:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
result:SetScript("OnClick", function()
|
|
if M.selected then HandleModifiedItemClick(GetTradeSkillItemLink(M.selected)) end
|
|
end)
|
|
F.name = content:CreateFontString(nil, "ARTWORK")
|
|
F.name:SetFontObject(FONTS.med2)
|
|
F.name:SetJustifyH("LEFT")
|
|
F.name:SetJustifyV("TOP")
|
|
F.name:SetPoint("LEFT", result, "RIGHT", N.name[1], N.name[2])
|
|
F.tools = content:CreateFontString(nil, "ARTWORK")
|
|
F.tools:SetFontObject(FONTS.small2)
|
|
F.tools:SetJustifyH("LEFT")
|
|
F.tools:SetJustifyV("TOP")
|
|
F.tools:SetPoint("TOPLEFT", F.name, "BOTTOMLEFT", N.tools[1], N.tools[2])
|
|
F.cooldown = content:CreateFontString(nil, "ARTWORK", "GameFontRedSmall")
|
|
F.cooldown:SetJustifyH("LEFT")
|
|
F.cooldown:SetWidth(N.cooldown)
|
|
F.description = content:CreateFontString(nil, "ARTWORK")
|
|
F.description:SetFontObject(FONTS.small2)
|
|
F.description:SetJustifyH("LEFT")
|
|
F.description:SetJustifyV("TOP")
|
|
skin.card = F
|
|
-- Reagents
|
|
local Rg = N.reagents
|
|
local reagents = CreateFrame("Frame", "ForeverUITradeSkillReagents", content)
|
|
reagents:SetWidth(Rg.tag[1])
|
|
reagents:SetHeight(Rg.tag[2])
|
|
local tag = reagents:CreateFontString(nil, "BACKGROUND", "GameFontNormalSmall")
|
|
tag:SetJustifyH("LEFT")
|
|
tag:SetWidth(Rg.tag[1])
|
|
tag:SetHeight(Rg.tag[2])
|
|
tag:SetPoint("TOPLEFT", reagents, "TOPLEFT", 0, 0)
|
|
-- SPELL_REAGENTS, the label of 3.3.5's page in the client's language; it ends with a line
|
|
-- break meant for spell tooltips
|
|
tag:SetText((string.gsub(SPELL_REAGENTS, "|n$", "")))
|
|
skin.reagents, skin.slots = reagents, {}
|
|
-- Buttons
|
|
createButtons(page)
|
|
Tpl.CloseButton(TradeSkillFrameCloseButton, f)
|
|
TradeSkillFrameCloseButton:SetFrameLevel(base + NV.closeButton)
|
|
hooksecurefunc("TradeSkillFrame_Update", M.Refresh)
|
|
hooksecurefunc("TradeSkillFrame_SetSelection", M.Refresh)
|
|
end
|
|
|
|
M.Skin()
|
|
|
|
local watcher = CreateFrame("Frame")
|
|
watcher:RegisterEvent("ADDON_LOADED")
|
|
watcher:RegisterEvent("UPDATE_TRADESKILL_RECAST")
|
|
watcher:SetScript("OnEvent", function(_, event, name)
|
|
if event == "ADDON_LOADED" then
|
|
if name == "Blizzard_TradeSkillUI" then M.Skin() end
|
|
elseif M.skin and TradeSkillFrame:IsShown() and M.skin.buttons.counter.active then
|
|
M.skin.buttons.counter:SetNumber(GetTradeskillRepeatCount())
|
|
M.UpdateArrows()
|
|
end
|
|
end)
|