vanilla-wow-addons – Rev 1
?pathlinks?
--[[
Name: AceEvent-2.0
Revision: $Rev: 4599 $
Author(s): ckknight (ckknight@gmail.com)
Inspired By: AceEvent 1.x by Turan (<email here>)
Website: http://www.wowace.com/
Documentation: http://wiki.wowace.com/index.php/AceEvent-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
Description: Mixin to allow for event handling and inter-addon communication.
Dependencies: AceLibrary, AceOO-2.0, Compost-2.0 (optional)
]]
local MAJOR_VERSION = "AceEvent-2.0"
local MINOR_VERSION = "$Revision: 4599 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local Mixin = AceOO.Mixin
local AceEvent = Mixin {
"RegisterEvent",
"UnregisterEvent",
"UnregisterAllEvents",
"TriggerEvent",
"ScheduleEvent",
"ScheduleRepeatingEvent",
"CancelScheduledEvent",
"CancelAllScheduledEvents",
"TriggerDelayedEvent", -- remove on July 23
"CancelDelayedEvent", -- remove on July 23
"IsEventRegistered",
"IsEventScheduled",
}
local Compost = AceLibrary:HasInstance("Compost-2.0") and AceLibrary("Compost-2.0")
function AceEvent:RegisterEvent(event, method, once)
AceEvent:argCheck(event, 2, "string")
AceEvent:argCheck(method, 3, "string", "function", "nil")
AceEvent:argCheck(once, 4, "boolean", "nil")
if not method then
method = event
end
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
end
if not AceEvent.registry[event] then
AceEvent.registry[event] = Compost and Compost:Acquire() or {}
AceEvent.frame:RegisterEvent(event)
end
AceEvent.registry[event][self] = method
if once then
if not AceEvent.onceRegistry then
AceEvent.onceRegistry = Compost and Compost:Acquire() or {}
end
if not AceEvent.onceRegistry[event] then
AceEvent.onceRegistry[event] = Compost and Compost:Acquire() or {}
end
AceEvent.onceRegistry[event][self] = true
else
if AceEvent.onceRegistry and AceEvent.onceRegistry[event] then
AceEvent.onceRegistry[event][self] = nil
end
end
end
local _G = getfenv(0)
function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
AceEvent:argCheck(event, 2, "string")
local _G_event = _G.event
_G.event = event
if AceEvent.registry[event] then
if AceEvent.onceRegistry and AceEvent.onceRegistry[event] then
for obj in pairs(AceEvent.onceRegistry[event]) do
local mem, time
if AceEvent.debugTable then
if not AceEvent.debugTable[event] then
AceEvent.debugTable[event] = Compost and Compost:Acquire() or {}
end
if not AceEvent.debugTable[event][obj] then
AceEvent.debugTable[event][obj] = Compost and Compost:AcquireHash(
'mem', 0,
'time', 0
) or {
mem = 0,
time = 0
}
end
mem, time = gcinfo(), GetTime()
end
local method = AceEvent.registry[event][obj]
AceEvent.registry[event][obj] = nil
AceEvent.onceRegistry[event][obj] = nil
if type(method) == "string" then
if obj[method] then
obj[method](obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent.debugTable then
mem, time = mem - gcinfo(), time - GetTime()
AceEvent.debugTable[event][obj].mem = AceEvent.debugTable[event][obj].mem + mem
AceEvent.debugTable[event][obj].time = AceEvent.debugTable[event][obj].time + time
end
obj = nil
end
end
for obj, method in pairs(AceEvent.registry[event]) do
local mem, time
if AceEvent.debugTable then
if not AceEvent.debugTable[event] then
AceEvent.debugTable[event] = Compost and Compost:Acquire() or {}
end
if not AceEvent.debugTable[event][obj] then
AceEvent.debugTable[event][obj] = Compost and Compost:AcquireHash(
'mem', 0,
'time', 0
) or {
mem = 0,
time = 0
}
end
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
if obj[method] then
obj[method](obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
else -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent.debugTable then
mem, time = mem - gcinfo(), time - GetTime()
AceEvent.debugTable[event][obj].mem = AceEvent.debugTable[event][obj].mem + mem
AceEvent.debugTable[event][obj].time = AceEvent.debugTable[event][obj].time + time
end
end
end
_G.event = _G_event
end
local GetTime = GetTime
local delayRegistry
local function OnUpdate()
local t = GetTime()
local last = nil
for k,v in pairs(delayRegistry) do
if v.time <= t then
if v.repeatDelay then
v.time = t + v.repeatDelay
last = k
else
delayRegistry[k] = nil
end
local event = v.event
if type(event) == "function" then
event(unpack(v))
else
AceEvent:TriggerEvent(event, unpack(v))
end
if not v.repeatDelay and Compost then
Compost:Reclaim(v)
end
k = last
else
last = k
end
end
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
end
local stage = 3
if tonumber(date("%Y%m%d")) < 20060716 then
stage = 1
elseif tonumber(date("%Y%m%d")) < 20060723 then
stage = 2
end
if stage <= 2 then
function AceEvent:TriggerDelayedEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if stage == 2 then
local line = string.gsub(debugstack(), ".-\n(.-)\n.*", "%1")
DEFAULT_CHAT_MESSAGE:AddMessage(line .. " - `TriggerDelayedEvent' has been replaced with `ScheduleEvent'. This will cause an error on July 23, 2006.")
end
self:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:CancelDelayedEvent(t)
if stage == 2 then
local line = string.gsub(debugstack(), ".-\n(.-)\n.*", "%1")
DEFAULT_CHAT_MESSAGE:AddMessage(line .. " - `CancelDelayedEvent' has been replaced with `CancelScheduledEvent'. This will cause an error on July 23, 2006.")
end
self:CancelScheduledEvent(t)
end
end
local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
local id
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(delay, 4, "number")
self:CancelScheduledEvent(id)
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
if not AceEvent.delayRegistry then
AceEvent.delayRegistry = Compost and Compost:Acquire() or {}
delayRegistry = AceEvent.delayRegistry
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
end
local t
if type(id) == "table" then
for k in pairs(id) do
id[k] = nil
end
table.setn(id, 0)
t = id
else
t = Compost and Compost:Acquire() or {}
end
t.n = 0
table.insert(t, a1)
table.insert(t, a2)
table.insert(t, a3)
table.insert(t, a4)
table.insert(t, a5)
table.insert(t, a6)
table.insert(t, a7)
table.insert(t, a8)
table.insert(t, a9)
table.insert(t, a10)
table.insert(t, a11)
table.insert(t, a12)
table.insert(t, a13)
table.insert(t, a14)
table.insert(t, a15)
table.insert(t, a16)
table.insert(t, a17)
table.insert(t, a18)
table.insert(t, a19)
table.insert(t, a20)
t.event = event
t.time = GetTime() + delay
t.self = self
t.id = id or t
t.repeatDelay = repeating and delay
AceEvent.delayRegistry[t.id] = t
AceEvent.frame:Show()
return t.id
end
function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:CancelScheduledEvent(t)
AceEvent:argCheck(t, 2, "string", "table")
if AceEvent.delayRegistry then
local v = AceEvent.delayRegistry[t]
if v then
AceEvent.delayRegistry[t] = nil
if Compost then
Compost:Reclaim(v)
end
if not next(AceEvent.delayRegistry) then
AceEvent.frame:Hide()
end
return true
end
end
return false
end
function AceEvent:IsEventScheduled(t)
AceEvent:argCheck(t, 2, "string", "table")
if AceEvent.delayRegistry then
local v = AceEvent.delayRegistry[t]
if v then
if Compost then
Compost:Reclaim(v)
end
return true, v.time - GetTime()
end
end
return false, nil
end
function AceEvent:UnregisterEvent(event)
AceEvent:argCheck(event, 2, "string")
if AceEvent.registry[event] and AceEvent.registry[event][self] then
AceEvent.registry[event][self] = nil
else
AceEvent:error("Cannot unregister an event that you are not registered with.")
end
end
function AceEvent:UnregisterAllEvents()
for event, data in pairs(AceEvent.registry) do
data[self] = nil
end
end
function AceEvent:CancelAllScheduledEvents()
if AceEvent.delayRegistry then
for k,v in pairs(AceEvent.delayRegistry) do
if v.self == target then
if Compost then
Compost:Reclaim(v)
end
AceEvent.delayRegistry[k] = nil
end
end
end
end
function AceEvent:IsEventRegistered(event)
AceEvent:argCheck(event, 2, "string")
if AceEvent.registry[event] and AceEvent.registry[event][self] then
return true, AceEvent.registry[event][self]
end
return false, nil
end
function AceEvent:OnEmbedDisable(target)
self.UnregisterAllEvents(target)
self.CancelAllScheduledEvents(target)
end
function AceEvent:EnableDebugging()
if not self.debugTable then
self.debugTable = {}
end
end
function AceEvent:IsFullyInitialized()
return self.postInit or false
end
function AceEvent:IsPostPlayerLogin()
return self.playerLogin or false
end
function AceEvent:activate(oldLib, oldDeactivate)
AceEvent = self
if oldLib then
self.onceRegistry = oldLib.onceRegistry
self.delayRegistry = oldLib.delayRegistry
self.registry = oldLib.registry
self.frame = oldLib.frame
self.debugTable = oldLib.debugTable
self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
end
if not self.registry then
self.registry = {}
end
if not self.frame then
self.frame = CreateFrame("Frame")
end
self.frame:SetScript("OnEvent", function()
if event then
self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
end
end)
if self.delayRegistry then
delayRegistry = self.delayRegistry
self.frame:SetScript("OnUpdate", OnUpdate)
end
self:UnregisterAllEvents()
self:CancelAllScheduledEvents()
if not self.playerLogin then
self:RegisterEvent("PLAYER_LOGIN", function()
self.playerLogin = true
end, true)
end
if not self.postInit then
local isReload = true
local function func()
self.postInit = true
self:TriggerEvent("AceEvent_FullyInitialized")
self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
self:UnregisterEvent("SPELLS_CHANGED")
end
self:RegisterEvent("MEETINGSTONE_CHANGED", function()
self.playerLogin = true
self:ScheduleEvent("AceEvent_FullyInitialized", func, isReload and 1 or 4)
end, true)
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
end)
self:RegisterEvent("SPELLS_CHANGED", function()
isReload = false
end)
end
self.super.activate(self, oldLib, oldDeactivate)
if oldLib then
oldDeactivate(oldLib)
end
end
local function external(self, major, instance)
if major == "Compost-2.0" then
Compost = instance
end
end
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate, nil, external)
AceEvent = AceLibrary(MAJOR_VERSION)