/trunk/Libs
## Interface: 50300 |
## Title: Lib: DataBrokerIcon-1.0 |
## Notes: Allows addons to register to recieve a lightweight minimap icon as an alternative to more heavy LDB displays. |
## Author: Rabbit |
## X-eMail: rabbit.magtheridon@mail.com |
## X-Category: Library |
## X-License: GPLv2 or later |
## X-Credits: copystring for Barrel. |
## X-Curse-Packaged-Version: r36-release |
## X-Curse-Project-Name: LibDBIcon-1.0 |
## X-Curse-Project-ID: libdbicon-1-0 |
## X-Curse-Repository-ID: wow/libdbicon-1-0/mainline |
libs\LibStub\LibStub.lua |
libs\CallbackHandler-1.0\CallbackHandler-1.0.lua |
libs\LibDataBroker-1.1\LibDataBroker-1.1.lua |
LibDBIcon-1.0\LibDBIcon-1.0.lua |
assert(LibStub, "LibDataBroker-1.1 requires LibStub") |
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0") |
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4) |
if not lib then return end |
oldminor = oldminor or 0 |
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib) |
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {} |
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks |
if oldminor < 2 then |
lib.domt = { |
__metatable = "access denied", |
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end, |
} |
end |
if oldminor < 3 then |
lib.domt.__newindex = function(self, key, value) |
if not attributestorage[self] then attributestorage[self] = {} end |
if attributestorage[self][key] == value then return end |
attributestorage[self][key] = value |
local name = namestorage[self] |
if not name then return end |
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self) |
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self) |
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self) |
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self) |
end |
end |
if oldminor < 2 then |
function lib:NewDataObject(name, dataobj) |
if self.proxystorage[name] then return end |
if dataobj then |
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table") |
self.attributestorage[dataobj] = {} |
for i,v in pairs(dataobj) do |
self.attributestorage[dataobj][i] = v |
dataobj[i] = nil |
end |
end |
dataobj = setmetatable(dataobj or {}, self.domt) |
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name |
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj) |
return dataobj |
end |
end |
if oldminor < 1 then |
function lib:DataObjectIterator() |
return pairs(self.proxystorage) |
end |
function lib:GetDataObjectByName(dataobjectname) |
return self.proxystorage[dataobjectname] |
end |
function lib:GetNameByDataObject(dataobject) |
return self.namestorage[dataobject] |
end |
end |
if oldminor < 4 then |
local next = pairs(attributestorage) |
function lib:pairs(dataobject_or_name) |
local t = type(dataobject_or_name) |
assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)") |
local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name |
assert(attributestorage[dataobj], "Data object not found") |
return next, attributestorage[dataobj], nil |
end |
local ipairs_iter = ipairs(attributestorage) |
function lib:ipairs(dataobject_or_name) |
local t = type(dataobject_or_name) |
assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)") |
local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name |
assert(attributestorage[dataobj], "Data object not found") |
return ipairs_iter, attributestorage[dataobj], 0 |
end |
end |
-- 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] |
if not LibStub or LibStub.minor < LIBSTUB_MINOR then |
LibStub = LibStub or {libs = {}, minors = {} } |
_G[LIBSTUB_MAJOR] = LibStub |
LibStub.minor = LIBSTUB_MINOR |
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 |
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 |
function LibStub:IterateLibraries() return pairs(self.libs) end |
setmetatable(LibStub, { __call = LibStub.GetLibrary }) |
end |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ |
..\FrameXML\UI.xsd"> |
<Script file="CallbackHandler-1.0.lua"/> |
</Ui> |
--[[ $Id: CallbackHandler-1.0.lua 895 2009-12-06 16:28:55Z nevcairiel $ ]] |
local MAJOR, MINOR = "CallbackHandler-1.0", 5 |
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) |
if not CallbackHandler then return end -- No upgrade needed |
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} |
-- Lua APIs |
local tconcat = table.concat |
local assert, error, loadstring = assert, error, loadstring |
local setmetatable, rawset, rawget = setmetatable, rawset, rawget |
local next, select, pairs, type, tostring = next, select, pairs, type, tostring |
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded |
-- List them here for Mikk's FindGlobals script |
-- GLOBALS: geterrorhandler |
local xpcall = xpcall |
local function errorhandler(err) |
return geterrorhandler()(err) |
end |
local function CreateDispatcher(argCount) |
local code = [[ |
local next, xpcall, eh = ... |
local method, ARGS |
local function call() method(ARGS) end |
local function dispatch(handlers, ...) |
local index |
index, method = next(handlers) |
if not method then return end |
local OLD_ARGS = ARGS |
ARGS = ... |
repeat |
xpcall(call, eh) |
index, method = next(handlers, index) |
until not method |
ARGS = OLD_ARGS |
end |
return dispatch |
]] |
local ARGS, OLD_ARGS = {}, {} |
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end |
code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", ")) |
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) |
end |
local Dispatchers = setmetatable({}, {__index=function(self, argCount) |
local dispatcher = CreateDispatcher(argCount) |
rawset(self, argCount, dispatcher) |
return dispatcher |
end}) |
-------------------------------------------------------------------------- |
-- CallbackHandler:New |
-- |
-- target - target object to embed public APIs in |
-- RegisterName - name of the callback registration API, default "RegisterCallback" |
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" |
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. |
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused) |
-- TODO: Remove this after beta has gone out |
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused") |
RegisterName = RegisterName or "RegisterCallback" |
UnregisterName = UnregisterName or "UnregisterCallback" |
if UnregisterAllName==nil then -- false is used to indicate "don't want this method" |
UnregisterAllName = "UnregisterAllCallbacks" |
end |
-- we declare all objects and exported APIs inside this closure to quickly gain access |
-- to e.g. function names, the "target" parameter, etc |
-- Create the registry object |
local events = setmetatable({}, meta) |
local registry = { recurse=0, events=events } |
-- registry:Fire() - fires the given event/message into the registry |
function registry:Fire(eventname, ...) |
if not rawget(events, eventname) or not next(events[eventname]) then return end |
local oldrecurse = registry.recurse |
registry.recurse = oldrecurse + 1 |
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) |
registry.recurse = oldrecurse |
if registry.insertQueue and oldrecurse==0 then |
-- Something in one of our callbacks wanted to register more callbacks; they got queued |
for eventname,callbacks in pairs(registry.insertQueue) do |
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. |
for self,func in pairs(callbacks) do |
events[eventname][self] = func |
-- fire OnUsed callback? |
if first and registry.OnUsed then |
registry.OnUsed(registry, target, eventname) |
first = nil |
end |
end |
end |
registry.insertQueue = nil |
end |
end |
-- Registration of a callback, handles: |
-- self["method"], leads to self["method"](self, ...) |
-- self with function ref, leads to functionref(...) |
-- "addonId" (instead of self) with function ref, leads to functionref(...) |
-- all with an optional arg, which, if present, gets passed as first argument (after self if present) |
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) |
if type(eventname) ~= "string" then |
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) |
end |
method = method or eventname |
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. |
if type(method) ~= "string" and type(method) ~= "function" then |
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) |
end |
local regfunc |
if type(method) == "string" then |
-- self["method"] calling style |
if type(self) ~= "table" then |
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) |
elseif self==target then |
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) |
elseif type(self[method]) ~= "function" then |
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) |
end |
if select("#",...)>=1 then -- this is not the same as testing for arg==nil! |
local arg=select(1,...) |
regfunc = function(...) self[method](self,arg,...) end |
else |
regfunc = function(...) self[method](self,...) end |
end |
else |
-- function ref with self=object or self="addonId" |
if type(self)~="table" and type(self)~="string" then |
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2) |
end |
if select("#",...)>=1 then -- this is not the same as testing for arg==nil! |
local arg=select(1,...) |
regfunc = function(...) method(arg,...) end |
else |
regfunc = method |
end |
end |
if events[eventname][self] or registry.recurse<1 then |
-- if registry.recurse<1 then |
-- we're overwriting an existing entry, or not currently recursing. just set it. |
events[eventname][self] = regfunc |
-- fire OnUsed callback? |
if registry.OnUsed and first then |
registry.OnUsed(registry, target, eventname) |
end |
else |
-- we're currently processing a callback in this registry, so delay the registration of this new entry! |
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency |
registry.insertQueue = registry.insertQueue or setmetatable({},meta) |
registry.insertQueue[eventname][self] = regfunc |
end |
end |
-- Unregister a callback |
target[UnregisterName] = function(self, eventname) |
if not self or self==target then |
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) |
end |
if type(eventname) ~= "string" then |
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) |
end |
if rawget(events, eventname) and events[eventname][self] then |
events[eventname][self] = nil |
-- Fire OnUnused callback? |
if registry.OnUnused and not next(events[eventname]) then |
registry.OnUnused(registry, target, eventname) |
end |
end |
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then |
registry.insertQueue[eventname][self] = nil |
end |
end |
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds |
if UnregisterAllName then |
target[UnregisterAllName] = function(...) |
if select("#",...)<1 then |
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) |
end |
if select("#",...)==1 and ...==target then |
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) |
end |
for i=1,select("#",...) do |
local self = select(i,...) |
if registry.insertQueue then |
for eventname, callbacks in pairs(registry.insertQueue) do |
if callbacks[self] then |
callbacks[self] = nil |
end |
end |
end |
for eventname, callbacks in pairs(events) do |
if callbacks[self] then |
callbacks[self] = nil |
-- Fire OnUnused callback? |
if registry.OnUnused and not next(callbacks) then |
registry.OnUnused(registry, target, eventname) |
end |
end |
end |
end |
end |
end |
return registry |
end |
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it |
-- try to upgrade old implicit embeds since the system is selfcontained and |
-- relies on closures to work. |
--[[ |
Name: DBIcon-1.0 |
Revision: $Rev: 34 $ |
Author(s): Rabbit (rabbit.magtheridon@gmail.com) |
Description: Allows addons to register to recieve a lightweight minimap icon as an alternative to more heavy LDB displays. |
Dependencies: LibStub |
License: GPL v2 or later. |
]] |
--[[ |
Copyright (C) 2008-2011 Rabbit |
This program is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public License |
as published by the Free Software Foundation; either version 2 |
of the License, or (at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
]] |
----------------------------------------------------------------------- |
-- DBIcon-1.0 |
-- |
-- Disclaimer: Most of this code was ripped from Barrel but fixed, streamlined |
-- and cleaned up a lot so that it no longer sucks. |
-- |
local DBICON10 = "LibDBIcon-1.0" |
local DBICON10_MINOR = tonumber(("$Rev: 34 $"):match("(%d+)")) |
if not LibStub then error(DBICON10 .. " requires LibStub.") end |
local ldb = LibStub("LibDataBroker-1.1", true) |
if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end |
local lib = LibStub:NewLibrary(DBICON10, DBICON10_MINOR) |
if not lib then return end |
lib.disabled = lib.disabled or nil |
lib.objects = lib.objects or {} |
lib.callbackRegistered = lib.callbackRegistered or nil |
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) |
lib.notCreated = lib.notCreated or {} |
function lib:IconCallback(event, name, key, value, dataobj) |
if lib.objects[name] then |
if key == "icon" then |
lib.objects[name].icon:SetTexture(value) |
elseif key == "iconCoords" then |
lib.objects[name].icon:UpdateCoord() |
elseif key == "iconR" then |
local _, g, b = lib.objects[name].icon:GetVertexColor() |
lib.objects[name].icon:SetVertexColor(value, g, b) |
elseif key == "iconG" then |
local r, _, b = lib.objects[name].icon:GetVertexColor() |
lib.objects[name].icon:SetVertexColor(r, value, b) |
elseif key == "iconB" then |
local r, g = lib.objects[name].icon:GetVertexColor() |
lib.objects[name].icon:SetVertexColor(r, g, value) |
end |
end |
end |
if not lib.callbackRegistered then |
ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__icon", "IconCallback") |
ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconCoords", "IconCallback") |
ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconR", "IconCallback") |
ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconG", "IconCallback") |
ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconB", "IconCallback") |
lib.callbackRegistered = true |
end |
-- Tooltip code ripped from StatBlockCore by Funkydude |
local function getAnchors(frame) |
local x, y = frame:GetCenter() |
if not x or not y then return "CENTER" end |
local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or "" |
local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM" |
return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf |
end |
local function onEnter(self) |
if self.isMoving then return end |
local obj = self.dataObject |
if obj.OnTooltipShow then |
GameTooltip:SetOwner(self, "ANCHOR_NONE") |
GameTooltip:SetPoint(getAnchors(self)) |
obj.OnTooltipShow(GameTooltip) |
GameTooltip:Show() |
elseif obj.OnEnter then |
obj.OnEnter(self) |
end |
end |
local function onLeave(self) |
local obj = self.dataObject |
GameTooltip:Hide() |
if obj.OnLeave then obj.OnLeave(self) end |
end |
-------------------------------------------------------------------------------- |
local onClick, onMouseUp, onMouseDown, onDragStart, onDragStop, onDragEnd, updatePosition |
do |
local minimapShapes = { |
["ROUND"] = {true, true, true, true}, |
["SQUARE"] = {false, false, false, false}, |
["CORNER-TOPLEFT"] = {false, false, false, true}, |
["CORNER-TOPRIGHT"] = {false, false, true, false}, |
["CORNER-BOTTOMLEFT"] = {false, true, false, false}, |
["CORNER-BOTTOMRIGHT"] = {true, false, false, false}, |
["SIDE-LEFT"] = {false, true, false, true}, |
["SIDE-RIGHT"] = {true, false, true, false}, |
["SIDE-TOP"] = {false, false, true, true}, |
["SIDE-BOTTOM"] = {true, true, false, false}, |
["TRICORNER-TOPLEFT"] = {false, true, true, true}, |
["TRICORNER-TOPRIGHT"] = {true, false, true, true}, |
["TRICORNER-BOTTOMLEFT"] = {true, true, false, true}, |
["TRICORNER-BOTTOMRIGHT"] = {true, true, true, false}, |
} |
function updatePosition(button) |
local angle = math.rad(button.db and button.db.minimapPos or button.minimapPos or 225) |
local x, y, q = math.cos(angle), math.sin(angle), 1 |
if x < 0 then q = q + 1 end |
if y > 0 then q = q + 2 end |
local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND" |
local quadTable = minimapShapes[minimapShape] |
if quadTable[q] then |
x, y = x*80, y*80 |
else |
local diagRadius = 103.13708498985 --math.sqrt(2*(80)^2)-10 |
x = math.max(-80, math.min(x*diagRadius, 80)) |
y = math.max(-80, math.min(y*diagRadius, 80)) |
end |
button:SetPoint("CENTER", Minimap, "CENTER", x, y) |
end |
end |
function onClick(self, b) if self.dataObject.OnClick then self.dataObject.OnClick(self, b) end end |
function onMouseDown(self) self.isMouseDown = true; self.icon:UpdateCoord() end |
function onMouseUp(self) self.isMouseDown = false; self.icon:UpdateCoord() end |
do |
local function onUpdate(self) |
local mx, my = Minimap:GetCenter() |
local px, py = GetCursorPosition() |
local scale = Minimap:GetEffectiveScale() |
px, py = px / scale, py / scale |
if self.db then |
self.db.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360 |
else |
self.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360 |
end |
updatePosition(self) |
end |
function onDragStart(self) |
self:LockHighlight() |
self.isMouseDown = true |
self.icon:UpdateCoord() |
self:SetScript("OnUpdate", onUpdate) |
self.isMoving = true |
GameTooltip:Hide() |
end |
end |
function onDragStop(self) |
self:SetScript("OnUpdate", nil) |
self.isMouseDown = false |
self.icon:UpdateCoord() |
self:UnlockHighlight() |
self.isMoving = nil |
end |
local defaultCoords = {0, 1, 0, 1} |
local function updateCoord(self) |
local coords = self:GetParent().dataObject.iconCoords or defaultCoords |
local deltaX, deltaY = 0, 0 |
if not self:GetParent().isMouseDown then |
deltaX = (coords[2] - coords[1]) * 0.05 |
deltaY = (coords[4] - coords[3]) * 0.05 |
end |
self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY) |
end |
local function createButton(name, object, db) |
local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap) |
button.dataObject = object |
button.db = db |
button:SetFrameStrata("MEDIUM") |
button:SetSize(31, 31) |
button:SetFrameLevel(8) |
button:RegisterForClicks("anyUp") |
button:RegisterForDrag("LeftButton") |
button:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight") |
local overlay = button:CreateTexture(nil, "OVERLAY") |
overlay:SetSize(53, 53) |
overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder") |
overlay:SetPoint("TOPLEFT") |
local background = button:CreateTexture(nil, "BACKGROUND") |
background:SetSize(20, 20) |
background:SetTexture("Interface\\Minimap\\UI-Minimap-Background") |
background:SetPoint("TOPLEFT", 7, -5) |
local icon = button:CreateTexture(nil, "ARTWORK") |
icon:SetSize(17, 17) |
icon:SetTexture(object.icon) |
icon:SetPoint("TOPLEFT", 7, -6) |
button.icon = icon |
button.isMouseDown = false |
local r, g, b = icon:GetVertexColor() |
icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b) |
icon.UpdateCoord = updateCoord |
icon:UpdateCoord() |
button:SetScript("OnEnter", onEnter) |
button:SetScript("OnLeave", onLeave) |
button:SetScript("OnClick", onClick) |
if not db or not db.lock then |
button:SetScript("OnDragStart", onDragStart) |
button:SetScript("OnDragStop", onDragStop) |
end |
button:SetScript("OnMouseDown", onMouseDown) |
button:SetScript("OnMouseUp", onMouseUp) |
lib.objects[name] = button |
if lib.loggedIn then |
updatePosition(button) |
if not db or not db.hide then button:Show() |
else button:Hide() end |
end |
lib.callbacks:Fire("LibDBIcon_IconCreated", button, name) -- Fire 'Icon Created' callback |
end |
-- We could use a metatable.__index on lib.objects, but then we'd create |
-- the icons when checking things like :IsRegistered, which is not necessary. |
local function check(name) |
if lib.notCreated[name] then |
createButton(name, lib.notCreated[name][1], lib.notCreated[name][2]) |
lib.notCreated[name] = nil |
end |
end |
lib.loggedIn = lib.loggedIn or false |
-- Wait a bit with the initial positioning to let any GetMinimapShape addons |
-- load up. |
if not lib.loggedIn then |
local f = CreateFrame("Frame") |
f:SetScript("OnEvent", function() |
for _, object in pairs(lib.objects) do |
updatePosition(object) |
if not lib.disabled and (not object.db or not object.db.hide) then object:Show() |
else object:Hide() end |
end |
lib.loggedIn = true |
f:SetScript("OnEvent", nil) |
f = nil |
end) |
f:RegisterEvent("PLAYER_LOGIN") |
end |
local function getDatabase(name) |
return lib.notCreated[name] and lib.notCreated[name][2] or lib.objects[name].db |
end |
function lib:Register(name, object, db) |
if not object.icon then error("Can't register LDB objects without icons set!") end |
if lib.objects[name] or lib.notCreated[name] then error("Already registered, nubcake.") end |
if not lib.disabled and (not db or not db.hide) then |
createButton(name, object, db) |
else |
lib.notCreated[name] = {object, db} |
end |
end |
function lib:Lock(name) |
if not lib:IsRegistered(name) then return end |
if lib.objects[name] then |
lib.objects[name]:SetScript("OnDragStart", nil) |
lib.objects[name]:SetScript("OnDragStop", nil) |
end |
local db = getDatabase(name) |
if db then db.lock = true end |
end |
function lib:Unlock(name) |
if not lib:IsRegistered(name) then return end |
if lib.objects[name] then |
lib.objects[name]:SetScript("OnDragStart", onDragStart) |
lib.objects[name]:SetScript("OnDragStop", onDragStop) |
end |
local db = getDatabase(name) |
if db then db.lock = nil end |
end |
function lib:Hide(name) |
if not lib.objects[name] then return end |
lib.objects[name]:Hide() |
end |
function lib:Show(name) |
if lib.disabled then return end |
check(name) |
lib.objects[name]:Show() |
updatePosition(lib.objects[name]) |
end |
function lib:IsRegistered(name) |
return (lib.objects[name] or lib.notCreated[name]) and true or false |
end |
function lib:Refresh(name, db) |
if lib.disabled then return end |
check(name) |
local button = lib.objects[name] |
if db then button.db = db end |
updatePosition(button) |
if not button.db or not button.db.hide then |
button:Show() |
else |
button:Hide() |
end |
if not button.db or not button.db.lock then |
button:SetScript("OnDragStart", onDragStart) |
button:SetScript("OnDragStop", onDragStop) |
else |
button:SetScript("OnDragStart", nil) |
button:SetScript("OnDragStop", nil) |
end |
end |
function lib:GetMinimapButton(name) |
return lib.objects[name] |
end |
function lib:EnableLibrary() |
lib.disabled = nil |
for name, object in pairs(lib.objects) do |
if not object.db or not object.db.hide then |
object:Show() |
updatePosition(object) |
end |
end |
for name, data in pairs(lib.notCreated) do |
if not data.db or not data.db.hide then |
createButton(name, data[1], data[2]) |
lib.notCreated[name] = nil |
end |
end |
end |
function lib:DisableLibrary() |
lib.disabled = true |
for name, object in pairs(lib.objects) do |
object:Hide() |
end |
end |
LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons. |
LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon. |
Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data. |
LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons. |
Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them. |
Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table. |
h2. Links |
* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api |
* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications |
* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb |
## Interface: 50001 |
## Title: Lib: LibStub |
## Notes: Universal Library Stub |
## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel |
## X-Website: http://www.wowace.com/addons/libstub/ |
## X-Category: Library |
## X-License: Public Domain |
## X-Curse-Packaged-Version: 1.0.3-50001 |
## X-Curse-Project-Name: LibStub |
## X-Curse-Project-ID: libstub |
## X-Curse-Repository-ID: wow/libstub/mainline |
LibStub.lua |
debugstack = debug.traceback |
strmatch = string.match |
loadfile("../LibStub.lua")() |
local proxy = newproxy() -- non-string |
assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata |
local success, ret = pcall(LibStub.GetLibrary, proxy, true) |
assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. |
assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. |
assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement |
debugstack = debug.traceback |
strmatch = string.match |
loadfile("../LibStub.lua")() |
-- Pretend like loaded libstub is old and doesn't have :IterateLibraries |
assert(LibStub.minor) |
LibStub.minor = LibStub.minor - 0.0001 |
LibStub.IterateLibraries = nil |
loadfile("../LibStub.lua")() |
assert(type(LibStub.IterateLibraries)=="function") |
-- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created |
LibStub.IterateLibraries = 123 |
loadfile("../LibStub.lua")() |
assert(LibStub.IterateLibraries == 123) |
-- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created |
LibStub.minor = LibStub.minor + 0.0001 |
loadfile("../LibStub.lua")() |
assert(LibStub.IterateLibraries == 123) |
-- Again with a huge number |
LibStub.minor = LibStub.minor + 1234567890 |
loadfile("../LibStub.lua")() |
assert(LibStub.IterateLibraries == 123) |
print("OK") |
debugstack = debug.traceback |
strmatch = string.match |
loadfile("../LibStub.lua")() |
local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy |
assert(lib) -- should return the library table |
assert(not oldMinor) -- should not return the old minor, since it didn't exist |
-- the following is to create data and then be able to check if the same data exists after the fact |
function lib:MyMethod() |
end |
local MyMethod = lib.MyMethod |
lib.MyTable = {} |
local MyTable = lib.MyTable |
local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail |
assert(not newLib) -- should not return since out of date |
local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail |
assert(not newLib) -- should not return since out of date |
local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version |
assert(newLib) -- library table |
assert(rawequal(newLib, lib)) -- should be the same reference as the previous |
assert(newOldMinor == 1) -- should return the minor version of the previous version |
assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved |
assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved |
local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) |
assert(newLib) -- library table |
assert(newOldMinor == 2) -- previous version was 2 |
local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) |
assert(newLib) |
assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) |
local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string |
assert(newLib) |
assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) |
debugstack = debug.traceback |
strmatch = string.match |
loadfile("../LibStub.lua")() |
for major, library in LibStub:IterateLibraries() do |
-- check that MyLib doesn't exist yet, by iterating through all the libraries |
assert(major ~= "MyLib") |
end |
assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking |
assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. |
local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib |
assert(lib) -- check it exists |
assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference |
assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version |
local count=0 |
for major, library in LibStub:IterateLibraries() do |
-- check that MyLib exists somewhere in the libraries, by iterating through all the libraries |
if major == "MyLib" then -- we found it! |
count = count +1 |
assert(rawequal(library, lib)) -- verify that the references are equal |
end |
end |
assert(count == 1) -- verify that we actually found it, and only once |
-- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ |
-- 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 |
-- 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.") |
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) |
return self.libs[major], self.minors[major] |
end |
function LibStub:IterateLibraries() return pairs(self.libs) 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 |
--[[ $Id: CallbackHandler-1.0.lua 895 2009-12-06 16:28:55Z nevcairiel $ ]] |
local MAJOR, MINOR = "CallbackHandler-1.0", 5 |
--[[ $Id: CallbackHandler-1.0.lua 14 2010-08-09 00:43:38Z mikk $ ]] |
local MAJOR, MINOR = "CallbackHandler-1.0", 6 |
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) |
if not CallbackHandler then return end -- No upgrade needed |
regfunc = function(...) self[method](self,...) end |
end |
else |
-- function ref with self=object or self="addonId" |
if type(self)~="table" and type(self)~="string" then |
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2) |
-- function ref with self=object or self="addonId" or self=thread |
if type(self)~="table" and type(self)~="string" and type(self)~="thread" then |
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) |
end |
if select("#",...)>=1 then -- this is not the same as testing for arg==nil! |