Skip to content

Instantly share code, notes, and snippets.

@Phanx
Created August 7, 2016 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Phanx/2e9f77fb210a25dea90f22dfe9abc26f to your computer and use it in GitHub Desktop.
Save Phanx/2e9f77fb210a25dea90f22dfe9abc26f to your computer and use it in GitHub Desktop.
------------------------------------------------------------------------
-- Local variables
------------------------------------------------------------------------
local BREAKITDOWN, ns = ...
local defaults = {
width = 250, -- width of the list window
rowHeight = 24, -- height of each item in the list window
maxRows = 10, -- maximum number of rows to show at once
sortKey = "name", -- name or total?
sortDirection = "ascending", -- ascending or descending?
confirmReset = false, -- require confirmation when clicking reset?
saveResults = true, -- save results between sessions?
}
local actions = {}
for _, id in pairs({
13262, -- Disenchant
51005, -- Milling
31252, -- Prospecting
11993, -- Herb Gathering
10248, -- Mining
}) do
local name = GetSpellInfo(id)
if name then
actions[name] = true
end
end
local L = setmetatable({}, { __index = function(t, k)
local v = tostring(k)
rawset(t, k, v)
return v
end })
local db
local gathering
local results
------------------------------------------------------------------------
-- Initialization
------------------------------------------------------------------------
local addon = CreateFrame("Frame", "BreakItDown", UIParent)
addon:SetScript("OnEvent", function(self, event, ...) return self[event] and self[event](self, ...) end)
addon:RegisterEvent("ADDON_LOADED")
addon:Hide()
function addon:ADDON_LOADED(name)
if name ~= BREAKITDOWN then return end
local function copyDefaults(src, dst)
if not src then return {} end
if not dst then dst = {} end
for k, v in pairs(src) do
if type(v) == "table" then
dst[k] = copyDefaults(v, dst[k])
elseif type(dst[k]) ~= type(v) then
dst[k] = v
end
end
return dst
end
db = copyDefaults(defaults, BreakItDownDB)
BreakItDownDB = db
if db.saveResults then
results = type(db.results) == "table" and db.results or {}
db.results = results
else
results = {}
db.results = nil
end
self.results = results -- outside access for debugging
self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
self:RegisterEvent("LOOT_OPENED")
end
------------------------------------------------------------------------
-- Core logic
------------------------------------------------------------------------
function addon:UNIT_SPELLCAST_SUCCEEDED(unit, spell)
if unit ~= "player" or not actions[spell] then return end
-- print(spell, "succeeded.")
gathering = true
end
function addon:LOOT_OPENED()
if not gathering then return end
local n = GetNumLootItems()
-- print("Loot window opened with", n, "items.")
for i = 1, n do
local icon, name, quantity, locked = GetLootSlotInfo(i)
if quantity > 0 then
local t = results[name]
if not t then
t = {}
results[name] = t
end
local link = GetLootSlotLink(i)
t.color = link:match("|cff(%x%x%x%x%x%x)")
t.name = name
t.icon = icon
t.link = link
t.total = (t.total or 0) + quantity
local _, size = DEFAULT_CHAT_FRAME:GetFont()
-- print(string.format("|T%s:%d:%d:0:%d|t |cff%s%s|r x%d (%d)", icon, size * 0.6, size * 0.6, 1, t.color, name, quantity, t.total))
end
end
gathering = nil
if self:IsShown() then
self:Update()
end
end
------------------------------------------------------------------------
-- Display logic
------------------------------------------------------------------------
do
local sorted = {}
local sortby = {
ascending = function(a, b) return results[a][db.sortKey] < results[b][db.sortKey] end, -- A-Z, 0-9
descending = function(a, b) return results[a][db.sortKey] > results[b][db.sortKey] end, -- Z-A, 9-0
}
function addon:Update()
for name in pairs(results) do
-- print("Processing result:", name)
table.insert(sorted, name)
end
local numResultsToShow = math.min(db.maxRows, #sorted)
if numResultsToShow == 0 then
-- print("Populating row 1")
local row = self.itemButtons[1]
row.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
row.name:SetText(L["Nothing to report!"])
row.name:SetTextColor(GameFontDisable:GetTextColor())
row.total:SetText(" ")
self:SetHeight(12 + self.titleText:GetHeight() + 6 + db.rowHeight + 6 + 24 + 12)
numResultsToShow = 1
else
table.sort(sorted, sortby[db.sortDirection])
for i = 1, numResultsToShow do
-- print("Populating row", i)
local data = results[sorted[i]]
local row = self.itemButtons[i]
row.icon:SetTexture(data.icon)
row.name:SetFormattedText("|cff%s%s|r", data.color, data.name)
row.name:SetTextColor(GameFontHighlight:GetTextColor())
row.total:SetText(data.total)
row.link = data.link
row:Show()
end
wipe(sorted)
self:SetHeight(12 + self.titleText:GetHeight() + 6 + (numResultsToShow * db.rowHeight) + (numResultsToShow - 1) + 6 + 24 + 12)
end
for i = numResultsToShow + 1, #self.itemButtons do
-- print("Clearing row", i)
local row = self.itemButtons[i]
row:Hide()
row.icon:SetTexture("")
row.name:SetText(" ")
row.total:SetText(" ")
row.link = nil
end
end
end
------------------------------------------------------------------------
-- Visual elements
------------------------------------------------------------------------
function addon:SetupFrame()
tinsert(UISpecialFrames, "BreakItDown")
if db.x and db.y then
self:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", db.x, db.y)
else
self:SetPoint("CENTER")
end
self:SetWidth(db.width)
self:SetBackdrop({
bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 8,
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 }
})
self:SetBackdropColor(10/255, 10/255, 10/255, 1)
self:SetBackdropBorderColor(1, 1, 1, 1)
local function StopMoving(self)
self:StopMovingOrSizing()
local x, y = self:GetLeft(), self:GetTop()
self:ClearAllPoints()
self:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", x, y)
end
self:EnableMouse(true)
self:SetMovable(true)
self:SetClampedToScreen(true)
self:RegisterForDrag("LeftButton")
self:SetScript("OnDragStart", self.StartMoving)
self:SetScript("OnDragStop", StopMoving)
self:SetScript("OnHide", StopMoving)
local tt = self:CreateFontString(nil, "OVERLAY", "NumberFontNormal")
tt:SetPoint("TOPLEFT", 10, -12)
tt:SetPoint("TOPRIGHT", -10, -12)
tt:SetJustifyH("CENTER")
tt:SetText(L["Break It Down"])
tt:SetTextColor(GameFontNormal:GetTextColor())
self.titleText = tt
local function item_OnEnter(item)
if item.link then
-- print("OnEnter", item.link)
GameTooltip:SetOwner(item, "ANCHOR_NONE")
GameTooltip:SetPoint("TOPLEFT", item, "TOPRIGHT", 14, 5)
GameTooltip:SetHyperlink(item.link)
end
end
local function item_OnLeave(item)
GameTooltip:Hide()
end
local function item_OnClick(item, button)
if button == "RightButton" then
if IsAltKeyDown() then
results[item.name] = nil
self:Update()
end
elseif IsModifiedClick() then
HandleModifiedItemClick(item.link)
end
end
local items = setmetatable({}, { __index = function(items, i)
local item = CreateFrame("Button", nil, self)
item:SetHeight(db.rowHeight)
if i == 1 then
item:SetPoint("TOPLEFT", tt, "BOTTOMLEFT", 2, -6)
item:SetPoint("TOPRIGHT", tt, "BOTTOMRIGHT", -2, -6)
else
item:SetPoint("TOPLEFT", items[i-1], "BOTTOMLEFT", 0, -1)
item:SetPoint("TOPRIGHT", items[i-1], "BOTTOMRIGHT", 0, -1)
end
local icon = item:CreateTexture(nil, "OVERLAY")
icon:SetPoint("TOPLEFT")
icon:SetPoint("BOTTOMLEFT")
icon:SetWidth(db.rowHeight)
item.icon = icon
local total = item:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
total:SetPoint("TOPRIGHT")
total:SetPoint("BOTTOMRIGHT")
total:SetJustifyH("RIGHT")
item.total = total
local name = item:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
name:SetPoint("TOPLEFT", icon, "TOPRIGHT", 4, 0)
name:SetPoint("BOTTOMLEFT", icon, "BOTTOMRIGHT", 4, 0)
name:SetPoint("RIGHT", total, "LEFT", -4, 0)
name:SetJustifyH("LEFT")
item.name = name
item.id = i
item:EnableMouse(true)
item:RegisterForClicks("AnyUp")
item:SetScript("OnEnter", item_OnEnter)
item:SetScript("OnLeave", item_OnLeave)
item:SetScript("OnClick", item_OnClick)
rawset(items, i, item)
return item
end })
self.itemButtons = items
local reset = CreateFrame("Button", nil, self)
reset:SetNormalFontObject(GameFontNormalSmall)
reset:SetDisabledFontObject(GameFontDisable)
reset:SetHighlightFontObject(GameFontHighlightSmall)
reset:SetNormalTexture([[Interface\Buttons\UI-Panel-Button-Up]])
reset:GetNormalTexture():SetTexCoord(0, 0.625, 0, 0.6875)
reset:SetPushedTexture([[Interface\Buttons\UI-Panel-Button-Down]])
reset:GetPushedTexture():SetTexCoord(0, 0.625, 0, 0.6875)
reset:SetHighlightTexture([[Interface\Buttons\UI-Panel-Button-Highlight]])
reset:GetHighlightTexture():SetTexCoord(0, 0.625, 0, 0.6875)
reset:GetHighlightTexture():SetBlendMode("ADD")
reset:SetDisabledTexture([[Interface\Buttons\UI-Panel-Button-Disabled]])
reset:GetDisabledTexture():SetTexCoord(0, 0.625, 0, 0.6875)
reset:SetPoint("BOTTOMLEFT", 12, 12)
reset:SetWidth(80)
reset:SetHeight(24)
reset:SetText(RESET)
reset:SetScript("OnClick", function()
wipe(results)
if self:IsShown() then
self:Update()
end
end)
self.resetButton = reset
local close = CreateFrame("Button", nil, self)
close:SetNormalFontObject(GameFontNormalSmall)
close:SetHighlightFontObject(GameFontHighlightSmall)
close:SetNormalTexture([[Interface\Buttons\UI-Panel-Button-Up]])
close:GetNormalTexture():SetTexCoord(0, 0.625, 0, 0.6875)
close:SetPushedTexture([[Interface\Buttons\UI-Panel-Button-Down]])
close:GetPushedTexture():SetTexCoord(0, 0.625, 0, 0.6875)
close:SetHighlightTexture([[Interface\Buttons\UI-Panel-Button-Highlight]])
close:GetHighlightTexture():SetTexCoord(0, 0.625, 0, 0.6875)
close:GetHighlightTexture():SetBlendMode("ADD")
close:SetPoint("BOTTOMRIGHT", -12, 12)
close:SetPoint("TOPLEFT", reset, "TOPRIGHT", 4, 0)
close:SetText(CLOSE)
close:SetScript("OnClick", function()
self:Hide()
end)
self.closeButton = close
self.SetupFrame = nil
self:Show()
end
------------------------------------------------------------------------
-- Display actions
------------------------------------------------------------------------
addon:SetScript("OnShow", function(self)
if self.SetupFrame then
self:SetupFrame()
end
self:Update()
end)
SLASH_BREAKITDOWN1 = "/bid"
SlashCmdList.BREAKITDOWN = function()
if addon:IsShown() then
addon:Hide()
else
addon:Show()
end
end
------------------------------------------------------------------------
-- Tests
------------------------------------------------------------------------
do
local items = {
-- Herbs
{ 52989, 52987, 52988, 52986, 52985, 52984, 85983, 36908, 36906, 36905, 36903, 39970, 37921, 36901, 36907, 36904 },
-- Ore
{ 52183, 52184, 52185, 53038, 36910, 36912, 36909 },
-- Disenchant
{ 52722, 52721, 52720, 52719, 52718, 52555, 34057, 34052, 34053, 34055, 34056, 34054 },
-- Milling
{ 61979, 61980, 39343, 43109 },
-- Prospecting
{ 52327, 52179, 52177, 52181, 52182, 52180, 52178, 52192, 52195, 52194, 52193, 52190, 52191, 36923, 36929, 36926, 36917, 36932, 36920, 36930, 36933, 36924, 36921, 36918, 36927, 36931, 36934, 36922, 36925, 36919, 36928, 46849, 24243 },
}
function addon:Test(np, ni, clear)
self:Hide()
if clear then
wipe(results)
end
for i = 1, (np or 2) do
local set = items[math.random(#items)]
for i = 1, (ni or 5) do
local id = set[math.random(#set)]
local name, link, _, _, _, _, _, _, _, icon = GetItemInfo(id)
if name then
local t = results[name]
if not t then
t = {}
results[name] = t
end
t.color = link:match("|cff(%x%x%x%x%x%x)")
t.name = name
t.icon = icon
t.total = GetItemCount(id) > 0 and GetItemCount(id) or math.random(1, 300)
t.link = link
end
end
end
self:Show()
end
end
--[[
Example tests:
/run BreakItDown:Test()
/run BreakItDown:Test(3, 3)
/run BreakItDown:Test(nil, nil, true)
/run wipe(BreakItDown.results)
]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment