Apply Patch
This commit is contained in:
+330
@@ -0,0 +1,330 @@
|
||||
--[[ ShardCap options window, shown under AddOns in ClassicAPI's AddOn Options
|
||||
(Game Menu > AddOn Options, or /shardcap options).
|
||||
|
||||
Uses the later-client panel protocol that ClassicAPI backports
|
||||
(InterfaceOptions_AddCategory with okay / cancel / default / refresh).
|
||||
Without it this file does nothing and the slash commands still work.
|
||||
|
||||
Changes apply at once. Cancel (and Escape) puts back the settings you had
|
||||
when the window was opened; Defaults resets the page that is shown.
|
||||
Lua 5.0: no `...` expressions, no select().
|
||||
]]
|
||||
|
||||
if type(InterfaceOptions_AddCategory) ~= "function" or not ShardCapAPI then return end
|
||||
|
||||
local API = ShardCapAPI
|
||||
local DEFAULTS = API.DEFAULTS
|
||||
|
||||
local function DB() return API.GetDB() end
|
||||
local function Changed() API.Schedule(0.3) end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Snapshot for Cancel (shared by both pages; one restore is enough)
|
||||
------------------------------------------------------------------------------
|
||||
local KEYS = { "cap", "notify", "sort", "combat", "reagents" }
|
||||
local saved
|
||||
|
||||
local function CopyBags(t)
|
||||
if not t then return nil end
|
||||
local c = {}
|
||||
for k, v in pairs(t) do c[k] = v end
|
||||
return c
|
||||
end
|
||||
|
||||
local function Snapshot()
|
||||
local db = DB()
|
||||
if saved or not db then return end
|
||||
saved = { soulbags = CopyBags(db.soulbags) }
|
||||
for _, k in ipairs(KEYS) do saved[k] = db[k] end
|
||||
end
|
||||
|
||||
local function Restore()
|
||||
local db = DB()
|
||||
if not saved or not db then saved = nil return end
|
||||
for _, k in ipairs(KEYS) do db[k] = saved[k] end
|
||||
db.soulbags = CopyBags(saved.soulbags)
|
||||
saved = nil
|
||||
Changed()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Widgets (same templates ClassicAPI's own panel uses)
|
||||
------------------------------------------------------------------------------
|
||||
local numControls = 0
|
||||
local function NextName()
|
||||
numControls = numControls + 1
|
||||
return "ShardCapOptionsControl" .. numControls
|
||||
end
|
||||
|
||||
local function RefreshControls(page)
|
||||
if not DB() then return end
|
||||
page.updating = true
|
||||
for _, control in ipairs(page.controls) do control:Update() end
|
||||
if page.OnRefresh then page.OnRefresh() end
|
||||
page.updating = nil
|
||||
end
|
||||
|
||||
local function NewPage(name, parent, title, subtitle)
|
||||
local page = CreateFrame("Frame")
|
||||
page.name = name
|
||||
page.parent = parent
|
||||
page.controls = {}
|
||||
|
||||
local heading = page:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
|
||||
heading:SetPoint("TOPLEFT", page, "TOPLEFT", 16, -16)
|
||||
heading:SetText(title)
|
||||
page.y = -40
|
||||
if subtitle then
|
||||
local text = page:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
text:SetPoint("TOPLEFT", heading, "BOTTOMLEFT", 0, -8)
|
||||
text:SetPoint("RIGHT", page, "RIGHT", -32, 0)
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetText(subtitle)
|
||||
page.y = -64
|
||||
end
|
||||
|
||||
page.refresh = function() Snapshot(); RefreshControls(page) end
|
||||
page.okay = function() saved = nil end
|
||||
page.cancel = function() Restore() end
|
||||
return page
|
||||
end
|
||||
|
||||
local function AddHeader(page, text)
|
||||
local header = page:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
||||
header:SetPoint("TOPLEFT", page, "TOPLEFT", 16, page.y - 8)
|
||||
header:SetText(text)
|
||||
page.y = page.y - 28
|
||||
end
|
||||
|
||||
local function AddText(page, height)
|
||||
local fs = page:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
fs:SetPoint("TOPLEFT", page, "TOPLEFT", 20, page.y)
|
||||
fs:SetPoint("RIGHT", page, "RIGHT", -16, 0)
|
||||
fs:SetJustifyH("LEFT")
|
||||
page.y = page.y - (height or 16)
|
||||
return fs
|
||||
end
|
||||
|
||||
-- get() / set(value); enabledIf() greys the box out while it returns false.
|
||||
local function AddCheckbox(page, label, tooltip, get, set, enabledIf, x)
|
||||
local check = CreateFrame("CheckButton", NextName(), page, "OptionsCheckButtonTemplate")
|
||||
check:SetPoint("TOPLEFT", page, "TOPLEFT", x or 16, page.y)
|
||||
local text = getglobal(check:GetName() .. "Text")
|
||||
text:SetText(label)
|
||||
check.tooltipText = tooltip
|
||||
check:SetScript("OnClick", function()
|
||||
set(this:GetChecked() and true or false)
|
||||
RefreshControls(page)
|
||||
end)
|
||||
check.Update = function(self)
|
||||
self:SetChecked(get())
|
||||
if not enabledIf or enabledIf() then
|
||||
self:Enable()
|
||||
text:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
|
||||
else
|
||||
self:Disable()
|
||||
text:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
|
||||
end
|
||||
end
|
||||
table.insert(page.controls, check)
|
||||
if not x then page.y = page.y - 30 end
|
||||
return check, text
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Page 1: ShardCap
|
||||
------------------------------------------------------------------------------
|
||||
local main = NewPage("ShardCap", nil, "ShardCap " .. API.VERSION,
|
||||
"Keeps your Soul Shards at a cap when you leave combat.")
|
||||
|
||||
AddHeader(main, "Carrying")
|
||||
local statusShards = AddText(main)
|
||||
local statusReagents = AddText(main)
|
||||
local statusBags = AddText(main, 22)
|
||||
|
||||
-- Cap: slider for quick changes (0-100), box for an exact value (0-200)
|
||||
AddHeader(main, "Shard cap")
|
||||
local MAX_SLIDER, MAX_CAP = 100, 200
|
||||
local slider = CreateFrame("Slider", NextName(), main, "OptionsSliderTemplate")
|
||||
slider:SetPoint("TOPLEFT", main, "TOPLEFT", 24, main.y - 14)
|
||||
slider:SetWidth(220)
|
||||
slider:SetMinMaxValues(0, MAX_SLIDER)
|
||||
slider:SetValueStep(1)
|
||||
slider.tooltipText = "Shards to keep. Anything above this is deleted when you leave combat."
|
||||
getglobal(slider:GetName() .. "Text"):SetText("Shards to keep")
|
||||
getglobal(slider:GetName() .. "Low"):SetText("0")
|
||||
getglobal(slider:GetName() .. "High"):SetText(MAX_SLIDER)
|
||||
|
||||
local box = CreateFrame("EditBox", NextName(), main, "InputBoxTemplate")
|
||||
box:SetWidth(40)
|
||||
box:SetHeight(20)
|
||||
box:SetPoint("LEFT", slider, "RIGHT", 18, 0)
|
||||
box:SetAutoFocus(false)
|
||||
box:SetNumeric(true)
|
||||
box:SetMaxLetters(3)
|
||||
local boxFocus, boxCancel = false, false
|
||||
|
||||
local function SetCap(v)
|
||||
local db = DB()
|
||||
if not db or v == db.cap then return end
|
||||
db.cap = v
|
||||
Changed()
|
||||
end
|
||||
|
||||
slider:SetScript("OnValueChanged", function()
|
||||
local v = math.floor(this:GetValue() + 0.5)
|
||||
if main.updating then return end
|
||||
box:SetText(v)
|
||||
SetCap(v)
|
||||
if main.OnRefresh then main.OnRefresh() end
|
||||
end)
|
||||
|
||||
local function ApplyBox()
|
||||
local v = tonumber(box:GetText())
|
||||
if v and v >= 0 and v <= MAX_CAP then
|
||||
SetCap(math.floor(v))
|
||||
else
|
||||
API.Print("The cap must be a whole number from 0 to " .. MAX_CAP .. ".")
|
||||
end
|
||||
RefreshControls(main)
|
||||
end
|
||||
box:SetScript("OnEditFocusGained", function() boxFocus = true end)
|
||||
box:SetScript("OnEditFocusLost", function()
|
||||
boxFocus = false
|
||||
if boxCancel then boxCancel = false; RefreshControls(main) else ApplyBox() end
|
||||
end)
|
||||
box:SetScript("OnEnterPressed", function() this:ClearFocus() end)
|
||||
box:SetScript("OnEscapePressed", function() boxCancel = true; this:ClearFocus() end)
|
||||
|
||||
slider.Update = function(self)
|
||||
local cap = DB().cap
|
||||
if cap > MAX_SLIDER then self:SetValue(MAX_SLIDER) else self:SetValue(cap) end
|
||||
if not boxFocus then box:SetText(cap) end
|
||||
end
|
||||
table.insert(main.controls, slider)
|
||||
main.y = main.y - 50
|
||||
|
||||
local hint = AddText(main, 20)
|
||||
hint:SetText("|cffaaaaaaType a value up to " .. MAX_CAP .. " in the box for caps above " .. MAX_SLIDER .. ".|r")
|
||||
|
||||
AddHeader(main, "Options")
|
||||
AddCheckbox(main, "Chat notifications",
|
||||
"Print a line in chat whenever ShardCap deletes or moves something.",
|
||||
function() return DB().notify end, function(v) DB().notify = v end)
|
||||
AddCheckbox(main, "Trim during combat",
|
||||
"Also delete shards above the cap while you are in combat. Off: wait until combat ends.",
|
||||
function() return DB().combat end, function(v) DB().combat = v; Changed() end)
|
||||
|
||||
local trim = CreateFrame("Button", NextName(), main, "UIPanelButtonTemplate")
|
||||
trim:SetWidth(120)
|
||||
trim:SetHeight(22)
|
||||
trim:SetPoint("TOPLEFT", main, "TOPLEFT", 20, main.y - 8)
|
||||
trim:SetText("Trim now")
|
||||
trim:SetScript("OnClick", function() API.Schedule(0, true) end)
|
||||
trim:SetScript("OnEnter", function()
|
||||
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||||
GameTooltip:SetText("Delete shards above the cap right now, even in combat.", nil, nil, nil, nil, 1)
|
||||
end)
|
||||
trim:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
||||
|
||||
main.OnRefresh = function()
|
||||
local shards, reagents, bags = API.StatusLines()
|
||||
statusShards:SetText(shards)
|
||||
statusReagents:SetText(reagents)
|
||||
statusBags:SetText(bags)
|
||||
end
|
||||
|
||||
main.default = function()
|
||||
local db = DB()
|
||||
db.cap, db.notify, db.combat = DEFAULTS.cap, DEFAULTS.notify, DEFAULTS.combat
|
||||
Changed()
|
||||
RefreshControls(main)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Page 2: Soul Bag
|
||||
------------------------------------------------------------------------------
|
||||
local bagPage = NewPage("Soul Bag", main.name, "Soul Bag",
|
||||
"What goes in your soul bag, and which bags count as one.")
|
||||
|
||||
AddHeader(bagPage, "Sorting")
|
||||
AddCheckbox(bagPage, "Move shards into the soul bag",
|
||||
"Move shards from your normal bags into free soul bag slots, and merge partial stacks.",
|
||||
function() return DB().sort end, function(v) DB().sort = v; Changed() end)
|
||||
AddCheckbox(bagPage, "Also move Demonic Figurines and Infernal Stones",
|
||||
"Only uses soul bag slots that are not needed to hold your shard cap. "
|
||||
.. "Skipped on servers where shards don't stack.",
|
||||
function() return DB().reagents end, function(v) DB().reagents = v; Changed() end)
|
||||
|
||||
AddHeader(bagPage, "Soul bags")
|
||||
local function IsAuto() return DB().soulbags == nil end
|
||||
AddCheckbox(bagPage, "Detect soul bags automatically",
|
||||
"Recognizes soul bags by item type. Turn this off to choose the bags yourself.",
|
||||
IsAuto,
|
||||
function(v)
|
||||
local db = DB()
|
||||
if v then
|
||||
db.soulbags = nil
|
||||
else
|
||||
db.soulbags = {}
|
||||
for b = 1, 4 do if API.AutoIsSoulBag(b) then db.soulbags[b] = true end end
|
||||
end
|
||||
Changed()
|
||||
end)
|
||||
|
||||
local function BagName(bag)
|
||||
local link = GetInventoryItemLink("player", ContainerIDToInventoryID(bag))
|
||||
if not link then return nil end
|
||||
local _, _, name = string.find(link, "%[(.-)%]")
|
||||
return name
|
||||
end
|
||||
|
||||
for bag = 1, 4 do
|
||||
local b = bag
|
||||
local check, label = AddCheckbox(bagPage, "Bag " .. b,
|
||||
"Treat this bag as a soul bag. Only available when automatic detection is off.",
|
||||
function() return API.IsSoulBag(b) end,
|
||||
function(v)
|
||||
local db = DB()
|
||||
if not db.soulbags then db.soulbags = {} end
|
||||
if v then db.soulbags[b] = true else db.soulbags[b] = nil end
|
||||
Changed()
|
||||
end,
|
||||
function() return not IsAuto() and BagName(b) ~= nil end,
|
||||
36)
|
||||
local update = check.Update
|
||||
check.Update = function(self)
|
||||
label:SetText("Bag " .. b .. ": " .. (BagName(b) or "|cff808080empty slot|r"))
|
||||
update(self)
|
||||
end
|
||||
bagPage.y = bagPage.y - 26
|
||||
end
|
||||
|
||||
bagPage.default = function()
|
||||
local db = DB()
|
||||
db.sort, db.reagents, db.soulbags = DEFAULTS.sort, DEFAULTS.reagents, nil
|
||||
Changed()
|
||||
RefreshControls(bagPage)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Live refresh while a page is shown (bags change as you loot)
|
||||
------------------------------------------------------------------------------
|
||||
local function LiveRefresh(page)
|
||||
local elapsed = 0
|
||||
page:SetScript("OnUpdate", function()
|
||||
elapsed = elapsed + arg1
|
||||
if elapsed < 0.5 then return end
|
||||
elapsed = 0
|
||||
if not boxFocus then RefreshControls(this) end
|
||||
end)
|
||||
end
|
||||
LiveRefresh(main)
|
||||
LiveRefresh(bagPage)
|
||||
|
||||
InterfaceOptions_AddCategory(main)
|
||||
InterfaceOptions_AddCategory(bagPage)
|
||||
|
||||
API.OpenOptions = function()
|
||||
InterfaceOptionsFrame_OpenToCategory(main)
|
||||
end
|
||||
Reference in New Issue
Block a user