/tags
local ChatProfiles_Defaults = { |
["ChatWindowProfiles"] = { |
["default6"] = { |
["messages"] = { |
}, |
["channels"] = { |
}, |
}, |
["default3"] = { |
["messages"] = { |
}, |
["channels"] = { |
}, |
}, |
["default5"] = { |
["messages"] = { |
}, |
["channels"] = { |
}, |
}, |
["default2"] = { |
["messages"] = { |
"OPENING", -- [1] |
"TRADESKILLS", -- [2] |
"PET_INFO", -- [3] |
"COMBAT_XP_GAIN", -- [4] |
"COMBAT_HONOR_GAIN", -- [5] |
"COMBAT_MISC_INFO", -- [6] |
}, |
["channels"] = { |
}, |
}, |
["default4"] = { |
["messages"] = { |
}, |
["channels"] = { |
}, |
}, |
["default7"] = { |
["messages"] = { |
}, |
["channels"] = { |
}, |
}, |
["default1"] = { |
["messages"] = { |
"SYSTEM", -- [1] |
"SYSTEM_NOMENU", -- [2] |
"SAY", -- [3] |
"EMOTE", -- [4] |
"YELL", -- [5] |
"WHISPER", -- [6] |
"PARTY", -- [7] |
"RAID", -- [8] |
"RAID_LEADER", -- [9] |
"RAID_WARNING", -- [10] |
"BATTLEGROUND", -- [11] |
"BATTLEGROUND_LEADER", -- [12] |
"GUILD", -- [13] |
"GUILD_OFFICER", -- [14] |
"MONSTER_SAY", -- [15] |
"MONSTER_YELL", -- [16] |
"MONSTER_EMOTE", -- [17] |
"MONSTER_WHISPER", -- [18] |
"MONSTER_BOSS_EMOTE", -- [19] |
"MONSTER_BOSS_WHISPER", -- [20] |
"ERRORS", -- [21] |
"AFK", -- [22] |
"DND", -- [23] |
"IGNORED", -- [24] |
"BG_HORDE", -- [25] |
"BG_ALLIANCE", -- [26] |
"BG_NEUTRAL", -- [27] |
"COMBAT_FACTION_CHANGE", -- [28] |
"SKILL", -- [29] |
"LOOT", -- [30] |
"MONEY", -- [31] |
"CHANNEL", -- [32] |
"ACHIEVEMENT", -- [33] |
"GUILD_ACHIEVEMENT", -- [34] |
}, |
["channels"] = { |
}, |
}, |
}, |
["auto"] = false, |
["currentProfile"]="default", |
["GlobalProfiles"] = { |
["default"] = { |
"default1", -- [1] |
"default2", -- [2] |
"default3", -- [3] |
"default4", -- [4] |
"default5", -- [5] |
"default6", -- [6] |
"default7", -- [7] |
}, |
}, |
}; |
local ldb = LibStub:GetLibrary("LibDataBroker-1.1") |
local frame = CreateFrame("FRAME","ChatProfilesFrame") |
frame:RegisterEvent("ADDON_LOADED") |
frame:RegisterEvent("PARTY_MEMBERS_CHANGED") |
local UnknownIconPath = "Interface\\Icons\\INV_Misc_QuestionMark" |
local OnIconPath ="Interface\\Icons\\INV_Jewelry_Ring_64" |
local OffIconPath ="Interface\\Icons\\INV_Jewelry_Ring_65" |
local ldbstream = ldb:NewDataObject("ChatProfiles",{type = "data source", icon = UnknownIconPath, label="ChatProfiles", text = ""}) |
CHATPROFILES_LOADED = false; |
--taken from http://www.wowwiki.com/Extracting_info_from_a_slash_command#Parsing_Into_Tables, 2009-04-01 |
local function MsgToTable( msg ) |
if not msg then return end |
local t = {}; |
gsub( msg, "%S+", function(w) |
tinsert( t, w ) |
end) |
return t; |
end |
local function ChatMessage(msg) |
DEFAULT_CHAT_FRAME:AddMessage("|cff99BBEEChatProfiles:|r "..msg); |
end |
local function LDBAutoChanged() |
if ChatProfiles.auto then |
ldbstream.icon = OnIconPath |
else |
ldbstream.icon = OffIconPath |
end |
end |
local function LDBProfileChanged() |
ldbstream.text = ChatProfiles.currentProfile |
end |
local function DisableAuto() |
ChatProfiles.auto = false; |
ChatMessage("Auto is now |cffAA0033off|r") |
LDBAutoChanged() |
end |
function LoadChatWindowProfile(chatFrame, profile) |
ChatFrame_RemoveAllMessageGroups(chatFrame); |
ChatFrame_RemoveAllChannels(chatFrame); |
for i=1,#profile["messages"] do |
ChatFrame_AddMessageGroup(chatFrame, profile["messages"][i]); |
end |
for i=1,#profile["channels"] do |
ChatFrame_AddChannel(chatFrame, profile["channels"][i]); |
end |
end |
local function CreateGlobalProfile(profileName) |
ChatProfiles.GlobalProfiles[profileName]={}; |
for i=1,7 do |
local messages = { GetChatWindowMessages(i)}; |
local channels = { GetChatWindowChannels(i)}; |
local channels2={}; |
for i=1,#channels do |
if i%2==1 then |
local value = floor(i/2)+1; |
channels2[value] = channels[i]; |
end |
end |
ChatProfiles.ChatWindowProfiles[profileName..i]={["messages"]=messages,["channels"]=channels2}; |
ChatProfiles.GlobalProfiles[profileName][i] = profileName..i; |
end |
if profileName ~= "lastprofile" then ChatMessage("A profile named '"..profileName.."' has been created") end |
end |
local function LoadGlobalProfile(profileName) |
if ChatProfiles.GlobalProfiles[profileName]==nil then |
ChatMessage("No profile named '"..profileName.."' loading 'default' instead"); |
LoadGlobalProfile("default"); |
DisableAuto(); |
else |
if profileName ~= "lastprofile" then CreateGlobalProfile("lastprofile") end |
for i in pairs(ChatProfiles.GlobalProfiles[profileName]) do |
LoadChatWindowProfile(getglobal("ChatFrame"..i),ChatProfiles.ChatWindowProfiles[ChatProfiles.GlobalProfiles[profileName][i]]); |
end |
if profileName ~= "lastprofile" then ChatMessage("Profile '"..profileName.."' has been loaded, get last profile with /cp last") |
else ChatMessage("Last profile has been loaded") end |
ChatProfiles.currentProfile=profileName; |
end |
end |
local function UpdateGlobalProfile() |
if ChatProfiles.auto then |
if GetNumRaidMembers()>0 then |
if ChatProfiles.currentProfile ~="raid" then |
LoadGlobalProfile("raid"); |
end |
elseif GetNumPartyMembers()>0 then |
if ChatProfiles.currentProfile ~="party" then |
LoadGlobalProfile("party"); |
end |
else |
if ChatProfiles.currentProfile ~="solo" then |
LoadGlobalProfile("solo"); |
end |
end |
end |
LDBAutoChanged() |
LDBProfileChanged() |
end |
-- local function DeleteGlobalProfile(profileName) |
-- if (profileName == "default" or profileName == "lastprofile") then |
-- ChatMessage("You can't delete profile '"..profileName.."'"); |
-- else |
-- tremove(ChatProfiles.GlobalProfiles,profileName); |
-- for i=1,7 do |
-- tremove(ChatProfiles.ChatWindowProfiles,profileName..i); |
-- end |
-- ChatMessage("Profile '"..profileName.."' has been deleted"); |
-- end |
-- end |
local function SetAuto(state) |
ChatProfiles.auto = state; |
ChatMessage("Auto is now "..(state and "|cff339911on|r" or "|cffAA0033off|r")); |
UpdateGlobalProfile(); |
end |
local function ToggleAuto() |
if ChatProfiles.auto then SetAuto(false) else SetAuto(true) end |
end |
local function ChatProfiles_SlashCommandHandler(msg) |
if msg == "auto" then |
ChatMessage("Auto is "..(ChatProfiles.auto and "|cff339911on|r" or "|cffAA0033off|r")) |
elseif msg == "auto on" then |
SetAuto(true); |
elseif msg == "auto off" then |
SetAuto(false); |
elseif msg == "auto toggle" then |
ToggleAuto(); |
elseif msg == "last" then |
LoadGlobalProfile("lastprofile"); |
SetAuto(false); |
elseif msg == "profiles" then |
local text="Profiles\n"; |
for v in pairs(ChatProfiles.GlobalProfiles) do |
if v == ChatProfiles.currentProfile then |
text=text.."|cff77BBEE"..v.."|r\n" |
else |
text=text..v.."\n" |
end |
end |
ChatMessage(text); |
elseif msg == "current" then |
ChatMessage("Current profile is '"..ChatProfiles.currentProfile.."'"); |
elseif msg == "frames" then |
local text ="Frame Name : #\n"; |
for i=1,7 do text=text..GetChatWindowInfo(i)..": "..i.."\n" end |
ChatMessage(text); |
elseif msg == "store" then |
ChatMessage("/cp store profileName"); |
elseif msg == "load" then |
ChatMessage("/cp load profileName"); |
else |
msg = MsgToTable(msg); |
if #msg==2 then |
if msg[1] == "store" then |
CreateGlobalProfile(msg[2]); |
elseif msg[1] == "load" then |
LoadGlobalProfile(msg[2]); |
SetAuto(false); |
-- elseif msg[1] == "delete" then |
-- DeleteGlobalProfile(msg[2]); |
end |
else |
--No match found, return standard phrase |
ChatMessage("/cp <command>\n<command>: auto [/on/off/toggle], last, current, profiles, frames, store, load"); |
end |
end |
end |
function ldbstream:OnTooltipShow() |
self:AddLine("Profiles:") |
local text=""; |
for v in pairs(ChatProfiles.GlobalProfiles) do |
if v == ChatProfiles.currentProfile then |
text=text.."|cff77BBEE"..v.."|r\n" |
else |
text=text.."|cffffffff"..v.."|r\n" |
end |
end |
self:AddLine(text) |
self:AddLine("Auto: "..(ChatProfiles.auto and "|cff339911on|r" or "|cffAA0033off|r")); |
end |
function ldbstream:OnEnter() |
GameTooltip:SetOwner(self, "ANCHOR_NONE") |
GameTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT") |
GameTooltip:ClearLines() |
ldbstream.OnTooltipShow(GameTooltip) |
GameTooltip:Show() |
end |
function ldbstream:OnLeave() |
GameTooltip:Hide() |
end |
function ldbstream:OnClick(self, button) |
ToggleAuto() |
end |
local function OnEvent(self, event, ...) |
if event=="ADDON_LOADED" and arg1 == "ChatProfiles" then |
if ChatProfiles == nil then |
ChatProfiles = ChatProfiles_Defaults; |
end |
CHATPROFILES_LOADED = true; |
DEFAULT_CHAT_FRAME:AddMessage("|cff99BBEEChatProfiles|r loaded successfully! Auto is "..(ChatProfiles.auto and "|cff339911on|r" or "|cffAA0033off|r")); |
UpdateGlobalProfile(); |
elseif event=="PARTY_MEMBERS_CHANGED" and CHATPROFILES_LOADED then |
--ChatMessage("Party!"); |
UpdateGlobalProfile(); |
end |
end |
frame:SetScript("OnEvent", OnEvent); |
SLASH_CHATPROFILES1 = "/chatprofiles"; |
SLASH_CHATPROFILES2 = "/cp"; |
SlashCmdList["CHATPROFILES"] = function (msg) ChatProfiles_SlashCommandHandler(msg) end; |
## Interface: 30000 |
## Title: ChatProfiles |
## Notes: Changes chat profiles based on events. |
## Author: Nitra - Nagrand (EU) |
## X-eMail: niteniten58@gmail.com |
## X-Embeds: CallbackHandler-1.0, LibStub |
## Version: 0.2beta |
## DefaultState: Enabled |
## LoadOnDemand: 0 |
## SavedVariablesPerCharacter: ChatProfiles |
libs\LibStub\LibStub.lua |
libs\CallbackHandler-1.0\CallbackHandler-1.0.lua |
libs\LibDataBroker-1.1\LibDataBroker-1.1.lua |
ChatProfiles.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 |
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 |
------------------------------------------------------------------------ |
r90 | nevcairiel | 2008-09-30 06:01:35 +0000 (Tue, 30 Sep 2008) | 1 line |
Changed paths: |
A /tags/1.0 |
A /tags/1.0/.pkgmeta |
A /tags/1.0/LibStub.lua |
A /tags/1.0/LibStub.toc |
Add 1.0 tag |
------------------------------------------------------------------------ |
-- 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 |
## Interface: 20400 |
## Title: Lib: LibStub |
## Notes: Universal Library Stub |
## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel |
## X-Website: http://jira.wowace.com/browse/LS |
## X-Category: Library |
## X-License: Public Domain |
LibStub.lua |
--[[ $Id: CallbackHandler-1.0.lua 3 2008-09-29 16:54:20Z nevcairiel $ ]] |
local MAJOR, MINOR = "CallbackHandler-1.0", 3 |
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} |
local type = type |
local pcall = pcall |
local pairs = pairs |
local assert = assert |
local concat = table.concat |
local loadstring = loadstring |
local next = next |
local select = select |
local type = type |
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", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(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. |
<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> |