WoWInterface SVN LootTracker

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 59 to Rev 60
    Reverse comparison

Rev 59 → Rev 60

trunk/LootTracker/LootTracker.lua
1192,7 → 1192,9
self:RestorePosition(tip:GetName())
end
 
--[[ OH Frame stuff]]--
--[[
--OH Frame stuff
--]]--
--[[ frame generalization stuff ]]--
-- for the tooltip stuff
local RegisterCheckOption, RegisterSliderOption
branches/LootTracker-Rewrite-Ace3/Localization.deDE.lua New file
0,0 → 1,6
--Localization.deDE.lua
if GetLocale() ~= "deDE" then return end
 
LootTrackerLocals = setmetatable({
["Sets"] = "Sätze",
}, {__index = LootTrackerLocals})
Property changes : Added: svn:mime-type + text/plain Added: svn:eol-style + native
branches/LootTracker-Rewrite-Ace3/LootTracker.lua New file
0,0 → 1,2151
-- [[ LootTrack Debug Levels ]]--
local _version = "1.08-20200"
--[[ Localisations ]]--
local L = LootTrackerLocals
--[[ Variables ]]--
local _
local _db -- to hold the list database
local _itemCache
local _playerName = UnitName('player') -- available at login
local _server = GetRealmName()
local _bagItems, _bankItems = {}, {}
local _bankOpen
local _hooked = false
local _equippedSlots = {
HeadSlot = false,
NeckSlot = false,
ShoulderSlot = false,
BackSlot = false,
ChestSlot = false,
ShirtSlot = false,
TabardSlot = false,
WristSlot = false,
HandsSlot = false,
WaistSlot = false,
LegsSlot = false,
FeetSlot = false,
Finger0Slot = false,
Finger1Slot = false,
Trinket0Slot = false,
Trinket1Slot = false,
MainHandSlot = false,
SecondaryHandSlot = false,
RangedSlot = false,
}
 
local MAXITEMS = 40000
local ClickTip = LibStub:GetLibrary("ClickTip-Beta0", true)
 
-- Binding Variables
BINDING_HEADER_LOOTTRACKER = "LootTracker (".._version..")"
BINDING_NAME_LTTOGGLECONFIG = L["Toggle Config"]
BINDING_NAME_LTTOGGLETRACK = L["Toggle Tracker"]
 
 
--[[ For OH Stuff ]]--
local OH = LibStub:GetLibrary("OptionHouse-1.1")
local ui = OH:RegisterAddOn("LootTracker", "LootTracker", "JoshBorke", _version)
local ohpar = OH and OH:GetFrame("addon")
 
local configFrame, visFrame
local currentSet-- current set means we've selected a set as a sub cat
local selectedSet -- selectSet is the ID of the line we've currently selected
local selectedLine -- selectedLine is the index of the line we've currently selected
 
LootTracker = DongleStub("Dongle-1.0"):New("LootTracker")
local LootTracker = LootTracker
--[[ Local functions ]]--
--[[ Function to handle initialization ]]--
function LootTracker:Initialize()
self.defaults = {
profile = {
positions = {},
trackedLists = {},
tracker = {
old = {
alpha = 1,
scale = 1,
combatHidden = false,
locked = false,
squish = false,
},
new = {
alpha = 1,
scale = 1,
combatHidden = false,
locked = false,
squish = false,
},
ctc = false,
hideifnone = false,
collapsed = {},
}
},
global = {
lists = {}, -- for storing lists
cache = {}, -- for storing bag/bank items
items ={}, -- for storing item->name conversions
},
}
self:CreateSlashCommands()
if (not _hooked) then
hooksecurefunc('SetItemRef',
function(link, text, button)
if (not link) then return end
if (self.inputItemFrame and self.inputItemFrame:IsShown()) then
if (IsShiftKeyDown()) then
local name,link = GetItemInfo(link)
self.inputItemFrame.item:SetText(link)
end
end
end )
hooksecurefunc('ChatEdit_InsertLink',
function(text)
if (not text) then return end
if (self.inputItemFrame and self.inputItemFrame:IsShown()) then
if (IsShiftKeyDown()) then
local name,link = GetItemInfo(text)
self.inputItemFrame.item:SetText(link)
end
end
end )
_hooked = true
end
for name in pairs(_equippedSlots) do
_equippedSlots[name] = GetInventorySlotInfo(name)
end
end
 
function LootTracker:Enable()
self.db = self:InitializeDB("LootTrackerDB", self.defaults)
_db = self.db
_itemCache = self.db.global.cache
if (not _itemCache[_server]) then
_itemCache[_server] = {
[_playerName] = {}
}
elseif (not _itemCache[_server][_playerName]) then
_itemCache[_server][_playerName] = {}
end
self:UpdateItemIDs()
self:RegisterEvent("BANKFRAME_OPENED", "UpdateBankItemCounts")
self:RegisterEvent("BANKFRAME_CLOSED", function() _bankOpen = false end)
self:RegisterEvent("PLAYERBANKSLOTS_CHANGED", "UpdateBankItemCounts")
self:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED", "UpdateBankItemCounts")
self:RegisterEvent("BAG_UPDATE", "UpdateBagItemCounts")
self:RegisterEvent("PLAYER_REGEN_DISABLED", function()
local options = _db.profile.tracker
if options.old.combatHidden and self.oldTracker then self.oldTracker:Hide() end
if options.new.combatHidden and self.newTracker then self.newTracker:Hide() end
end )
self:RegisterEvent("PLAYER_REGEN_ENABLED", function()
local options = _db.profile.tracker
if options.old.shown and self.oldTracker then self:ShowTracker() end
if options.new.shown and self.newTracker then self.newTracker:Show() end
end)
self:UpdateBagItemCounts()
self:PruneSets()
if not ClickTip then
_db.profile.tracker.new.shown = false
end
if (_db.profile.tracker.old.shown) then
self:ShowTracker()
end
if (_db.profile.tracker.new.shown) then
self:ShowNewTracker()
end
ui:RegisterCategory(L["Visuals"], self, "CreateRandomConfigs")
ui:RegisterCategory(L["Sets"], self, "PopulateOHFrame", true) -- don't cache the frame
local sets = _db.global.lists
for i = 1, #sets do
ui:RegisterSubCategory(L["Sets"], sets[i], self, "PopulateOHFrame", true) -- don't cache the frame
end
end
 
function LootTracker:Disable()
--self:SavePosition("LootTrackerTrackingFrame")
self:SavePosition("LootTrackerConfigFrame")
end
 
function LootTracker:CreateSlashCommands()
local cmd = self:InitializeSlashCommand("LootTracker Slash Command", "LOOTTRACKER", "loottracker", "lt", "ltr")
local ShowConfig = function(opt)
local tolower = string.lower
if tolower(opt) == 'vis' then
OH:Open("LootTracker",L["Visuals"])
elseif tolower(opt) == ' sets' then
OH:Open("LootTracker",L["Sets"])
else
OH:Open("LootTracker")
end
end
cmd:RegisterSlashHandler("config - Show configuration frame", "^config(.*)$", ShowConfig)
cmd:RegisterSlashHandler("sets - Show the sets configuration", "^sets$", function() OH:Open("LootTracker",L["Sets"]) end)
cmd:RegisterSlashHandler("visuals - Show the visual configurations", "^vis.*$", function() OH:Open("LootTracker",L["Visuals"]) end)
local Reset = function()
self:ResetOptions()
_db:ResetDB()
_itemCache = _db.global.cache
self.currentSet = nil
if (self.configFrame) then
self:UpdateSetScroll()
self:UpdateItemScroll()
end
end
local ResetCache = function()
_db.global.cache = {}
_itemCache = _db.global.cache
self:UpdateBagItemCounts()
if (self.configFrame) then
self:UpdateItemScroll()
end
self:PopulateTrackerFrame()
self:PopulateNewTracker()
end
cmd:RegisterSlashHandler("reset - Reset the configuration", "^reset$", Reset)
cmd:RegisterSlashHandler("resetCache - Reset the item count totals", "^resetCache$", ResetCache)
end
 
function LootTracker:UpdateBagItemCounts()
local match = string.match
local itemLink, itemID, count
local cache = _itemCache[_server][_playerName]
local name
if (not cache) then
cache = {}
_itemCache[_server][_playerName] = cache
end
local bagItems = cache.bagItems
if (not bagItems) then
bagItems = {}
cache.bagItems = bagItems
end
for item, count in pairs(bagItems) do
bagItems[item] = 0
end
for name, id in pairs(_equippedSlots) do
itemLink = GetInventoryItemLink("player", id)
if (itemLink) then
name = GetItemInfo(itemLink)
if (name) then
count = GetInventoryItemCount("player", id)
bagItems[name] = count + (bagItems[name] or 0)
end
end
end
for bag = 0, 4 do
for slot = 1, GetContainerNumSlots(bag) do
itemLink = GetContainerItemLink(bag, slot)
if (itemLink) then
--itemID = match(itemLink, "item:(%-?%d+)")
name = GetItemInfo(itemLink)
if (name) then
_, count = GetContainerItemInfo(bag, slot)
--bagItems[itemID] = count + (bagItems[itemID] or 0)
bagItems[name] = count + (bagItems[name] or 0)
end
end
end
end
if (_bankOpen) then
self:UpdateBankItemCounts() -- no event fires for putting an item in the bank
end
if (self.oldTracker and self.oldTracker:IsShown()) then
self:PopulateTrackerFrame() -- update the tracker frame
self:PopulateNewTracker() -- update the tracker frame
end
end
 
function LootTracker:UpdateBankItemCounts()
local match = string.match
local itemLink, itemID, count
local cache = _itemCache[_server][_playerName]
local name
if (not cache) then
cache = {}
_itemCache[_server][_playerName] = cache
end
local bankItems = cache.bankItems
if (not bankItems) then
bankItems = {}
cache.bankItems = bankItems
end
for item, count in pairs(bankItems) do
bankItems[item] = 0
end
local bag = -1
_bankOpen = true
local bankSlots = GetNumBankSlots()
for slot = 1, GetContainerNumSlots(bag) do
itemLink = GetContainerItemLink(bag, slot)
if (itemLink) then
--itemID = match(itemLink, "item:(%-?%d+)")
name = GetItemInfo(itemLink)
_, count = GetContainerItemInfo(bag, slot)
--bankItems[itemID] = count + (bankItems[itemID] or 0)
bankItems[name] = count + (bankItems[name] or 0)
end
end
if (bankSlots > 0) then
for cbag = 1, bankSlots do
bag = cbag + 4
for slot = 1, GetContainerNumSlots(bag) do
itemLink = GetContainerItemLink(bag, slot)
if (itemLink) then
--itemID = match(itemLink, "item:(%-?%d+)")
_, count = GetContainerItemInfo(bag, slot)
name = GetItemInfo(itemLink)
--bankItems[itemID] = count + (bankItems[itemID] or 0)
bankItems[name] = count + (bankItems[name] or 0)
--self:Print(string.format("%s: %s", name, count))
end
end
end
end
if (self.oldTracker and self.oldTracker:IsShown()) then
self:PopulateTrackerFrame() -- update the tracker frame
self:PopulateNewTracker() -- update the tracker frame
end
end
 
function LootTracker:GetItemCount(name, player)
local cache = _itemCache[_server]
if (not cache) then return 0 end
local total = 0
if (_db.profile.tracker.ctc and not player) then
player = _playerName
end
if (player) then
cache = cache[player]
if (not cache) then return total end
for bag, items in pairs(cache) do
if (items[name]) then
total = items[name] + total
end
end
else
for player, bags in pairs(cache) do
for bag, items in pairs(bags) do
if (items[name]) then
total = items[name] + total
end
end
end
end
return total
end
 
function LootTracker:UpdateSetName(setName)
if (self.newSet) then
self:CreateNewSet(setName)
return
else
local lists = _db.global.lists
if (not _db.global) then _db.global = {} end
if (not _db.global.lists) then
_db.global.lists = {}
lists = _db.global.lists
end
ui:RemoveSubCategory(L["Sets"], self.currentSet) -- remove the current set name
ui:RegisterSubCategory(L["Sets"], setName, self, "PopulateOHFrame", true) -- don't cache the frame
if (lists[self.currentSet]) then
lists[setName] = lists[self.currentSet]
lists[self.currentSet] = nil
table.insert(lists, setName)
for index, set in pairs(lists) do
if (set == self.currentSet) then
table.remove(lists, index)
end
end
table.sort(lists)
end
end
end
 
function LootTracker:CreateNewSet(setName)
local _lists = _db.global.lists
if (not _db.global) then _db.global = {} end
if (not _db.global.lists) then
_db.global.lists = {}
_lists = _db.global.lists
end
if (not _lists[setName]) then
_lists[setName] = {}
table.insert(_lists, setName)
table.sort(_lists)
ui:RegisterSubCategory(L["Sets"], setName, self, "PopulateOHFrame", true) -- don't cache the frame
self:updateScrollList()
end
end
 
function LootTracker:RemoveSet(setName)
local _lists = _db.global.lists
if (not _db.global) then _db.global = {} end
if (not _db.global.lists) then
_db.global.lists = {}
_lists = _db.global.lists
end
if (_lists[setName]) then
_lists[setName] = nil
for index, set in pairs(_lists) do
if (set == setName) then
table.remove(_lists, index)
end
end
-- make sure to remove it from the tracked list
local tracked = _db.profile.trackedLists
if tracked then
for i=1,#tracked do
local list = tracked[i]
if list == setName then
table.remove(tracked, i)
end
end
end
end
return true
end
 
-- called to prune out previously removed sets
function LootTracker:PruneSets()
local tracked = _db.profile.trackedLists
local lists = _db.global.lists
local list
local i, max = 1, #tracked
while (true) do
list = tracked[i]
if (list and not lists[list]) then
table.remove(tracked,i)
else
i = i+1
end
if (i > max) then break end
end
end
 
local function myListSort(id1, id2)
local name1, name2
if (id1) then
name1 = GetItemInfo(id1)
end
if (id2) then
name2 = GetItemInfo(id2)
end
if (not name1 or not name2) then return end
return name1 < name2
end
 
function LootTracker:UpdateItemIDs()
-- here we update the items lookup table in case we don't have one generated already
local cache = _itemCache[_server]
local itemsDB = _db.global.items
local name, link, itemID
local name2, link2, found
local MAXITEMS = 40000
for player, bags in pairs(cache) do
for bag, items in pairs(bags) do
for item, count in pairs(items) do
name, link = GetItemInfo(item)
if (not name) then
found = false
for i=1, MAXITEMS do
if (not found) then
name2, link2 = GetItemInfo(i)
if (name == name2) then
name = name2
link = link2
found = true
end
end
end
end
if (name and link) then
itemID = string.match(link, "item:(%-?%d+)")
itemsDB[name] = itemID
itemsDB[itemID] = name
end
end
end
end
end
 
function LootTracker:GetItemID(name,id)
local db = _db.global.items
local res
local name2, link, itemID
if (name) then
res = db[name]
elseif (id) then
res = db[id]
end
if (not res) then
for i=1, MAXITEMS do
name2, link = GetItemInfo(i)
if (name == name2) then
break
end
end
itemID = string.match(link, "item:(%-?%d+)")
res = itemID
end
return res
end
 
function LootTracker:GetItemNameFromInput(input)
local name
local lower = string.lower
local linput = lower(input)
local itemID = string.match(input, "item:(%-?%d+)")
if (not itemID) then
local db = _db.global.items
-- find the itemID...
if db[input] then
local name, itemLink = GetItemInfo(db[input])
if name then
return name, string.match(itemLink, "item:(%-?%d+)")
end
end
for i=1, MAXITEMS do
local name, itemLink = GetItemInfo(i)
if name then
if lower(name or '') == lower(input) or string.match(itemLink, "item:(%-?%d+)") == input then
return name, string.match(itemLink, "item:(%-?%d+)")
end
end
end
else
name = GetItemInfo(itemID)
end
return name, itemID
end
 
function LootTracker:UpdateItem(itemLink, count)
local list = _db.global.lists[currentSet]
local name, itemID = self:GetItemNameFromInput(itemLink)
local found
if (not name) then return false end
if (not list) then return false end
if (not itemID) then return false end
if (count == '') then count = nil end
for index, ID in pairs(list) do
if (ID == name) then
found = true
end
end
if (not found) then
_db.global.items[itemID] = name
_db.global.items[name] = itemID
table.insert(list, name)
table.sort(list, myListSort)
end
list[name] = count --or 0
return true
end
 
function LootTracker:RemoveItem(itemID, set)
local list = _db.global.lists[set]
if (not list or not itemID) then return false end
list[itemID] = nil
for index, ID in pairs(list) do
if (ID == itemID) then
table.remove(list, index)
end
end
return true
end
 
function LootTracker:IsSetTracked(setName)
local lists = _db.profile.trackedLists
for index, list in pairs(lists) do
if (list == setName) then
return true
end
end
end
 
function LootTracker:ToggleTrackSet(setName)
local lists = _db.profile.trackedLists
local found = false
for index, list in pairs(lists) do
if (list == setName) then
found = true
table.remove(lists, index) -- removing from a sorted lists leaves it sorted
end
end
if (found) then return false end -- if we removed, return false
table.insert(lists, setName)
table.sort(lists)
return true -- adding = return true
end
 
--[[ Frame Functions ]]--
 
function LootTracker:AddToTip(itemName)
local cache = _itemCache[_server]
if (not cache) then return end
local count
local txt = ''
for player in pairs(cache) do
count = self:GetItemCount(itemName, player)
if (count and count > 0) then
GameTooltip:AddLine(string.format("%s: %d", player, self:GetItemCount(itemName, player)))
end
end
end
 
local TL, TR, BL, BR = "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT"
-- copied from PerfectRaid, credit goes to cladhaire
function LootTracker:SavePosition(name)
local f = getglobal(name)
if (not f) then return end
local x,y = f:GetCenter()
local anchor = 'CENTER'
local s = f:GetEffectiveScale()
 
--x,y = x*s,y*s
 
local opt = _db.profile.positions[name]
if not opt then
_db.profile.positions[name] = {}
opt = _db.profile.positions[name]
end
local h, w = UIParent:GetHeight(), UIParent:GetWidth()
local xOff, yOff, anchor = 0, 0, 'CENTER'
local fW, fH = f:GetWidth() / 2, f:GetHeight() / 2
local left, top, right, bottom = x - fW, y + fH, x + fW, y - fH
if (x > w/2) then -- on the right half of the screen
if (y > h/2) then -- top half
xOff = -(w - right)
yOff = -(h - top)
anchor = TR
else -- bottom half
xOff = -(w - right)
yOff = bottom
anchor = BR
end
else -- on the left half of the screen
if (y > h/2) then -- top half
xOff = left
yOff = -(h - top)
anchor = TL
else -- bottom half
xOff = left
yOff = bottom
anchor = BL
end
end
opt.PosX = xOff*s
opt.PosY = yOff*s
opt.anchor = anchor
end
 
-- copied from PerfectRaid, credit goes to cladhaire
function LootTracker:RestorePosition(name)
local f = getglobal(name)
local opt = _db.profile.positions[name]
if not opt then
_db.profile.positions[name] = {}
opt = _db.profile.positions[name]
end
local h, w = UIParent:GetHeight(), UIParent:GetWidth()
 
local x = opt.PosX
local y = opt.PosY
local anchor = opt.anchor
 
local s = f:GetEffectiveScale()
 
if not x or not y or not anchor then
f:ClearAllPoints()
f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
return
end
 
x,y = x/s,y/s
f:ClearAllPoints()
f:SetPoint(anchor, UIParent, anchor, x, y)
end
 
function LootTracker:CreateTrackerFrame()
if (self.oldTracker) then return end
local tooltip = CreateFrame('GameTooltip', 'LootTrackerTrackingFrame', UIParent, 'GameTooltipTemplate')
tooltip:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 16,
insets = { left = 5, right = 5, top = 5, bottom = 5 },
})
tooltip:SetBackdropColor(24/255, 24/255, 24/255, 1)
tooltip:EnableMouse(true)
tooltip:SetMovable(true)
--tooltip:RegisterForDrag("LeftButton")
tooltip:SetScript("OnMouseDown",function(this, button) tooltip:StartMoving() end)
tooltip:SetScript("OnMouseUp",function() self:SavePosition(tooltip:GetName()); tooltip:StopMovingOrSizing() end)
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
tooltip:SetClampedToScreen(true)
tooltip:SetFrameStrata("BACKGROUND")
tooltip:Show()
tooltip:SetScript("OnShow", function() self:PopulateTrackerFrame() end)
self.oldTracker = tooltip
return tooltip
end
 
function LootTracker:CreateSetInputFrame()
if (self.inputSetFrame) then return end
local frame = CreateFrame('Frame', nil, OH:GetFrame("addon"))
frame:SetFrameStrata("DIALOG")
frame:SetFrameLevel(frame:GetFrameLevel()+6)
frame:SetWidth(250)
frame:SetHeight(75)
frame:SetBackdrop({
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 16,
insets = { left = 1, right = 1, top = 1, bottom = 1 },
})
frame:ClearAllPoints()
frame:SetBackdropColor(24/255, 24/255, 24/255)
frame:EnableMouse(true)
frame:SetMovable(true)
frame:RegisterForDrag("LeftButton")
frame:Show()
frame:SetScript("OnDragStart", function() this:StartMoving() end)
frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
frame:SetClampedToScreen(true)
local e = CreateFrame('EditBox','LootTrackerSetEditBox',frame,'InputBoxTemplate')
local f = frame:CreateFontString(nil,'OVERLAY','GameFontNormalSmall')
e.label = f
e:SetHeight(26)
e:SetWidth(225)
f:SetPoint('BOTTOMLEFT',e,'TOPLEFT',-2,0)
e:SetAutoFocus(true)
e:SetFont("Fonts\\FRIZQT__.TTF", 16)
e:SetTextColor(1,1,1)
f:SetText('Set Name')
e:SetPoint('TOPLEFT', frame, 'TOPLEFT', 15, -23)
frame.ok = self:CreateButton(frame, 75, 20, 'Ok', 'BOTTOMLEFT', frame, 'BOTTOMLEFT', 10, 5)
frame.cancel = self:CreateButton(frame, 75, 20, 'Cancel', 'BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -10, 5)
frame:SetScript("OnHide", function(this) e:SetText('') end)
frame.editBox = e
frame.editBox:SetScript("OnEnterPressed",
function(this)
self:UpdateSetName(e:GetText())
selectedLine = nil
self:updateScrollList(true)
frame:Hide()
end )
frame.cancel:SetScript("OnClick", function(this) frame:Hide() end)
frame.editBox:SetScript("OnEscapePressed", function(this) frame:Hide() end)
frame.ok:SetScript("OnClick",
function(this)
self:UpdateSetName(e:GetText())
selectedLine = nil
self:updateScrollList(true)
frame:Hide()
end )
frame:SetPoint('CENTER')
self.inputSetFrame = frame
end
 
function LootTracker:CreateItemInputFrame()
if (self.inputItemFrame) then return end
local frame = CreateFrame('Frame', nil, OH:GetFrame("addon"))
frame:SetFrameStrata("DIALOG")
frame:SetFrameLevel(frame:GetFrameLevel()+7)
frame:SetWidth(250)
frame:SetHeight(75)
frame:SetBackdrop({
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 16,
insets = { left = 1, right = 1, top = 1, bottom = 1 },
})
frame:ClearAllPoints()
frame:SetBackdropColor(24/255, 24/255, 24/255)
frame:EnableMouse(true)
frame:SetMovable(true)
frame:RegisterForDrag("LeftButton")
frame:Show()
frame:SetScript("OnDragStart", function() this:StartMoving() end)
frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
frame:SetClampedToScreen(true)
local e = CreateFrame('EditBox','LootTrackerItemCountEditBox',frame,'InputBoxTemplate')
local f = frame:CreateFontString(nil,'OVERLAY','GameFontNormalSmall')
e.label = f
e:SetHeight(26)
e:SetWidth(45)
f:SetPoint('BOTTOMLEFT',e,'TOPLEFT',-2,0)
e:SetAutoFocus(false)
e:SetFont("Fonts\\FRIZQT__.TTF", 16)
e:SetTextColor(1,1,1)
f:SetText('Goal')
e:SetPoint('TOPLEFT', frame, 'TOPLEFT', 15, -23)
frame.num = e
f = frame:CreateFontString(nil, 'OVERLAY', 'GameFontNormalSmall')
f:SetText('x')
f:SetPoint('LEFT', frame.num, 'RIGHT', 1, 0)
e:SetNumeric(true)
e:SetMaxLetters(4)
 
e = CreateFrame('EditBox','LootTrackerItemNameEditBox',frame,'InputBoxTemplate')
e:SetPoint('LEFT', frame.num, 'RIGHT', 12, 0)
e:SetHeight(26)
e:SetWidth(165)
e:SetAutoFocus(false)
e:SetFont("Fonts\\FRIZQT__.TTF", 16)
e:SetTextColor(1,1,1)
f = frame:CreateFontString(nil,'OVERLAY','GameFontNormalSmall')
e.label = f
f:SetPoint('BOTTOMLEFT',e,'TOPLEFT',-2,0)
f:SetText('Item')
frame.item = e
frame.ok = self:CreateButton(frame, 75, 20, 'Ok', 'BOTTOMLEFT', frame, 'BOTTOMLEFT', 10, 5)
frame.cancel = self:CreateButton(frame, 75, 20, 'Cancel', 'BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -10, 5)
frame.num:SetScript("OnTabPressed", function(this) frame.item:SetFocus() end)
frame.item:SetScript("OnEnterPressed",
function(this)
local result = self:UpdateItem(frame.item:GetText(), frame.num:GetText())
if result then
frame.item:SetText('')
frame.num:SetText('')
self:updateScrollList()
self:PopulateTrackerFrame()
self:PopulateNewTracker()
if (not IsShiftKeyDown()) then
frame:Hide()
end
else
UIErrorsFrame:AddMessage(L['LootTracker: Invalid item entered.'])
end
end )
frame:SetScript("OnHide", function(this)
frame.item:SetText('')
frame.num:SetText('')
end )
frame.cancel:SetScript("OnClick",function(this) frame:Hide() end)
frame.item:SetScript("OnEscapePressed", function(this) frame:Hide() end)
frame.ok:SetScript("OnClick",
function(this)
local result = self:UpdateItem(frame.item:GetText(), frame.num:GetText())
if result then
frame.item:SetText('')
frame.num:SetText('')
self:updateScrollList()
self:PopulateTrackerFrame()
self:PopulateNewTracker()
if (not IsShiftKeyDown()) then
frame:Hide()
end
else
UIErrorsFrame:AddMessage('LootTracker: Invalid item entered.')
end
end )
frame:SetPoint('CENTER')
self.inputItemFrame = frame
end
 
-- idea (and most of the code) taken from KC_Items2
function LootTracker:CreateButton(parent, width, height, text, ...)
local button = CreateFrame('Button', nil, parent, 'OptionsButtonTemplate')
button:SetWidth(width)
button:SetHeight(height)
 
button:SetFont("Fonts\\FRIZQT__.TTF", 12)
--button:SetTextColor(1,1,1)
button:SetText(text)
 
if select("#",...) > 0 then button:SetPoint(...) end
 
return button
end
 
function LootTracker:ShowTracker()
_db.profile.tracker.old.shown = true
if (not self.oldTracker) then
self:CreateTrackerFrame()
if (_db.profile.tracker.old.lock) then
self.oldTracker:SetBackdropBorderColor(24/255, 24/255, 24/255, 0)
self.oldTracker:EnableMouse(false)
end
end
self.oldTracker:Show()
self.oldTracker:SetOwner(UIParent, "ANCHOR_NONE")
self.oldTracker:SetScale(_db.profile.tracker.old.scale)
self.oldTracker:SetAlpha(_db.profile.tracker.old.alpha)
self:PopulateTrackerFrame()
end
 
function LootTracker:ToggleConfig()
OH:Open("LootTracker")
end
 
function LootTracker:ToggleTracker()
if (LootTrackerTrackingFrame) then
if (LootTrackerTrackingFrame:IsVisible()) then
LootTrackerTrackingFrame:Hide()
return
end
end
LootTracker:ShowTracker()
end
 
function LootTracker:ShowSetInputFrame(text)
if (not self.inputSetFrame) then
self:CreateSetInputFrame()
end
if (text) then
self.inputSetFrame.editBox:SetText(text)
end
self.inputSetFrame:Show()
end
 
function LootTracker:ShowItemInputFrame(text, count)
if (not self.inputItemFrame) then
self:CreateItemInputFrame()
end
if (text) then
self.inputItemFrame.item:SetText(text)
end
if (count) then
self.inputItemFrame.num:SetText(count)
end
self.inputItemFrame:Show()
end
 
-- follwing bit of code taken from tablet-2.0. credit goes to them
local getLine, freeLine
do
local tinsert, tremove = table.insert, table.remove
local textures = {}
getLine = function(parent)
local t = tremove(textures)
if (not t) then
t = parent:CreateFontString(nil, 'ARTWORK')
t:SetFontObject(GameTooltipText)
end
t:Show()
t:SetParent(parent)
return t
end
freeLine = function(t)
t:SetText('')
t:SetParent(UIParent)
t:Hide()
tinsert(textures, t)
end
end
 
function LootTracker:AddLineToTracker(text, r, g, b)
local frame = self.oldTracker
local prev = frame.prev
local offset = frame.offset or 1
local line = frame.lines[offset] or getLine(frame)
frame.lines[offset] = line
if (prev and prev ~= line) then
line:SetPoint('TOPLEFT', prev, 'BOTTOMLEFT')
else
line:SetPoint('TOPLEFT', frame, 'TOPLEFT', 6, -5)
end
line:SetText(text)
line:SetTextColor(r, g, b)
line:Show()
frame.offset = offset + 1
frame.prev = line
end
 
function LootTracker:PopulateTrackerFrame()
local tracked = _db.profile.trackedLists
local lists = _db.global.lists
local options = _db.profile.tracker.old
local list, items, name, item
local tip = self.oldTracker
local text
local count
if (not tip) then return end -- jump out if we aren't showing anything
if (not options.shown) then tip:Hide() return end -- it's hidden, don't show it
tip:ClearLines()
local hideifnone = _db.profile.tracker.hideifnone
local hideincomplete = _db.profile.tracker.hideincomplete
local squish = options.squish
local continue
--tip:SetScale(options.scale)
if (options.lock) then
tip:SetBackdropBorderColor(24/255, 24/255, 24/255, 0)
tip:EnableMouse(false)
end
tip:AddLine("LootTracker", 0.75, 0.61, 0)
for i=1, #tracked do
list = tracked[i]
tip:AddLine(list, 0.75, 0.61, 0)
items = lists[list]
for j=1, #items do
continue = false
name = items[j]
count = self:GetItemCount(name)
if hideifnone and count == 0 then
continue = true
end
if (items[name]) then
if hideincomplete and count < tonumber(items[name]) then continue = true end
text = string.format("%d/%d", count, items[name])
else
text = count
end
if not continue then
if (squish) then
text = string.format(" - %s: %s", name or 'name', text or 'text')
tip:AddLine(text, 0.8, 0.8, 0.8)
else
tip:AddDoubleLine(' - '..name..':', text, 0.8, 0.8, 0.8)
end
end
end
end
tip:Show()
local r, g, b = tip:GetBackdropColor()
tip:SetBackdropColor(r, g, b, options.alpha)
self:RestorePosition(tip:GetName())
end
 
--[[ all new stuff ]]--
 
function LootTracker:IsSetCollapsed(set)
return _db.profile.tracker.collapsed[set]
end
 
function LootTracker:CollapseSet(set, collapse)
_db.profile.tracker.collapsed[set] = collapse
end
 
function LootTracker:ToggleCollapsedSet(set)
_db.profile.tracker.collapsed[set] = not _db.profile.tracker.collapsed[set]
end
 
function LootTracker:CreateNewTracker()
if (self.newTracker) then return end
local tooltip = ClickTip:GetTip("LTAdvancedTracker", UIParent)
tooltip:EnableMouse(true)
tooltip:SetMovable(true)
tooltip:SetScript("OnMouseDown",function(this, button) this:StartMoving() end)
tooltip:SetScript("OnMouseUp",function() self:SavePosition(tooltip:GetName()); tooltip:StopMovingOrSizing() end)
self.newTracker = tooltip
tooltip:SetScript("OnShow", function() self:PopulateNewTracker() end)
tooltip:SetClampedToScreen(true)
return tooltip
end
 
local clickers = {
SetClicker = function(set)
if (set) then
LootTracker:ToggleCollapsedSet(set)
LootTracker:PopulateNewTracker()
end
end,
--ItemClicker = function() return end,
}
 
local function ClickHandler(line, button)
local f = line.ltType
local func = clickers[f]
if (func and type(func) == "function") then
func(line.ltParam)
else
-- clicked on a item
--ChatFrame1:AddMessage("Clicked!")
end
end
 
function LootTracker:ShowNewTracker()
_db.profile.tracker.new.shown = true
if (not self.newTracker) then
self:CreateNewTracker()
if (_db.profile.tracker.new.lock) then
self.newTracker:SetBackdropBorderColor(24/255, 24/255, 24/255, 0)
self.newTracker:EnableMouse(false)
end
end
self.newTracker:Show()
self.newTracker:SetScale(_db.profile.tracker.new.scale)
self.newTracker:SetAlpha(_db.profile.tracker.new.alpha)
self:PopulateNewTracker()
end
local tipLines = {}
function LootTracker:PopulateNewTracker()
local tracked = _db.profile.trackedLists
local lists = _db.global.lists
local options = _db.profile.tracker
local list, items, name, item
local tip = self.newTracker
local text
local cLineN = 1
local collapsed
if (not tip) then return end -- jump out if we aren't showing anything
if (not options.new.shown) then tip:Hide() return end -- it's hidden, don't show it
local squish = options.new.squish
local hideifnone = options.hideifnone
local hideincomplete = options.hideincomplete
tip:SetScale(options.new.scale)
if (options.new.lock) then
tip:SetBackdropBorderColor(24/255, 24/255, 24/255, 0)
tip:EnableMouse(false)
end
local line, entries = tip:GetLine(cLineN)
if (entries and entries > 1) then
tip:ChangeLine(line, 1)
tip:ChangeEntry(line, 1, "LootTracker", 0.75, 0.61, 0, GameTooltipHeaderText)
elseif (entries) then
tip:ChangeEntry(line, 1, "LootTracker", 0.75, 0.61, 0, GameTooltipHeaderText)
else
line = tip:AddLine("LootTracker", 0.75, 0.61, 0, GameTooltipHeaderText)
end
line:EnableMouse(nil)
cLineN = cLineN + 1
for i=1, #tracked do
list = tracked[i]
line, entries = tip:GetLine(cLineN)
collapsed = self:IsSetCollapsed(list)
text = (collapsed and "+ " or "- ") .. list
if (entries) then
if (entries > 1) then
tip:ChangeLine(line, 1)
tip:ChangeEntry(line, 1, text, 0.75, 0.61, 0, GameTooltipText)
else
tip:ChangeEntry(line, 1, text, 0.75, 0.61, 0, GameTooltipText)
end
else
line = tip:AddLine(text, 0.75, 0.61, 0, GameTooltipText)
line:SetScript("OnClick", ClickHandler)
line:SetMovable(true)
line:RegisterForDrag('LeftButton')
line:SetScript('OnDragStart', function(this, button) tip:StartMoving() end)
line:SetScript('OnDragStop', function(this) self:SavePosition(tip:GetName()); tip:StopMovingOrSizing() end)
end
line.ltType = "SetClicker"
line.ltParam = list
line:EnableMouse(true)
cLineN = cLineN + 1
if (not collapsed) then
items = lists[list]
for j=1, #items do
local continue = false
line, entries = tip:GetLine(cLineN)
name = items[j]
local count = self:GetItemCount(name)
if hideifnone and count == 0 then continue = true end
if (items[name]) then
if hideincomplete and count < tonumber(items[name]) then continue = true end
text = string.format("%d/%d", count, items[name])
else
text = count
end
if not continue then
if (squish) then
text = string.format(" - %s: %s", name or 'name', text or 'text')
if (entries) then
if (entries > 1) then
tip:ChangeLine(line, 1)
tip:ChangeEntry(line, 1, text, nil, nil, nil, GameTooltipText)
else
tip:ChangeEntry(line, 1, text, nil, nil, nil, GameTooltipText)
end
else
line = tip:AddLine(text, nil, nil, nil, GameTooltipText)
line:SetScript("OnClick", ClickHandler)
line:EnableMouse(true)
end
else
if (entries) then
if (entries ~= 2) then
tip:ChangeLine(line, 2)
tip:ChangeEntry(line, 1, ' - '..name..':', 0.8, 0.8, 0.8, GameTooltipText)
tip:ChangeEntry(line, 2, text, 0.75, 0.61, 0, GameTooltipText)
else
tip:ChangeEntry(line, 1, ' - '..name..':', 0.8, 0.8, 0.8, GameTooltipText)
tip:ChangeEntry(line, 2, text, 0.75, 0.61, 0, GameTooltipText)
end
else
line = tip:AddDoubleLine(' - '..name..':', text, 0.8, 0.8, 0.8, 0.75, 0.61, 0, GameTooltipText, GameTooltipText)
line:SetScript("OnClick", ClickHandler)
line:SetMovable(true)
line:RegisterForDrag('LeftButton')
line:SetScript('OnDragStart', function(this, button) tip:StartMoving() end)
line:SetScript('OnDragStop', function(this) self:SavePosition(tip:GetName()); tip:StopMovingOrSizing() end)
end
end
line.ltType = "ItemClicker"
line.ltParam = name
cLineN = cLineN + 1
end
end
end
end
tip:ClearLines(cLineN)
tip:Show()
local r, g, b = tip:GetBackdropColor()
tip:SetBackdropColor(r, g, b, options.alpha)
self:RestorePosition(tip:GetName())
end
 
--[[
--OH Frame stuff
--]]--
--[[ frame generalization stuff ]]--
-- for the tooltip stuff
local RegisterCheckOption, RegisterSliderOption
do
local helps = {} -- for storing help stuff
-- timeout is how long before we forget we were showing, timeToShow is how
-- long before we actually show, these values seem fairly sane
local timeOut, timeToShow = 2.0, 0.5
local totalElapsed, showTooltip, state = 0
local onUpdate = function(frame, elapsed)
totalElapsed = totalElapsed + elapsed
if showTooltip then
if totalElapsed > timeToShow and state == 1 then -- actually show stuff
helps[showTooltip](showTooltip)
state = 2
totalElapsed = 0
end
if totalElapsed < timeOut and state == 2 then -- we need to reshow the tooltip quickly
helps[showTooltip](showTooltip)
state = 2
totalElapsed = 0
end
else
if totalElapsed > timeOut then -- reset our timeout
state = 1
visFrame:SetScript("OnUpdate", nil)
end
end
end
local registerHelp = function(frame, helpFunc)
helps[frame] = helpFunc
end
local showHelp = function(frame)
showTooltip = frame
totalElapsed = 0
if state ~= 2 then state = 1 end
if visFrame then
visFrame:SetScript("OnUpdate", onUpdate)
end
end
local hideHelp = function()
totalElapsed = 0
showTooltip = nil
state = 2
GameTooltip:Hide()
end
RegisterCheckOption = function(frame, get, set, help)
frame:SetScript("OnClick", function(self) set(self:GetChecked() or false) end )
frame:SetScript("OnShow", function(self) self:SetChecked(get()) end )
if help then
registerHelp(frame, help)
frame:SetScript("OnEnter", showHelp)
frame:SetScript("OnLeave", hideHelp)
end
end
RegisterSliderOption = function(frame, get, set, help)
frame:SetScript("OnValueChanged", function(self) set(self:GetValue()) end )
frame:SetScript("OnShow", function(self) self:SetValue(get()) end )
if help then
registerHelp(frame, help)
frame:SetScript("OnEnter", showHelp)
frame:SetScript("OnLeave", hideHelp)
end
end
end
 
local function CreateCheckButton(par)
local f = CreateFrame('CheckButton', nil, par)
f:SetHeight(32)
f:SetWidth(32)
f.text = f:CreateFontString(nil, nil, "GameFontNormalSmall")
f.text:SetPoint("LEFT", f, "RIGHT", -2, 0)
local t = f:CreateTexture()
f:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
f:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down")
f:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
f:GetHighlightTexture():SetBlendMode("ADD")
f:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
f:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disable")
f:SetHitRectInsets(0, -100, 0, 0)
f:SetScript("OnEnter", function(self)
if self.tooltipText then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText(this.tooltipText, nil, nil, nil, nil, 1)
end
if self.tooltipRequirement then
GameTooltip:AddLine(this.tooltipRequirement, "", 1.0, 1.0, 1.0)
GameTooltip:Show()
end
end )
f:SetScript("OnLeave", function(self) GameTooltip:Hide() end)
return f
end
 
local bg = {
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
tile = true,
tileSize = 8,
edgeSize = 8,
insets = { left = 3, right = 3, top = 6, bottom = 6 }
}
local function CreateSlider(par)
local f = CreateFrame('Slider', nil, par)
f:SetBackdrop(bg)
f:SetWidth(128)
f:SetHeight(17)
f:SetOrientation("HORIZONTAL")
f:SetHitRectInsets(0, 0, -10, -10)
local fs = f:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
fs:SetPoint('BOTTOM', f, "TOP", 0, 2)
f.text = fs
fs = f:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
fs:SetPoint("TOPLEFT", f, "BOTTOMLEFT", 2, 3)
f.low = fs
fs = f:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
fs:SetPoint("TOPRIGHT", f, "BOTTOMRIGHT", -2, 3)
f.high = fs
local text = f:CreateTexture()
text:SetTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
text:SetHeight(32)
text:SetWidth(32)
f:SetThumbTexture(text)
f.thumb = text
f:SetScript("OnEnter", function(self)
if self.tooltipText then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetText(this.tooltipText, nil, nil, nil, nil, 1)
end
if self.tooltipRequirement then
GameTooltip:AddLine(this.tooltipRequirement, "", 1.0, 1.0, 1.0)
GameTooltip:Show()
end
end )
f:SetScript("OnLeave", function(self) GameTooltip:Hide() end)
return f
end
 
local boxBG = {
--bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", --options frame background
bgFile = "Interface\\ChatFrame\\ChatFrameBackground", -- kc_linkview frame background
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true,
tileSize = 16,
edgeSize = 16,
insets = { left = 5, right = 5, top = 5, bottom = 5 }
}
 
function LootTracker:CreateRandomConfigs()
local frame = CreateFrame('Frame', nil, OH:GetFrame("addon"))
frame:Show()
visFrame = frame
local options = _db.profile
local box, check, slider
 
box = CreateFrame('Frame', nil, frame)
box:SetBackdrop(boxBG)
box:SetBackdropBorderColor(0.4, 0.4, 0.4)
box:SetBackdropColor(24/255, 24/255, 24/255)
box:SetHeight(80)
box:SetWidth(10)
box:SetPoint("TOPLEFT", 5, -15)
box:SetPoint("TOPRIGHT", frame, -5, -15)
box.title = box:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
box.title:SetPoint("BOTTOMLEFT", box, "TOPLEFT", 9, 0)
box.title:SetText(L["Standard Tracker Options"])
self.oldTrackerBox = box
 
check = CreateCheckButton(box)
check:SetPoint("TOPLEFT", 5, -5)
check.text:SetText(L["Show normal tracker"])
RegisterCheckOption(check, function() return options.tracker.old.shown end,
function(val)
options.tracker.old.shown = val
if val then self:ShowTracker() elseif self.oldTracker then self.oldTracker:Hide() end
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
if this:GetChecked() then
GameTooltip:SetText(L['Use this checkbox to hide the normal tracker'])
else
GameTooltip:SetText(L['Use this checkbox to show the normal tracker'])
end
GameTooltip:Show()
end)
self.showOldTracker = check
 
check = CreateCheckButton(frame)
check:SetPoint("TOPLEFT", self.showOldTracker, "TOPRIGHT", 200, 0)
check.text:SetText(L["Hide in combat"])
RegisterCheckOption(check, function() return options.tracker.old.combatHidden end,
function(val)
options.tracker.old.combatHidden = val
if val and InCombatLockdown() and self.oldTracker then
self.oldTracker:Hide()
end
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Hide in combat'])
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to show the tracker while in combat'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to hide the tracker while in combat'], nil, nil, nil, 1)
end
GameTooltip:Show()
end )
self.hideInCombatOld = check
 
check = CreateCheckButton(frame)
check:SetPoint("TOPLEFT", self.hideInCombatOld, "TOPRIGHT", 200, 0)
check.text:SetText(L["Lock Tracker"])
RegisterCheckOption(check, function() return options.tracker.old.lock end,
function(val)
options.tracker.old.lock = val
if self.oldTracker then
self.oldTracker:SetBackdropBorderColor(24/255, 24/255, 24/255, options.tracker.old.lock and 0 or 1)
self.oldTracker:EnableMouse(not options.tracker.old.lock)
end
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Lock Tracker'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to unlock the tracker'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to lock the tracker in its current position'], nil, nil, nil, 1)
end
GameTooltip:Show()
end )
self.lockOldTracker = check
 
check = CreateCheckButton(frame)
check:SetPoint("TOPLEFT", self.showOldTracker, "BOTTOMLEFT", 0, 0)
check.text:SetText(L["Squish numbers to name"])
RegisterCheckOption(check, function() return options.tracker.old.squish end,
function(val)
options.tracker.old.squish = val
self:PopulateTrackerFrame()
self:PopulateNewTracker()
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Squish numbers to name'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to separate item counts from the item name'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to force item counts next to the item name'], nil, nil, nil, 1)
end
GameTooltip:Show()
end )
self.squishOld = check
 
slider = CreateSlider(frame)
slider:SetPoint("TOPLEFT", self.squishOld, "TOPRIGHT", 200, -10)
slider.text:SetText(L["Background Alpha"])
slider.low:SetText(0)
slider.high:SetText(100)
slider:SetMinMaxValues(0, 100)
slider:SetValueStep(5)
RegisterSliderOption(slider, function() return options.tracker.old.alpha*100 end, function(val)
local alpha = val/100
options.tracker.old.alpha = alpha
if self.oldTracker then
local r, g, b = self.oldTracker:GetBackdropColor()
self.oldTracker:SetBackdropColor(r, g, b, alpha)
r, g, b = self.oldTracker:GetBackdropBorderColor()
self.oldTracker:SetBackdropBorderColor(r, g, b, alpha)
end
end, function()
GameTooltip:SetOwner(slider, "ANCHOR_LEFT")
GameTooltip:SetText(L['Background Alpha'])
GameTooltip:AddLine()
GameTooltip:AddLine(L['Use this slider to change the transparency of the background for the tracker'], nil, nil, nil, 1)
GameTooltip:Show()
end)
self.alphaOld = slider
 
--[[slider = CreateSlider(frame)
slider:SetPoint("TOPLEFT", self.alphaOld, "TOPRIGHT", 108, 0)
slider.text:SetText(L["Scale"])
slider.low:SetText(1)
slider.high:SetText(200)
slider:SetMinMaxValues(1, 200)
slider:SetValueStep(20)
RegisterSliderOption(slider, function() return options.tracker.old.scale*100 end, function(val)
scale = val/100
options.tracker.old.scale = scale
if self.oldTracker then
self:SavePosition('LootTrackerTrackingFrame')
self.oldTracker:SetScale(scale)
self:RestorePosition('LootTrackerTrackingFrame')
end
end)
self.scaleOld = slider]]--
 
if ClickTip then
box = CreateFrame('Frame', nil, frame)
box:SetBackdrop(boxBG)
box:SetBackdropBorderColor(0.4, 0.4, 0.4)
box:SetBackdropColor(24/255, 24/255, 24/255)
box:SetHeight(80)
box:SetWidth(10)
box:SetPoint("TOPLEFT", self.oldTrackerBox, "BOTTOMLEFT", 0, -15)
box:SetPoint("TOPRIGHT", self.oldTrackerBox, "BOTTOMRIGHT", 0, -15)
box.title = box:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
box.title:SetPoint("BOTTOMLEFT", box, "TOPLEFT", 9, 0)
box.title:SetText(L["Advanced Tracker Options"])
self.newTrackerBox = box
 
check = CreateCheckButton(box)
check:SetPoint("TOPLEFT", 5, -5)
check.text:SetText(L["Show advanced tracker"])
RegisterCheckOption(check, function() return options.tracker.new.shown end,
function(val)
options.tracker.new.shown = val
if val then self:ShowNewTracker() elseif self.newTracker then self.newTracker:Hide() end
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
if this:GetChecked() then
GameTooltip:SetText(L['Use this checkbox to hide the advanced tracker'])
else
GameTooltip:SetText(L['Use this checkbox to show the advanced tracker'])
end
GameTooltip:Show()
end)
self.showNewTracker = check
 
check = CreateCheckButton(frame)
check:SetPoint("TOPLEFT", self.showNewTracker, "TOPRIGHT", 200, 0)
check.text:SetText(L["Hide in combat"])
RegisterCheckOption(check, function() return options.tracker.new.combatHidden end,
function(val)
options.tracker.new.combatHidden = val
if val and InCombatLockdown() and self.newTracker then
self.newTracker:Hide()
end
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Hide in combat'])
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to show the tracker while in combat'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to hide the tracker while in combat'], nil, nil, nil, 1)
end
GameTooltip:Show()
end )
self.hideInCombatNew = check
 
check = CreateCheckButton(frame)
check:SetPoint("TOPLEFT", self.hideInCombatNew, "TOPRIGHT", 200, 0)
check.text:SetText(L["Lock advanced tracker"])
RegisterCheckOption(check, function() return options.tracker.new.lock end,
function(val)
options.tracker.new.lock = val
if self.newTracker then
self.newTracker:SetBackdropBorderColor(24/255, 24/255, 24/255, options.tracker.new.lock and 0 or 1)
self.newTracker:EnableMouse(not options.tracker.new.lock)
end
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Lock Tracker'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to unlock the tracker'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to lock the tracker in its current position'], nil, nil, nil, 1)
end
GameTooltip:Show()
end )
self.lockNewTracker = check
 
check = CreateCheckButton(frame)
check:SetPoint("TOPLEFT", self.showNewTracker, "BOTTOMLEFT", 0, 0)
check.text:SetText(L["Squish numbers to name"])
RegisterCheckOption(check, function() return options.tracker.new.squish end,
function(val)
options.tracker.new.squish = val
self:PopulateTrackerFrame()
self:PopulateNewTracker()
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Squish numbers to name'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to separate item counts from the item name'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to force item counts next to the item name'], nil, nil, nil, 1)
end
GameTooltip:Show()
end )
self.squishNew = check
 
slider = CreateSlider(frame)
slider:SetPoint("TOPLEFT", self.squishNew, "TOPRIGHT", 200, -10)
slider.text:SetText(L["Background Alpha"])
slider.low:SetText(0)
slider.high:SetText(100)
slider:SetMinMaxValues(0, 100)
slider:SetValueStep(5)
RegisterSliderOption(slider, function() return options.tracker.new.alpha*100 end,
function(val)
local alpha = val/100
options.tracker.new.alpha = alpha
if self.newTracker then
local r, g, b = self.newTracker:GetBackdropColor()
self.newTracker:SetBackdropColor(r, g, b, alpha)
r, g, b = self.newTracker:GetBackdropBorderColor()
self.newTracker:SetBackdropBorderColor(r, g, b, alpha)
end
end, function()
GameTooltip:SetOwner(slider, "ANCHOR_LEFT")
GameTooltip:SetText(L['Background Alpha'])
GameTooltip:AddLine()
GameTooltip:AddLine(L['Use this slider to change the transparency of the background for the tracker'], nil, nil, nil, 1)
GameTooltip:Show()
end)
self.alphaNew = slider
 
--[[slider = CreateSlider(frame)
slider:SetPoint("TOPLEFT", self.alphaOld, "TOPRIGHT", 108, 0)
slider.text:SetText(L["Scale"])
slider.low:SetText(1)
slider.high:SetText(200)
slider:SetMinMaxValues(1, 200)
slider:SetValueStep(20)
RegisterSliderOption(slider, function() return options.tracker.old.scale*100 end, function(val)
scale = val/100
options.tracker.old.scale = scale
if self.oldTracker then
self:SavePosition('LootTrackerTrackingFrame')
self.oldTracker:SetScale(scale)
self:RestorePosition('LootTrackerTrackingFrame')
end
end)
self.scaleOld = slider]]--
end
 
box = CreateFrame('Frame', nil, frame)
box:SetBackdrop(boxBG)
box:SetBackdropBorderColor(0.4, 0.4, 0.4)
box:SetBackdropColor(24/255, 24/255, 24/255)
box:SetHeight(80)
box:SetWidth(10)
box:SetPoint("TOPLEFT", self.newTrackerBox or self.oldTrackerBox, "BOTTOMLEFT", 0, -15)
box:SetPoint("TOPRIGHT", self.newTrackerBox or self.oldTrackerBox, "BOTTOMRIGHT", 0, -15)
box.title = box:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
box.title:SetPoint("BOTTOMLEFT", box, "TOPLEFT", 9, 0)
box.title:SetText(L["Global Tracker Options"])
self.newTrackerBox = box
 
check = CreateCheckButton(box)
check:SetPoint("TOPLEFT", 5, -5)
check.text:SetText(L["Hide if no items available"])
RegisterCheckOption(check, function() return options.tracker.hideifnone end,
function(val)
options.tracker.hideifnone = val
self:PopulateTrackerFrame()
self:PopulateNewTracker()
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Hide if no items available'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to show the item in the tracker even if there are no items available'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to hide the item in the tracker if there are no items available'], nil, nil, nil, 1)
end
GameTooltip:Show()
end)
self.hideIfNone = check
 
check = CreateCheckButton(box)
check:SetPoint("TOPLEFT", self.hideIfNone, "BOTTOMLEFT", 0, 0)
check.text:SetText(L["Hide if incomplete"])
RegisterCheckOption(check, function() return options.tracker.hideincomplete end,
function(val)
options.tracker.hideincomplete = val
self:PopulateTrackerFrame()
self:PopulateNewTracker()
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Hide if incomplete'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to show the item in the tracker even if the goal has not been met'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to hide the item in the tracker if the goal has not been met'], nil, nil, nil, 1)
end
GameTooltip:Show()
end)
self.hideIncomplete = check
 
check = CreateCheckButton(box)
check:SetPoint("TOPLEFT", 5, -5)
check.text:SetText(L["Current toon count only"])
check:SetPoint("TOPLEFT", self.hideIfNone, "TOPRIGHT", 200, 0)
RegisterCheckOption(check, function() return options.tracker.ctc end,
function(val)
options.tracker.ctc = val
self:PopulateTrackerFrame()
self:PopulateNewTracker()
end, function(this)
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(L['Current toon count only'])
GameTooltip:AddLine()
if this:GetChecked() then
GameTooltip:AddLine(L['Use this checkbox to show item totals from all toons'], nil, nil, nil, 1)
else
GameTooltip:AddLine(L['Use this checkbox to only show item totals from current toon'], nil, nil, nil, 1)
end
GameTooltip:Show()
end)
self.currentToonCount = check
return frame
end
 
local function updateTextures(show)
for i = 1, #configFrame.rows do
local button = configFrame.rows[i]
if show then
button.item:Show()
button.left:ClearAllPoints()
button.left:SetPoint('LEFT', button, 'LEFT', 34, 2)
--button.highlight:ClearAllPoints()
button.highlight:SetPoint('TOPLEFT', button, 'TOPLEFT', 33, 0)
button.name:ClearAllPoints()
button.name:SetPoint("TOPLEFT", button, "TOPLEFT", 43, 0)
button.count:SetText('Item')
button.count:Show()
else
button.item:Hide()
button.left:ClearAllPoints()
button.left:SetPoint('LEFT', button, 'LEFT', 2, 2)
--button.highlight:ClearAllPoints()
button.highlight:SetPoint('TOPLEFT', button, 'TOPLEFT', 1, 0)
button.name:ClearAllPoints()
button.name:SetPoint("TOPLEFT", button, "TOPLEFT", 9, 0)
button.count:SetText('')
button.count:Hide()
end
end
end
 
local function updateButtons()
if not configFrame.curBtn then
configFrame.RemoveX:Disable()
configFrame.EditX:Disable()
else
configFrame.RemoveX:Enable()
configFrame.EditX:Enable()
end
end
 
local function trackList(row)
local button = configFrame.rows[row]
local set = _db.global.lists[button.index]
local added = LootTracker:ToggleTrackSet(set)
LootTracker:PopulateTrackerFrame()
LootTracker:PopulateNewTracker()
if (added) then
button.check:Show()
button.check:ClearAllPoints()
button.check:SetPoint("LEFT", button, 'LEFT', button.name:GetStringWidth()+24, 0)
else
button.check:Hide()
end
end
 
local function onLeave() GameTooltip:Hide() end
 
local function onEnter(this)
if this.link then
if this.link ~= true then
GameTooltip:SetOwner(this,"ANCHOR_LEFT")
GameTooltip:SetHyperlink(this.link)
LootTracker:AddToTip(this.itemName)
GameTooltip:Show()
else
GameTooltip:SetOwner(this,"ANCHOR_LEFT")
GameTooltip:SetText(this.name:GetText())
LootTracker:AddToTip(this.itemName)
GameTooltip:Show()
end
elseif this.itemName then
GameTooltip:SetOwner(this,"ANCHOR_LEFT")
LootTracker:AddToTip(this.itemName)
GameTooltip:Show()
else -- it is a set, add the number of items
local set = _db.global.lists[this.index]
local items = _db.global.lists[set]
local numItems = items and #items or 0
GameTooltip:SetOwner(this,"ANCHOR_LEFT")
GameTooltip:SetText(set)
local name, link, rarity, level, minlevel, itype, subtype, stackCount, equipLoc, text
local item, itemID
for i=1, numItems do
item = items[i]
itemID = LootTracker:GetItemID(item)
name, link, rarity, level, minlevel, itype, subtype, stackCount, equipLoc, text = GetItemInfo(itemID)
if (items[name]) then
GameTooltip:AddDoubleLine(name or item, string.format("%d/%d", LootTracker:GetItemCount(name), items[name]))
else
GameTooltip:AddDoubleLine(name or item, LootTracker:GetItemCount(name))
end
end
GameTooltip:AddLine()
if (LootTracker:IsSetTracked(set)) then
GameTooltip:AddLine(L["Hint: Shift click to remove from tracker"], 0, 1, 0, 1)
else
GameTooltip:AddLine(L["Hint: Shift click to add to tracker"], 0, 1, 0, 1)
end
GameTooltip:Show()
end
end
 
local function updateHighlights(clickedRow, reset)
if reset and configFrame.curBtn then
configFrame.curBtn:UnlockHighlight()
configFrame.curBtn = nil
end
 
if clickedRow then
local button = configFrame.rows[clickedRow]
if button == configFrame.curBtn then
button:UnlockHighlight()
configFrame.curBtn = nil
else
if configFrame.curBtn then configFrame.curBtn:UnlockHighlight() end
configFrame.curBtn = button
button:LockHighlight()
end
selectedLine = button.index
end
updateButtons()
end
 
function LootTracker:updateScrollList(resetHighlights)
local scrollFrame = configFrame.scroll
local itemID
if resetHighlights then updateHighlights(nil, true) end
if not currentSet then
local sets, numSets = _db.global.lists
local offset = FauxScrollFrame_GetOffset(scrollFrame)
numSets = #sets
local resize = numSets <= 8
local buttons, maxButtons = configFrame.rows, #configFrame.rows
FauxScrollFrame_Update(scrollFrame, numSets, maxButtons, scrollFrame.buttonHeight)
local i, j, button
for i=1,maxButtons do
j=i + offset
button = buttons[i]
button.link = nil
button.itemName = nil
if j <= numSets then
button.name:SetText(sets[j])
if (self:IsSetTracked(sets[j])) then
button.check:SetPoint('LEFT', button, 'LEFT', button.name:GetStringWidth()+24,0)
button.check:Show()
else
button.check:Hide()
end
if resize then
button:SetWidth(625)
else
button:SetWidth(600)
end
button:Show()
button.index = j
if j == selectedLine then
button:LockHighlight()
configFrame.curBtn = button
end
else
button.index = nil
button:SetText('')
button:Hide()
end
end
else
local buttons, maxButtons = configFrame.rows, #configFrame.rows
local highlights = scrollFrame.highlights
local numItems, items = 0
items = _db.global.lists[currentSet]
if (items) then numItems = #items end
local resize = numItems <= 8
FauxScrollFrame_Update(scrollFrame, numItems, maxButtons, scrollFrame.buttonHeight)
local i, j, item, link, name, itemID
local name, link, rarity, level, minlevel, itype, subtype, stackCount, equipLoc, text
local offset = FauxScrollFrame_GetOffset(scrollFrame)
local button
for i=1,maxButtons do
j=i + offset
button = buttons[i]
if j <= numItems then
item = items[j]
itemID = self:GetItemID(item)
name, link, rarity, level, minlevel, itype, subtype, stackCount, equipLoc, text = GetItemInfo(itemID)
button.name:SetText(link or name or item or 'Error')
if (items[name]) then
button.count:SetText(string.format("%d/%d", self:GetItemCount(name), items[name]))
else
button.count:SetText(self:GetItemCount(name))
end
if text then
button.texture:SetTexture(text)
else
button.texture:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
end
if resize then
button:SetWidth(625)
else
button:SetWidth(600)
end
button.index = j
button.link = link or true
button.itemName = name
button:Show()
else
button.index = nil
button.link = nil
button.itemName = nil
button:SetText('')
button:Hide()
end
button.check:Hide()
end
end
end
 
local function createConfigFrame(self)
local name = "LTOHConfig"
 
local frame = CreateFrame('Frame', name, OH:GetFrame("addon"))
frame:SetToplevel(true)
frame:SetAllPoints()
 
local RemoveX = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
RemoveX:SetWidth(80)
RemoveX:SetHeight(22)
RemoveX:SetPoint("BOTTOMRIGHT", OH:GetFrame("main"), "BOTTOMRIGHT", -8, 14)
RemoveX:SetText(L["Remove Set"])
frame.RemoveX = RemoveX
RemoveX:SetScript("OnClick", function(f)
if not currentSet then -- current set means we've selected a set as a sub cat
local setName = _db.global.lists[selectedLine]
local removed = self:RemoveSet(setName)
if removed then
selectedLine = nil
ui:RemoveSubCategory(L["Sets"], setName) -- remove the sub cat
updateHighlights(nil, true)
self:updateScrollList()
end
else
local set = _db.global.lists[currentSet]
local item = set[selectedLine]
local removed = self:RemoveItem(item, currentSet)
if removed then
selectedLine = nil
updateHighlights(nil, true)
self:updateScrollList()
end
end
end)
 
local EditX = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
EditX:SetWidth(80)
EditX:SetHeight(22)
EditX:SetPoint("RIGHT", RemoveX, "LEFT")
EditX:SetText(L["Rename Set"])
EditX:SetScript("OnClick", function() end)
frame.EditX = EditX
EditX:SetScript('OnClick',
function(f)
if not currentSet then
self.newSet = nil
self.currentSet = _db.global.lists[selectedLine]
self:ShowSetInputFrame(_db.global.lists[selectedLine])
else
local set = _db.global.lists[currentSet]
local name = set[selectedLine]
local item = self:GetItemID(name)
local count = set[name]
local n2, link = GetItemInfo(item)
if not n2 then
self:ShowItemInputFrame(item, count)
else
self:ShowItemInputFrame(link, count)
end
end
end)
 
local AddX = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
AddX:SetWidth(80)
AddX:SetHeight(22)
AddX:SetPoint("RIGHT", EditX, "LEFT")
AddX:SetText(L["Add Set"])
frame.AddX = AddX
AddX:SetScript("OnClick",
function(f)
if not currentSet then
self.newSet = true
self:ShowSetInputFrame()
else
self:ShowItemInputFrame()
end
end)
 
-- stolen from optionhouse and modified to look like AH
frame.rows = {}
for i=1, 8 do
local button = CreateFrame("Button", nil, frame)
button:SetWidth(597)
button:SetHeight(37)
local texture = button:CreateTexture(nil, "BACKGROUND")
texture:SetTexture("Interface\\AuctionFrame\\UI-AuctionItemNameFrame")
button.right = texture
texture:SetTexCoord(0.75, 0.828125, 0, 1.0)
texture:SetPoint("RIGHT", button, "RIGHT", 0, 2)
texture:SetWidth(10)
texture:SetHeight(32)
local texture = button:CreateTexture(nil, "BACKGROUND")
texture:SetTexture("Interface\\AuctionFrame\\UI-AuctionItemNameFrame")
button.left = texture
texture:SetTexCoord(0, 0.078125, 0, 1.0)
texture:SetPoint("Left", button, "LEFT", 34, 2)
texture:SetWidth(10)
texture:SetHeight(32)
local texture = button:CreateTexture(nil, "BACKGROUND")
texture:SetTexture("Interface\\AuctionFrame\\UI-AuctionItemNameFrame")
button.center = texture
texture:SetTexCoord(0.078125, 0.75, 0, 1.0)
texture:SetPoint("LEFT", button.left, "RIGHT", 0, 0)
texture:SetPoint("RIGHT", button.right, "LEFT", 0, 0)
texture:SetWidth(10)
texture:SetHeight(32)
local name = button:CreateFontString(nil, "BACKGROUND", 'GameFontNormal')
button.name = name
name:SetPoint("TOPLEFT", button, "TOPLEFT", 43, 0)
name:SetHeight(32)
name:SetWidth(167)
name:SetJustifyH("LEFT")
name:SetText("Button: "..i)
name:SetTextColor(1,1,1)
button.check = button:CreateTexture('BACKGROUND')
button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
button.check:SetHeight(16)
button.check:SetWidth(16)
button.check:Show()
button.check:SetPoint('LEFT', name, 'RIGHT', 0, 0)
local count = button:CreateFontString(nil, "BACKGROUND", 'GameFontNormal')
button.count = count
count:SetHeight(32)
count:SetWidth(167)
count:SetJustifyH("RIGHT")
count:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0)
count:SetText("Count: "..i)
local item = CreateFrame('Button', nil, button)
local texture = item:CreateTexture(nil, 'BORDER')
texture:SetHeight(60)
texture:SetWidth(60)
texture:SetTexture("Interface\\Buttons\\UI-QuickSlot2")
texture:SetPoint("CENTER", item, "CENTER", 0, 0)
item:SetHeight(32)
item:SetWidth(32)
item:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0)
item:SetNormalTexture(texture)
item:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
button.item = item
button.texture = item:CreateTexture(nil, "ARTWORK")
button.texture:SetAllPoints(item)
 
local texture = button:CreateTexture(nil, 'HIGHLIGHT')
texture:SetWidth(597)
texture:SetHeight(32)
texture:SetPoint('TOPLEFT', button, 'TOPLEFT', 33, 0)
texture:SetPoint('TOPRIGHT', button, 'TOPRIGHT', 0, 0)
texture:SetTexture("Interface\\HelpFrame\\HelpFrameButton-Highlight")
texture:SetTexCoord(0, 1, 0, 0.578125)
texture:SetBlendMode("add")
button.highlight = texture
button:SetHighlightTexture(texture)
button:SetHighlightTexture("Interface\\HelpFrame\\HelpFrameButton-Highlight")
button:SetScript("OnClick", function(self, button)
if IsShiftKeyDown() and not currentSet then
trackList(i)
return
end
updateHighlights(i)
end)
button:SetScript("OnEnter", onEnter)
button:SetScript("OnLeave", onLeave)
if( i > 1 ) then
button:SetPoint("TOPLEFT", frame.rows[i-1], "BOTTOMLEFT", 0, 0)
else
button:SetPoint("TOPLEFT", frame, "TOPLEFT", 195, -110)
end
frame.rows[i] = button
end
 
frame.scroll = CreateFrame("ScrollFrame", name.."Scroll", frame, "FauxScrollFrameTemplate")
frame.scroll.buttonHeight = 37
frame.scroll:SetPoint("TOPLEFT", frame, "TOPLEFT", 25, -105)
frame.scroll:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -35, 38)
frame.scroll:SetScript("OnVerticalScroll", function() FauxScrollFrame_OnVerticalScroll(frame.scroll.buttonHeight, function() self:updateScrollList() end) end)
 
local texture = frame.scroll:CreateTexture(nil, "BACKGROUND")
texture:SetWidth(31)
texture:SetHeight(256)
texture:SetPoint("TOPLEFT", frame.scroll, "TOPRIGHT", -2, 5)
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ScrollBar")
texture:SetTexCoord(0, 0.484375, 0, 1.0)
 
local texture = frame.scroll:CreateTexture(nil, "BACKGROUND")
texture:SetWidth(31)
texture:SetHeight(106)
texture:SetPoint("BOTTOMLEFT", frame.scroll, "BOTTOMRIGHT", -2, -2)
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ScrollBar")
texture:SetTexCoord(0.515625, 1.0, 0, 0.4140625)
return frame
end
 
function LootTracker:PopulateOHFrame(cat, subcat)
if not configFrame then
configFrame = createConfigFrame(self)
end
if cat and subcat == '' then
currentSet = nil
elseif cat and subcat ~= '' then
if cat == L["Sets"] then
currentSet = subcat
end
end
if not currentSet then
configFrame.AddX:SetText(L["Add Set"])
configFrame.EditX:SetText(L["Rename Set"])
configFrame.RemoveX:SetText(L["Remove Set"])
else
configFrame.AddX:SetText(L["Add Item"])
configFrame.EditX:SetText(L["Edit Item"])
configFrame.RemoveX:SetText(L["Del Item"])
end
updateTextures(currentSet)
updateHighlights(nil, true)
self:updateScrollList()
configFrame:Show()
return configFrame
end
 
function LootTracker:ResetOptions()
local sets = _db.global.lists
local ui = ui
for i = 1, #sets do
ui:RemoveSubCategory(L["Sets"], sets[i]) -- remove the sub cat
end
end
Property changes : Added: svn:mime-type + text/plain Added: svn:eol-style + native
branches/LootTracker-Rewrite-Ace3/libs/LocaleQuery.lua New file
0,0 → 1,46
 
-------------------------------
-- Author Settings --
-------------------------------
 
local addonname = "LootTracker" -- The name of your addon, duh!
local contact = "joshborke@gmail.com" -- This is the email address you wish localizers to contact you at
 
-- This table indicates what locales are supported by your addon
-- true == fully translated
-- false or nil == no translations
-- any other value == partially translated
local locales = {
deDE = false, -- German
enGB = false, -- British English
enUS = true, -- American English
esES = false, -- Spanish
frFR = false, -- French
koKR = false, -- Korean
ruRU = false, -- Russian
zhCN = false, -- Chinese (simplified)
zhTW = false, -- Chinese (traditional)
}
 
 
------------------------------
-- Locale testing --
------------------------------
 
local loc = GetLocale()
local status = locales[loc]
 
if not status then -- Not translated
local s = loc == "deDE" and "%s wurde nicht in deine Sprache uebersetzt. Wenn du helfen moechtest wende dich bitte an <%s> fuer Details, wie du Uebersetzungen einsenden kannst."
or loc == "frFR" and "%s n'a pas \195\169t\195\169 traduit dans votre langue. Veuillez contacter <%s> pour les d\195\169tails concernant la submission de traductions."
or loc == "esES" and "%s no ha sido traducido a tu lenguaje. Por favor contacta con <%s> para los detalles del envio de traducciones."
or "%s has not been translated into your language. Please contact <%s> for details on submitting translations."
DEFAULT_CHAT_FRAME:AddMessage(string.format(s, addonname, contact))
elseif status ~= true then -- Partially translated
local s = loc == "deDE" and "%s wurde nur teilweise in deine Sprache uebersetzt. Wenn du helfen moechtest wende dich bitte an <%s> fuer Details, wie du Uebersetzungen einsenden kannst."
or loc == "frFR" and "%s n'est que partiellement traduit dans votre langue. Veuillez contacter <%s> pour les d\195\169tails concernant la submission de traductions."
or loc == "esES" and "%s sólo está parcialmente traducido a tu lenguaje. Por favor contacta con <%s> para los detalles del envio de traducciones."
or "%s is only partially translated into your language. Please contact <%s> for details on submitting translations."
DEFAULT_CHAT_FRAME:AddMessage(string.format(s, addonname, contact))
end
 
Property changes : Added: svn:eol-style + native Added: svn:mime-type + text/plain
branches/LootTracker-Rewrite-Ace3/libs/Dongle.lua New file
0,0 → 1,1283
--[[-------------------------------------------------------------------------
Copyright (c) 2006-2007, Dongle Development Team
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the Dongle Development Team nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------]]
local major = "DongleStub"
local minor = tonumber(string.match("$Revision: 313 $", "(%d+)") or 1)
 
local g = getfenv(0)
 
if not g.DongleStub or g.DongleStub:IsNewerVersion(major, minor) then
local lib = setmetatable({}, {
__call = function(t,k)
if type(t.versions) == "table" and t.versions[k] then
return t.versions[k].instance
else
error("Cannot find a library with name '"..tostring(k).."'", 2)
end
end
})
 
function lib:IsNewerVersion(major, minor)
local versionData = self.versions and self.versions[major]
 
-- If DongleStub versions have differing major version names
-- such as DongleStub-Beta0 and DongleStub-1.0-RC2 then a second
-- instance will be loaded, with older logic. This code attempts
-- to compensate for that by matching the major version against
-- "^DongleStub", and handling the version check correctly.
 
if major:match("^DongleStub") then
local oldmajor,oldminor = self:GetVersion()
if self.versions and self.versions[oldmajor] then
return minor > oldminor
else
return true
end
end
 
if not versionData then return true end
local oldmajor,oldminor = versionData.instance:GetVersion()
return minor > oldminor
end
 
local function NilCopyTable(src, dest)
for k,v in pairs(dest) do dest[k] = nil end
for k,v in pairs(src) do dest[k] = v end
end
 
function lib:Register(newInstance, activate, deactivate)
assert(type(newInstance.GetVersion) == "function",
"Attempt to register a library with DongleStub that does not have a 'GetVersion' method.")
 
local major,minor = newInstance:GetVersion()
assert(type(major) == "string",
"Attempt to register a library with DongleStub that does not have a proper major version.")
assert(type(minor) == "number",
"Attempt to register a library with DongleStub that does not have a proper minor version.")
 
-- Generate a log of all library registrations
if not self.log then self.log = {} end
table.insert(self.log, string.format("Register: %s, %s", major, minor))
 
if not self:IsNewerVersion(major, minor) then return false end
if not self.versions then self.versions = {} end
 
local versionData = self.versions[major]
if not versionData then
-- New major version
versionData = {
["instance"] = newInstance,
["deactivate"] = deactivate,
}
 
self.versions[major] = versionData
if type(activate) == "function" then
table.insert(self.log, string.format("Activate: %s, %s", major, minor))
activate(newInstance)
end
return newInstance
end
 
local oldDeactivate = versionData.deactivate
local oldInstance = versionData.instance
 
versionData.deactivate = deactivate
 
local skipCopy
if type(activate) == "function" then
table.insert(self.log, string.format("Activate: %s, %s", major, minor))
skipCopy = activate(newInstance, oldInstance)
end
 
-- Deactivate the old libary if necessary
if type(oldDeactivate) == "function" then
local major, minor = oldInstance:GetVersion()
table.insert(self.log, string.format("Deactivate: %s, %s", major, minor))
oldDeactivate(oldInstance, newInstance)
end
 
-- Re-use the old table, and discard the new one
if not skipCopy then
NilCopyTable(newInstance, oldInstance)
end
return oldInstance
end
 
function lib:GetVersion() return major,minor end
 
local function Activate(new, old)
-- This code ensures that we'll move the versions table even
-- if the major version names are different, in the case of
-- DongleStub
if not old then old = g.DongleStub end
 
if old then
new.versions = old.versions
new.log = old.log
end
g.DongleStub = new
end
 
-- Actually trigger libary activation here
local stub = g.DongleStub or lib
lib = stub:Register(lib, Activate)
end
 
--[[-------------------------------------------------------------------------
Begin Library Implementation
---------------------------------------------------------------------------]]
 
local major = "Dongle-1.0"
local minor = tonumber(string.match("$Revision: 629 $", "(%d+)") or 1) + 500
-- ** IMPORTANT NOTE **
-- Due to some issues we had previously with Dongle revision numbers
-- we need to artificially inflate the minor revision number, to ensure
-- we load sequentially.
 
assert(DongleStub, string.format("%s requires DongleStub.", major))
 
if not DongleStub:IsNewerVersion(major, minor) then return end
 
local Dongle = {}
local methods = {
"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents", "IsEventRegistered",
"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages", "TriggerMessage", "IsMessageRegistered",
"EnableDebug", "IsDebugEnabled", "Print", "PrintF", "Debug", "DebugF", "Echo", "EchoF",
"InitializeDB",
"InitializeSlashCommand",
"NewModule", "HasModule", "IterateModules",
}
 
local registry = {}
local lookup = {}
local loadqueue = {}
local loadorder = {}
local events = {}
local databases = {}
local commands = {}
local messages = {}
 
local frame
 
--[[-------------------------------------------------------------------------
Message Localization
---------------------------------------------------------------------------]]
 
local L = {
["ADDMESSAGE_REQUIRED"] = "The frame you specify must have an 'AddMessage' method.",
["ALREADY_REGISTERED"] = "A Dongle with the name '%s' is already registered.",
["BAD_ARGUMENT"] = "bad argument #%d to '%s' (%s expected, got %s)",
["BAD_ARGUMENT_DB"] = "bad argument #%d to '%s' (DongleDB expected)",
["CANNOT_DELETE_ACTIVE_PROFILE"] = "You cannot delete your active profile. Change profiles, then attempt to delete.",
["DELETE_NONEXISTANT_PROFILE"] = "You cannot delete a non-existant profile.",
["MUST_CALLFROM_DBOBJECT"] = "You must call '%s' from a Dongle database object.",
["MUST_CALLFROM_REGISTERED"] = "You must call '%s' from a registered Dongle.",
["MUST_CALLFROM_SLASH"] = "You must call '%s' from a Dongle slash command object.",
["PROFILE_DOES_NOT_EXIST"] = "Profile '%s' doesn't exist.",
["REPLACE_DEFAULTS"] = "You are attempting to register defaults with a database that already contains defaults.",
["SAME_SOURCE_DEST"] = "Source/Destination profile cannot be the same profile.",
["EVENT_REGISTER_SPECIAL"] = "You cannot register for the '%s' event. Use the '%s' method instead.",
["Unknown"] = "Unknown",
["INJECTDB_USAGE"] = "Usage: DongleCmd:InjectDBCommands(db, ['copy', 'delete', 'list', 'reset', 'set'])",
["DBSLASH_PROFILE_COPY_DESC"] = "profile copy <name> - Copies profile <name> into your current profile.",
["DBSLASH_PROFILE_COPY_PATTERN"] = "^profile copy (.+)$",
["DBSLASH_PROFILE_DELETE_DESC"] = "profile delete <name> - Deletes the profile <name>.",
["DBSLASH_PROFILE_DELETE_PATTERN"] = "^profile delete (.+)$",
["DBSLASH_PROFILE_LIST_DESC"] = "profile list - Lists all valid profiles.",
["DBSLASH_PROFILE_LIST_PATTERN"] = "^profile list$",
["DBSLASH_PROFILE_RESET_DESC"] = "profile reset - Resets the current profile.",
["DBSLASH_PROFILE_RESET_PATTERN"] = "^profile reset$",
["DBSLASH_PROFILE_SET_DESC"] = "profile set <name> - Sets the current profile to <name>.",
["DBSLASH_PROFILE_SET_PATTERN"] = "^profile set (.+)$",
["DBSLASH_PROFILE_LIST_OUT"] = "Profile List:",
}
 
--[[-------------------------------------------------------------------------
Utility functions for Dongle use
---------------------------------------------------------------------------]]
 
local function assert(level,condition,message)
if not condition then
error(message,level)
end
end
 
local function argcheck(value, num, ...)
if type(num) ~= "number" then
error(L["BAD_ARGUMENT"]:format(2, "argcheck", "number", type(num)), 1)
end
 
for i=1,select("#", ...) do
if type(value) == select(i, ...) then return end
end
 
local types = strjoin(", ", ...)
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
error(L["BAD_ARGUMENT"]:format(num, name, types, type(value)), 3)
end
 
local function safecall(func,...)
local success,err = pcall(func,...)
if not success then
geterrorhandler()(err)
end
end
 
--[[-------------------------------------------------------------------------
Dongle constructor, and DongleModule system
---------------------------------------------------------------------------]]
 
function Dongle:New(name, obj)
argcheck(name, 2, "string")
argcheck(obj, 3, "table", "nil")
 
if not obj then
obj = {}
end
 
if registry[name] then
error(string.format(L["ALREADY_REGISTERED"], name))
end
 
local reg = {["obj"] = obj, ["name"] = name}
 
registry[name] = reg
lookup[obj] = reg
lookup[name] = reg
 
for k,v in pairs(methods) do
obj[v] = self[v]
end
 
-- Add this Dongle to the end of the queue
table.insert(loadqueue, obj)
return obj,name
end
 
function Dongle:NewModule(name, obj)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "NewModule"))
argcheck(name, 2, "string")
argcheck(obj, 3, "table", "nil")
 
obj,name = Dongle:New(name, obj)
 
if not reg.modules then reg.modules = {} end
reg.modules[obj] = obj
reg.modules[name] = obj
 
return obj,name
end
 
function Dongle:HasModule(module)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "HasModule"))
argcheck(module, 2, "string", "table")
 
return reg.modules and reg.modules[module]
end
 
local function ModuleIterator(t, name)
if not t then return end
local obj
repeat
name,obj = next(t, name)
until type(name) == "string" or not name
 
return name,obj
end
 
function Dongle:IterateModules()
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "IterateModules"))
 
return ModuleIterator, reg.modules
end
 
--[[-------------------------------------------------------------------------
Event registration system
---------------------------------------------------------------------------]]
 
local function OnEvent(frame, event, ...)
local eventTbl = events[event]
if eventTbl then
for obj,func in pairs(eventTbl) do
if type(func) == "string" then
if type(obj[func]) == "function" then
safecall(obj[func], obj, event, ...)
end
else
safecall(func, event, ...)
end
end
end
end
 
local specialEvents = {
["PLAYER_LOGIN"] = "Enable",
["PLAYER_LOGOUT"] = "Disable",
}
 
function Dongle:RegisterEvent(event, func)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "RegisterEvent"))
argcheck(event, 2, "string")
argcheck(func, 3, "string", "function", "nil")
 
local special = (self ~= Dongle) and specialEvents[event]
if special then
error(string.format(L["EVENT_REGISTER_SPECIAL"], event, special), 3)
end
 
-- Name the method the same as the event if necessary
if not func then func = event end
 
if not events[event] then
events[event] = {}
frame:RegisterEvent(event)
end
events[event][self] = func
end
 
function Dongle:UnregisterEvent(event)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "UnregisterEvent"))
argcheck(event, 2, "string")
 
local tbl = events[event]
if tbl then
tbl[self] = nil
if not next(tbl) then
events[event] = nil
frame:UnregisterEvent(event)
end
end
end
 
function Dongle:UnregisterAllEvents()
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "UnregisterAllEvents"))
 
for event,tbl in pairs(events) do
tbl[self] = nil
if not next(tbl) then
events[event] = nil
frame:UnregisterEvent(event)
end
end
end
 
function Dongle:IsEventRegistered(event)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "IsEventRegistered"))
argcheck(event, 2, "string")
 
local tbl = events[event]
return tbl
end
 
--[[-------------------------------------------------------------------------
Inter-Addon Messaging System
---------------------------------------------------------------------------]]
 
function Dongle:RegisterMessage(msg, func)
argcheck(self, 1, "table")
argcheck(msg, 2, "string")
argcheck(func, 3, "string", "function", "nil")
 
-- Name the method the same as the message if necessary
if not func then func = msg end
 
if not messages[msg] then
messages[msg] = {}
end
messages[msg][self] = func
end
 
function Dongle:UnregisterMessage(msg)
argcheck(self, 1, "table")
argcheck(msg, 2, "string")
 
local tbl = messages[msg]
if tbl then
tbl[self] = nil
if not next(tbl) then
messages[msg] = nil
end
end
end
 
function Dongle:UnregisterAllMessages()
argcheck(self, 1, "table")
 
for msg,tbl in pairs(messages) do
tbl[self] = nil
if not next(tbl) then
messages[msg] = nil
end
end
end
 
function Dongle:TriggerMessage(msg, ...)
argcheck(self, 1, "table")
argcheck(msg, 2, "string")
local msgTbl = messages[msg]
if not msgTbl then return end
 
for obj,func in pairs(msgTbl) do
if type(func) == "string" then
if type(obj[func]) == "function" then
safecall(obj[func], obj, msg, ...)
end
else
safecall(func, msg, ...)
end
end
end
 
function Dongle:IsMessageRegistered(msg)
argcheck(self, 1, "table")
argcheck(msg, 2, "string")
 
local tbl = messages[msg]
return tbl[self]
end
 
--[[-------------------------------------------------------------------------
Debug and Print utility functions
---------------------------------------------------------------------------]]
 
function Dongle:EnableDebug(level, frame)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "EnableDebug"))
argcheck(level, 2, "number", "nil")
argcheck(frame, 3, "table", "nil")
 
assert(3, type(frame) == "nil" or type(frame.AddMessage) == "function", L["ADDMESSAGE_REQUIRED"])
reg.debugFrame = frame or ChatFrame1
reg.debugLevel = level
end
 
function Dongle:IsDebugEnabled()
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "EnableDebug"))
 
return reg.debugLevel, reg.debugFrame
end
 
local function argsToStrings(a1, ...)
if select("#", ...) > 0 then
return tostring(a1), argsToStrings(...)
else
return tostring(a1)
end
end
 
local function printHelp(obj, method, header, frame, msg, ...)
local reg = lookup[obj]
assert(4, reg, string.format(L["MUST_CALLFROM_REGISTERED"], method))
 
local name = reg.name
 
if header then
msg = "|cFF33FF99"..name.."|r: "..tostring(msg)
end
 
if select("#", ...) > 0 then
msg = string.join(", ", msg, argsToStrings(...))
end
 
frame:AddMessage(msg)
end
 
local function printFHelp(obj, method, header, frame, msg, ...)
local reg = lookup[obj]
assert(4, reg, string.format(L["MUST_CALLFROM_REGISTERED"], method))
 
local name = reg.name
local success,txt
 
if header then
msg = "|cFF33FF99%s|r: " .. msg
success,txt = pcall(string.format, msg, name, ...)
else
success,txt = pcall(string.format, msg, ...)
end
 
if success then
frame:AddMessage(txt)
else
error(string.gsub(txt, "'%?'", string.format("'%s'", method)), 3)
end
end
 
function Dongle:Print(msg, ...)
local reg = lookup[self]
assert(1, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "Print"))
argcheck(msg, 2, "number", "string", "boolean", "table", "function", "thread", "userdata")
return printHelp(self, "Print", true, DEFAULT_CHAT_FRAME, msg, ...)
end
 
function Dongle:PrintF(msg, ...)
local reg = lookup[self]
assert(1, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "PrintF"))
argcheck(msg, 2, "number", "string", "boolean", "table", "function", "thread", "userdata")
return printFHelp(self, "PrintF", true, DEFAULT_CHAT_FRAME, msg, ...)
end
 
function Dongle:Echo(msg, ...)
local reg = lookup[self]
assert(1, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "Echo"))
argcheck(msg, 2, "number", "string", "boolean", "table", "function", "thread", "userdata")
return printHelp(self, "Echo", false, DEFAULT_CHAT_FRAME, msg, ...)
end
 
function Dongle:EchoF(msg, ...)
local reg = lookup[self]
assert(1, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "EchoF"))
argcheck(msg, 2, "number", "string", "boolean", "table", "function", "thread", "userdata")
return printFHelp(self, "EchoF", false, DEFAULT_CHAT_FRAME, msg, ...)
end
 
function Dongle:Debug(level, ...)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "Debug"))
argcheck(level, 2, "number")
 
if reg.debugLevel and level <= reg.debugLevel then
printHelp(self, "Debug", true, reg.debugFrame, ...)
end
end
 
function Dongle:DebugF(level, ...)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "DebugF"))
argcheck(level, 2, "number")
 
if reg.debugLevel and level <= reg.debugLevel then
printFHelp(self, "DebugF", true, reg.debugFrame, ...)
end
end
 
--[[-------------------------------------------------------------------------
Database System
---------------------------------------------------------------------------]]
 
local dbMethods = {
"RegisterDefaults", "SetProfile", "GetProfiles", "DeleteProfile", "CopyProfile",
"GetCurrentProfile", "ResetProfile", "ResetDB",
"RegisterNamespace",
}
 
local function copyTable(src)
local dest = {}
for k,v in pairs(src) do
if type(k) == "table" then
k = copyTable(k)
end
if type(v) == "table" then
v = copyTable(v)
end
dest[k] = v
end
return dest
end
 
local function copyDefaults(dest, src, force)
for k,v in pairs(src) do
if k == "*" then
if type(v) == "table" then
-- Values are tables, need some magic here
local mt = {
__cache = {},
__index = function(t,k)
local mt = getmetatable(dest)
local cache = rawget(mt, "__cache")
local tbl = rawget(cache, k)
if not tbl then
local parent = t
local parentkey = k
tbl = copyTable(v)
rawset(cache, k, tbl)
local mt = getmetatable(tbl)
if not mt then
mt = {}
setmetatable(tbl, mt)
end
local newindex = function(t,k,v)
rawset(parent, parentkey, t)
rawset(t, k, v)
end
rawset(mt, "__newindex", newindex)
end
return tbl
end,
}
setmetatable(dest, mt)
-- Now need to set the metatable on any child tables
for dkey,dval in pairs(dest) do
copyDefaults(dval, v)
end
else
-- Values are not tables, so this is just a simple return
local mt = {__index = function() return v end}
setmetatable(dest, mt)
end
elseif type(v) == "table" then
if not dest[k] then dest[k] = {} end
copyDefaults(dest[k], v, force)
else
if (dest[k] == nil) or force then
dest[k] = v
end
end
end
end
 
local function removeDefaults(db, defaults)
if not db then return end
for k,v in pairs(defaults) do
if k == "*" and type(v) == "table" then
-- check for any defaults that have been changed
local mt = getmetatable(db)
local cache = rawget(mt, "__cache")
 
for cacheKey,cacheValue in pairs(cache) do
removeDefaults(cacheValue, v)
if next(cacheValue) ~= nil then
-- Something's changed
rawset(db, cacheKey, cacheValue)
end
end
-- Now loop through all the actual k,v pairs and remove
for key,value in pairs(db) do
removeDefaults(value, v)
end
elseif type(v) == "table" and db[k] then
removeDefaults(db[k], v)
if not next(db[k]) then
db[k] = nil
end
else
if db[k] == defaults[k] then
db[k] = nil
end
end
end
end
 
local function initSection(db, section, svstore, key, defaults)
local sv = rawget(db, "sv")
 
local tableCreated
if not sv[svstore] then sv[svstore] = {} end
if not sv[svstore][key] then
sv[svstore][key] = {}
tableCreated = true
end
 
local tbl = sv[svstore][key]
 
if defaults then
copyDefaults(tbl, defaults)
end
rawset(db, section, tbl)
 
return tableCreated, tbl
end
 
local dbmt = {
__index = function(t, section)
local keys = rawget(t, "keys")
local key = keys[section]
if key then
local defaultTbl = rawget(t, "defaults")
local defaults = defaultTbl and defaultTbl[section]
 
if section == "profile" then
local new = initSection(t, section, "profiles", key, defaults)
if new then
Dongle:TriggerMessage("DONGLE_PROFILE_CREATED", t, rawget(t, "parent"), rawget(t, "sv_name"), key)
end
elseif section == "profiles" then
local sv = rawget(t, "sv")
if not sv.profiles then sv.profiles = {} end
rawset(t, "profiles", sv.profiles)
elseif section == "global" then
local sv = rawget(t, "sv")
if not sv.global then sv.global = {} end
if defaults then
copyDefaults(sv.global, defaults)
end
rawset(t, section, sv.global)
else
initSection(t, section, section, key, defaults)
end
end
 
return rawget(t, section)
end
}
 
local function initdb(parent, name, defaults, defaultProfile, olddb)
-- This allows us to use an arbitrary table as base instead of saved variable name
local sv
if type(name) == "string" then
sv = getglobal(name)
if not sv then
sv = {}
setglobal(name, sv)
end
elseif type(name) == "table" then
sv = name
end
 
-- Generate the database keys for each section
local char = string.format("%s - %s", UnitName("player"), GetRealmName())
local realm = GetRealmName()
local class = select(2, UnitClass("player"))
local race = select(2, UnitRace("player"))
local faction = UnitFactionGroup("player")
local factionrealm = string.format("%s - %s", faction, realm)
 
-- Make a container for profile keys
if not sv.profileKeys then sv.profileKeys = {} end
 
-- Try to get the profile selected from the char db
local profileKey = sv.profileKeys[char] or defaultProfile or char
sv.profileKeys[char] = profileKey
 
local keyTbl= {
["char"] = char,
["realm"] = realm,
["class"] = class,
["race"] = race,
["faction"] = faction,
["factionrealm"] = factionrealm,
["global"] = true,
["profile"] = profileKey,
["profiles"] = true, -- Don't create until we need
}
 
-- If we've been passed an old database, clear it out
if olddb then
for k,v in pairs(olddb) do olddb[k] = nil end
end
 
-- Give this database the metatable so it initializes dynamically
local db = setmetatable(olddb or {}, dbmt)
 
-- Copy methods locally
for idx,method in pairs(dbMethods) do
db[method] = Dongle[method]
end
 
-- Set some properties in the object we're returning
db.profiles = sv.profiles
db.keys = keyTbl
db.sv = sv
db.sv_name = name
db.defaults = defaults
db.parent = parent
 
databases[db] = true
 
return db
end
 
function Dongle:InitializeDB(name, defaults, defaultProfile)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "InitializeDB"))
argcheck(name, 2, "string", "table")
argcheck(defaults, 3, "table", "nil")
argcheck(defaultProfile, 4, "string", "nil")
 
return initdb(self, name, defaults, defaultProfile)
end
 
-- This function operates on a Dongle DB object
function Dongle.RegisterDefaults(db, defaults)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "RegisterDefaults"))
assert(3, db.defaults == nil, L["REPLACE_DEFAUTS"])
argcheck(defaults, 2, "table")
 
for section,key in pairs(db.keys) do
if defaults[section] and rawget(db, section) then
copyDefaults(db[section], defaults[section])
end
end
 
db.defaults = defaults
end
 
function Dongle:ClearDBDefaults()
for db in pairs(databases) do
local defaults = db.defaults
local sv = db.sv
 
if db and defaults then
for section,key in pairs(db.keys) do
if defaults[section] and rawget(db, section) then
removeDefaults(db[section], defaults[section])
end
end
 
for section,key in pairs(db.keys) do
local tbl = rawget(db, section)
if tbl and not next(tbl) then
if sv[section] then
if type(key) == "string" then
sv[section][key] = nil
else
sv[section] = nil
end
end
end
end
end
end
end
 
function Dongle.SetProfile(db, name)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "SetProfile"))
argcheck(name, 2, "string")
 
local old = db.profile
local defaults = db.defaults and db.defaults.profile
 
if defaults then
-- Remove the defaults from the old profile
removeDefaults(old, defaults)
end
 
db.profile = nil
db.keys["profile"] = name
db.sv.profileKeys[db.keys.char] = name
 
Dongle:TriggerMessage("DONGLE_PROFILE_CHANGED", db, db.parent, db.sv_name, db.keys.profile)
end
 
function Dongle.GetProfiles(db, t)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "GetProfiles"))
argcheck(t, 2, "table", "nil")
 
t = t or {}
local i = 1
for profileKey in pairs(db.sv.profiles) do
t[i] = profileKey
i = i + 1
end
return t, i - 1
end
 
function Dongle.GetCurrentProfile(db)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "GetCurrentProfile"))
return db.keys.profile
end
 
function Dongle.DeleteProfile(db, name)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "DeleteProfile"))
argcheck(name, 2, "string")
 
if db.keys.profile == name then
error(L["CANNOT_DELETE_ACTIVE_PROFILE"], 2)
end
 
assert(type(db.sv.profiles[name]) == "table", L["DELETE_NONEXISTANT_PROFILE"])
 
db.sv.profiles[name] = nil
Dongle:TriggerMessage("DONGLE_PROFILE_DELETED", db, db.parent, db.sv_name, name)
end
 
function Dongle.CopyProfile(db, name)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "CopyProfile"))
argcheck(name, 2, "string")
 
assert(3, db.keys.profile ~= name, L["SAME_SOURCE_DEST"])
assert(3, type(db.sv.profiles[name]) == "table", string.format(L["PROFILE_DOES_NOT_EXIST"], name))
 
local profile = db.profile
local source = db.sv.profiles[name]
 
copyDefaults(profile, source, true)
Dongle:TriggerMessage("DONGLE_PROFILE_COPIED", db, db.parent, db.sv_name, name, db.keys.profile)
end
 
function Dongle.ResetProfile(db)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "ResetProfile"))
 
local profile = db.profile
 
for k,v in pairs(profile) do
profile[k] = nil
end
 
local defaults = db.defaults and db.defaults.profile
if defaults then
copyDefaults(profile, defaults)
end
Dongle:TriggerMessage("DONGLE_PROFILE_RESET", db, db.parent, db.sv_name, db.keys.profile)
end
 
 
function Dongle.ResetDB(db, defaultProfile)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "ResetDB"))
argcheck(defaultProfile, 2, "nil", "string")
 
local sv = db.sv
for k,v in pairs(sv) do
sv[k] = nil
end
 
local parent = db.parent
 
initdb(parent, db.sv_name, db.defaults, defaultProfile, db)
Dongle:TriggerMessage("DONGLE_DATABASE_RESET", db, parent, db.sv_name, db.keys.profile)
Dongle:TriggerMessage("DONGLE_PROFILE_CHANGED", db, db.parent, db.sv_name, db.keys.profile)
return db
end
 
function Dongle.RegisterNamespace(db, name, defaults)
assert(3, databases[db], string.format(L["MUST_CALLFROM_DBOBJECT"], "RegisterNamespace"))
argcheck(name, 2, "string")
argcheck(defaults, 3, "nil", "string")
 
local sv = db.sv
if not sv.namespaces then sv.namespaces = {} end
if not sv.namespaces[name] then
sv.namespaces[name] = {}
end
 
local newDB = initdb(db, sv.namespaces[name], defaults, db.keys.profile)
-- Remove the :SetProfile method from newDB
newDB.SetProfile = nil
 
if not db.children then db.children = {} end
table.insert(db.children, newDB)
return newDB
end
 
--[[-------------------------------------------------------------------------
Slash Command System
---------------------------------------------------------------------------]]
 
local slashCmdMethods = {
"InjectDBCommands",
"RegisterSlashHandler",
"PrintUsage",
}
 
local function OnSlashCommand(cmd, cmd_line)
if cmd.patterns then
for idx,tbl in pairs(cmd.patterns) do
local pattern = tbl.pattern
if string.match(cmd_line, pattern) then
local handler = tbl.handler
if type(tbl.handler) == "string" then
local obj
-- Look in the command object before we look at the parent object
if cmd[handler] then obj = cmd end
if cmd.parent[handler] then obj = cmd.parent end
if obj then
obj[handler](obj, string.match(cmd_line, pattern))
end
else
handler(string.match(cmd_line, pattern))
end
return
end
end
end
cmd:PrintUsage()
end
 
function Dongle:InitializeSlashCommand(desc, name, ...)
local reg = lookup[self]
assert(3, reg, string.format(L["MUST_CALLFROM_REGISTERED"], "InitializeSlashCommand"))
argcheck(desc, 2, "string")
argcheck(name, 3, "string")
argcheck(select(1, ...), 4, "string")
for i = 2,select("#", ...) do
argcheck(select(i, ...), i+2, "string")
end
 
local cmd = {}
cmd.desc = desc
cmd.name = name
cmd.parent = self
cmd.slashes = { ... }
for idx,method in pairs(slashCmdMethods) do
cmd[method] = Dongle[method]
end
 
local genv = getfenv(0)
 
for i = 1,select("#", ...) do
genv["SLASH_"..name..tostring(i)] = "/"..select(i, ...)
end
 
genv.SlashCmdList[name] = function(...) OnSlashCommand(cmd, ...) end
 
commands[cmd] = true
 
return cmd
end
 
function Dongle.RegisterSlashHandler(cmd, desc, pattern, handler)
assert(3, commands[cmd], string.format(L["MUST_CALLFROM_SLASH"], "RegisterSlashHandler"))
 
argcheck(desc, 2, "string")
argcheck(pattern, 3, "string")
argcheck(handler, 4, "function", "string")
 
if not cmd.patterns then
cmd.patterns = {}
end
 
table.insert(cmd.patterns, {
["desc"] = desc,
["handler"] = handler,
["pattern"] = pattern,
})
end
 
function Dongle.PrintUsage(cmd)
assert(3, commands[cmd], string.format(L["MUST_CALLFROM_SLASH"], "PrintUsage"))
local parent = cmd.parent
 
parent:Echo(cmd.desc.."\n".."/"..table.concat(cmd.slashes, ", /")..":\n")
if cmd.patterns then
for idx,tbl in ipairs(cmd.patterns) do
parent:Echo(" - " .. tbl.desc)
end
end
end
 
local dbcommands = {
["copy"] = {
L["DBSLASH_PROFILE_COPY_DESC"],
L["DBSLASH_PROFILE_COPY_PATTERN"],
"CopyProfile",
},
["delete"] = {
L["DBSLASH_PROFILE_DELETE_DESC"],
L["DBSLASH_PROFILE_DELETE_PATTERN"],
"DeleteProfile",
},
["list"] = {
L["DBSLASH_PROFILE_LIST_DESC"],
L["DBSLASH_PROFILE_LIST_PATTERN"],
},
["reset"] = {
L["DBSLASH_PROFILE_RESET_DESC"],
L["DBSLASH_PROFILE_RESET_PATTERN"],
"ResetProfile",
},
["set"] = {
L["DBSLASH_PROFILE_SET_DESC"],
L["DBSLASH_PROFILE_SET_PATTERN"],
"SetProfile",
},
}
 
function Dongle.InjectDBCommands(cmd, db, ...)
assert(3, commands[cmd], string.format(L["MUST_CALLFROM_SLASH"], "InjectDBCommands"))
assert(3, databases[db], string.format(L["BAD_ARGUMENT_DB"], 2, "InjectDBCommands"))
local argc = select("#", ...)
assert(3, argc > 0, L["INJECTDB_USAGE"])
 
for i=1,argc do
local cmdname = string.lower(select(i, ...))
local entry = dbcommands[cmdname]
assert(entry, L["INJECTDB_USAGE"])
local func = entry[3]
 
local handler
if cmdname == "list" then
handler = function(...)
local profiles = db:GetProfiles()
db.parent:Print(L["DBSLASH_PROFILE_LIST_OUT"] .. "\n" .. strjoin("\n", unpack(profiles)))
end
else
handler = function(...) db[entry[3]](db, ...) end
end
 
cmd:RegisterSlashHandler(entry[1], entry[2], handler)
end
end
 
--[[-------------------------------------------------------------------------
Internal Message/Event Handlers
---------------------------------------------------------------------------]]
 
local function PLAYER_LOGOUT(event)
Dongle:ClearDBDefaults()
for k,v in pairs(registry) do
local obj = v.obj
if type(obj["Disable"]) == "function" then
safecall(obj["Disable"], obj)
end
end
end
 
local PLAYER_LOGIN
do
local lockPlayerLogin = false
 
function PLAYER_LOGIN()
if lockPlayerLogin then return end
 
lockPlayerLogin = true
 
local obj = table.remove(loadorder, 1)
while obj do
if type(obj.Enable) == "function" then
safecall(obj.Enable, obj)
end
obj = table.remove(loadorder, 1)
end
 
lockPlayerLogin = false
end
end
 
local function ADDON_LOADED(event, ...)
local obj = table.remove(loadqueue, 1)
while obj do
table.insert(loadorder, obj)
 
if type(obj.Initialize) == "function" then
safecall(obj.Initialize, obj)
end
 
obj = table.remove(loadqueue, 1)
end
 
if IsLoggedIn() then
PLAYER_LOGIN()
end
end
 
local function DONGLE_PROFILE_CHANGED(msg, db, parent, sv_name, profileKey)
local children = db.children
if children then
for i,namespace in ipairs(children) do
local old = namespace.profile
local defaults = namespace.defaults and namespace.defaults.profile
 
if defaults then
-- Remove the defaults from the old profile
removeDefaults(old, defaults)
end
 
namespace.profile = nil
namespace.keys["profile"] = profileKey
end
end
end
 
--[[-------------------------------------------------------------------------
DongleStub required functions and registration
---------------------------------------------------------------------------]]
 
function Dongle:GetVersion() return major,minor end
 
local function Activate(self, old)
if old then
registry = old.registry or registry
lookup = old.lookup or lookup
loadqueue = old.loadqueue or loadqueue
loadorder = old.loadorder or loadorder
events = old.events or events
databases = old.databases or databases
commands = old.commands or commands
messages = old.messages or messages
frame = old.frame or CreateFrame("Frame")
else
frame = CreateFrame("Frame")
local reg = {obj = self, name = "Dongle"}
registry[major] = reg
lookup[self] = reg
lookup[major] = reg
end
 
self.registry = registry
self.lookup = lookup
self.loadqueue = loadqueue
self.loadorder = loadorder
self.events = events
self.databases = databases
self.commands = commands
self.messages = messages
self.frame = frame
 
frame:SetScript("OnEvent", OnEvent)
 
local lib = old or self
 
-- Lets make sure the lookup table has us.
lookup[lib] = lookup[major]
 
-- Register for events using Dongle itself
lib:RegisterEvent("ADDON_LOADED", ADDON_LOADED)
lib:RegisterEvent("PLAYER_LOGIN", PLAYER_LOGIN)
lib:RegisterEvent("PLAYER_LOGOUT", PLAYER_LOGOUT)
lib:RegisterMessage("DONGLE_PROFILE_CHANGED", DONGLE_PROFILE_CHANGED)
 
-- Convert all the modules handles
for name,obj in pairs(registry) do
for k,v in ipairs(methods) do
obj[k] = self[v]
end
end
 
-- Convert all database methods
for db in pairs(databases) do
for idx,method in ipairs(dbMethods) do
db[method] = self[method]
end
end
 
-- Convert all slash command methods
for cmd in pairs(commands) do
for idx,method in ipairs(slashCmdMethods) do
cmd[method] = self[method]
end
end
end
 
-- Lets nuke any Dongle deactivate functions, please
-- I hate nasty hacks.
if DongleStub.versions and DongleStub.versions[major] then
local reg = DongleStub.versions[major]
reg.deactivate = nil
end
 
Dongle = DongleStub:Register(Dongle, Activate)
Property changes : Added: svn:mime-type + text/plain Added: svn:eol-style + native
branches/LootTracker-Rewrite-Ace3/libs/OptionHouse.lua New file
0,0 → 1,1451
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
-- LibStub is hereby placed in the Public Domain
-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local LibStub = _G[LIBSTUB_MAJOR]
 
-- Check to see is this version of the stub is obsolete
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
 
-- LibStub:NewLibrary(major, minor)
-- major (string) - the major version of the library
-- minor (string or number ) - the minor version of the library
--
-- returns nil if a newer or same version of the lib is already present
-- returns empty library object or old library object if upgrade is needed
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
 
local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
return self.libs[major], oldminor
end
 
-- LibStub:GetLibrary(major, [silent])
-- major (string) - the major version of the library
-- silent (boolean) - if true, library is optional, silently return nil if its not found
--
-- throws an error if the library can not be found (except silent is set)
-- returns the library object if found
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
 
-- LibStub:IterateLibraries()
--
-- Returns an iterator for the currently registered libraries
function LibStub:IterateLibraries()
return pairs(self.libs)
end
 
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
 
--[[-------------------------------------------------------------------------
Copyright (c) 2006-2007, Dongle Development Team
All rights reserved.
 
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
 
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the Dongle Development Team nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------]]
 
--[[-------------------------------------------------------------------------
Begin Library Implementation
---------------------------------------------------------------------------]]
local major = "OptionHouse-1.1"
local minor = tonumber(string.match("$Revision: 638 $", "(%d+)") or 1)
 
assert(LibStub, string.format("%s requires LibStub.", major))
 
local OHInstance, oldRevision = LibStub:NewLibrary(major, minor)
if( not OHInstance ) then return end
 
local L = {
["ERROR_NO_FRAME"] = "No frame returned for the addon \"%s\", category \"%s\", sub category \"%s\".",
["NO_FUNC_PASSED"] = "You must associate a function with a category.",
["BAD_ARGUMENT"] = "bad argument #%d to '%s' (%s expected, got %s)",
["MUST_CALL"] = "You must call '%s' from an OptionHouse addon object.",
["ADDON_ALREADYREG"] = "The addon '%s' is already registered with OptionHouse.",
["UNKNOWN_TAB"] = "Cannot open tab #%d, only %d tabs are registered.",
["CATEGORY_ALREADYREG"] = "The category '%s' already exists in '%s'",
["NO_CATEGORYEXISTS"] = "No category named '%s' in '%s' exists.",
["NO_SUBCATEXISTS"] = "No sub-category '%s' exists in '%s' for the addon '%s'.",
["NO_PARENTCAT"] = "No parent category named '%s' exists in %s'",
["SUBCATEGORY_ALREADYREG"] = "The sub-category named '%s' already exists in the category '%s' for '%s'",
["UNKNOWN_FRAMETYPE"] = "Unknown frame type given '%s', only 'main', 'perf', 'addon', 'config' are supported.",
["OPTION_HOUSE"] = "OptionHouse",
["ENTERED_COMBAT"] = "|cFF33FF99OptionHouse|r: Configuration window closed due to entering combat.",
["IN_COMBAT"] = "|cFF33FF99OptionHouse|r: Configuration window cannot be opened while in combat.",
["SEARCH"] = "Search...",
["ADDON_OPTIONS"] = "Addons",
["VERSION"] = "Version: %s",
["AUTHOR"] = "Author: %s",
["TOTAL_SUBCATEGORIES"] = "Sub Categories: %d",
["TAB_MANAGEMENT"] = "Management",
["TAB_PERFORMANCE"] = "Performance",
}
 
local function assert(level,condition,message)
if( not condition ) then
error(message,level)
end
end
 
local function argcheck(value, num, ...)
if( type(num) ~= "number" ) then
error(L["BAD_ARGUMENT"]:format(2, "argcheck", "number", type(num)), 1)
end
 
for i=1,select("#", ...) do
if( type(value) == select(i, ...) ) then return end
end
 
local types = string.join(", ", ...)
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]")
error(L["BAD_ARGUMENT"]:format(num, name, types, type(value)), 3)
end
 
-- OptionHouse
local OptionHouse = {}
local tabfunctions = {}
local methods = {"RegisterCategory", "RegisterSubCategory", "RemoveCategory", "RemoveSubCategory"}
local addons = {}
local regFrames = {}
local openedByMenu
local evtFrame
local frame
 
-- TABS
local function resizeTab(tab)
local textWidth = tab:GetFontString():GetWidth()
 
tab.middleActive:SetWidth(textWidth)
tab.middleInactive:SetWidth(textWidth)
 
tab:SetWidth((2 * tab.leftActive:GetWidth()) + textWidth)
tab.highlightTexture:SetWidth(textWidth + 20)
end
 
local function tabSelected(tab)
tab:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
tab.highlightTexture:Hide()
 
tab.leftActive:Show()
tab.middleActive:Show()
tab.rightActive:Show()
 
tab.leftInactive:Hide()
tab.middleInactive:Hide()
tab.rightInactive:Hide()
end
 
local function tabDeselected(tab)
tab:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
tab.highlightTexture:Show()
 
tab.leftInactive:Show()
tab.middleInactive:Show()
tab.rightInactive:Show()
 
tab.leftActive:Hide()
tab.middleActive:Hide()
tab.rightActive:Hide()
end
 
local function setTab(id)
if( frame.selectedTab ) then
tabDeselected(frame.tabs[frame.selectedTab])
end
 
frame.selectedTab = id
tabSelected(frame.tabs[id])
end
 
local function tabOnClick(self)
local id
if( type(self) ~= "number" ) then
id = self:GetID()
else
id = self
end
 
setTab(id)
 
for tabID, tab in pairs(tabfunctions) do
if( tabID == id ) then
if( type(tab.func) == "function" ) then
tab.func()
else
tab.handler[tab.func](tab.handler)
end
 
if( tab.type == "browse" ) then
frame.topLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-TopLeft")
frame.top:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-Top")
frame.topRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-TopRight")
frame.bottomLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-BotLeft")
frame.bottom:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-Bot")
frame.bottomRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-BotRight")
elseif( tab.type == "bid" ) then
frame.topLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-TopLeft")
frame.top:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-Top")
frame.topRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-TopRight")
frame.bottomLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotLeft")
frame.bottom:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-Bot")
frame.bottomRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotRight")
end
 
elseif( type(tab.func) == "function" ) then
tab.func(true)
else
tab.handler[tab.func](tab.handler, true)
end
end
end
 
local function createTab(text, id)
local tab = frame.tabs[id]
if( not tab ) then
tab = CreateFrame("Button", nil, frame)
tab:SetHighlightFontObject(GameFontHighlightSmall)
tab:SetTextFontObject(GameFontNormalSmall)
tab:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
tab:SetText(text)
tab:SetWidth(115)
tab:SetHeight(32)
tab:SetID(id)
tab:SetScript("OnClick", tabOnClick)
tab:GetFontString():SetPoint("CENTER", 0, 2)
 
tab.highlightTexture = tab:GetHighlightTexture()
tab.highlightTexture:ClearAllPoints()
tab.highlightTexture:SetPoint("CENTER", tab:GetFontString(), 0, 0)
tab.highlightTexture:SetBlendMode("ADD")
 
-- TAB SELECTED TEXTURES
tab.leftActive = tab:CreateTexture(nil, "ARTWORK")
tab.leftActive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ActiveTab")
tab.leftActive:SetHeight(32)
tab.leftActive:SetWidth(20)
tab.leftActive:SetPoint("TOPLEFT", tab, "TOPLEFT")
tab.leftActive:SetTexCoord(0, 0.15625, 0, 1.0)
 
tab.middleActive = tab:CreateTexture(nil, "ARTWORK")
tab.middleActive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ActiveTab")
tab.middleActive:SetHeight(32)
tab.middleActive:SetWidth(20)
tab.middleActive:SetPoint("LEFT", tab.leftActive, "RIGHT")
tab.middleActive:SetTexCoord(0.15625, 0.84375, 0, 1.0)
 
tab.rightActive = tab:CreateTexture(nil, "ARTWORK")
tab.rightActive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ActiveTab")
tab.rightActive:SetHeight(32)
tab.rightActive:SetWidth(20)
tab.rightActive:SetPoint("LEFT", tab.middleActive, "RIGHT")
tab.rightActive:SetTexCoord(0.84375, 1.0, 0, 1.0)
 
-- TAB DESELECTED TEXTURES
tab.leftInactive = tab:CreateTexture(nil, "ARTWORK")
tab.leftInactive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-InActiveTab")
tab.leftInactive:SetHeight(32)
tab.leftInactive:SetWidth(20)
tab.leftInactive:SetPoint("TOPLEFT", tab, "TOPLEFT")
tab.leftInactive:SetTexCoord(0, 0.15625, 0, 1.0)
 
tab.middleInactive = tab:CreateTexture(nil, "ARTWORK")
tab.middleInactive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-InActiveTab")
tab.middleInactive:SetHeight(32)
tab.middleInactive:SetWidth(20)
tab.middleInactive:SetPoint("LEFT", tab.leftInactive, "RIGHT")
tab.middleInactive:SetTexCoord(0.15625, 0.84375, 0, 1.0)
 
tab.rightInactive = tab:CreateTexture(nil, "ARTWORK")
tab.rightInactive:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-InActiveTab")
tab.rightInactive:SetHeight(32)
tab.rightInactive:SetWidth(20)
tab.rightInactive:SetPoint("LEFT", tab.middleInactive, "RIGHT")
tab.rightInactive:SetTexCoord(0.84375, 1.0, 0, 1.0)
 
frame.totalTabs = frame.totalTabs + 1
frame.tabs[id] = tab
end
 
tab:SetText(text)
tab:Show()
 
tabDeselected(tab)
resizeTab(tab)
 
if( id == 1 ) then
tab:SetPoint("TOPLEFT", frame, "BOTTOMLEFT", 15, 11)
else
tab:SetPoint("TOPLEFT", frame.tabs[id - 1], "TOPRIGHT", -8, 0)
end
end
 
-- SCROLL FRAME
local function onVerticalScroll(self, offset)
offset = ceil(offset)
 
self.bar:SetValue(offset)
self.offset = ceil(offset / self.displayNum)
 
if( self.offset < 0 ) then
self.offset = 0
end
 
local min, max = self.bar:GetMinMaxValues()
 
if( min == offset ) then
self.up:Disable()
else
self.up:Enable()
end
 
if( max == offset ) then
self.down:Disable()
else
self.down:Enable()
end
 
self.updateFunc(self.updateHandler)
end
 
local function onMouseWheel(self, offset)
if( self.scroll ) then self = self.scroll end
if( offset > 0 ) then
self.bar:SetValue(self.bar:GetValue() - (self.bar:GetHeight() / 2))
else
self.bar:SetValue(self.bar:GetValue() + (self.bar:GetHeight() / 2))
end
end
 
local function onParentMouseWheel(self, offset)
onMouseWheel(self.scroll, offset)
end
 
local function updateScroll(scroll, totalRows)
local max = (totalRows - scroll.displayNum) * scroll.displayNum
 
-- Macs are unhappy if max is less then the min
if( max < 0 ) then
max = 0
end
 
scroll.bar:SetMinMaxValues(0, max)
 
if( totalRows > scroll.displayNum ) then
scroll:Show()
scroll.bar:Show()
scroll.up:Show()
scroll.down:Show()
scroll.bar:GetThumbTexture():Show()
else
scroll:Hide()
scroll.bar:Hide()
scroll.up:Hide()
scroll.down:Hide()
scroll.bar:GetThumbTexture():Hide()
end
end
 
local function onValueChanged(self, offset)
self:GetParent():SetVerticalScroll(offset)
end
 
local function scrollButtonUp(self)
local parent = self:GetParent()
parent:SetValue(parent:GetValue() - (parent:GetHeight() / 2))
PlaySound("UChatScrollButton")
end
 
local function scrollButtonDown(self)
local parent = self:GetParent()
parent:SetValue(parent:GetValue() + (parent:GetHeight() / 2))
PlaySound("UChatScrollButton")
end
 
local function createScrollFrame(frame, displayNum, onScroll)
frame:EnableMouseWheel(true)
frame:SetScript("OnMouseWheel", onParentMouseWheel)
 
frame.scroll = CreateFrame("ScrollFrame", nil, frame)
frame.scroll:EnableMouseWheel(true)
frame.scroll:SetWidth(16)
frame.scroll:SetHeight(270)
frame.scroll:SetScript("OnVerticalScroll", onVerticalScroll)
frame.scroll:SetScript("OnMouseWheel", onMouseWheel)
 
frame.scroll.offset = 0
frame.scroll.displayNum = displayNum
frame.scroll.updateHandler = frame
frame.scroll.updateFunc = onScroll
 
-- Actual bar for scrolling
frame.scroll.bar = CreateFrame("Slider", nil, frame.scroll)
frame.scroll.bar:SetValueStep(frame.scroll.displayNum)
frame.scroll.bar:SetMinMaxValues(0, 0)
frame.scroll.bar:SetValue(0)
frame.scroll.bar:SetWidth(16)
frame.scroll.bar:SetScript("OnValueChanged", onValueChanged)
frame.scroll.bar:SetPoint("TOPLEFT", frame.scroll, "TOPRIGHT", 6, -16)
frame.scroll.bar:SetPoint("BOTTOMLEFT", frame.scroll, "BOTTOMRIGHT", 6, -16)
 
-- Up/Down buttons
frame.scroll.up = CreateFrame("Button", nil, frame.scroll.bar, "UIPanelScrollUpButtonTemplate")
frame.scroll.up:ClearAllPoints()
frame.scroll.up:SetPoint( "BOTTOM", frame.scroll.bar, "TOP" )
frame.scroll.up:SetScript("OnClick", scrollButtonUp)
 
frame.scroll.down = CreateFrame("Button", nil, frame.scroll.bar, "UIPanelScrollDownButtonTemplate")
frame.scroll.down:ClearAllPoints()
frame.scroll.down:SetPoint( "TOP", frame.scroll.bar, "BOTTOM" )
frame.scroll.down:SetScript("OnClick", scrollButtonDown)
 
-- That square thingy that shows where the bar is
frame.scroll.bar:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
local thumb = frame.scroll.bar:GetThumbTexture()
 
thumb:SetHeight(16)
thumb:SetWidth(16)
thumb:SetTexCoord(0.25, 0.75, 0.25, 0.75)
 
-- Border graphic
frame.scroll.barUpTexture = frame.scroll:CreateTexture(nil, "BACKGROUND")
frame.scroll.barUpTexture:SetWidth(31)
frame.scroll.barUpTexture:SetHeight(256)
frame.scroll.barUpTexture:SetPoint("TOPLEFT", frame.scroll.up, "TOPLEFT", -7, 5)
frame.scroll.barUpTexture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ScrollBar")
frame.scroll.barUpTexture:SetTexCoord(0, 0.484375, 0, 1.0)
 
frame.scroll.barDownTexture = frame.scroll:CreateTexture(nil, "BACKGROUND")
frame.scroll.barDownTexture:SetWidth(31)
frame.scroll.barDownTexture:SetHeight(106)
frame.scroll.barDownTexture:SetPoint("BOTTOMLEFT", frame.scroll.down, "BOTTOMLEFT", -7, -3)
frame.scroll.barDownTexture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-ScrollBar")
frame.scroll.barDownTexture:SetTexCoord(0.515625, 1.0, 0, 0.4140625)
end
 
-- SEARCH INPUT
local function focusGained(self)
if( self.searchText ) then
self.searchText = nil
self:SetText("")
self:SetTextColor(1, 1, 1, 1)
end
end
 
local function focusLost(self)
if( not self.searchText and string.trim(self:GetText()) == "" ) then
self.searchText = true
self:SetText(L["SEARCH"])
self:SetTextColor(0.90, 0.90, 0.90, 0.80)
end
end
 
local function createSearchInput(frame, onChange)
frame.search = CreateFrame("EditBox", nil, frame, "InputBoxTemplate")
frame.search:SetHeight(19)
frame.search:SetWidth(150)
frame.search:SetAutoFocus(false)
frame.search:ClearAllPoints()
frame.search:SetPoint("CENTER", frame, "BOTTOMLEFT", 100, 25)
 
frame.search.searchText = true
frame.search:SetText(L["SEARCH"])
frame.search:SetTextColor(0.90, 0.90, 0.90, 0.80)
frame.search:SetScript("OnTextChanged", onChange)
frame.search:SetScript("OnEditFocusGained", focusGained)
frame.search:SetScript("OnEditFocusLost", focusLost)
end
 
-- ADDON CONFIGURATION
local function showTooltip(self)
if( self.tooltip ) then
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1)
end
end
 
local function hideTooltip()
GameTooltip:Hide()
end
 
local function sortCategories(a, b)
if( not b ) then
return false
end
 
local aType = type(a.data.sortID)
local bType = type(b.data.sortID)
 
-- Sort categories/sub categories
if( aType == "number" and bType == "number" ) then
if( a.data.sortID == b.data.sortID ) then
return ( a.name < b.name )
end
 
return ( a.data.sortID < b.data.sortID )
elseif( aType == "number" and bType ~= "number" ) then
return true
elseif( bType == "number" and aType ~= "number" ) then
return false
end
 
return ( a.name < b.name )
end
 
-- Adds the actual row, will attempt to reuse the current row if able to
local function addCategoryRow(type, name, tooltip, data, parent, addon)
local frame = regFrames.addon
for i=1, #(frame.categories) do
-- Match type/name first
if( frame.categories[i].type == type and frame.categories[i].name == name ) then
-- Then make sure it's correct addons parent, if it's a category
if( (parent and frame.categories[i].parent and frame.categories[i].parent == parent) or (not parent and not frame.categories[i].parent) ) then
-- Now make sure it's the correct addon if it's a sub category
if( (addon and frame.categories[i].addon and frame.categories[i].addon == addon) or (not addon and not frame.categories[i].addon) ) then
frame.categories[i].tooltip = tooltip
frame.categories[i].data = data
return
end
end
end
end
 
if( not data ) then
data = {}
end
 
if( type == "addon" ) then
data.sortID = name
elseif( not data.sortID ) then
data.sortID = 9999999
end
 
table.insert(frame.categories, {name = name, type = type, tooltip = tooltip, data = data, parent = parent, addon = addon} )
frame.resortList = true
end
 
-- This removes the entire addon, we don't use this unless
-- we're removing the last category
local function removeAddonListing(addon)
local frame = regFrames.addon
for i=#(frame.categories), 1, -1 do
if( frame.categories[i].addon == addon ) then
table.remove(frame.categories, i)
end
end
end
 
-- Remove a specific category and/or sub category listing
-- without needing to recreate the entire list
local function removeCategoryListing(addon, name)
local frame = regFrames.addon
for i=#(frame.categories), 1, -1 do
-- Remove the category requested
if( frame.categories[i].type == "category" and frame.categories[i].name == name and frame.categories[i].addon == addon ) then
table.remove(frame.categories, i)
 
-- Remove all of it's sub categories
elseif( frame.categories[i].type == "subcat" and frame.categories[i].parent == name and frame.categories[i].addon == addon ) then
table.remove(frame.categories, i)
end
end
end
 
local function removeSubCategoryListing(addon, parentCat, name)
local frame = regFrames.addon
for i=#(frame.categories), 1, -1 do
-- Remove the specific sub category
if( frame.categories[i].type == "subcat" and frame.categories[i].name == name and frame.categories[i].parent == parentCat and frame.categories[i].addon == addon ) then
table.remove(frame.categories, i)
end
end
end
 
-- We have a seperate function for adding addons
-- so we can update a single addon out of the entire list
-- if it's categories/sub categories get changed, or a new ones added
local function addCategoryListing(name, addon)
local tooltip = "|cffffffff" .. (addon.title or name) .. "|r"
local data
 
if( addon.version ) then
tooltip = tooltip .. "\n" .. string.format(L["VERSION"], addon.version)
end
 
if( addon.author ) then
tooltip = tooltip .. "\n" .. string.format(L["AUTHOR"], addon.author)
end
 
-- One category, make clicking the addon open that category
if( addon.totalCats == 1 and addon.totalSubs == 0 ) then
for catName, cat in pairs(addon.categories) do
data = cat
data.parentCat = catName
break
end
 
-- Multiple categories, or sub categories
else
for catName, cat in pairs(addon.categories) do
cat.parentCat = catName
addCategoryRow("category", catName, cat.totalSubs > 0 and string.format(L["TOTAL_SUBCATEGORIES"], cat.totalSubs), cat, name, name)
 
for subCatName, subCat in pairs(cat.sub) do
subCat.parentCat = catName
addCategoryRow("subcat", subCatName, nil, subCat, catName, name)
end
end
end
 
addCategoryRow("addon", name, (addon.version or addon.author) and tooltip, data, nil, name)
end
 
-- Recreates the entire listing
local function createCategoryListing()
regFrames.addon.categories = {}
 
for name, addon in pairs(addons) do
addCategoryListing(name, addon)
end
end
 
local function openConfigFrame(data)
local frame = regFrames.addon
 
-- Clicking on an addon with multiple categories or sub categories will cause no data
if( not data ) then
-- Make sure the frames hidden when only the addon button is selected
if( frame.shownFrame ) then
frame.shownFrame:Hide()
end
return
end
 
if( data.handler or data.func ) then
data.frame = nil
 
if( type(data.func) == "string" ) then
data.frame = data.handler[data.func](data.handler, data.parentCat or frame.selectedCategory, frame.selectedSubCat)
elseif( type(data.handler) == "function" ) then
data.frame = data.handler(data.parentCat or frame.selectedCategory, frame.selectedSubCat)
end
 
-- Mostly this is for authors, but it lets us clean up the logic a bit
if( not data.frame ) then
error(string.format(L["ERROR_NO_FRAME"], frame.selectedAddon, data.parentCat or frame.selectedCategory, frame.selectedSubCat), 3)
end
 
-- Validate location/width/height and force parent
if( not data.frame:GetPoint() ) then
data.frame:SetPoint("TOPLEFT", frame, "TOPLEFT", 190, -103)
end
 
if( data.frame:GetWidth() > 630 or data.frame:GetWidth() == 0 ) then
data.frame:SetWidth(630)
end
 
if( data.frame:GetHeight() > 305 or data.frame:GetHeight() == 0 ) then
data.frame:SetHeight(305)
end
 
data.frame:SetParent(frame)
data.frame:SetFrameStrata("DIALOG")
 
if( not data.noCache ) then
local category
 
-- Figure out which category we're modifying
if( frame.selectedSubCat ~= "" ) then
category = addons[frame.selectedAddon].categories[frame.selectedCategory].sub[frame.selectedSubCat]
elseif( frame.selectedCategory ~= "" ) then
category = addons[frame.selectedAddon].categories[frame.selectedCategory]
elseif( frame.selectedAddon ~= "" ) then
for catName, _ in pairs(addons[frame.selectedAddon].categories) do
category = addons[frame.selectedAddon].categories[catName]
end
end
 
-- Remove the handler/func and save the frame for next time
if( category ) then
category.handler = nil
category.func = nil
category.frame = data.frame
end
end
end
 
if( frame.shownFrame ) then
frame.shownFrame:Hide()
end
 
-- Now show the current one
if( data.frame and frame.selectedAddon ~= "" ) then
data.frame:Show()
frame.shownFrame = data.frame
end
end
 
-- Displays the actual button
local function displayCategoryRow(type, text, data, tooltip, highlighted)
local frame = regFrames.addon
 
-- We have to let this run completely
-- so we know how many rows we have total
frame.totalRows = frame.totalRows + 1
if( frame.totalRows <= frame.scroll.offset or frame.rowID >= 15 ) then
return
end
 
frame.rowID = frame.rowID + 1
 
local button = frame.buttons[frame.rowID]
local line = frame.lines[frame.rowID]
 
if( highlighted ) then
button:LockHighlight()
else
button:UnlockHighlight()
end
 
if( type == "addon" ) then
button:SetText(text)
button:GetFontString():SetPoint("LEFT", button, "LEFT", 4, 0)
button:GetNormalTexture():SetAlpha(1.0)
line:Hide()
 
elseif( type == "category" ) then
button:SetText(HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE)
button:GetFontString():SetPoint("LEFT", button, "LEFT", 12, 0)
button:GetNormalTexture():SetAlpha(0.4)
line:Hide()
 
elseif( type == "subcat" ) then
button:SetText(HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE)
button:GetFontString():SetPoint("LEFT", button, "LEFT", 20, 0)
button:GetNormalTexture():SetAlpha(0.0)
line:SetTexCoord(0, 0.4375, 0, 0.625)
line:Show()
end
 
button.fs = button:GetFontString()
button.tooltip = tooltip
button.data = data
button.type = type
button.catText = text
button:Show()
end
 
local function updateConfigList(openAlso)
local frame = regFrames.addon
frame.rowID = 0
frame.totalRows = 0
 
local lastID
local searchBy = string.trim(string.lower(frame.search:GetText()))
if( searchBy == "" or frame.search.searchText ) then
searchBy = nil
end
 
-- Make sure stuff matches our search results
for id, row in pairs(frame.categories) do
if( searchBy and not string.match(string.lower(row.name), searchBy) ) then
frame.categories[id].hide = true
else
frame.categories[id].hide = nil
end
end
 
-- Resort list if needed
if( frame.resortList ) then
table.sort(frame.categories, sortCategories)
frame.resortList = nil
end
 
-- Now display
local opened
for _, addon in pairs(frame.categories) do
if( not addon.hide and addon.type == "addon" ) then
-- Total addons
if( addon.name == frame.selectedAddon ) then
displayCategoryRow(addon.type, addon.name, addon.data, addon.tooltip, true)
 
for _, cat in pairs(frame.categories) do
-- Show all the categories with the addon as the parent
if( not cat.hide and cat.parent == addon.name and cat.type == "category" ) then
-- Total categories of the selected addon
if( cat.name == frame.selectedCategory ) then
displayCategoryRow(cat.type, cat.name, cat.data, cat.tooltip, true)
 
for _, subCat in pairs(frame.categories) do
-- We don't have to check type, because it's the only one that has .addon set
if( not subCat.hide and subCat.parent == cat.name and subCat.addon == addon.name ) then
-- Total sub categories of the selected addons selected category
displayCategoryRow(subCat.type, subCat.name, subCat.data, subCat.tooltip, subCat.name == frame.selectedSubCat)
 
lastID = frame.rowID
if( openAlso ) then
opened = subCat.data
end
end
end
 
if( lastID ) then
frame.lines[lastID]:SetTexCoord(0.4375, 0.875, 0, 0.625)
end
 
-- Okay open the category then
if( not opened and openAlso ) then
opened = cat.data
end
else
displayCategoryRow(cat.type, cat.name, cat.data, cat.tooltip)
end
end
end
 
if( not opened and openAlso ) then
opened = addon.data
end
else
displayCategoryRow(addon.type, addon.name, addon.data, addon.tooltip)
end
end
end
 
if( opened ) then
openConfigFrame(opened)
end
 
updateScroll(frame.scroll, frame.totalRows)
 
local wrapSize = 145
if( frame.totalRows > 15 ) then
wrapSize = 135
end
 
for i=1, 15 do
local button = frame.buttons[i]
if( frame.totalRows > 15 ) then
button:SetWidth(140)
else
button:SetWidth(156)
end
 
if( button.fs ) then
local wrapAt = wrapSize
if( button.type == "category" ) then
wrapAt = wrapAt - 5
elseif( frame.buttons[i].type == "subcat" ) then
wrapAt = wrapAt - 10
end
 
if( button.fs:GetStringWidth() > wrapAt ) then
button.fs:SetWidth(wrapAt)
else
button.fs:SetWidth(button.fs:GetStringWidth())
end
end
 
-- We have less then 15 rows used
-- and our index is equal or past our current
if( frame.rowID < 15 and i > frame.rowID ) then
button:Hide()
end
end
end
 
local function expandConfigList(self)
local frame = regFrames.addon
 
if( self.type == "addon" ) then
if( frame.selectedAddon == self.catText ) then
frame.selectedAddon = ""
else
frame.selectedAddon = self.catText
end
 
frame.selectedCategory = ""
frame.selectedSubCat = ""
 
elseif( self.type == "category" ) then
if( frame.selectedCategory == self.catText ) then
frame.selectedCategory = ""
self.data = nil
else
frame.selectedCategory = self.catText
end
 
frame.selectedSubCat = ""
 
elseif( self.type == "subcat" ) then
if( frame.selectedSubCat == self.catText ) then
frame.selectedSubCat = ""
 
-- Make sure the frame gets hidden when deselecting
self.data = addons[frame.selectedAddon].categories[frame.selectedCategory]
else
frame.selectedSubCat = self.catText
end
end
 
openConfigFrame(self.data)
updateConfigList()
end
 
 
local function createAddonFrame(hide)
local frame = regFrames.addon
 
if( frame and hide ) then
frame:Hide()
return
elseif( hide ) then
return
elseif( not frame ) then
frame = CreateFrame("Frame", nil, regFrames.main)
frame:SetFrameStrata("DIALOG")
frame:SetAllPoints(regFrames.main)
 
regFrames.addon = frame
 
frame.buttons = {}
frame.lines = {}
for i=1, 15 do
local button = CreateFrame("Button", nil, frame)
frame.buttons[i] = button
 
button:SetHighlightFontObject(GameFontHighlightSmall)
button:SetTextFontObject(GameFontNormalSmall)
button:SetScript("OnClick", expandConfigList)
button:SetScript("OnEnter", showTooltip)
button:SetScript("OnLeave", hideTooltip)
button:SetWidth(140)
button:SetHeight(20)
 
button:SetNormalTexture("Interface\\AuctionFrame\\UI-AuctionFrame-FilterBG")
button:GetNormalTexture():SetTexCoord(0, 0.53125, 0, 0.625)
 
button:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
button:GetHighlightTexture():SetBlendMode("ADD")
 
-- For sub categories only
local line = button:CreateTexture(nil, "BACKGROUND")
frame.lines[i] = line
 
line:SetWidth(7)
line:SetHeight(20)
line:SetPoint("LEFT", 13, 0)
line:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-FilterLines")
line:SetTexCoord(0, 0.4375, 0, 0.625)
 
if( i > 1 ) then
button:SetPoint("TOPLEFT", frame.buttons[i - 1], "BOTTOMLEFT", 0, 0)
else
button:SetPoint("TOPLEFT", 23, -105)
end
end
 
createScrollFrame(frame, 15, updateConfigList)
frame.scroll:SetPoint("TOPRIGHT", frame, "TOPLEFT", 158, -105)
 
createSearchInput(frame, updateConfigList)
createCategoryListing()
end
 
-- Reset selection
frame.selectedAddon = ""
frame.selectedCategory = ""
frame.selectedSubCat = ""
 
-- Hide the open config frame
if( frame.shownFrame ) then
frame.shownFrame:Hide()
end
 
updateConfigList()
ShowUIPanel(frame)
end
 
local function createOHFrame()
if( regFrames.main ) then
return
end
 
frame = CreateFrame("Frame", nil, UIParent)
frame:CreateTitleRegion()
frame:SetClampedToScreen(true)
frame:SetMovable(false)
frame:SetFrameStrata("DIALOG")
frame:SetWidth(832)
frame:SetHeight(447)
frame:SetPoint("TOPLEFT", 0, -104)
frame.totalTabs = 0
frame.tabs = {}
 
regFrames.main = frame
 
-- If we don't hide it ourself, the panel layout becomes messed up
-- because dynamically created frames are created shown
frame:Hide()
 
frame:SetScript("OnHide", function()
if( openedByMenu ) then
openedByMenu = nil
 
PlaySound("gsTitleOptionExit");
ShowUIPanel(GameMenuFrame)
end
end)
frame:SetScript("OnShow", function()
if( OptionHouseDB and OptionHouseDB.position ) then
frame:ClearAllPoints()
frame:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", OptionHouseDB.position.x, OptionHouseDB.position.y)
end
end)
 
frame:SetAttribute("UIPanelLayout-defined", true)
frame:SetAttribute("UIPanelLayout-enabled", true)
frame:SetAttribute("UIPanelLayout-area", "doublewide")
frame:SetAttribute("UIPanelLayout-whileDead", true)
table.insert(UISpecialFrames, name)
 
local title = frame:GetTitleRegion()
title:SetWidth(757)
title:SetHeight(20)
title:SetPoint("TOPLEFT", 75, -15)
 
-- Embedded version wont include the icon cause authors are more whiny then users
-- Also, we want to use different methods of frame dragging
if( not IsAddOnLoaded("OptionHouse") ) then
local texture = frame:CreateTexture(nil, "OVERLAY")
texture:SetWidth(57)
texture:SetHeight(57)
texture:SetPoint("TOPLEFT", 9, -7)
SetPortraitTexture(texture, "player")
 
frame:EnableMouse(true)
else
local texture = frame:CreateTexture(nil, "OVERLAY")
texture:SetWidth(128)
texture:SetHeight(128)
texture:SetPoint("TOPLEFT", 9, -2)
texture:SetTexture("Interface\\AddOns\\OptionHouse\\GnomePortrait")
 
frame:EnableMouse(false)
frame:SetMovable(not OptionHouseDB.locked)
 
-- This goes in the entire bar where "OptionHouse" title text is
local mover = CreateFrame("Button", nil, frame)
mover:SetPoint("TOP", 25, -15)
mover:SetHeight(19)
mover:SetWidth(730)
 
mover:SetScript("OnLeave", hideTooltip)
mover:SetScript("OnEnter", showTooltip)
mover:SetScript("OnMouseUp", function(self)
if( self.isMoving ) then
local parent = self:GetParent()
parent:StopMovingOrSizing()
OptionHouseDB.position = {x = parent:GetLeft(), y = parent:GetTop()}
 
self.isMoving = nil
end
end)
 
mover:SetScript("OnMouseDown", function(self, mouse)
local parent = self:GetParent()
 
-- Start moving!
if( parent:IsMovable() and mouse == "LeftButton" ) then
self.isMoving = true
parent:StartMoving()
 
-- Reset position
elseif( mouse == "RightButton" ) then
parent:ClearAllPoints()
parent:SetPoint("TOPLEFT", 0, -104)
 
OptionHouseDB.position = nil
end
end)
end
 
local title = frame:CreateFontString(nil, "OVERLAY")
title:SetFontObject(GameFontNormal)
title:SetPoint("TOP", 0, -18)
title:SetText(L["OPTION_HOUSE"])
 
frame.topLeft = frame:CreateTexture(nil, "ARTWORK")
frame.topLeft:SetWidth(256)
frame.topLeft:SetHeight(256)
frame.topLeft:SetPoint("TOPLEFT", 0, 0)
 
frame.top = frame:CreateTexture(nil, "ARTWORK")
frame.top:SetWidth(320)
frame.top:SetHeight(256)
frame.top:SetPoint("TOPLEFT", 256, 0)
 
frame.topRight = frame:CreateTexture(nil, "ARTWORK")
frame.topRight:SetWidth(256)
frame.topRight:SetHeight(256)
frame.topRight:SetPoint("TOPLEFT", frame.top, "TOPRIGHT", 0, 0)
 
frame.bottomLeft = frame:CreateTexture(nil, "ARTWORK")
frame.bottomLeft:SetWidth(256)
frame.bottomLeft:SetHeight(256)
frame.bottomLeft:SetPoint("TOPLEFT", 0, -256)
 
frame.bottom = frame:CreateTexture(nil, "ARTWORK")
frame.bottom:SetWidth(320)
frame.bottom:SetHeight(256)
frame.bottom:SetPoint("TOPLEFT", 256, -256)
 
frame.bottomRight = frame:CreateTexture(nil, "ARTWORK")
frame.bottomRight:SetWidth(256)
frame.bottomRight:SetHeight(256)
frame.bottomRight:SetPoint("TOPLEFT", frame.bottom, "TOPRIGHT", 0, 0)
 
-- Make sure the configuration tab is first
local tabs = {{func = createAddonFrame, text = L["ADDON_OPTIONS"], type = "browse"}}
createTab(L["ADDON_OPTIONS"], 1)
 
for id, tab in pairs(tabfunctions) do
table.insert(tabs, tab)
createTab(tab.text, id + 1)
end
 
tabfunctions = tabs
 
local button = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
button:SetPoint("TOPRIGHT", 3, -8)
button:SetScript("OnClick", function()
HideUIPanel(frame)
end)
end
 
-- PRIVATE API's
-- While these aren't locked down to prevent being used
-- You ARE using them are your own risk for future compatability
function OptionHouse:CreateSearchInput(frame, onChange)
createSearchInput(frame, onChange)
end
 
function OptionHouse:UpdateScroll(scroll, totalRows)
updateScroll(scroll, totalRows)
end
 
function OptionHouse:CreateScrollFrame(frame, displayNum, onScroll)
createScrollFrame(frame, displayNum, onScroll)
end
 
function OptionHouse.RegisterTab(self, text, func, type)
-- Simple, effective you can't register a tab unless we list it here
-- I highly doubt will ever need to add another one
if( text ~= L["TAB_MANAGEMENT"] and text ~= L["TAB_PERFORMANCE"] ) then return end
 
table.insert(tabfunctions, {func = func, handler = self, text = text, type = type})
 
-- Will create all of the tabs when the frame is created if needed
if( not frame ) then
return
end
 
createTab(text, #(tabfunctions))
end
 
function OptionHouse.UnregisterTab(self, text)
for i=#(tabfunctions), 1, -1 do
if( tabfunctions[i].text == text ) then
table.remove(tabfunctions, i)
end
end
 
for i=1, frame.totalTabs do
if( tabfunctions[i] ) then
createTab(tabfunctions[i].text, i)
else
frame.tabs[i]:Hide()
end
end
end
 
function OptionHouse.GetAddOnData(self, name)
if( not addons[name] ) then
return nil, nil, nil
end
 
return addons[name].title, addons[name].author, addons[name].version
end
 
function OptionHouse.RegisterFrame(self, type, frame)
if( type ~= "addon" and type ~= "manage" and type ~= "perf" and type ~= "main" ) then
error(string.format(L["UNKNOWN_FRAMETYPE"], type), 3)
end
 
regFrames[type] = frame
end
 
-- PUBLIC API's
function OptionHouse:GetFrame(type)
if( type ~= "addon" and type ~= "manage" and type ~= "perf" and type ~= "main" ) then
error(string.format(L["UNKNOWN_FRAMETYPE"], type), 3)
end
 
return regFrames[type]
end
 
function OptionHouse:Open(addonName, parentCat, childCat)
if( InCombatLockdown() ) then
DEFAULT_CHAT_FRAME:AddMessage(L["IN_COMBAT"])
return
end
 
argcheck(addonName, 1, "string", "nil")
argcheck(parentCat, 2, "string", "nil")
argcheck(childCat, 3, "string", "nil")
 
createOHFrame()
tabOnClick(1)
 
if( not addonName ) then
ShowUIPanel(frame)
return
end
 
regFrames.addon.selectedAddon = addonName or ""
regFrames.addon.selectedCategory = parentCat or ""
regFrames.addon.selectedSubCat = childCat or ""
 
updateConfigList(true)
ShowUIPanel(frame)
end
 
function OptionHouse:OpenTab(id)
if( InCombatLockdown() ) then
DEFAULT_CHAT_FRAME:AddMessage(L["IN_COMBAT"])
return
end
 
argcheck(id, 1, "number")
 
createOHFrame()
assert(3, #(tabfunctions) > id, string.format(L["UNKNOWN_TAB"], id, #(tabfunctions)))
 
tabOnClick(id)
ShowUIPanel(frame)
end
 
function OptionHouse:RegisterAddOn(name, title, author, version)
argcheck(name, 1, "string")
argcheck(title, 2, "string", "nil")
argcheck(author, 3, "string", "nil")
argcheck(version, 4, "string", "number", "nil")
assert(3, not addons[name], string.format(L["ADDON_ALREADYREG"], name))
 
addons[name] = {title = title, author = author, version = version, totalCats = 0, totalSubs = 0, categories = {}}
addons[name].obj = {name = name}
 
-- So we can upgrade the function pointer if a newer rev is found
for id, method in pairs(methods) do
addons[name].obj[method] = OptionHouse[method]
end
 
if( regFrames.addon ) then
addCategoryListing(name, addons[name])
updateConfigList()
end
 
return addons[name].obj
end
 
function OptionHouse.RegisterCategory(addon, name, handler, func, noCache, sortID)
argcheck(name, 2, "string")
argcheck(handler, 3, "string", "function", "table")
argcheck(func, 4, "string", "function", "nil")
argcheck(noCache, 5, "boolean", "number", "nil")
argcheck(sortID, 6, "number", "nil")
assert(3, handler or func, L["NO_FUNC_PASSED"])
assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RegisterCategory"))
assert(3, addons[addon.name].categories, string.format(L["CATEGORY_ALREADYREG"], name, addon.name))
 
-- Category numbers are required so we know when to skip it because only one category/sub cat exists
addons[addon.name].totalCats = addons[addon.name].totalCats + 1
addons[addon.name].categories[name] = {func = func, handler = handler, noCache = noCache, sub = {}, totalSubs = 0, sortID = sortID or 9999999}
 
if( regFrames.addon ) then
addCategoryListing(addon.name, addons[addon.name])
updateConfigList()
end
end
 
function OptionHouse.RegisterSubCategory(addon, parentCat, name, handler, func, noCache, sortID)
argcheck(parentCat, 2, "string")
argcheck(name, 3, "string")
argcheck(handler, 4, "string", "function", "table")
argcheck(func, 5, "string", "function", "nil")
argcheck(noCache, 6, "boolean", "number", "nil")
argcheck(sortID, 7, "number", "nil")
assert(3, handler or func, L["NO_FUNC_PASSED"])
assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RegisterSubCategory"))
assert(3, addons[addon.name].categories[parentCat], string.format(L["NO_PARENTCAT"], parentCat, addon.name))
assert(3, not addons[addon.name].categories[parentCat].sub[name], string.format(L["SUBCATEGORY_ALREADYREG"], name, parentCat, addon.name))
 
addons[addon.name].totalSubs = addons[addon.name].totalSubs + 1
addons[addon.name].categories[parentCat].totalSubs = addons[addon.name].categories[parentCat].totalSubs + 1
addons[addon.name].categories[parentCat].sub[name] = {handler = handler, func = func, noCache = noCache, sortID = sortID or 9999999}
 
if( regFrames.addon ) then
addCategoryListing(addon.name, addons[addon.name])
updateConfigList()
end
end
 
function OptionHouse.RemoveCategory(addon, name)
argcheck(name, 2, "string")
assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RemoveCategory"))
assert(3, addons[addon.name].categories[name], string.format(L["NO_CATEGORYEXISTS"], name, addon.name))
 
addons[addon.name].totalCats = addons[addon.name].totalCats - 1
addons[addon.name].totalSubs = addons[addon.name].totalSubs - addons[addon.name].categories[name].totalSubs
addons[addon.name].categories[name] = nil
 
if( regFrames.addon ) then
if( addons[addon.name].totalCats == 0 ) then
removeAddonListing(addon.name)
else
removeCategoryListing(addon.name, name)
end
 
updateConfigList()
end
end
 
function OptionHouse.RemoveSubCategory(addon, parentCat, name)
argcheck(parentCat, 2, "string")
argcheck(name, 2, "string")
assert(3, addons[addon.name], string.format(L["MUST_CALL"], "RemoveSubCategory"))
assert(3, addons[addon.name].categories[parentCat], string.format(L["NO_PARENTCAT"], name, addon.name))
assert(3, addons[addon.name].categories[parentCat].sub[name], string.format(L["NO_SUBCATEXISTS"], name, parentCat, addon.name))
 
addons[addon.name].totalSubs = addons[addon.name].totalSubs - 1
addons[addon.name].categories[parentCat].totalSubs = addons[addon.name].categories[parentCat].totalSubs - 1
addons[addon.name].categories[parentCat].sub[name] = nil
 
if( regFrames.addon ) then
-- If this means we only have no more sub categories
-- and only one category we need to change how it works
if( addons[addon.name].totalSubs == 0 and addons[addon.name].totalCats == 1 ) then
removeAddonListing(addon.name)
addCategoryListing(addon.name, addons[addon.name])
else
removeSubCategoryListing(addon.name, parentCat, name)
end
 
updateConfigList()
end
end
 
function OptionHouse:GetVersion() return major, minor end
 
local function instanceLoaded()
if( oldRevision ) then
addons = OHInstance.addons or addons
evtFrame = OHInstance.evtFrame or evtFrame
tabfunctions = OHInstance.tabfunctions or tabfunctions
else
-- Secure headers are supported so don't want the window stuck open in combat
evtFrame = CreateFrame("Frame")
evtFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
evtFrame:RegisterEvent("ADDON_LOADED")
evtFrame:SetScript("OnEvent",function(self, event)
if( event == "PLAYER_REGEN_DISABLED" and frame and frame:IsShown() ) then
HideUIPanel(frame)
DEFAULT_CHAT_FRAME:AddMessage(L["ENTERED_COMBAT"])
end
end)
 
-- Make sure it hasn't been created already.
-- don't have to upgrade the referance because it just uses the slash command
-- which will upgrade below to use the current version anyway
if( not GameMenuButtonOptionHouse ) then
local menubutton = CreateFrame("Button", "GameMenuButtonOptionHouse", GameMenuFrame, "GameMenuButtonTemplate")
menubutton:SetText(L["OPTION_HOUSE"])
menubutton:SetScript("OnClick", function()
openedByMenu = true
 
PlaySound("igMainMenuOption")
HideUIPanel(GameMenuFrame)
SlashCmdList["OPTHOUSE"]()
end)
 
-- Position below "Interface Options"
local a1, fr, a2, x, y = GameMenuButtonKeybindings:GetPoint()
menubutton:SetPoint(a1, fr, a2, x, y)
 
GameMenuButtonKeybindings:SetPoint(a1, menubutton, a2, x, y)
GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + 25)
end
end
 
OptionHouse.addons = addons
OptionHouse.evtFrame = evtFrame
OptionHouse.tabfunctions = tabfunctions
 
-- Upgrade functions to point towards the latest revision
for name, addon in pairs(addons) do
for _, method in pairs(methods) do
addon.obj[method] = OptionHouse[method]
end
end
 
SLASH_OPTHOUSE1 = "/opthouse"
SLASH_OPTHOUSE2 = "/oh"
SlashCmdList["OPTHOUSE"] = function(...)
if( select(1, ...) == "" ) then
OptionHouse:Open()
else
OptionHouse:Open(...)
end
end
 
-- Now make it active
for k, v in pairs(OptionHouse) do
OHInstance[k] = v
end
end
 
instanceLoaded()
Property changes : Added: svn:eol-style + native Added: svn:mime-type + text/plain
branches/LootTracker-Rewrite-Ace3/Bindings.xml New file
0,0 → 1,8
<Bindings>
<Binding name="LTTOGGLECONFIG" header="LOOTTRACKER">
LootTracker:ToggleConfig()
</Binding>
<Binding name="LTTOGGLETRACK">
LootTracker:ToggleTracker()
</Binding>
</Bindings>
Property changes : Added: svn:mime-type + text/xml Added: svn:eol-style + native
branches/LootTracker-Rewrite-Ace3/LootTracker.toc New file
0,0 → 1,15
## Interface: 20400
## Title: LootTracker
## Version: 2.00-20400
## Notes: This provides a frame that will show you what loot you are tracking and how much you have of it.
## DefaultState: Enabled
## LoadOnDemand: 0
## SavedVariables: LootTrackerDB
## OptionalDeps: ClickTip, Ace3
 
libs.xml
 
localizations/LootTracker.enUS.lua
localizations/LootTracker.deDE.lua
 
LootTracker.lua
Property changes : Added: svn:eol-style + native Added: svn:mime-type + text/plain
branches/LootTracker-Rewrite-Ace3/Localization.enUS.lua New file
0,0 → 1,52
local debug = false
LootTrackerLocals = setmetatable({
['Add Item'] = 'Add Item',
['Add Set'] = 'Add Set',
['Advanced Tracker Options'] = 'Advance Tracker Options',
['Background Alpha'] = 'Background Alpha',
['Current toon count only'] = 'Current toon count only',
['Del Item'] = 'Del Item',
['Edit Item' ] = 'Edit Item',
['Global Tracker Options'] = 'Global Tracker Options',
['Hide if incomplete'] = 'Hide if incomplete',
['Hide if no items available'] = 'Hide if no items available',
['Hide in combat'] = 'Hide in combat',
['Hint: Shift click to add to tracker'] = 'Hint: Shift click to add to tracker',
['Hint: Shift click to remove from tracker'] = 'Hint: Shift click to remove from tracker',
['Lock advanced tracker'] = 'Lock advanced tracker',
['Lock Tracker'] = 'Lock Tracker',
['LootTracker: Invalid item entered.'] = 'LootTracker: Invalid item entered.',
['Remove Set'] = 'Remove Set',
['Rename Set' ] = 'Rename Set',
['Sets'] = 'Sets',
['Show advanced tracker'] = 'Show advanced tracker',
['Show normal tracker'] = 'Show normal tracker',
['Squish numbers to name'] = 'Squish numbers to name',
['Standard Tracker Options'] = 'Standard Tracker Options',
['Toggle Config'] = 'Toggle Config',
['Toggle Tracker'] = 'Toggle Tracker',
['Use this checkbox to force item counts next to the item name'] = 'Use this checkbox to force item counts next to the item name',
['Use this checkbox to hide the advanced tracker'] = 'Use this checkbox to hide the advanced tracker',
['Use this checkbox to hide the item in the tracker if the goal has not been met'] = 'Use this checkbox to hide the item in the tracker if the goal has not been met',
['Use this checkbox to hide the item in the tracker if there are no items available'] = 'Use this checkbox to hide the item in the tracker if there are no items available',
['Use this checkbox to hide the normal tracker'] = 'Use this checkbox to hide the normal tracker',
['Use this checkbox to hide the tracker while in combat'] = 'Use this checkbox to hide the tracker while in combat',
['Use this checkbox to lock the tracker in its current position'] = 'Use this checkbox to lock the tracker in its current position',
['Use this checkbox to only show item totals from current toon'] = 'Use this checkbox to only show item totals from current toon',
['Use this checkbox to separate item counts from the item name'] = 'Use this checkbox to separate item counts from the item name',
['Use this checkbox to show item totals from all toons'] = 'Use this checkbox to show item totals from all toons',
['Use this checkbox to show the advanced tracker'] = 'Use this checkbox to show the advanced tracker',
['Use this checkbox to show the item in the tracker even if the goal has not been met'] = 'Use this checkbox to show the item in the tracker even if the goal has not been met',
['Use this checkbox to show the item in the tracker even if there are no items available'] = 'Use this checkbox to show the item in the tracker even if there are no items available',
['Use this checkbox to show the normal tracker'] = 'Use this checkbox to show the normal tracker',
['Use this checkbox to show the tracker while in combat'] = 'Use this checkbox to show the tracker while in combat',
['Use this checkbox to unlock the tracker'] = 'Use this checkbox to unlock the tracker',
['Use this slider to change the transparency of the background for the tracker'] = 'Use this slider to change the transparency of the background for the tracker',
['Visuals'] = 'Visuals',
}, {__index = function(self, key)
rawset(self, key, key)
if debug then
ChatFrame1:AddMessage("Missing "..tostring(key))
end
return key
end})
Property changes : Added: svn:mime-type + text/plain Added: svn:eol-style + native