vanilla-wow-addons – Rev 1
?pathlinks?
--[[
Name: AnchorsAway-1.0
Revision:
Author: Xuerian (sky.shell@gmail.com)
Website: none
Documentation: none
SVN:
Description: Row stacking and anchoring template
Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2
]]
local vmajor, vminor = "AnchorsAway-1.0", "$Revision: 14544 $"
if not AceLibrary then error(vmajor .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(vmajor, vminor) then return end
if not AceLibrary:HasInstance("AceEvent-2.0") then error(vmajor .. " requires AceEvent-2.0") end
if not AceLibrary:HasInstance("AceLocale-2.2") then error(vmajor .. " requires AceLocale-2.2") end
-------------------------------------------
------- Localization ----------
-------------------------------------------
local L = AceLibrary("AceLocale-2.2"):new("AnchorsAway")
L:RegisterTranslations("enUS", function()
return {
catGrowth = "Row growth",
catPosSelf = "Anchor point...",
catPosTarget = "To...",
catPosOffset = "Offset frame...",
optPositioning = "Positioning",
optLock = "Lock",
optAnchor = "Show Anchor",
optPosVert = "Vertically",
optPosHoriz = "Horizontally",
optTimeout = "Timeout",
optThreshold = "Stack Threshold",
descPositioning = "Position and attachment of rows in the stack",
descAnchor = "Show anchor for this stack",
descPosVert = "Offset the row vertically from the point you choose to anchor it to by a specific amount",
descPosHoriz = "Offset the row horizontally from the point you choose to anchor it to by a specific amount",
descTimeout = "Time before each row fades. |cFFFF5522Setting this to 0 disables timed fading entirely",
descDirection = "Direction stacks grow",
descThreshold = "Maximum number of rows displayed at any given time",
optPos = {
TOPLEFT = "Top left corner",
TOP = "Top edge",
TOPRIGHT = "Top right corner",
RIGHT = "Right edge",
BOTTOMRIGHT = "Bottom right corner",
BOTTOM = "Bottom edge",
BOTTOMLEFT = "Bottom left corner",
LEFT = "Left edge",
TOPLEFT = "Top left corner",
},
}
end)
L:RegisterTranslations("frFR", function()
return {
catGrowth = "Croissance des lignes",
catPosSelf = "Point d'ancrage...",
catPosTarget = "Vers...",
catPosOffset = "D\195\169calage de la fen\195\170tre...",
optPositioning = "Positionnement",
optAnchor = "Afficher l'ancrage",
optPosVert = "Verticalement",
optPosHoriz = "Horizontalement",
optTimeout = "Dur\195\169 d'affichage",
optDirection = "Direction",
optThreshold = "Nombre de ligne affich\195\169",
descPositioning = "Position de chaque ligne",
descAnchor = "Afficher l'ancrage pour cette ligne",
descPosVert = "D\195\169cale la ligne verticalement depuis le point que vous avez choisie d'ancrer du nombre sp\195\169cifi\195\169",
descPosHoriz = "D\195\169cale la ligne horizontalement depuis le point que vous avez choisie d'ancrer du nombre sp\195\169cifi\195\169",
descTimeout = "Dur\195\169 avant disparition des lignes. |cFFFF5522A 0, d\195\169sactive la disparition compl\195\168tement",
descDirection = "Direction de l'affichage des lignes de loot",
descThreshold = "Nombre maximum de lignes affich\195\169 simultan\195\169ment",
optPos = {
TOPLEFT = "Coin sup\195\169rieur gauche",
TOP = "Bord sup\195\169rieur",
TOPRIGHT = "Coin sup\195\169rieur droit",
RIGHT = "Bord droit",
BOTTOMRIGHT = "Coin inf\195\169rieur droit",
BOTTOM = "Bord infr\195\169rieur",
BOTTOMLEFT = "Coin inf\195\169rieur gauche",
LEFT = "Bord gauche",
TOPLEFT = "Coin sup\195\169rieur gauche",
},
}
end)
-------------------------------------------
------- Definition ----------
-------------------------------------------
local AnchorsAway = { }
AceLibrary("AceEvent-2.0"):embed(AnchorsAway)
function AnchorsAway:NewStack(stackname, icon, db)
db.AnchorsAway = db.AnchorsAway or {}
if not db.AnchorsAway[stackname] then
db.AnchorsAway[stackname] = { lock = false, anchor = true, attach = { self = "TOPLEFT", target = "BOTTOMLEFT", x = 0, y = 0 }, scale = 1, timeout = 15, threshold = 6, pos = {} }
end
local stackdb = db.AnchorsAway[stackname]
if not self.stacks then self.stacks = { } end
self.stacks[stackname] = {
rows = {},
rowstack = {},
built = 0,
shown = 0,
index = 'key',
db = stackdb,
dismissable = true,
detachable = false,
icon = icon
}
return self.stacks[stackname]
end
function AnchorsAway:Restack(stack, sortkey)
sortkey = sortkey or stack.index
for k, v in pairs(stack.rowstack) do
v:ClearAllPoints()
if not v:IsVisible() then
table.remove(stack.rowstack, k)
end
end
for k, v in iteratetable(stack.rowstack, sortkey) do
self:StackRow(stack, stack.rowstack[k], k == 1 and stack.frame or stack.rowstack[k-1], k)
stack:SizeRow(stack, v)
end
end
function AnchorsAway:StackRow(stack, row, target)
row:ClearAllPoints()
row:SetPoint(stack.db.attach.self, target, stack.db.attach.target, stack.db.attach.x, stack.db.attach.y)
end
function AnchorsAway:AcquireRow(stack)
local nextkey = table.getn(stack.rowstack) + 1
stack.shown = stack.shown +1
local id
if table.getn(stack.rows) < nextkey then
stack:BuildRow(stack, nextkey)
id = nextkey
else
for i = 1, table.getn(stack.rows) do
if stack.rows[i] and not stack.rows[i].active then
id = i
break
end
end
end
stack.rows[id].active = true
return stack.rows[id], id
end
function AnchorsAway:PushRow(stack)
local row, id = self:AcquireRow(stack)
local db = stack.db
table.insert(stack.rowstack, 1, row)
if stack.rowstack[2] and stack.rowstack[2] ~= stack.rowstack[1] then
self:StackRow(stack, stack.rowstack[2], stack.rowstack[1], 2)
elseif stack.rowstack[2] then
--DevTools_Dump(stack.rowstack)
return nil
end
self:StackRow(stack, stack.rowstack[1], stack.frame, 1)
row:Show()
if stack.shown > db.threshold then
self:PopRow(stack, nil, nil, db.threshold+1)
end
UIFrameFadeIn(row, 0.5, 0, 1)
if db.timeout > 0 then
row.event = self:ScheduleEvent(tostring(id), self.PopRow, db.timeout, self, stack, id, true)
end
row.key = self.uid
self.uid = self.uid + 1
return row
end
function AnchorsAway:PopRow(stack, id, event, stackid, time, func)
if not id then
id = stack.rowstack[stackid].id
end
if stack.rows[id].event and not event then
self:CancelScheduledEvent(stack.rows[id].event)
end
UIFrameFadeIn(stack.rows[id], time or 1, 1, 0)
stack.rows[id].fadeInfo.finishedFunc = function() self:RemoveRow(stack, stack.rows[id]) if func then func() end end
end
function AnchorsAway:RemoveRow(stack, row)
row:ClearAllPoints()
stack.shown = stack.shown -1
row:Hide()
self:ClearRow(stack, row.id)
for k,v in ipairs(stack.rowstack) do
if v == row then
table.remove(stack.rowstack, k)
break
end
end
end
function AnchorsAway:ClearRow(stack, id)
local row = stack.rows[id]
if row.event then
self:CancelScheduledEvent(row.event)
end
row.active = false
row:ClearAllPoints()
if stack.clear then stack.clear(row) end
end
function AnchorsAway:DragStart(stack, culprit)
if not stack.db.lock then
stack.frame:StartMoving()
if culprit then
culprit.dragging = true
end
end
end
function AnchorsAway:DragStop(stack, culprit)
stack.frame:StopMovingOrSizing()
if culprit then
culprit.dragging = false
end
if not stack.db.lock then
stack.db.pos = { x = stack.frame:GetLeft(), y = stack.frame:GetTop() }
end
end
function AnchorsAway:OnRowHide(stack, culprit)
if culprit.dragging then
self:DragStop(stack, culprit)
end
end
function AnchorsAway:NewAnchor(stackname, anchorname, icon, db, dewdrop)
local stack = self:NewStack(stackname, icon, db)
stack.frame = CreateFrame("Frame", "AnchorsAway_"..stackname.."_Anchor", UIParent)
stack.frame.anchortext = stack.frame:CreateFontString("AnchorsAway_"..stackname.."_AnchorText", "ARTWORK", "GameFontNormal")
stack.frame:SetMovable(1)
stack.frame:RegisterForDrag("LeftButton")
stack.frame:SetScript("OnDragStart", function() self:DragStart(stack) end)
stack.frame:SetScript("OnDragStop", function() self:DragStop(stack) end)
local anchor = anchorname or stackname
stack.frame.anchortext:ClearAllPoints()
stack.frame.anchortext:SetAllPoints(stack.frame)
stack.frame.anchortext:SetJustifyH("CENTER")
stack.frame.anchortext:SetJustifyV("MIDDLE")
stack.frame.anchortext:SetText("|cAAAAAAAA"..anchor)
stack.frame:SetWidth(150)
stack.frame:SetHeight(20)
stack.frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", stack.db.pos.x or GetScreenWidth()/2, stack.db.pos.y or GetScreenWidth()/2)
stack.frame:SetBackdrop({r = 0, g = 0, b = 0, a = 0.9})
stack.frame:SetBackdropBorderColor(.5, .5, .5, 1)
stack.name = stackname
stack.anchorname = anchorname
if dewdrop then
stack.opts = self:Opts(stack)
dewdrop:Register(stack.frame, 'children', function() dewdrop:FeedAceOptionsTable({ type = "group", args = stack.opts}) end, 'cursorX', true, 'cursorY', true)
end
stack.frame:Show()
if stack.db.anchor then
stack.frame:EnableMouse(1)
UIFrameFadeIn(stack.frame, 0.5, 0, 1)
else
stack.frame:EnableMouse(0)
stack.frame:SetAlpha(0)
end
return stack
end
local hcolor = "|cFF77BBFF"
local specialmenu = "|cFF44EE66"
function AnchorsAway:Opts(stack)
if stack.opts then return stack.opts end
local db = stack.db
local skeleton = {
header = {
type = "header",
icon = stack.icon,
iconWidth = 24,
iconHeight = 24,
name = hcolor..stack.anchorname,
order = 1
},
anchor = {
type = "toggle",
name = L["optAnchor"],
desc = L["optAnchor"],
set = function()
db.anchor = not db.anchor
stack.frame:EnableMouse(db.anchor)
if db.anchor then
if stack.frame:GetAlpha() < 1 then
UIFrameFadeIn(stack.frame, 0.5, 0, 1)
end
elseif stack.frame:GetAlpha() > 0 then
UIFrameFadeIn(stack.frame, 0.5, 1, 0)
end
end,
get = function() return db.anchor end,
order = 2,
},
lock = {
type = "toggle",
name = L["optLock"],
desc = L["optLock"],
get = function()
return db.lock
end,
set = function(v)
db.lock = v
end,
order = 4
},
spacer = {
type = "header",
order = 6
},
positioning = {
type = "group",
name = L["optPositioning"],
desc = L["descPositioning"],
args = {
offset = {
type = "header",
name = hcolor..L["catPosOffset"],
order = 1
},
horiz = {
type = "range",
icon = "Interface\\Buttons\\UI-SliderBar-Button-Vertical",
iconHeight = 24,
iconWidth = 24,
name = L["optPosHoriz"],
desc = L["descPosHoriz"],
get = function()
return db.attach.x
end,
set = function(v)
db.attach.x = v
end,
min = -20,
max = 20,
step = 1,
order = 2
},
vert = {
type = "range",
name = L["optPosVert"],
icon = "Interface\\Buttons\\UI-SliderBar-Button-Horizontal",
iconHeight = 24,
iconWidth = 24,
desc = L["descPosVert"],
get = function()
return db.attach.y
end,
set = function(v)
db.attach.y = v
end,
min = -20,
max = 20,
step = 1,
order = 3
},
spacer = {
type = "header",
order = 5
},
self = {
type = "header",
name = hcolor..L["catPosSelf"],
order = 10
},
spacer2 = {
type = "header",
order = 20
},
target = {
type = "header",
name = hcolor..L["catPosTarget"],
order = 30
},
},
order = 8
},
timeout = {
type = "range",
name = L["optTimeout"],
desc = L["descTimeout"],
get = function()
return db.timeout
end,
set = function(v)
db.timeout = v
end,
min = 0,
max = 200,
step = 5,
order = 12
},
threshold = {
type = "range",
name = L["optThreshold"],
desc = L["descThreshold"],
get = function()
return db.threshold
end,
set = function(v)
db.threshold = v
end,
min = 1,
max = 40,
step = 1,
order = 14
},
}
local selfattach = self:AttachMenu(11, stack, "self")
local targetattach = self:AttachMenu(31, stack, "target")
for k, v in pairs(selfattach) do
skeleton.positioning.args["self"..v.point] = v
end
for k, v in pairs(targetattach) do
skeleton.positioning.args["target"..v.point] = v
end
return skeleton
end
function AnchorsAway:AttachMenu(offset, stack, point)
local points = { "TOPLEFT", "TOP", "TOPRIGHT", "RIGHT", "BOTTOMRIGHT", "BOTTOM", "BOTTOMLEFT", "LEFT" }
local toggles = { }
for key, val in pairs(points) do
local tempval = val
local tmp = {
type = "toggle",
name =L["optPos"][tempval],
desc = L["optPos"][tempval],
isRadio = true,
checked = variable == tempval,
set = function(v)
variable = tempval;
stack.db.attach[point] = tempval
self:Restack(stack)
end,
get = function()
return stack.db.attach[point] == tempval
end,
point = tempval,
order = offset + key - 1,
}
table.insert(toggles, tmp)
end
return toggles
end
local function activate(self, oldLib, oldDeactivate)
self.stacks = oldLib and oldLib.stacks or {}
self.uid = oldLib and oldLib.uid or 1
end
-- Spread the voodoo. Thanks to ckk.
do
local mySort = function(a, b)
if not a then
return false
end
if not b then
return true
end
if type(a) == "string" then
return string.upper(a) < string.upper(b)
else
return a < b
end
end
local mySort_reverse = function(a, b)
if not b then
return false
end
if not a then
return true
end
if type(a) == "string" then
return string.upper(a) > string.upper(b)
else
return a > b
end
end
local current
local sorts = setmetatable({}, {__index=function(self, sortBy)
local x = function(a, b)
if not a or not b then
return false
elseif type(current[a][sortBy]) == "string" then
return string.upper(current[a][sortBy]) < string.upper(current[b][sortBy])
else
return current[a][sortBy] < current[b][sortBy]
end
end
self[sortBy] = x
return x
end})
local sorts_reverse = setmetatable({}, {__index=function(self, sortBy)
local x = function(a, b)
if not a or not b then
return false
elseif type(current[a][sortBy]) == "string" then
return string.upper(current[a][sortBy]) > string.upper(current[b][sortBy])
else
return current[a][sortBy] > current[b][sortBy]
end
end
self[sortBy] = x
return x
end})
local iters; iters = setmetatable({}, {__index=function(self, t)
local q; q = function(tab)
local position = t['#'] + 1
local x = t[position]
if not x then
for k in pairs(t) do
t[k] = nil
end
tsetn(t, 0)
iters[t] = q
return
end
t['#'] = position
return x, tab[x]
end
return q
end, __mode='k'})
function iteratetable(tab, key, reverse)
local t = next(iters) or {}
local iter = iters[t]
iters[t] = nil
for k, v in pairs(tab) do
table.insert(t, k)
end
if not key then
table.sort(t, reverse and mySort_reverse or mySort)
else
current = tab
table.sort(t, reverse and sorts_reverse[key] or sorts[key])
current = nil
end
t['#'] = 0
return iter, tab
end
end
AceLibrary:Register(AnchorsAway, vmajor, vminor, activate)
AnchorsAway = nil
Generated by GNU Enscript 1.6.5.90.