annotate Libs/AceAddon-3.0/AceAddon-3.0.lua @ 25:ac501d71c890 tip

Added tag v8.2.0.024 for changeset 389dcaeebc47
author Tercioo
date Fri, 28 Jun 2019 20:07:27 -0300
parents fc346da3afd9
children
rev   line source
tercio@0 1 --- **AceAddon-3.0** provides a template for creating addon objects.
tercio@0 2 -- It'll provide you with a set of callback functions that allow you to simplify the loading
tercio@0 3 -- process of your addon.\\
tercio@0 4 -- Callbacks provided are:\\
tercio@0 5 -- * **OnInitialize**, which is called directly after the addon is fully loaded.
tercio@0 6 -- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
tercio@0 7 -- * **OnDisable**, which is only called when your addon is manually being disabled.
tercio@0 8 -- @usage
tercio@0 9 -- -- A small (but complete) addon, that doesn't do anything,
tercio@0 10 -- -- but shows usage of the callbacks.
tercio@0 11 -- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
tercio@0 12 --
tercio@0 13 -- function MyAddon:OnInitialize()
tercio@0 14 -- -- do init tasks here, like loading the Saved Variables,
tercio@0 15 -- -- or setting up slash commands.
tercio@0 16 -- end
tercio@0 17 --
tercio@0 18 -- function MyAddon:OnEnable()
tercio@0 19 -- -- Do more initialization here, that really enables the use of your addon.
tercio@0 20 -- -- Register Events, Hook functions, Create Frames, Get information from
tercio@0 21 -- -- the game that wasn't available in OnInitialize
tercio@0 22 -- end
tercio@0 23 --
tercio@0 24 -- function MyAddon:OnDisable()
tercio@0 25 -- -- Unhook, Unregister Events, Hide frames that you created.
tercio@0 26 -- -- You would probably only use an OnDisable if you want to
tercio@0 27 -- -- build a "standby" mode, or be able to toggle modules on/off.
tercio@0 28 -- end
tercio@0 29 -- @class file
tercio@0 30 -- @name AceAddon-3.0.lua
tercio@0 31 -- @release $Id: AceAddon-3.0.lua 1084 2013-04-27 20:14:11Z nevcairiel $
tercio@0 32
tercio@0 33 local MAJOR, MINOR = "AceAddon-3.0", 12
tercio@0 34 local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
tercio@0 35
tercio@0 36 if not AceAddon then return end -- No Upgrade needed.
tercio@0 37
tercio@0 38 AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
tercio@0 39 AceAddon.addons = AceAddon.addons or {} -- addons in general
tercio@0 40 AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
tercio@0 41 AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
tercio@0 42 AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
tercio@0 43 AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
tercio@0 44
tercio@0 45 -- Lua APIs
tercio@0 46 local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
tercio@0 47 local fmt, tostring = string.format, tostring
tercio@0 48 local select, pairs, next, type, unpack = select, pairs, next, type, unpack
tercio@0 49 local loadstring, assert, error = loadstring, assert, error
tercio@0 50 local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
tercio@0 51
tercio@0 52 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
tercio@0 53 -- List them here for Mikk's FindGlobals script
tercio@0 54 -- GLOBALS: LibStub, IsLoggedIn, geterrorhandler
tercio@0 55
tercio@0 56 --[[
tercio@0 57 xpcall safecall implementation
tercio@0 58 ]]
tercio@0 59 local xpcall = xpcall
tercio@0 60
tercio@0 61 local function errorhandler(err)
tercio@0 62 return geterrorhandler()(err)
tercio@0 63 end
tercio@0 64
tercio@0 65 local function CreateDispatcher(argCount)
tercio@0 66 local code = [[
tercio@0 67 local xpcall, eh = ...
tercio@0 68 local method, ARGS
tercio@0 69 local function call() return method(ARGS) end
tercio@0 70
tercio@0 71 local function dispatch(func, ...)
tercio@0 72 method = func
tercio@0 73 if not method then return end
tercio@0 74 ARGS = ...
tercio@0 75 return xpcall(call, eh)
tercio@0 76 end
tercio@0 77
tercio@0 78 return dispatch
tercio@0 79 ]]
tercio@0 80
tercio@0 81 local ARGS = {}
tercio@0 82 for i = 1, argCount do ARGS[i] = "arg"..i end
tercio@0 83 code = code:gsub("ARGS", tconcat(ARGS, ", "))
tercio@0 84 return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
tercio@0 85 end
tercio@0 86
tercio@0 87 local Dispatchers = setmetatable({}, {__index=function(self, argCount)
tercio@0 88 local dispatcher = CreateDispatcher(argCount)
tercio@0 89 rawset(self, argCount, dispatcher)
tercio@0 90 return dispatcher
tercio@0 91 end})
tercio@0 92 Dispatchers[0] = function(func)
tercio@0 93 return xpcall(func, errorhandler)
tercio@0 94 end
tercio@0 95
tercio@0 96 local function safecall(func, ...)
tercio@0 97 -- we check to see if the func is passed is actually a function here and don't error when it isn't
tercio@0 98 -- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
tercio@0 99 -- present execution should continue without hinderance
tercio@0 100 if type(func) == "function" then
tercio@0 101 return Dispatchers[select('#', ...)](func, ...)
tercio@0 102 end
tercio@0 103 end
tercio@0 104
tercio@0 105 -- local functions that will be implemented further down
tercio@0 106 local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
tercio@0 107
tercio@0 108 -- used in the addon metatable
tercio@0 109 local function addontostring( self ) return self.name end
tercio@0 110
tercio@0 111 -- Check if the addon is queued for initialization
tercio@0 112 local function queuedForInitialization(addon)
tercio@0 113 for i = 1, #AceAddon.initializequeue do
tercio@0 114 if AceAddon.initializequeue[i] == addon then
tercio@0 115 return true
tercio@0 116 end
tercio@0 117 end
tercio@0 118 return false
tercio@0 119 end
tercio@0 120
tercio@0 121 --- Create a new AceAddon-3.0 addon.
tercio@0 122 -- Any libraries you specified will be embeded, and the addon will be scheduled for
tercio@0 123 -- its OnInitialize and OnEnable callbacks.
tercio@0 124 -- The final addon object, with all libraries embeded, will be returned.
tercio@0 125 -- @paramsig [object ,]name[, lib, ...]
tercio@0 126 -- @param object Table to use as a base for the addon (optional)
tercio@0 127 -- @param name Name of the addon object to create
tercio@0 128 -- @param lib List of libraries to embed into the addon
tercio@0 129 -- @usage
tercio@0 130 -- -- Create a simple addon object
tercio@0 131 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
tercio@0 132 --
tercio@0 133 -- -- Create a Addon object based on the table of a frame
tercio@0 134 -- local MyFrame = CreateFrame("Frame")
tercio@0 135 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
tercio@0 136 function AceAddon:NewAddon(objectorname, ...)
tercio@0 137 local object,name
tercio@0 138 local i=1
tercio@0 139 if type(objectorname)=="table" then
tercio@0 140 object=objectorname
tercio@0 141 name=...
tercio@0 142 i=2
tercio@0 143 else
tercio@0 144 name=objectorname
tercio@0 145 end
tercio@0 146 if type(name)~="string" then
tercio@0 147 error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
tercio@0 148 end
tercio@0 149 if self.addons[name] then
tercio@0 150 error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
tercio@0 151 end
tercio@0 152
tercio@0 153 object = object or {}
tercio@0 154 object.name = name
tercio@0 155
tercio@0 156 local addonmeta = {}
tercio@0 157 local oldmeta = getmetatable(object)
tercio@0 158 if oldmeta then
tercio@0 159 for k, v in pairs(oldmeta) do addonmeta[k] = v end
tercio@0 160 end
tercio@0 161 addonmeta.__tostring = addontostring
tercio@0 162
tercio@0 163 setmetatable( object, addonmeta )
tercio@0 164 self.addons[name] = object
tercio@0 165 object.modules = {}
tercio@0 166 object.orderedModules = {}
tercio@0 167 object.defaultModuleLibraries = {}
tercio@0 168 Embed( object ) -- embed NewModule, GetModule methods
tercio@0 169 self:EmbedLibraries(object, select(i,...))
tercio@0 170
tercio@0 171 -- add to queue of addons to be initialized upon ADDON_LOADED
tercio@0 172 tinsert(self.initializequeue, object)
tercio@0 173 return object
tercio@0 174 end
tercio@0 175
tercio@0 176
tercio@0 177 --- Get the addon object by its name from the internal AceAddon registry.
tercio@0 178 -- Throws an error if the addon object cannot be found (except if silent is set).
tercio@0 179 -- @param name unique name of the addon object
tercio@0 180 -- @param silent if true, the addon is optional, silently return nil if its not found
tercio@0 181 -- @usage
tercio@0 182 -- -- Get the Addon
tercio@0 183 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 184 function AceAddon:GetAddon(name, silent)
tercio@0 185 if not silent and not self.addons[name] then
tercio@0 186 error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
tercio@0 187 end
tercio@0 188 return self.addons[name]
tercio@0 189 end
tercio@0 190
tercio@0 191 -- - Embed a list of libraries into the specified addon.
tercio@0 192 -- This function will try to embed all of the listed libraries into the addon
tercio@0 193 -- and error if a single one fails.
tercio@0 194 --
tercio@0 195 -- **Note:** This function is for internal use by :NewAddon/:NewModule
tercio@0 196 -- @paramsig addon, [lib, ...]
tercio@0 197 -- @param addon addon object to embed the libs in
tercio@0 198 -- @param lib List of libraries to embed into the addon
tercio@0 199 function AceAddon:EmbedLibraries(addon, ...)
tercio@0 200 for i=1,select("#", ... ) do
tercio@0 201 local libname = select(i, ...)
tercio@0 202 self:EmbedLibrary(addon, libname, false, 4)
tercio@0 203 end
tercio@0 204 end
tercio@0 205
tercio@0 206 -- - Embed a library into the addon object.
tercio@0 207 -- This function will check if the specified library is registered with LibStub
tercio@0 208 -- and if it has a :Embed function to call. It'll error if any of those conditions
tercio@0 209 -- fails.
tercio@0 210 --
tercio@0 211 -- **Note:** This function is for internal use by :EmbedLibraries
tercio@0 212 -- @paramsig addon, libname[, silent[, offset]]
tercio@0 213 -- @param addon addon object to embed the library in
tercio@0 214 -- @param libname name of the library to embed
tercio@0 215 -- @param silent marks an embed to fail silently if the library doesn't exist (optional)
tercio@0 216 -- @param offset will push the error messages back to said offset, defaults to 2 (optional)
tercio@0 217 function AceAddon:EmbedLibrary(addon, libname, silent, offset)
tercio@0 218 local lib = LibStub:GetLibrary(libname, true)
tercio@0 219 if not lib and not silent then
tercio@0 220 error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
tercio@0 221 elseif lib and type(lib.Embed) == "function" then
tercio@0 222 lib:Embed(addon)
tercio@0 223 tinsert(self.embeds[addon], libname)
tercio@0 224 return true
tercio@0 225 elseif lib then
tercio@0 226 error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
tercio@0 227 end
tercio@0 228 end
tercio@0 229
tercio@0 230 --- Return the specified module from an addon object.
tercio@0 231 -- Throws an error if the addon object cannot be found (except if silent is set)
tercio@0 232 -- @name //addon//:GetModule
tercio@0 233 -- @paramsig name[, silent]
tercio@0 234 -- @param name unique name of the module
tercio@0 235 -- @param silent if true, the module is optional, silently return nil if its not found (optional)
tercio@0 236 -- @usage
tercio@0 237 -- -- Get the Addon
tercio@0 238 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 239 -- -- Get the Module
tercio@0 240 -- MyModule = MyAddon:GetModule("MyModule")
tercio@0 241 function GetModule(self, name, silent)
tercio@0 242 if not self.modules[name] and not silent then
tercio@0 243 error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
tercio@0 244 end
tercio@0 245 return self.modules[name]
tercio@0 246 end
tercio@0 247
tercio@0 248 local function IsModuleTrue(self) return true end
tercio@0 249
tercio@0 250 --- Create a new module for the addon.
tercio@0 251 -- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
tercio@0 252 -- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
tercio@0 253 -- an addon object.
tercio@0 254 -- @name //addon//:NewModule
tercio@0 255 -- @paramsig name[, prototype|lib[, lib, ...]]
tercio@0 256 -- @param name unique name of the module
tercio@0 257 -- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
tercio@0 258 -- @param lib List of libraries to embed into the addon
tercio@0 259 -- @usage
tercio@0 260 -- -- Create a module with some embeded libraries
tercio@0 261 -- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
tercio@0 262 --
tercio@0 263 -- -- Create a module with a prototype
tercio@0 264 -- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
tercio@0 265 -- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
tercio@0 266 function NewModule(self, name, prototype, ...)
tercio@0 267 if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
tercio@0 268 if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
tercio@0 269
tercio@0 270 if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
tercio@0 271
tercio@0 272 -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
tercio@0 273 -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
tercio@0 274 local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
tercio@0 275
tercio@0 276 module.IsModule = IsModuleTrue
tercio@0 277 module:SetEnabledState(self.defaultModuleState)
tercio@0 278 module.moduleName = name
tercio@0 279
tercio@0 280 if type(prototype) == "string" then
tercio@0 281 AceAddon:EmbedLibraries(module, prototype, ...)
tercio@0 282 else
tercio@0 283 AceAddon:EmbedLibraries(module, ...)
tercio@0 284 end
tercio@0 285 AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
tercio@0 286
tercio@0 287 if not prototype or type(prototype) == "string" then
tercio@0 288 prototype = self.defaultModulePrototype or nil
tercio@0 289 end
tercio@0 290
tercio@0 291 if type(prototype) == "table" then
tercio@0 292 local mt = getmetatable(module)
tercio@0 293 mt.__index = prototype
tercio@0 294 setmetatable(module, mt) -- More of a Base class type feel.
tercio@0 295 end
tercio@0 296
tercio@0 297 safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
tercio@0 298 self.modules[name] = module
tercio@0 299 tinsert(self.orderedModules, module)
tercio@0 300
tercio@0 301 return module
tercio@0 302 end
tercio@0 303
tercio@0 304 --- Returns the real name of the addon or module, without any prefix.
tercio@0 305 -- @name //addon//:GetName
tercio@0 306 -- @paramsig
tercio@0 307 -- @usage
tercio@0 308 -- print(MyAddon:GetName())
tercio@0 309 -- -- prints "MyAddon"
tercio@0 310 function GetName(self)
tercio@0 311 return self.moduleName or self.name
tercio@0 312 end
tercio@0 313
tercio@0 314 --- Enables the Addon, if possible, return true or false depending on success.
tercio@0 315 -- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
tercio@0 316 -- and enabling all modules of the addon (unless explicitly disabled).\\
tercio@0 317 -- :Enable() also sets the internal `enableState` variable to true
tercio@0 318 -- @name //addon//:Enable
tercio@0 319 -- @paramsig
tercio@0 320 -- @usage
tercio@0 321 -- -- Enable MyModule
tercio@0 322 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 323 -- MyModule = MyAddon:GetModule("MyModule")
tercio@0 324 -- MyModule:Enable()
tercio@0 325 function Enable(self)
tercio@0 326 self:SetEnabledState(true)
tercio@0 327
tercio@0 328 -- nevcairiel 2013-04-27: don't enable an addon/module if its queued for init still
tercio@0 329 -- it'll be enabled after the init process
tercio@0 330 if not queuedForInitialization(self) then
tercio@0 331 return AceAddon:EnableAddon(self)
tercio@0 332 end
tercio@0 333 end
tercio@0 334
tercio@0 335 --- Disables the Addon, if possible, return true or false depending on success.
tercio@0 336 -- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
tercio@0 337 -- and disabling all modules of the addon.\\
tercio@0 338 -- :Disable() also sets the internal `enableState` variable to false
tercio@0 339 -- @name //addon//:Disable
tercio@0 340 -- @paramsig
tercio@0 341 -- @usage
tercio@0 342 -- -- Disable MyAddon
tercio@0 343 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 344 -- MyAddon:Disable()
tercio@0 345 function Disable(self)
tercio@0 346 self:SetEnabledState(false)
tercio@0 347 return AceAddon:DisableAddon(self)
tercio@0 348 end
tercio@0 349
tercio@0 350 --- Enables the Module, if possible, return true or false depending on success.
tercio@0 351 -- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
tercio@0 352 -- @name //addon//:EnableModule
tercio@0 353 -- @paramsig name
tercio@0 354 -- @usage
tercio@0 355 -- -- Enable MyModule using :GetModule
tercio@0 356 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 357 -- MyModule = MyAddon:GetModule("MyModule")
tercio@0 358 -- MyModule:Enable()
tercio@0 359 --
tercio@0 360 -- -- Enable MyModule using the short-hand
tercio@0 361 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 362 -- MyAddon:EnableModule("MyModule")
tercio@0 363 function EnableModule(self, name)
tercio@0 364 local module = self:GetModule( name )
tercio@0 365 return module:Enable()
tercio@0 366 end
tercio@0 367
tercio@0 368 --- Disables the Module, if possible, return true or false depending on success.
tercio@0 369 -- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
tercio@0 370 -- @name //addon//:DisableModule
tercio@0 371 -- @paramsig name
tercio@0 372 -- @usage
tercio@0 373 -- -- Disable MyModule using :GetModule
tercio@0 374 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 375 -- MyModule = MyAddon:GetModule("MyModule")
tercio@0 376 -- MyModule:Disable()
tercio@0 377 --
tercio@0 378 -- -- Disable MyModule using the short-hand
tercio@0 379 -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
tercio@0 380 -- MyAddon:DisableModule("MyModule")
tercio@0 381 function DisableModule(self, name)
tercio@0 382 local module = self:GetModule( name )
tercio@0 383 return module:Disable()
tercio@0 384 end
tercio@0 385
tercio@0 386 --- Set the default libraries to be mixed into all modules created by this object.
tercio@0 387 -- Note that you can only change the default module libraries before any module is created.
tercio@0 388 -- @name //addon//:SetDefaultModuleLibraries
tercio@0 389 -- @paramsig lib[, lib, ...]
tercio@0 390 -- @param lib List of libraries to embed into the addon
tercio@0 391 -- @usage
tercio@0 392 -- -- Create the addon object
tercio@0 393 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
tercio@0 394 -- -- Configure default libraries for modules (all modules need AceEvent-3.0)
tercio@0 395 -- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
tercio@0 396 -- -- Create a module
tercio@0 397 -- MyModule = MyAddon:NewModule("MyModule")
tercio@0 398 function SetDefaultModuleLibraries(self, ...)
tercio@0 399 if next(self.modules) then
tercio@0 400 error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
tercio@0 401 end
tercio@0 402 self.defaultModuleLibraries = {...}
tercio@0 403 end
tercio@0 404
tercio@0 405 --- Set the default state in which new modules are being created.
tercio@0 406 -- Note that you can only change the default state before any module is created.
tercio@0 407 -- @name //addon//:SetDefaultModuleState
tercio@0 408 -- @paramsig state
tercio@0 409 -- @param state Default state for new modules, true for enabled, false for disabled
tercio@0 410 -- @usage
tercio@0 411 -- -- Create the addon object
tercio@0 412 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
tercio@0 413 -- -- Set the default state to "disabled"
tercio@0 414 -- MyAddon:SetDefaultModuleState(false)
tercio@0 415 -- -- Create a module and explicilty enable it
tercio@0 416 -- MyModule = MyAddon:NewModule("MyModule")
tercio@0 417 -- MyModule:Enable()
tercio@0 418 function SetDefaultModuleState(self, state)
tercio@0 419 if next(self.modules) then
tercio@0 420 error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
tercio@0 421 end
tercio@0 422 self.defaultModuleState = state
tercio@0 423 end
tercio@0 424
tercio@0 425 --- Set the default prototype to use for new modules on creation.
tercio@0 426 -- Note that you can only change the default prototype before any module is created.
tercio@0 427 -- @name //addon//:SetDefaultModulePrototype
tercio@0 428 -- @paramsig prototype
tercio@0 429 -- @param prototype Default prototype for the new modules (table)
tercio@0 430 -- @usage
tercio@0 431 -- -- Define a prototype
tercio@0 432 -- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
tercio@0 433 -- -- Set the default prototype
tercio@0 434 -- MyAddon:SetDefaultModulePrototype(prototype)
tercio@0 435 -- -- Create a module and explicitly Enable it
tercio@0 436 -- MyModule = MyAddon:NewModule("MyModule")
tercio@0 437 -- MyModule:Enable()
tercio@0 438 -- -- should print "OnEnable called!" now
tercio@0 439 -- @see NewModule
tercio@0 440 function SetDefaultModulePrototype(self, prototype)
tercio@0 441 if next(self.modules) then
tercio@0 442 error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
tercio@0 443 end
tercio@0 444 if type(prototype) ~= "table" then
tercio@0 445 error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
tercio@0 446 end
tercio@0 447 self.defaultModulePrototype = prototype
tercio@0 448 end
tercio@0 449
tercio@0 450 --- Set the state of an addon or module
tercio@0 451 -- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
tercio@0 452 -- @name //addon//:SetEnabledState
tercio@0 453 -- @paramsig state
tercio@0 454 -- @param state the state of an addon or module (enabled=true, disabled=false)
tercio@0 455 function SetEnabledState(self, state)
tercio@0 456 self.enabledState = state
tercio@0 457 end
tercio@0 458
tercio@0 459
tercio@0 460 --- Return an iterator of all modules associated to the addon.
tercio@0 461 -- @name //addon//:IterateModules
tercio@0 462 -- @paramsig
tercio@0 463 -- @usage
tercio@0 464 -- -- Enable all modules
tercio@0 465 -- for name, module in MyAddon:IterateModules() do
tercio@0 466 -- module:Enable()
tercio@0 467 -- end
tercio@0 468 local function IterateModules(self) return pairs(self.modules) end
tercio@0 469
tercio@0 470 -- Returns an iterator of all embeds in the addon
tercio@0 471 -- @name //addon//:IterateEmbeds
tercio@0 472 -- @paramsig
tercio@0 473 local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
tercio@0 474
tercio@0 475 --- Query the enabledState of an addon.
tercio@0 476 -- @name //addon//:IsEnabled
tercio@0 477 -- @paramsig
tercio@0 478 -- @usage
tercio@0 479 -- if MyAddon:IsEnabled() then
tercio@0 480 -- MyAddon:Disable()
tercio@0 481 -- end
tercio@0 482 local function IsEnabled(self) return self.enabledState end
tercio@0 483 local mixins = {
tercio@0 484 NewModule = NewModule,
tercio@0 485 GetModule = GetModule,
tercio@0 486 Enable = Enable,
tercio@0 487 Disable = Disable,
tercio@0 488 EnableModule = EnableModule,
tercio@0 489 DisableModule = DisableModule,
tercio@0 490 IsEnabled = IsEnabled,
tercio@0 491 SetDefaultModuleLibraries = SetDefaultModuleLibraries,
tercio@0 492 SetDefaultModuleState = SetDefaultModuleState,
tercio@0 493 SetDefaultModulePrototype = SetDefaultModulePrototype,
tercio@0 494 SetEnabledState = SetEnabledState,
tercio@0 495 IterateModules = IterateModules,
tercio@0 496 IterateEmbeds = IterateEmbeds,
tercio@0 497 GetName = GetName,
tercio@0 498 }
tercio@0 499 local function IsModule(self) return false end
tercio@0 500 local pmixins = {
tercio@0 501 defaultModuleState = true,
tercio@0 502 enabledState = true,
tercio@0 503 IsModule = IsModule,
tercio@0 504 }
tercio@0 505 -- Embed( target )
tercio@0 506 -- target (object) - target object to embed aceaddon in
tercio@0 507 --
tercio@0 508 -- this is a local function specifically since it's meant to be only called internally
tercio@0 509 function Embed(target, skipPMixins)
tercio@0 510 for k, v in pairs(mixins) do
tercio@0 511 target[k] = v
tercio@0 512 end
tercio@0 513 if not skipPMixins then
tercio@0 514 for k, v in pairs(pmixins) do
tercio@0 515 target[k] = target[k] or v
tercio@0 516 end
tercio@0 517 end
tercio@0 518 end
tercio@0 519
tercio@0 520
tercio@0 521 -- - Initialize the addon after creation.
tercio@0 522 -- This function is only used internally during the ADDON_LOADED event
tercio@0 523 -- It will call the **OnInitialize** function on the addon object (if present),
tercio@0 524 -- and the **OnEmbedInitialize** function on all embeded libraries.
tercio@0 525 --
tercio@0 526 -- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
tercio@0 527 -- @param addon addon object to intialize
tercio@0 528 function AceAddon:InitializeAddon(addon)
tercio@0 529 safecall(addon.OnInitialize, addon)
tercio@0 530
tercio@0 531 local embeds = self.embeds[addon]
tercio@0 532 for i = 1, #embeds do
tercio@0 533 local lib = LibStub:GetLibrary(embeds[i], true)
tercio@0 534 if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
tercio@0 535 end
tercio@0 536
tercio@0 537 -- we don't call InitializeAddon on modules specifically, this is handled
tercio@0 538 -- from the event handler and only done _once_
tercio@0 539 end
tercio@0 540
tercio@0 541 -- - Enable the addon after creation.
tercio@0 542 -- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
tercio@0 543 -- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
tercio@0 544 -- It will call the **OnEnable** function on the addon object (if present),
tercio@0 545 -- and the **OnEmbedEnable** function on all embeded libraries.\\
tercio@0 546 -- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
tercio@0 547 --
tercio@0 548 -- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
tercio@0 549 -- Use :Enable on the addon itself instead.
tercio@0 550 -- @param addon addon object to enable
tercio@0 551 function AceAddon:EnableAddon(addon)
tercio@0 552 if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
tercio@0 553 if self.statuses[addon.name] or not addon.enabledState then return false end
tercio@0 554
tercio@0 555 -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
tercio@0 556 self.statuses[addon.name] = true
tercio@0 557
tercio@0 558 safecall(addon.OnEnable, addon)
tercio@0 559
tercio@0 560 -- make sure we're still enabled before continueing
tercio@0 561 if self.statuses[addon.name] then
tercio@0 562 local embeds = self.embeds[addon]
tercio@0 563 for i = 1, #embeds do
tercio@0 564 local lib = LibStub:GetLibrary(embeds[i], true)
tercio@0 565 if lib then safecall(lib.OnEmbedEnable, lib, addon) end
tercio@0 566 end
tercio@0 567
tercio@0 568 -- enable possible modules.
tercio@0 569 local modules = addon.orderedModules
tercio@0 570 for i = 1, #modules do
tercio@0 571 self:EnableAddon(modules[i])
tercio@0 572 end
tercio@0 573 end
tercio@0 574 return self.statuses[addon.name] -- return true if we're disabled
tercio@0 575 end
tercio@0 576
tercio@0 577 -- - Disable the addon
tercio@0 578 -- Note: This function is only used internally.
tercio@0 579 -- It will call the **OnDisable** function on the addon object (if present),
tercio@0 580 -- and the **OnEmbedDisable** function on all embeded libraries.\\
tercio@0 581 -- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
tercio@0 582 --
tercio@0 583 -- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
tercio@0 584 -- Use :Disable on the addon itself instead.
tercio@0 585 -- @param addon addon object to enable
tercio@0 586 function AceAddon:DisableAddon(addon)
tercio@0 587 if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
tercio@0 588 if not self.statuses[addon.name] then return false end
tercio@0 589
tercio@0 590 -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
tercio@0 591 self.statuses[addon.name] = false
tercio@0 592
tercio@0 593 safecall( addon.OnDisable, addon )
tercio@0 594
tercio@0 595 -- make sure we're still disabling...
tercio@0 596 if not self.statuses[addon.name] then
tercio@0 597 local embeds = self.embeds[addon]
tercio@0 598 for i = 1, #embeds do
tercio@0 599 local lib = LibStub:GetLibrary(embeds[i], true)
tercio@0 600 if lib then safecall(lib.OnEmbedDisable, lib, addon) end
tercio@0 601 end
tercio@0 602 -- disable possible modules.
tercio@0 603 local modules = addon.orderedModules
tercio@0 604 for i = 1, #modules do
tercio@0 605 self:DisableAddon(modules[i])
tercio@0 606 end
tercio@0 607 end
tercio@0 608
tercio@0 609 return not self.statuses[addon.name] -- return true if we're disabled
tercio@0 610 end
tercio@0 611
tercio@0 612 --- Get an iterator over all registered addons.
tercio@0 613 -- @usage
tercio@0 614 -- -- Print a list of all installed AceAddon's
tercio@0 615 -- for name, addon in AceAddon:IterateAddons() do
tercio@0 616 -- print("Addon: " .. name)
tercio@0 617 -- end
tercio@0 618 function AceAddon:IterateAddons() return pairs(self.addons) end
tercio@0 619
tercio@0 620 --- Get an iterator over the internal status registry.
tercio@0 621 -- @usage
tercio@0 622 -- -- Print a list of all enabled addons
tercio@0 623 -- for name, status in AceAddon:IterateAddonStatus() do
tercio@0 624 -- if status then
tercio@0 625 -- print("EnabledAddon: " .. name)
tercio@0 626 -- end
tercio@0 627 -- end
tercio@0 628 function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
tercio@0 629
tercio@0 630 -- Following Iterators are deprecated, and their addon specific versions should be used
tercio@0 631 -- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
tercio@0 632 function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
tercio@0 633 function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
tercio@0 634
tercio@0 635 -- Event Handling
tercio@0 636 local function onEvent(this, event, arg1)
tercio@0 637 -- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up
tercio@0 638 if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then
tercio@0 639 -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
tercio@0 640 while(#AceAddon.initializequeue > 0) do
tercio@0 641 local addon = tremove(AceAddon.initializequeue, 1)
tercio@0 642 -- this might be an issue with recursion - TODO: validate
tercio@0 643 if event == "ADDON_LOADED" then addon.baseName = arg1 end
tercio@0 644 AceAddon:InitializeAddon(addon)
tercio@0 645 tinsert(AceAddon.enablequeue, addon)
tercio@0 646 end
tercio@0 647
tercio@0 648 if IsLoggedIn() then
tercio@0 649 while(#AceAddon.enablequeue > 0) do
tercio@0 650 local addon = tremove(AceAddon.enablequeue, 1)
tercio@0 651 AceAddon:EnableAddon(addon)
tercio@0 652 end
tercio@0 653 end
tercio@0 654 end
tercio@0 655 end
tercio@0 656
tercio@0 657 AceAddon.frame:RegisterEvent("ADDON_LOADED")
tercio@0 658 AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
tercio@0 659 AceAddon.frame:SetScript("OnEvent", onEvent)
tercio@0 660
tercio@0 661 -- upgrade embeded
tercio@0 662 for name, addon in pairs(AceAddon.addons) do
tercio@0 663 Embed(addon, true)
tercio@0 664 end
tercio@0 665
tercio@0 666 -- 2010-10-27 nevcairiel - add new "orderedModules" table
tercio@0 667 if oldminor and oldminor < 10 then
tercio@0 668 for name, addon in pairs(AceAddon.addons) do
tercio@0 669 addon.orderedModules = {}
tercio@0 670 for module_name, module in pairs(addon.modules) do
tercio@0 671 tinsert(addon.orderedModules, module)
tercio@0 672 end
tercio@0 673 end
tercio@0 674 end