Files
OctoQuestRewards/UI.lua
T

147 lines
5.8 KiB
Lua

local A = OctoQuestRewards
local G = getfenv(0)
local panels = {
detail = { "QuestFrameDetailPanel", "QuestDetailScrollChildFrame", "QuestDetailScrollFrame", "QuestDescription", "QuestDetailRewardTitleText" },
progress = { "QuestFrameProgressPanel", "QuestProgressScrollChildFrame", "QuestProgressScrollFrame", "QuestProgressText" },
reward = { "QuestFrameRewardPanel", "QuestRewardScrollChildFrame", "QuestRewardScrollFrame", "QuestRewardText", "QuestRewardRewardTitleText" },
log = { "QuestLogFrame", "QuestLogDetailScrollChildFrame", "QuestLogDetailScrollFrame", "QuestLogQuestDescription", "QuestLogRewardTitleText" },
}
-- Copy the live font, including addon overrides, rather than just its template.
local function CopyFont(target, source)
if not source or not source.GetFont then return end
local font, size, flags = source:GetFont()
if font and size then target:SetFont(font, size, flags or "") end
end
function A.Number(value)
local s = tostring(math.floor(value))
local count
repeat s, count = string.gsub(s, "^(%-?%d+)(%d%d%d)", "%1,%2") until count == 0
return s
end
function A.Money(copper)
copper = math.floor(copper)
local gold = math.floor(copper / 10000)
local silver = math.floor(copper / 100) - gold * 100
local coins = copper - math.floor(copper / 100) * 100
local parts = {}
if gold > 0 then table.insert(parts, gold .. "g") end
if silver > 0 then table.insert(parts, silver .. "s") end
if coins > 0 then table.insert(parts, coins .. "c") end
return table.concat(parts, " ")
end
-- Read actual visible content extents, including the nested fading reward area.
-- Ignore textures and spacer frames, whose bounds aren't content bounds.
local function ContentBottom(object, block, top, scale, depth)
if object == block or not object:IsShown() or depth > 5 then return 0 end
local name = object:GetName() or ""
if string.find(name, "Spacer") then return 0 end
local bottom = 0
local isText = object:IsObjectType("FontString")
if (isText and object:GetText() and object:GetText() ~= "")
or object:IsObjectType("Button") or string.find(name, "MoneyFrame$") then
local b = object:GetBottom()
if b then
-- FontStrings inherit their parent's scale; don't assume Frame-only
-- methods exist on Vanilla regions.
local owner = isText and object:GetParent() or object
bottom = (top * scale - b * owner:GetEffectiveScale()) / scale
end
end
if object.GetRegions then
for _, region in ipairs({object:GetRegions()}) do
bottom = math.max(bottom, ContentBottom(region, block, top, scale, depth + 1))
end
end
if object.GetChildren then
for _, child in ipairs({object:GetChildren()}) do
bottom = math.max(bottom, ContentBottom(child, block, top, scale, depth + 1))
end
end
return bottom
end
function A.Render(kind)
local cfg = panels[kind]
local panel, child, scroll = G[cfg[1]], G[cfg[2]], G[cfg[3]]
if not panel or not child or not scroll then return end
if cfg.block then cfg.block:Hide() end
if not panel:IsVisible() then return end
local r = A.GetRecord(kind)
A.current = r
if A.db.debug and r then A.DebugRecord(r) end
local lines = {}
if r and r.xp and r.xp > 0 then table.insert(lines, "Estimated XP: " .. A.Number(r.xp)) end
if not cfg.block then
cfg.block = CreateFrame("Frame", nil, child)
cfg.block:SetWidth(child:GetWidth() - 15)
cfg.block.title = cfg.block:CreateFontString(nil, "ARTWORK", "QuestTitleFont")
cfg.block.title:SetPoint("TOPLEFT", cfg.block, "TOPLEFT", 0, 0)
cfg.block.title:SetText("Rewards")
cfg.block.text = cfg.block:CreateFontString(nil, "ARTWORK", "QuestFont")
cfg.block.text:SetJustifyH("LEFT")
cfg.baseHeight = child:GetHeight()
end
local block = cfg.block
-- Keep our previous extension out of the next layout calculation.
if cfg.lastHeight and child:GetHeight() == cfg.lastHeight then child:SetHeight(cfg.baseHeight) end
if table.getn(lines) == 0 then
block:Hide()
scroll:UpdateScrollChildRect()
return
end
local top, scale = child:GetTop(), child:GetEffectiveScale()
if not top then block:Hide(); return end
local bottom = ContentBottom(child, block, top, scale, 0)
local heading = cfg[5] and G[cfg[5]]
local example = G[cfg[4]]
CopyFont(block.text, example)
CopyFont(block.title, heading or G.QuestProgressTitleText)
local titleHeight = 0
if heading and heading:IsShown() then block.title:Hide()
else
block.title:Show()
titleHeight = block.title:GetHeight() + 5
end
block:ClearAllPoints()
block:SetPoint("TOPLEFT", child, "TOPLEFT", 5, -bottom - 12)
block:SetWidth(child:GetWidth() - 15)
block.text:ClearAllPoints()
block.text:SetPoint("TOPLEFT", block, "TOPLEFT", 0, -titleHeight)
block.text:SetWidth(block:GetWidth())
block.text:SetText(table.concat(lines, "\n"))
if example and example.GetTextColor then
block.text:SetTextColor(example:GetTextColor())
else block.text:SetTextColor(0, 0, 0) end
if heading and heading.GetTextColor then block.title:SetTextColor(heading:GetTextColor()) end
block:SetHeight(titleHeight + block.text:GetHeight())
cfg.lastHeight = math.max(cfg.baseHeight, bottom + 12 + block:GetHeight() + 12)
child:SetHeight(cfg.lastHeight)
block:Show()
scroll:UpdateScrollChildRect()
end
function A.RenderAll()
for kind in pairs(panels) do A.Render(kind) end
end
function A.HookScript(frame, script, callback)
if not frame then return end
if frame.HookScript then frame:HookScript(script, callback); return end
-- Vanilla has no HookScript. Chain the existing script with its original args.
local old = frame:GetScript(script)
frame:SetScript(script, function(...)
if old then old(unpack(arg)) end
callback()
end)
end
function A.SetupUI()
for _, cfg in pairs(panels) do
A.HookScript(G[cfg[1]], "OnShow", A.Schedule)
end
end