replace Ace3v with Ace3 ElvUI-TBC version

or easy tracking of code difference
This commit is contained in:
Pinya
2018-07-21 13:20:39 +03:00
parent bb867629d5
commit 332d53e7f6
59 changed files with 1975 additions and 2496 deletions
+104 -111
View File
@@ -35,10 +35,6 @@ local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceAddon then return end -- No Upgrade needed. if not AceAddon then return end -- No Upgrade needed.
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
local wipe, truncate = AceCore.wipe, AceCore.truncate
AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
AceAddon.addons = AceAddon.addons or {} -- addons in general AceAddon.addons = AceAddon.addons or {} -- addons in general
AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon. AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
@@ -47,9 +43,9 @@ AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized
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 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
-- Lua APIs -- Lua APIs
local tinsert, tconcat, tremove, tgetn = table.insert, table.concat, table.remove, table.getn local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
local strfmt, tostring = string.format, tostring local fmt, tostring = string.format, tostring
local pairs, next, type, unpack = pairs, next, type, unpack local select, pairs, next, type, unpack = select, pairs, next, type, unpack
local loadstring, assert, error = loadstring, assert, error local loadstring, assert, error = loadstring, assert, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
@@ -60,7 +56,51 @@ local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, r
--[[ --[[
xpcall safecall implementation xpcall safecall implementation
]] ]]
local safecall = AceCore.safecall local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = ...
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
-- we check to see if the func is passed is actually a function here and don't error when it isn't
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
-- present execution should continue without hinderance
if type(func) == "function" then
return Dispatchers[select('#', ...)](func, ...)
end
end
-- local functions that will be implemented further down -- local functions that will be implemented further down
local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
@@ -70,7 +110,7 @@ local function addontostring( self ) return self.name end
-- Check if the addon is queued for initialization -- Check if the addon is queued for initialization
local function queuedForInitialization(addon) local function queuedForInitialization(addon)
for i = 1, tgetn(AceAddon.initializequeue) do for i = 1, #AceAddon.initializequeue do
if AceAddon.initializequeue[i] == addon then if AceAddon.initializequeue[i] == addon then
return true return true
end end
@@ -93,34 +133,23 @@ end
-- -- Create a Addon object based on the table of a frame -- -- Create a Addon object based on the table of a frame
-- local MyFrame = CreateFrame("Frame") -- local MyFrame = CreateFrame("Frame")
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0") -- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
function AceAddon:NewAddon(objectorname,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) function AceAddon:NewAddon(objectorname, ...)
local object,name local object,name
local i=1
if type(objectorname)=="table" then if type(objectorname)=="table" then
object=objectorname object=objectorname
name=a0 name=...
i=2
else else
name=objectorname name=objectorname
end end
if type(name)~="string" then if type(name)~="string" then
error(strfmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2) error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
end end
if self.addons[name] then if self.addons[name] then
error(strfmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists.", name), 2) error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
end end
local args = new()
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
object = object or {} object = object or {}
object.name = name object.name = name
@@ -137,18 +166,14 @@ function AceAddon:NewAddon(objectorname,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
object.orderedModules = {} object.orderedModules = {}
object.defaultModuleLibraries = {} object.defaultModuleLibraries = {}
Embed( object ) -- embed NewModule, GetModule methods Embed( object ) -- embed NewModule, GetModule methods
if type(objectorname)=="table" then self:EmbedLibraries(object, select(i,...))
self:EmbedLibraries(object,nil,args)
elseif a0 then
self:EmbedLibraries(object,a0,args)
end
del(args)
-- add to queue of addons to be initialized upon ADDON_LOADED -- add to queue of addons to be initialized upon ADDON_LOADED
tinsert(self.initializequeue, object) tinsert(self.initializequeue, object)
return object return object
end end
--- Get the addon object by its name from the internal AceAddon registry. --- Get the addon object by its name from the internal AceAddon registry.
-- Throws an error if the addon object cannot be found (except if silent is set). -- Throws an error if the addon object cannot be found (except if silent is set).
-- @param name unique name of the addon object -- @param name unique name of the addon object
@@ -158,7 +183,7 @@ end
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon") -- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
function AceAddon:GetAddon(name, silent) function AceAddon:GetAddon(name, silent)
if not silent and not self.addons[name] then if not silent and not self.addons[name] then
error(strfmt("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'.", tostring(name)), 2) error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
end end
return self.addons[name] return self.addons[name]
end end
@@ -171,12 +196,10 @@ end
-- @paramsig addon, [lib, ...] -- @paramsig addon, [lib, ...]
-- @param addon addon object to embed the libs in -- @param addon addon object to embed the libs in
-- @param lib List of libraries to embed into the addon -- @param lib List of libraries to embed into the addon
function AceAddon:EmbedLibraries(addon,a1,arg) function AceAddon:EmbedLibraries(addon, ...)
if a1 then self:EmbedLibrary(addon, a1, false, 4) end for i=1,select("#", ... ) do
-- 10 is the max number of variable arguments in the function NewAddon and NewModule local libname = select(i, ...)
for i=1,10 do self:EmbedLibrary(addon, libname, false, 4)
if not arg[i] then return end
self:EmbedLibrary(addon, arg[i], false, 4)
end end
end end
@@ -194,13 +217,13 @@ end
function AceAddon:EmbedLibrary(addon, libname, silent, offset) function AceAddon:EmbedLibrary(addon, libname, silent, offset)
local lib = LibStub:GetLibrary(libname, true) local lib = LibStub:GetLibrary(libname, true)
if not lib and not silent then if not lib and not silent then
error(strfmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q.", tostring(libname)), offset or 2) error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
elseif lib and type(lib.Embed) == "function" then elseif lib and type(lib.Embed) == "function" then
lib:Embed(addon) lib:Embed(addon)
tinsert(self.embeds[addon], libname) tinsert(self.embeds[addon], libname)
return true return true
elseif lib then elseif lib then
error(strfmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable", libname), offset or 2) error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
end end
end end
@@ -217,7 +240,7 @@ end
-- MyModule = MyAddon:GetModule("MyModule") -- MyModule = MyAddon:GetModule("MyModule")
function GetModule(self, name, silent) function GetModule(self, name, silent)
if not self.modules[name] and not silent then if not self.modules[name] and not silent then
error(strfmt("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'.", tostring(name)), 2) error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
end end
return self.modules[name] return self.modules[name]
end end
@@ -240,39 +263,26 @@ local function IsModuleTrue(self) return true end
-- -- Create a module with a prototype -- -- Create a module with a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end } -- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0") -- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
function NewModule(self, name, prototype, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) function NewModule(self, name, prototype, ...)
if type(name) ~= "string" then error(strfmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2) end if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(strfmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'.", type(prototype)), 2) end 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
if self.modules[name] then error(strfmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists.", name), 2) end if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
-- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well. -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
-- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is. -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
local module = AceAddon:NewAddon(strfmt("%s_%s", self.name or tostring(self), name)) local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
module.IsModule = IsModuleTrue module.IsModule = IsModuleTrue
module:SetEnabledState(self.defaultModuleState) module:SetEnabledState(self.defaultModuleState)
module.moduleName = name module.moduleName = name
local args = new()
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
if type(prototype) == "string" then if type(prototype) == "string" then
AceAddon:EmbedLibraries(module, prototype, args) AceAddon:EmbedLibraries(module, prototype, ...)
else else
AceAddon:EmbedLibraries(module, nil, args) AceAddon:EmbedLibraries(module, ...)
end end
del(args) AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
AceAddon:EmbedLibraries(module, nil, self.defaultModuleLibraries)
if not prototype or type(prototype) == "string" then if not prototype or type(prototype) == "string" then
prototype = self.defaultModulePrototype or nil prototype = self.defaultModulePrototype or nil
@@ -284,7 +294,7 @@ function NewModule(self, name, prototype, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
setmetatable(module, mt) -- More of a Base class type feel. setmetatable(module, mt) -- More of a Base class type feel.
end end
safecall(self.OnModuleCreated, 2, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy. safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
self.modules[name] = module self.modules[name] = module
tinsert(self.orderedModules, module) tinsert(self.orderedModules, module)
@@ -385,23 +395,11 @@ end
-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0") -- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
-- -- Create a module -- -- Create a module
-- MyModule = MyAddon:NewModule("MyModule") -- MyModule = MyAddon:NewModule("MyModule")
function SetDefaultModuleLibraries(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) function SetDefaultModuleLibraries(self, ...)
if next(self.modules) then if next(self.modules) then
error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2) error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
end end
local args = self.defaultModuleLibraries or {} self.defaultModuleLibraries = {...}
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
self.defaultModuleLibraries = args
end end
--- Set the default state in which new modules are being created. --- Set the default state in which new modules are being created.
@@ -444,7 +442,7 @@ function SetDefaultModulePrototype(self, prototype)
error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2) error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
end end
if type(prototype) ~= "table" then if type(prototype) ~= "table" then
error(strfmt("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'.", type(prototype)), 2) error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
end end
self.defaultModulePrototype = prototype self.defaultModulePrototype = prototype
end end
@@ -528,12 +526,12 @@ end
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing. -- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- @param addon addon object to intialize -- @param addon addon object to intialize
function AceAddon:InitializeAddon(addon) function AceAddon:InitializeAddon(addon)
safecall(addon.OnInitialize, 1, addon) safecall(addon.OnInitialize, addon)
local embeds = self.embeds[addon] local embeds = self.embeds[addon]
for i = 1, tgetn(embeds) do for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true) local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedInitialize, 2, lib, addon) end if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
end end
-- we don't call InitializeAddon on modules specifically, this is handled -- we don't call InitializeAddon on modules specifically, this is handled
@@ -557,19 +555,19 @@ function AceAddon:EnableAddon(addon)
-- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable. -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
self.statuses[addon.name] = true self.statuses[addon.name] = true
safecall(addon.OnEnable, 1, addon) safecall(addon.OnEnable, addon)
-- make sure we're still enabled before continueing -- make sure we're still enabled before continueing
if self.statuses[addon.name] then if self.statuses[addon.name] then
local embeds = self.embeds[addon] local embeds = self.embeds[addon]
for i = 1, tgetn(embeds) do for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true) local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedEnable, 2, lib, addon) end if lib then safecall(lib.OnEmbedEnable, lib, addon) end
end end
-- enable possible modules. -- enable possible modules.
local modules = addon.orderedModules local modules = addon.orderedModules
for i = 1, tgetn(modules) do for i = 1, #modules do
self:EnableAddon(modules[i]) self:EnableAddon(modules[i])
end end
end end
@@ -592,18 +590,18 @@ function AceAddon:DisableAddon(addon)
-- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable. -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
self.statuses[addon.name] = false self.statuses[addon.name] = false
safecall(addon.OnDisable, 1, addon) safecall( addon.OnDisable, addon )
-- make sure we're still disabling... -- make sure we're still disabling...
if not self.statuses[addon.name] then if not self.statuses[addon.name] then
local embeds = self.embeds[addon] local embeds = self.embeds[addon]
for i = 1, tgetn(embeds) do for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true) local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedDisable, 2, lib, addon) end if lib then safecall(lib.OnEmbedDisable, lib, addon) end
end end
-- disable possible modules. -- disable possible modules.
local modules = addon.orderedModules local modules = addon.orderedModules
for i = 1, tgetn(modules) do for i = 1, #modules do
self:DisableAddon(modules[i]) self:DisableAddon(modules[i])
end end
end end
@@ -634,22 +632,12 @@ function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
local onEvent
do
local IsLoggedIn = false
-- Event Handling -- Event Handling
function onEvent() local function onEvent(this, event, arg1)
-- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up -- 2011-08-17 nevcairiel - ignore the load event of !DebugTools, so a potential startup error isn't swallowed up
-- Ace3v: When the ADDON_LOADED event is triggerd, global arg1 is the loaded addon name if (event == "ADDON_LOADED" and arg1 ~= "!DebugTools") or event == "PLAYER_LOGIN" then
-- so onEvent(event, arg1) won't work because it will cover the global variables
if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then
-- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
-- Ace3v: When an Ace3 addons is loaded, then he initializeque should not be empty unless while(#AceAddon.initializequeue > 0) do
-- the addon does not use the library. If an addon that does not use Ace3 library
-- is loaded, we will also receive the ADDON_LOADED event but in this case the
-- queue will be empty so we have nothing to do.
while(tgetn(AceAddon.initializequeue) > 0) do
local addon = tremove(AceAddon.initializequeue, 1) local addon = tremove(AceAddon.initializequeue, 1)
-- this might be an issue with recursion - TODO: validate -- this might be an issue with recursion - TODO: validate
if event == "ADDON_LOADED" then addon.baseName = arg1 end if event == "ADDON_LOADED" then addon.baseName = arg1 end
@@ -657,19 +645,14 @@ function onEvent()
tinsert(AceAddon.enablequeue, addon) tinsert(AceAddon.enablequeue, addon)
end end
if event == "PLAYER_LOGIN" then if IsLoggedIn() then
IsLoggedIn = true while(#AceAddon.enablequeue > 0) do
end
if IsLoggedIn then
while(tgetn(AceAddon.enablequeue) > 0) do
local addon = tremove(AceAddon.enablequeue, 1) local addon = tremove(AceAddon.enablequeue, 1)
AceAddon:EnableAddon(addon) AceAddon:EnableAddon(addon)
end end
end end
end end
end end
end -- onEvent
AceAddon.frame:RegisterEvent("ADDON_LOADED") AceAddon.frame:RegisterEvent("ADDON_LOADED")
AceAddon.frame:RegisterEvent("PLAYER_LOGIN") AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
@@ -679,3 +662,13 @@ AceAddon.frame:SetScript("OnEvent", onEvent)
for name, addon in pairs(AceAddon.addons) do for name, addon in pairs(AceAddon.addons) do
Embed(addon, true) Embed(addon, true)
end end
-- 2010-10-27 nevcairiel - add new "orderedModules" table
if oldminor and oldminor < 10 then
for name, addon in pairs(AceAddon.addons) do
addon.orderedModules = {}
for module_name, module in pairs(addon.modules) do
tinsert(addon.orderedModules, module)
end
end
end
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceAddon-3.0.lua"/> <Script file="AceAddon-3.0.lua"/>
</Ui> </Ui>
+68 -66
View File
@@ -9,7 +9,7 @@
-- make into AceComm. -- make into AceComm.
-- @class file -- @class file
-- @name AceComm-3.0 -- @name AceComm-3.0
-- @release $Id: AceComm-3.0.lua 1107 2014-02-19 16:40:32Z nevcairiel $ -- @release $Id: AceComm-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
--[[ AceComm-3.0 --[[ AceComm-3.0
@@ -17,25 +17,23 @@ TODO: Time out old data rotting around from dead senders? Not a HUGE deal since
]] ]]
local MAJOR, MINOR = "AceComm-3.0", 9 local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib")
local MAJOR, MINOR = "AceComm-3.0", 10
local AceComm,oldminor = LibStub:NewLibrary(MAJOR, MINOR) local AceComm,oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceComm then return end if not AceComm then return end
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib")
-- Lua APIs -- Lua APIs
local type, next, pairs, tostring = type, next, pairs, tostring local type, next, pairs, tostring = type, next, pairs, tostring
local strlen, strsub, strfind = string.len, string.sub, string.find local strsub, strfind = string.sub, string.find
local tinsert, tconcat, tgetn, tremove = table.insert, table.concat, table.getn, table.remove local tinsert, tconcat = table.insert, table.concat
local error, assert = error, assert local error, assert = error, assert
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
-- GLOBALS: LibStub, DEFAULT_CHAT_FRAME, geterrorhandler, RegisterAddonMessagePrefix -- GLOBALS: LibStub, DEFAULT_CHAT_FRAME, geterrorhandler
AceComm.embeds = AceComm.embeds or {} AceComm.embeds = AceComm.embeds or {}
@@ -43,27 +41,21 @@ AceComm.embeds = AceComm.embeds or {}
local MSG_MULTI_FIRST = "\001" local MSG_MULTI_FIRST = "\001"
local MSG_MULTI_NEXT = "\002" local MSG_MULTI_NEXT = "\002"
local MSG_MULTI_LAST = "\003" local MSG_MULTI_LAST = "\003"
local MSG_ESCAPE = "\004"
-- remove old structures (pre WoW 4.0) AceComm.multipart_origprefixes = AceComm.multipart_origprefixes or {} -- e.g. "Prefix\001"="Prefix", "Prefix\002"="Prefix"
AceComm.multipart_origprefixes = nil AceComm.multipart_reassemblers = AceComm.multipart_reassemblers or {} -- e.g. "Prefix\001"="OnReceiveMultipartFirst"
AceComm.multipart_reassemblers = nil
-- the multipart message spool: indexed by a combination of sender+distribution+ -- the multipart message spool: indexed by a combination of sender+distribution+
AceComm.multipart_spool = AceComm.multipart_spool or {} AceComm.multipart_spool = AceComm.multipart_spool or {}
--- Register for Addon Traffic on a specified prefix --- Register for Addon Traffic on a specified prefix
-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent), max 16 characters -- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent)
-- @param method Callback to call on message reception: Function reference, or method name (string) to call on self. Defaults to "OnCommReceived" -- @param method Callback to call on message reception: Function reference, or method name (string) to call on self. Defaults to "OnCommReceived"
function AceComm:RegisterComm(prefix, method) function AceComm:RegisterComm(prefix, method)
if method == nil then if method == nil then
method = "OnCommReceived" method = "OnCommReceived"
end end
if strlen(prefix) > 16 then -- TODO: 15?
error("AceComm:RegisterComm(prefix,method): prefix length is limited to 16 characters")
end
return AceComm._RegisterComm(self, prefix, method) -- created by CallbackHandler return AceComm._RegisterComm(self, prefix, method) -- created by CallbackHandler
end end
@@ -88,10 +80,19 @@ function AceComm:SendCommMessage(prefix, text, distribution, target, prio, callb
error('Usage: SendCommMessage(addon, "prefix", "text", "distribution"[, "target"[, "prio"[, callbackFn, callbackarg]]])', 2) error('Usage: SendCommMessage(addon, "prefix", "text", "distribution"[, "target"[, "prio"[, callbackFn, callbackarg]]])', 2)
end end
local textlen = strlen(text) if strfind(prefix, "[\001-\009]") then
-- Yes, the max is 255 even if the dev post said 256. I tested. Char 256+ get silently truncated. /Mikk, 20110327 if strfind(prefix, "[\001-\003]") then
-- Ace3v: substract the prefix length error("SendCommMessage: Characters \\001--\\003 in prefix are reserved for AceComm metadata", 2)
local maxtextlen = 254 - strlen(prefix) elseif not warnedPrefix then
-- I have some ideas about future extensions that require more control characters /mikk, 20090808
geterrorhandler()("SendCommMessage: Heads-up developers: Characters \\004--\\009 in prefix are reserved for AceComm future extension")
warnedPrefix = true
end
end
local textlen = #text
local maxtextlen = 254 - #prefix -- 254 is the max length of prefix + text that can be sent in one message
local queueName = prefix..distribution..(target or "") local queueName = prefix..distribution..(target or "")
local ctlCallback = nil local ctlCallback = nil
@@ -101,38 +102,29 @@ function AceComm:SendCommMessage(prefix, text, distribution, target, prio, callb
end end
end end
local forceMultipart if textlen <= maxtextlen then
if strfind(text, "^[\001-\009]") then -- 4.1+: see if the first character is a control character
-- we need to escape the first character with a \004
if textlen+1 > maxtextlen then -- would we go over the size limit?
forceMultipart = true -- just make it multipart, no escape problems then
else
text = "\004" .. text
end
end
if not forceMultipart and textlen <= maxtextlen then
-- fits all in one message -- fits all in one message
CTL:SendAddonMessage(prio, prefix, text, distribution, target, queueName, ctlCallback, textlen) CTL:SendAddonMessage(prio, prefix, text, distribution, target, queueName, ctlCallback, textlen)
else else
maxtextlen = maxtextlen - 1 -- 1 extra byte for part indicator in prefix(4.0)/start of message(4.1) maxtextlen = maxtextlen - 1 -- 1 extra byte for part indicator in prefix
-- first part -- first part
local chunk = strsub(text, 1, maxtextlen) local chunk = strsub(text, 1, maxtextlen)
CTL:SendAddonMessage(prio, prefix, MSG_MULTI_FIRST..chunk, distribution, target, queueName, ctlCallback, maxtextlen) CTL:SendAddonMessage(prio, prefix..MSG_MULTI_FIRST, chunk, distribution, target, queueName, ctlCallback, maxtextlen)
-- continuation -- continuation
local pos = 1+maxtextlen local pos = 1+maxtextlen
local prefix2 = prefix..MSG_MULTI_NEXT
while pos+maxtextlen <= textlen do while pos+maxtextlen <= textlen do
chunk = strsub(text, pos, pos+maxtextlen-1) chunk = strsub(text, pos, pos+maxtextlen-1)
CTL:SendAddonMessage(prio, prefix, MSG_MULTI_NEXT..chunk, distribution, target, queueName, ctlCallback, pos+maxtextlen-1) CTL:SendAddonMessage(prio, prefix2, chunk, distribution, target, queueName, ctlCallback, pos+maxtextlen-1)
pos = pos + maxtextlen pos = pos + maxtextlen
end end
-- final part -- final part
chunk = strsub(text, pos) chunk = strsub(text, pos)
CTL:SendAddonMessage(prio, prefix, MSG_MULTI_LAST..chunk, distribution, target, queueName, ctlCallback, textlen) CTL:SendAddonMessage(prio, prefix..MSG_MULTI_LAST, chunk, distribution, target, queueName, ctlCallback, textlen)
end end
end end
@@ -147,8 +139,8 @@ do
local t = next(compost) local t = next(compost)
if t then if t then
compost[t]=nil compost[t]=nil
for i=tgetn(t),3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten for i=#t,3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten
tremove(t) -- Ace3v: t[i] = nil wont affect the tgetn return value t[i]=nil
end end
return t return t
end end
@@ -210,11 +202,11 @@ do
if type(olddata) == "table" then if type(olddata) == "table" then
-- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat -- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat
tinsert(olddata, message) tinsert(olddata, message)
AceComm.callbacks:Fire(prefix, 3, tconcat(olddata, ""), distribution, sender) AceComm.callbacks:Fire(prefix, tconcat(olddata, ""), distribution, sender)
compost[olddata] = true compost[olddata] = true
else else
-- if we've only received a "first", the spooled data will still only be a string -- if we've only received a "first", the spooled data will still only be a string
AceComm.callbacks:Fire(prefix, 3, olddata..message, distribution, sender) AceComm.callbacks:Fire(prefix, olddata..message, distribution, sender)
end end
end end
end end
@@ -229,40 +221,50 @@ end
---------------------------------------- ----------------------------------------
if not AceComm.callbacks then if not AceComm.callbacks then
-- ensure that 'prefix to watch' table is consistent with registered
-- callbacks
AceComm.__prefixes = {}
AceComm.callbacks = CallbackHandler:New(AceComm, AceComm.callbacks = CallbackHandler:New(AceComm,
"_RegisterComm", "_RegisterComm",
"UnregisterComm", "UnregisterComm",
"UnregisterAllComm") "UnregisterAllComm")
end end
AceComm.callbacks.OnUsed = nil function AceComm.callbacks:OnUsed(target, prefix)
AceComm.callbacks.OnUnused = nil AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = prefix
AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = "OnReceiveMultipartFirst"
-- Ace3v: in vanilla, global vars: AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = prefix
-- event -> event type AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = "OnReceiveMultipartNext"
-- arg1 -> prefix
-- arg2 -> message AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = prefix
-- arg3 -> channel AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = "OnReceiveMultipartLast"
-- arg4 -> sender end
local function OnEvent()
local prefix, message, distribution, sender = arg1, arg2, arg3, arg4 function AceComm.callbacks:OnUnused(target, prefix)
AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = nil
AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = nil
AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = nil
AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = nil
AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = nil
AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = nil
end
local function OnEvent(this, event, ...)
if event == "CHAT_MSG_ADDON" then if event == "CHAT_MSG_ADDON" then
local _, _, control, rest = strfind(message, "^([\001-\009])(.*)") local prefix,message,distribution,sender = ...
if control then local reassemblername = AceComm.multipart_reassemblers[prefix]
if control==MSG_MULTI_FIRST then if reassemblername then
AceComm:OnReceiveMultipartFirst(prefix, rest, distribution, sender) -- multipart: reassemble
elseif control==MSG_MULTI_NEXT then local aceCommReassemblerFunc = AceComm[reassemblername]
AceComm:OnReceiveMultipartNext(prefix, rest, distribution, sender) local origprefix = AceComm.multipart_origprefixes[prefix]
elseif control==MSG_MULTI_LAST then aceCommReassemblerFunc(AceComm, origprefix, message, distribution, sender)
AceComm:OnReceiveMultipartLast(prefix, rest, distribution, sender)
elseif control==MSG_ESCAPE then
AceComm.callbacks:Fire(prefix, 3, rest, distribution, sender)
else
-- unknown control character, ignore SILENTLY (dont warn unnecessarily about future extensions!)
end
else else
-- single part: fire it off immediately and let CallbackHandler decide if it's registered or not -- single part: fire it off immediately and let CallbackHandler decide if it's registered or not
AceComm.callbacks:Fire(prefix, 3, message, distribution, sender) AceComm.callbacks:Fire(prefix, message, distribution, sender)
end end
else else
assert(false, "Received "..tostring(event).." event?!") assert(false, "Received "..tostring(event).." event?!")
@@ -303,4 +305,4 @@ end
-- Update embeds -- Update embeds
for target, v in pairs(AceComm.embeds) do for target, v in pairs(AceComm.embeds) do
AceComm:Embed(target) AceComm:Embed(target)
end end
+2 -1
View File
@@ -1,4 +1,5 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="ChatThrottleLib.lua"/> <Script file="ChatThrottleLib.lua"/>
<Script file="AceComm-3.0.lua"/> <Script file="AceComm-3.0.lua"/>
</Ui> </Ui>
+42 -66
View File
@@ -20,15 +20,10 @@
-- --
-- Can run as a standalone addon also, but, really, just embed it! :-) -- Can run as a standalone addon also, but, really, just embed it! :-)
-- --
-- LICENSE: ChatThrottleLib is released into the Public Domain
--
local CTL_VERSION = 23 local CTL_VERSION = 21
local AceCore = LibStub("AceCore-3.0") local _G = _G
local _G = AceCore._G
local hooksecurefunc = AceCore.hooksecurefunc
local wipe = AceCore.wipe
if _G.ChatThrottleLib then if _G.ChatThrottleLib then
if _G.ChatThrottleLib.version >= CTL_VERSION then if _G.ChatThrottleLib.version >= CTL_VERSION then
@@ -70,7 +65,6 @@ ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) i
local setmetatable = setmetatable local setmetatable = setmetatable
local table_remove = table.remove local table_remove = table.remove
local tinsert = table.insert
local tostring = tostring local tostring = tostring
local GetTime = GetTime local GetTime = GetTime
local math_min = math.min local math_min = math.min
@@ -78,9 +72,7 @@ local math_max = math.max
local next = next local next = next
local strlen = string.len local strlen = string.len
local GetFramerate = GetFramerate local GetFramerate = GetFramerate
local strlower = string.lower
local unpack,type,pairs,wipe = unpack,type,pairs,wipe
local UnitInRaid,UnitInParty = UnitInRaid,UnitInParty
----------------------------------------------------------------------- -----------------------------------------------------------------------
@@ -123,20 +115,24 @@ end
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- Recycling bin for pipes -- Recycling bin for pipes
-- A pipe is a plain integer-indexed queue of messages -- A pipe is a plain integer-indexed queue, which also happens to be a ring member
-- Pipes normally live in Rings of pipes (3 rings total, one per priority)
ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different
local PipeBin = setmetatable({}, {__mode="k"}) local PipeBin = setmetatable({}, {__mode="k"})
local function DelPipe(pipe) local function DelPipe(pipe)
for i = #pipe, 1, -1 do
pipe[i] = nil
end
pipe.prev = nil
pipe.next = nil
PipeBin[pipe] = true PipeBin[pipe] = true
end end
local function NewPipe() local function NewPipe()
local pipe = next(PipeBin) local pipe = next(PipeBin)
if pipe then if pipe then
wipe(pipe)
PipeBin[pipe] = nil PipeBin[pipe] = nil
return pipe return pipe
end end
@@ -213,12 +209,12 @@ function ChatThrottleLib:Init()
-- Use secure hooks as of v16. Old regular hook support yanked out in v21. -- Use secure hooks as of v16. Old regular hook support yanked out in v21.
self.securelyHooked = true self.securelyHooked = true
--SendChatMessage --SendChatMessage
hooksecurefunc("SendChatMessage", function(text, chattype, language, destination) hooksecurefunc("SendChatMessage", function(...)
return ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination) return ChatThrottleLib.Hook_SendChatMessage(...)
end) end)
--SendAddonMessage --SendAddonMessage
hooksecurefunc("SendAddonMessage", function(prefix, text, chattype, destination) hooksecurefunc("SendAddonMessage", function(...)
return ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination) return ChatThrottleLib.Hook_SendAddonMessage(...)
end) end)
end end
self.nBypass = 0 self.nBypass = 0
@@ -230,7 +226,7 @@ end
local bMyTraffic = false local bMyTraffic = false
function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination) function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...)
if bMyTraffic then if bMyTraffic then
return return
end end
@@ -239,13 +235,13 @@ function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destinat
self.avail = self.avail - size self.avail = self.avail - size
self.nBypass = self.nBypass + size -- just a statistic self.nBypass = self.nBypass + size -- just a statistic
end end
function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination) function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...)
if bMyTraffic then if bMyTraffic then
return return
end end
local self = ChatThrottleLib local self = ChatThrottleLib
local size = strlen(tostring(text or "")) + strlen(tostring(prefix or "")); local size = tostring(text or ""):len() + tostring(prefix or ""):len();
size = size + strlen(tostring(destination or "")) + self.MSG_OVERHEAD size = size + tostring(destination or ""):len() + self.MSG_OVERHEAD
self.avail = self.avail - size self.avail = self.avail - size
self.nBypass = self.nBypass + size -- just a statistic self.nBypass = self.nBypass + size -- just a statistic
end end
@@ -266,7 +262,7 @@ function ChatThrottleLib:UpdateAvail()
-- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then -- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then
avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5) avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5)
self.bChoking = true self.bChoking = true
elseif GetFramerate() < self.MIN_FPS then -- GetFrameRate call takes ~0.002 secs elseif GetFramerate() < self.MIN_FPS then -- GetFramerate call takes ~0.002 secs
avail = math_min(MAX_CPS, avail + newavail*0.5) avail = math_min(MAX_CPS, avail + newavail*0.5)
self.bChoking = true -- just a statistic self.bChoking = true -- just a statistic
else else
@@ -285,16 +281,12 @@ end
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- Despooling logic -- Despooling logic
-- Reminder:
-- - We have 3 Priorities, each containing a "Ring" construct ...
-- - ... made up of N "Pipe"s (1 for each destination/pipename)
-- - and each pipe contains messages
function ChatThrottleLib:Despool(Prio) function ChatThrottleLib:Despool(Prio)
local ring = Prio.Ring local ring = Prio.Ring
while ring.pos and Prio.avail > ring.pos[1].nSize do while ring.pos and Prio.avail > ring.pos[1].nSize do
local msg = table_remove(ring.pos, 1) local msg = table_remove(Prio.Ring.pos, 1)
if not ring.pos[1] then -- did we remove last msg in this pipe? if not Prio.Ring.pos[1] then
local pipe = Prio.Ring.pos local pipe = Prio.Ring.pos
Prio.Ring:Remove(pipe) Prio.Ring:Remove(pipe)
Prio.ByName[pipe.name] = nil Prio.ByName[pipe.name] = nil
@@ -302,31 +294,20 @@ function ChatThrottleLib:Despool(Prio)
else else
Prio.Ring.pos = Prio.Ring.pos.next Prio.Ring.pos = Prio.Ring.pos.next
end end
local didSend=false Prio.avail = Prio.avail - msg.nSize
local lowerDest = strlower(msg[3] or "") bMyTraffic = true
if lowerDest == "raid" and not UnitInRaid("player") then msg.f(unpack(msg, 1, msg.n))
-- do nothing bMyTraffic = false
elseif lowerDest == "party" and not UnitInParty("player") then Prio.nTotalSent = Prio.nTotalSent + msg.nSize
-- do nothing DelMsg(msg)
else
Prio.avail = Prio.avail - msg.nSize
bMyTraffic = true
msg.f(unpack(msg, 1, msg.n))
bMyTraffic = false
Prio.nTotalSent = Prio.nTotalSent + msg.nSize
DelMsg(msg)
didSend = true
end
-- notify caller of delivery (even if we didn't send it)
if msg.callbackFn then if msg.callbackFn then
msg.callbackFn (msg.callbackArg, didSend) msg.callbackFn (msg.callbackArg)
end end
-- USER CALLBACK MAY ERROR
end end
end end
function ChatThrottleLib.OnEvent() function ChatThrottleLib.OnEvent(this,event)
-- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too. -- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too.
local self = ChatThrottleLib local self = ChatThrottleLib
if event == "PLAYER_ENTERING_WORLD" then if event == "PLAYER_ENTERING_WORLD" then
@@ -336,10 +317,10 @@ function ChatThrottleLib.OnEvent()
end end
function ChatThrottleLib.OnUpdate() function ChatThrottleLib.OnUpdate(this,delay)
local self = ChatThrottleLib local self = ChatThrottleLib
self.OnUpdateDelay = self.OnUpdateDelay + arg1 self.OnUpdateDelay = self.OnUpdateDelay + delay
if self.OnUpdateDelay < 0.08 then if self.OnUpdateDelay < 0.08 then
return return
end end
@@ -393,6 +374,7 @@ end
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- Spooling logic -- Spooling logic
function ChatThrottleLib:Enqueue(prioname, pipename, msg) function ChatThrottleLib:Enqueue(prioname, pipename, msg)
local Prio = self.Prio[prioname] local Prio = self.Prio[prioname]
local pipe = Prio.ByName[pipename] local pipe = Prio.ByName[pipename]
@@ -404,11 +386,13 @@ function ChatThrottleLib:Enqueue(prioname, pipename, msg)
Prio.Ring:Add(pipe) Prio.Ring:Add(pipe)
end end
tinsert(pipe,msg) pipe[#pipe + 1] = msg
self.bQueueing = true self.bQueueing = true
end end
function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg) function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg)
if not self or not prio or not prefix or not text or not self.Prio[prio] then if not self or not prio or not prefix or not text or not self.Prio[prio] then
error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2) error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2)
@@ -417,7 +401,7 @@ function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, languag
error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2) error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
end end
local nSize = strlen(text) local nSize = text:len()
if nSize>255 then if nSize>255 then
error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2) error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2)
@@ -433,9 +417,8 @@ function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, languag
bMyTraffic = false bMyTraffic = false
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
if callbackFn then if callbackFn then
callbackFn (callbackArg, true) callbackFn (callbackArg)
end end
-- USER CALLBACK MAY ERROR
return return
end end
@@ -463,17 +446,10 @@ function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target,
error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2) error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
end end
local nSize = strlen(text); local nSize = prefix:len() + 1 + text:len();
if RegisterAddonMessagePrefix then if nSize>255 then
if nSize>255 then error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2)
error("ChatThrottleLib:SendAddonMessage(): message length cannot exceed 255 bytes", 2)
end
else
nSize = nSize + strlen(prefix) + 1
if nSize>255 then
error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2)
end
end end
nSize = nSize + self.MSG_OVERHEAD; nSize = nSize + self.MSG_OVERHEAD;
@@ -486,9 +462,8 @@ function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target,
bMyTraffic = false bMyTraffic = false
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
if callbackFn then if callbackFn then
callbackFn (callbackArg, true) callbackFn (callbackArg)
end end
-- USER CALLBACK MAY ERROR
return return
end end
@@ -525,3 +500,4 @@ if(WOWB_VER) then
end end
]] ]]
@@ -16,110 +16,87 @@ local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConsole then return end -- No upgrade needed if not AceConsole then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in. AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in.
AceConsole.commands = AceConsole.commands or {} -- table containing commands registered AceConsole.commands = AceConsole.commands or {} -- table containing commands registered
AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable
-- Lua APIs -- Lua APIs
local tinsert, tconcat, tgetn, tsetn = table.insert, table.concat, table.getn, table.setn local tconcat, tostring, select = table.concat, tostring, select
local tostring = tostring
local type, pairs, error = type, pairs, error local type, pairs, error = type, pairs, error
local format, strfind, strsub = string.format, string.find, string.sub local format, strfind, strsub = string.format, string.find, string.sub
local max = math.max local max = math.max
local strupper, strlower = string.upper, string.lower
-- WoW APIs -- WoW APIs
local _G = AceCore._G local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
-- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList -- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList
local Print
do local tmp={}
local tmp = {} local function Print(self,frame,...)
function Print(self, frame, arg) local n=0
if self ~= AceConsole then if self ~= AceConsole then
tmp[1] = "|cff33ff99"..tostring(self).."|r:" n=n+1
else tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
tmp[1] = ''
end end
if type(arg) == "string" then for i=1, select("#", ...) do
frame:AddMessage(tmp[1]..arg) n=n+1
else -- arg is table and may contain frame as first element if argument frame is nil tmp[n] = tostring(select(i, ...))
local b, e = frame and 1 or 2, tgetn(arg)
if e >= b then
frame = frame or arg[1]
for i=0,e-b do
tmp[2+i] = tostring(arg[b+i])
end
frame:AddMessage(tconcat(tmp," ",1,e-b+2)) -- explicitly, because the length is not affected by assignment
end
end end
frame:AddMessage( tconcat(tmp," ",1,n) )
end end
end -- Print
--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function) --- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] ... -- @paramsig [chatframe ,] ...
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function) -- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
-- @param ... List of any values to be printed -- @param ... List of any values to be printed
function AceConsole:Print(...) function AceConsole:Print(...)
local frame = arg[1] local frame = ...
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member? if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
return Print(self, nil, arg) return Print(self, frame, select(2,...))
else else
return Print(self, DEFAULT_CHAT_FRAME, arg) return Print(self, DEFAULT_CHAT_FRAME, ...)
end end
end end
--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function) --- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] "format"[, ...] -- @paramsig [chatframe ,] "format"[, ...]
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function) -- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
-- @param format Format string - same syntax as standard Lua format() -- @param format Format string - same syntax as standard Lua format()
-- @param ... Arguments to the format string -- @param ... Arguments to the format string
function AceConsole:Printf(a1, ...) function AceConsole:Printf(...)
local frame, succ, s local frame = ...
if type(a1) == "table" and a1.AddMessage then -- Is first argument something with an .AddMessage member? if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
frame, succ, s = a1, pcall(format, unpack(arg)) return Print(self, frame, format(select(2,...)))
else else
frame, succ, s = DEFAULT_CHAT_FRAME, pcall(format, a1, unpack(arg)) return Print(self, DEFAULT_CHAT_FRAME, format(...))
end end
if not succ then error(s,2) end
return Print(self, frame, s)
end end
--- Register a simple chat command --- Register a simple chat command
-- @param command Chat command to be registered WITHOUT leading "/" -- @param command Chat command to be registered WITHOUT leading "/"
-- @param func Function to call when the slash command is being used (funcref or methodname) -- @param func Function to call when the slash command is being used (funcref or methodname)
-- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true) -- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true)
function AceConsole:RegisterChatCommand( command, func, persist ) function AceConsole:RegisterChatCommand( command, func, persist )
if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand(command, func[, persist ]): 'command' - expected a string]], 2) end if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end
if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk
local name = "ACECONSOLE_"..strupper(command) local name = "ACECONSOLE_"..command:upper()
local t = type(func) if type( func ) == "string" then
if t == "string" then
-- Ace3v: prevent user from using AceConSole as self
if self == AceConsole then
error([[Usage: RegisterChatCommand(command, func[, persist]): 'self' - use your own 'self']], 2)
end
SlashCmdList[name] = function(input, editBox) SlashCmdList[name] = function(input, editBox)
self[func](self, input, editBox) self[func](self, input, editBox)
end end
elseif t == "function" then
SlashCmdList[name] = func
else else
error([[Usage: AceConsole:RegisterChatCommand(command, func[, persist ]): 'func' - expected a string or a function]], 2) SlashCmdList[name] = func
end end
_G["SLASH_"..name.."1"] = "/"..strlower(command) _G["SLASH_"..name.."1"] = "/"..command:lower()
AceConsole.commands[command] = name AceConsole.commands[command] = name
-- non-persisting commands are registered for enabling disabling -- non-persisting commands are registered for enabling disabling
if not persist then if not persist then
@@ -136,6 +113,7 @@ function AceConsole:UnregisterChatCommand( command )
if name then if name then
SlashCmdList[name] = nil SlashCmdList[name] = nil
_G["SLASH_" .. name .. "1"] = nil _G["SLASH_" .. name .. "1"] = nil
hash_SlashCmdList["/" .. command:upper()] = nil
AceConsole.commands[command] = nil AceConsole.commands[command] = nil
end end
end end
@@ -144,16 +122,18 @@ end
-- @return Iterator (pairs) over all commands -- @return Iterator (pairs) over all commands
function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
local function nils(n,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if n >= 1 then local function nils(n, ...)
return nil, nils(n-1,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) if n>1 then
elseif not argc or argc == 0 then return nil, nils(n-1, ...)
return elseif n==1 then
return nil, ...
else else
return a1, nils(0,argc-1,a2,a3,a4,a5,a6,a7,a8,a9,a10) return ...
end end
end end
--- Retreive one or more space-separated arguments from a string. --- Retreive one or more space-separated arguments from a string.
-- Treats quoted strings and itemlinks as non-spaced. -- Treats quoted strings and itemlinks as non-spaced.
-- @param str The raw argument string -- @param str The raw argument string
@@ -170,7 +150,7 @@ function AceConsole:GetArgs(str, numargs, startpos)
-- find start of new arg -- find start of new arg
pos = strfind(str, "[^ ]", pos) pos = strfind(str, "[^ ]", pos)
if not pos then -- whoops, end of string if not pos then -- whoops, end of string
return nils(numargs, 1, 1e9) return nils(numargs, 1e9)
end end
if numargs<1 then if numargs<1 then
@@ -225,7 +205,7 @@ function AceConsole:GetArgs(str, numargs, startpos)
end end
-- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink) -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
return strsub(str, startpos), nils(numargs-1, 1, 1e9) return strsub(str, startpos), nils(numargs-1, 1e9)
end end
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceConsole-3.0.lua"/> <Script file="AceConsole-3.0.lua"/>
</Ui> </Ui>
-204
View File
@@ -1,204 +0,0 @@
local ACECORE_MAJOR, ACECORE_MINOR = "AceCore-3.0", 1
local AceCore, oldminor = LibStub:NewLibrary(ACECORE_MAJOR, ACECORE_MINOR)
if not AceCore then return end -- No upgrade needed
AceCore._G = AceCore._G or _G
local _G = AceCore._G
local strsub, strgsub, strfind = string.sub, string.gsub, string.find
local tremove, tconcat = table.remove, table.concat
local tgetn, tsetn = table.getn, table.setn
local new, del
do
local list = setmetatable({}, {__mode = "k"})
function new()
local t = next(list)
if not t then
return {}
end
list[t] = nil
return t
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
tsetn(t,0)
list[t] = true
end
-- debug
function AceCore.listcount()
local count = 0
for k in list do
count = count + 1
end
return count
end
end -- AceCore.new, AceCore.del
AceCore.new, AceCore.del = new, del
local function errorhandler(err)
return geterrorhandler()(err)
end
AceCore.errorhandler = errorhandler
local function CreateSafeDispatcher(argCount)
local code = [[
local errorhandler = LibStub("AceCore-3.0").errorhandler
local method, UP_ARGS
local function call()
local func, ARGS = method, UP_ARGS
method, UP_ARGS = nil, NILS
return func(ARGS)
end
return function(func, ARGS)
method, UP_ARGS = func, ARGS
return xpcall(call, errorhandler)
end
]]
local c = 4*argCount-1
local s = "b01,b02,b03,b04,b05,b06,b07,b08,b09,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20"
code = strgsub(code, "UP_ARGS", string.sub(s,1,c))
s = "a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20"
code = strgsub(code, "ARGS", string.sub(s,1,c))
s = "nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil"
code = strgsub(code, "NILS", string.sub(s,1,c))
return assert(loadstring(code, "safecall SafeDispatcher["..tostring(argCount).."]"))()
end
local SafeDispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher
if argCount > 0 then
dispatcher = CreateSafeDispatcher(argCount)
else
dispatcher = function(func) return xpcall(func,errorhandler) end
end
rawset(self, argCount, dispatcher)
return dispatcher
end})
local function safecall(func,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
-- we check to see if the func is passed is actually a function here and don't error when it isn't
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
-- present execution should continue without hinderance
if type(func) == "function" then
return SafeDispatchers[argc](func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
AceCore.safecall = safecall
local function CreateDispatcher(argCount)
local code = [[
return function(func,ARGS)
return func(ARGS)
end
]]
local s = "a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20"
code = strgsub(code, "ARGS", string.sub(s,1,4*argCount-1))
return assert(loadstring(code, "call Dispatcher["..tostring(argCount).."]"))()
end
AceCore.Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher
if argCount > 0 then
dispatcher = CreateDispatcher(argCount)
else
dispatcher = function(func) return func() end
end
rawset(self, argCount, dispatcher)
return dispatcher
end})
-- some string functions
-- vanilla available string operations:
-- sub, gfind, rep, gsub, char, dump, find, upper, len, format, byte, lower
-- we will just replace every string.match with string.find in the code
function AceCore.strtrim(s)
return strgsub(s, "^%s*(.-)%s*$", "%1")
end
local function strsplit(delim, s, n)
if n and n < 2 then return s end
local beg = beg or 1
local i,j = string.find(s,delim,beg)
if not i then
return s, nil
end
return string.sub(s,1,j-1), strsplit(delim, string.sub(s,j+1), n and n-1 or nil)
end
AceCore.strsplit = strsplit
-- Ace3v: fonctions copied from AceHook-2.1
local protFuncs = {
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
TurnOrActionStart = true, TurnOrActionStop = true,
PitchUpStart = true, PitchUpStop = true,
PitchDownStart = true, PitchDownStop = true,
MoveBackwardStart = true, MoveBackwardStop = true,
MoveForwardStart = true, MoveForwardStop = true,
Jump = true, StrafeLeftStart = true,
StrafeLeftStop = true, StrafeRightStart = true,
StrafeRightStop = true, ToggleMouseMove = true,
ToggleRun = true, TurnLeftStart = true,
TurnLeftStop = true, TurnRightStart = true,
TurnRightStop = true,
}
local function issecurevariable(x)
return protFuncs[x] and 1 or nil
end
AceCore.issecurevariable = issecurevariable
local function hooksecurefunc(arg1, arg2, arg3)
if type(arg1) == "string" then
arg1, arg2, arg3 = _G, arg1, arg2
end
local orig = arg1[arg2]
if type(orig) ~= "function" then
error("The function "..arg2.." does not exist", 2)
end
arg1[arg2] = function(...)
local tmp = {orig(unpack(arg))}
arg3(unpack(arg))
return unpack(tmp)
end
end
AceCore.hooksecurefunc = hooksecurefunc
-- pickfirstset() - picks the first non-nil value and returns it
local function pickfirstset(argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if (argc <= 1) or (a1 ~= nil) then
return a1
else
return pickfirstset(argc-1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
end
end
AceCore.pickfirstset = pickfirstset
local function countargs(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if (a1 == nil) then return 0 end
return 1 + countargs(a2,a3,a4,a5,a6,a7,a8,a9,a10)
end
AceCore.countargs = countargs
-- wipe preserves metatable
function AceCore.wipe(t)
for k,v in pairs(t) do t[k] = nil end
tsetn(t,0)
return t
end
function AceCore.truncate(t,e)
e = e or tgetn(t)
for i=1,e do
if t[i] == nil then
tsetn(t,i-1)
return
end
end
tsetn(t,e)
end
@@ -1,3 +0,0 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="AceCore-3.0.lua"/>
</Ui>
+44 -57
View File
@@ -40,22 +40,18 @@
-- end -- end
-- @class file -- @class file
-- @name AceDB-3.0.lua -- @name AceDB-3.0.lua
-- @release $Id: AceDB-3.0.lua 1142 2016-07-11 08:36:19Z nevcairiel $ -- @release $Id: AceDB-3.0.lua 1124 2014-10-27 21:00:07Z funkydude $
local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 26 local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 26
local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR) local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
if not AceDB then return end -- No upgrade needed if not AceDB then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
-- Lua APIs -- Lua APIs
local type, pairs, next, error = type, pairs, next, error local type, pairs, next, error = type, pairs, next, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
local format, lower = string.format, string.lower
-- WoW APIs -- WoW APIs
local _G = AceCore._G local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -69,13 +65,6 @@ local CallbackDummy = { Fire = function() end }
local DBObjectLib = {} local DBObjectLib = {}
-- Ace3v: for all recursive functions we must declare the iterator as local again, this step is necessary in vanilla
-- Example:
-- for k,v in pairs(table) do
-- local v = v
-- ...
--[[------------------------------------------------------------------------- --[[-------------------------------------------------------------------------
AceDB Utility Functions AceDB Utility Functions
---------------------------------------------------------------------------]] ---------------------------------------------------------------------------]]
@@ -85,7 +74,6 @@ local function copyTable(src, dest)
if type(dest) ~= "table" then dest = {} end if type(dest) ~= "table" then dest = {} end
if type(src) == "table" then if type(src) == "table" then
for k,v in pairs(src) do for k,v in pairs(src) do
local v = v
if type(v) == "table" then if type(v) == "table" then
-- try to index the key first so that the metatable creates the defaults, if set, and use that table -- try to index the key first so that the metatable creates the defaults, if set, and use that table
v = copyTable(v, dest[k]) v = copyTable(v, dest[k])
@@ -105,7 +93,6 @@ local function copyDefaults(dest, src)
-- this happens if some value in the SV overwrites our default value with a non-table -- this happens if some value in the SV overwrites our default value with a non-table
--if type(dest) ~= "table" then return end --if type(dest) ~= "table" then return end
for k, v in pairs(src) do for k, v in pairs(src) do
local v = v
if k == "*" or k == "**" then if k == "*" or k == "**" then
if type(v) == "table" then if type(v) == "table" then
-- This is a metatable used for table defaults -- This is a metatable used for table defaults
@@ -153,12 +140,10 @@ local function removeDefaults(db, defaults, blocker)
setmetatable(db, nil) setmetatable(db, nil)
-- loop through the defaults and remove their content -- loop through the defaults and remove their content
for k,v in pairs(defaults) do for k,v in pairs(defaults) do
local v = v
if k == "*" or k == "**" then if k == "*" or k == "**" then
if type(v) == "table" then if type(v) == "table" then
-- Loop through all the actual k,v pairs and remove -- Loop through all the actual k,v pairs and remove
for key, value in pairs(db) do for key, value in pairs(db) do
local value = value
if type(value) == "table" then if type(value) == "table" then
-- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
if defaults[key] == nil and (not blocker or blocker[key] == nil) then if defaults[key] == nil and (not blocker or blocker[key] == nil) then
@@ -220,35 +205,36 @@ end
-- Metatable to handle the dynamic creation of sections and copying of sections. -- Metatable to handle the dynamic creation of sections and copying of sections.
local dbmt = { local dbmt = {
__index = function(t, section) __index = function(t, section)
local keys = rawget(t, "keys") local keys = rawget(t, "keys")
local key = keys[section] local key = keys[section]
if key then if key then
local defaultTbl = rawget(t, "defaults") local defaultTbl = rawget(t, "defaults")
local defaults = defaultTbl and defaultTbl[section] local defaults = defaultTbl and defaultTbl[section]
if section == "profile" then if section == "profile" then
if initSection(t, section, "profiles", key, defaults) then local new = initSection(t, section, "profiles", key, defaults)
-- Callback: OnNewProfile, database, newProfileKey if new then
t.callbacks:Fire("OnNewProfile", 2, t, key) -- Callback: OnNewProfile, database, newProfileKey
t.callbacks:Fire("OnNewProfile", t, key)
end
elseif section == "profiles" then
local sv = rawget(t, "sv")
if not sv.profiles then sv.profiles = {} end
rawset(t, "profiles", sv.profiles)
elseif section == "global" then
local sv = rawget(t, "sv")
if not sv.global then sv.global = {} end
if defaults then
copyDefaults(sv.global, defaults)
end
rawset(t, section, sv.global)
else
initSection(t, section, section, key, defaults)
end end
elseif section == "profiles" then
local sv = rawget(t, "sv")
if not sv.profiles then sv.profiles = {} end
rawset(t, "profiles", sv.profiles)
elseif section == "global" then
local sv = rawget(t, "sv")
if not sv.global then sv.global = {} end
if defaults then
copyDefaults(sv.global, defaults)
end
rawset(t, section, sv.global)
else
initSection(t, section, section, key, defaults)
end end
end
return rawget(t, section) return rawget(t, section)
end end
} }
local function validateDefaults(defaults, keyTbl, offset) local function validateDefaults(defaults, keyTbl, offset)
@@ -256,7 +242,7 @@ local function validateDefaults(defaults, keyTbl, offset)
offset = offset or 0 offset = offset or 0
for k in pairs(defaults) do for k in pairs(defaults) do
if not keyTbl[k] or k == "profiles" then if not keyTbl[k] or k == "profiles" then
error(format("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype.", k), 3 + offset) error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
end end
end end
end end
@@ -273,10 +259,10 @@ local realmKey = GetRealmName()
local charKey = UnitName("player") .. " - " .. realmKey local charKey = UnitName("player") .. " - " .. realmKey
local _, classKey = UnitClass("player") local _, classKey = UnitClass("player")
local _, raceKey = UnitRace("player") local _, raceKey = UnitRace("player")
local _, factionKey = UnitFactionGroup("player") local factionKey = UnitFactionGroup("player")
-- Ace3v: the faction key may error when in GM mode local factionrealmKey = factionKey .. " - " .. realmKey
factionKey = factionKey or "Others" local factionrealmregionKey = factionrealmKey .. " - " .. string.sub(GetCVar("realmList"), 1, 2):upper()
local localeKey = lower(GetLocale()) local localeKey = GetLocale():lower()
-- Actual database initialization function -- Actual database initialization function
local function initdb(sv, defaults, defaultProfile, olddb, parent) local function initdb(sv, defaults, defaultProfile, olddb, parent)
@@ -312,7 +298,8 @@ local function initdb(sv, defaults, defaultProfile, olddb, parent)
["class"] = classKey, ["class"] = classKey,
["race"] = raceKey, ["race"] = raceKey,
["faction"] = factionKey, ["faction"] = factionKey,
["factionrealm"] = factionKey .. " - " .. realmKey, ["factionrealm"] = factionrealmKey,
["factionrealmregion"] = factionrealmregionKey,
["profile"] = profileKey, ["profile"] = profileKey,
["locale"] = localeKey, ["locale"] = localeKey,
["global"] = true, ["global"] = true,
@@ -366,10 +353,10 @@ end
-- handle PLAYER_LOGOUT -- handle PLAYER_LOGOUT
-- strip all defaults from all databases -- strip all defaults from all databases
-- and cleans up empty sections -- and cleans up empty sections
local function logoutHandler() local function logoutHandler(frame, event)
if event == "PLAYER_LOGOUT" then if event == "PLAYER_LOGOUT" then
for db in pairs(AceDB.db_registry) do for db in pairs(AceDB.db_registry) do
db.callbacks:Fire("OnDatabaseShutdown", 1, db) db.callbacks:Fire("OnDatabaseShutdown", db)
db:RegisterDefaults(nil) db:RegisterDefaults(nil)
-- cleanup sections that are empty without defaults -- cleanup sections that are empty without defaults
@@ -449,7 +436,7 @@ function DBObjectLib:SetProfile(name)
local defaults = self.defaults and self.defaults.profile local defaults = self.defaults and self.defaults.profile
-- Callback: OnProfileShutdown, database -- Callback: OnProfileShutdown, database
self.callbacks:Fire("OnProfileShutdown", 1, self) self.callbacks:Fire("OnProfileShutdown", self)
if oldProfile and defaults then if oldProfile and defaults then
-- Remove the defaults from the old profile -- Remove the defaults from the old profile
@@ -473,7 +460,7 @@ function DBObjectLib:SetProfile(name)
end end
-- Callback: OnProfileChanged, database, newProfileKey -- Callback: OnProfileChanged, database, newProfileKey
self.callbacks:Fire("OnProfileChanged", 2, self, name) self.callbacks:Fire("OnProfileChanged", self, name)
end end
--- Returns a table with the names of the existing profiles in the database. --- Returns a table with the names of the existing profiles in the database.
@@ -549,7 +536,7 @@ function DBObjectLib:DeleteProfile(name, silent)
end end
-- Callback: OnProfileDeleted, database, profileKey -- Callback: OnProfileDeleted, database, profileKey
self.callbacks:Fire("OnProfileDeleted", 2, self, name) self.callbacks:Fire("OnProfileDeleted", self, name)
end end
--- Copies a named profile into the current profile, overwriting any conflicting --- Copies a named profile into the current profile, overwriting any conflicting
@@ -585,7 +572,7 @@ function DBObjectLib:CopyProfile(name, silent)
end end
-- Callback: OnProfileCopied, database, sourceProfileKey -- Callback: OnProfileCopied, database, sourceProfileKey
self.callbacks:Fire("OnProfileCopied", 2, self, name) self.callbacks:Fire("OnProfileCopied", self, name)
end end
--- Resets the current profile to the default values (if specified). --- Resets the current profile to the default values (if specified).
@@ -612,7 +599,7 @@ function DBObjectLib:ResetProfile(noChildren, noCallbacks)
-- Callback: OnProfileReset, database -- Callback: OnProfileReset, database
if not noCallbacks then if not noCallbacks then
self.callbacks:Fire("OnProfileReset", 2, self, self.keys["profile"]) self.callbacks:Fire("OnProfileReset", self)
end end
end end
@@ -643,9 +630,9 @@ function DBObjectLib:ResetDB(defaultProfile)
end end
-- Callback: OnDatabaseReset, database -- Callback: OnDatabaseReset, database
self.callbacks:Fire("OnDatabaseReset", 1, self) self.callbacks:Fire("OnDatabaseReset", self)
-- Callback: OnProfileChanged, database, profileKey -- Callback: OnProfileChanged, database, profileKey
self.callbacks:Fire("OnProfileChanged", 2, self, self.keys["profile"]) self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
return self return self
end end
+2 -1
View File
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceDB-3.0.lua"/> <Script file="AceDB-3.0.lua"/>
</Ui> </Ui>
+10 -13
View File
@@ -2,7 +2,7 @@
-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around -- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
-- CallbackHandler, and dispatches all game events or addon message to the registrees. -- CallbackHandler, and dispatches all game events or addon message to the registrees.
-- --
-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by -- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object -- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
-- and can be accessed directly, without having to explicitly call AceEvent itself.\\ -- and can be accessed directly, without having to explicitly call AceEvent itself.\\
-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you -- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
@@ -10,7 +10,9 @@
-- @class file -- @class file
-- @name AceEvent-3.0 -- @name AceEvent-3.0
-- @release $Id: AceEvent-3.0.lua 975 2010-10-23 11:26:18Z nevcairiel $ -- @release $Id: AceEvent-3.0.lua 975 2010-10-23 11:26:18Z nevcairiel $
local MAJOR, MINOR = "AceEvent-3.0", 3 local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
local MAJOR, MINOR = "AceEvent-3.0", 4
local AceEvent = LibStub:NewLibrary(MAJOR, MINOR) local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
if not AceEvent then return end if not AceEvent then return end
@@ -18,29 +20,27 @@ if not AceEvent then return end
-- Lua APIs -- Lua APIs
local pairs = pairs local pairs = pairs
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
-- APIs and registry for blizzard events, using CallbackHandler lib -- APIs and registry for blizzard events, using CallbackHandler lib
if not AceEvent.events then if not AceEvent.events then
AceEvent.events = CallbackHandler:New(AceEvent, AceEvent.events = CallbackHandler:New(AceEvent,
"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents") "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
end end
function AceEvent.events:OnUsed(target, eventname) function AceEvent.events:OnUsed(target, eventname)
AceEvent.frame:RegisterEvent(eventname) AceEvent.frame:RegisterEvent(eventname)
end end
function AceEvent.events:OnUnused(target, eventname) function AceEvent.events:OnUnused(target, eventname)
AceEvent.frame:UnregisterEvent(eventname) AceEvent.frame:UnregisterEvent(eventname)
end end
-- APIs and registry for IPC messages, using CallbackHandler lib -- APIs and registry for IPC messages, using CallbackHandler lib
if not AceEvent.messages then if not AceEvent.messages then
AceEvent.messages = CallbackHandler:New(AceEvent, AceEvent.messages = CallbackHandler:New(AceEvent,
"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages" "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
) )
AceEvent.SendMessage = AceEvent.messages.Fire AceEvent.SendMessage = AceEvent.messages.Fire
@@ -115,12 +115,9 @@ function AceEvent:OnEmbedDisable(target)
end end
-- Script to fire blizzard events into the event listeners -- Script to fire blizzard events into the event listeners
-- Ace3v: in vanilla the arguments are set to global:
-- event, arg1, arg2, arg3 ...
-- the user have always access to them, so we save the table cost here
local events = AceEvent.events local events = AceEvent.events
AceEvent.frame:SetScript("OnEvent", function() AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
events:Fire(event) events:Fire(event, ...)
end) end)
--- Finally: upgrade our old embeds --- Finally: upgrade our old embeds
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceEvent-3.0.lua"/> <Script file="AceEvent-3.0.lua"/>
</Ui> </Ui>
+20 -49
View File
@@ -15,9 +15,6 @@ local AceHook, oldminor = LibStub:NewLibrary(ACEHOOK_MAJOR, ACEHOOK_MINOR)
if not AceHook then return end -- No upgrade needed if not AceHook then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
AceHook.embeded = AceHook.embeded or {} AceHook.embeded = AceHook.embeded or {}
AceHook.registry = AceHook.registry or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) AceHook.registry = AceHook.registry or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end })
AceHook.handlers = AceHook.handlers or {} AceHook.handlers = AceHook.handlers or {}
@@ -39,9 +36,11 @@ local format = string.format
local assert, error = assert, error local assert, error = assert, error
-- WoW APIs -- WoW APIs
local hooksecurefunc, issecurevariable = AceCore.hooksecurefunc, AceCore.issecurevariable local issecurevariable, hooksecurefunc = issecurevariable, hooksecurefunc
local _G = _G
local _G = AceCore._G -- functions for later definition
local donothing, createHook, hook
local protectedScripts = { local protectedScripts = {
OnClick = true, OnClick = true,
@@ -80,25 +79,20 @@ function AceHook:OnEmbedDisable( target )
target:UnhookAll() target:UnhookAll()
end end
-- failsafe means even the hooking method fails, the original method will function createHook(self, handler, orig, secure, failsafe)
-- always be called
local function createHook(self, handler, orig, secure, failsafe)
local uid local uid
local method = type(handler) == "string" local method = type(handler) == "string"
-- Ace3v: when this function called in the "hook" function, we have
-- failsafe = not (raw or secure), so the first check condition
-- is same as "if failsafe" or "if not raw and not secure"
if failsafe and not secure then if failsafe and not secure then
-- failsafe hook creation -- failsafe hook creation
uid = function(...) uid = function(...)
if actives[uid] then if actives[uid] then
if method then if method then
self[handler](self,unpack(arg)) self[handler](self, ...)
else else
handler(unpack(arg)) handler(...)
end end
end end
return orig(unpack(arg)) return orig(...)
end end
-- /failsafe hook -- /failsafe hook
else else
@@ -106,12 +100,12 @@ local function createHook(self, handler, orig, secure, failsafe)
uid = function(...) uid = function(...)
if actives[uid] then if actives[uid] then
if method then if method then
return self[handler](self,unpack(arg)) return self[handler](self, ...)
else else
return handler(unpack(arg)) return handler(...)
end end
elseif not secure then -- backup on non secure elseif not secure then -- backup on non secure
return orig(unpack(arg)) return orig(...)
end end
end end
-- /hook -- /hook
@@ -119,18 +113,9 @@ local function createHook(self, handler, orig, secure, failsafe)
return uid return uid
end end
local function donothing() end function donothing() end
-- @param self function hook(self, obj, method, handler, script, secure, raw, forceSecure, usage)
-- @param obj nil or a frame object, use with script = true
-- @param method string, the name of a global function or the name of an object method
-- @param handler function, or string when it's a method of 'self', if nil then will use the same value as method
-- @param script boolean, must be true, if the hooked object is a frame
-- @param secure boolean, if hooking a secure script, if true the original script will be called first, else later
-- @param raw boolean, if raw hooking (replacing the original method)
-- @param forceSecure boolean, if forcing to hook a secure method
-- @param usage
local function hook(self, obj, method, handler, script, secure, raw, forceSecure, usage)
if not handler then handler = method end if not handler then handler = method end
-- These asserts make sure AceHooks's devs play by the rules. -- These asserts make sure AceHooks's devs play by the rules.
@@ -215,7 +200,6 @@ local function hook(self, obj, method, handler, script, secure, raw, forceSecure
local orig local orig
if script then if script then
-- Sometimes there is not a original function for a script.
orig = obj:GetScript(method) or donothing orig = obj:GetScript(method) or donothing
elseif obj then elseif obj then
orig = obj[method] orig = obj[method]
@@ -230,11 +214,11 @@ local function hook(self, obj, method, handler, script, secure, raw, forceSecure
uid = createHook(self, handler, orig, secure, not (raw or secure)) uid = createHook(self, handler, orig, secure, not (raw or secure))
if obj then if obj then
registry[self][obj] = registry[self][obj] or new() self.hooks[obj] = self.hooks[obj] or {}
registry[self][obj] = registry[self][obj] or {}
registry[self][obj][method] = uid registry[self][obj][method] = uid
if not secure then if not secure then
self.hooks[obj] = self.hooks[obj] or new()
self.hooks[obj][method] = orig self.hooks[obj][method] = orig
end end
@@ -242,12 +226,7 @@ local function hook(self, obj, method, handler, script, secure, raw, forceSecure
if not secure then if not secure then
obj:SetScript(method, uid) obj:SetScript(method, uid)
else else
obj:SetScript(method, function(...) obj:HookScript2(method, uid)
local tmp = {orig(unpack(arg))}
uid(unpack(arg))
return unpack(tmp)
end)
--obj:HookScript(method, uid) -- Ace3v: vanilla frame has no HookScript
end end
else else
if not secure then if not secure then
@@ -464,12 +443,8 @@ function AceHook:Unhook(obj, method)
actives[uid], handlers[uid] = nil, nil actives[uid], handlers[uid] = nil, nil
if obj then if obj then
local tmp = registry[self][obj] registry[self][obj][method] = nil
tmp[method] = nil registry[self][obj] = next(registry[self][obj]) and registry[self][obj] or nil
if not next(tmp) then
del(tmp)
registry[self][obj] = nil
end
-- if the hook reference doesnt exist, then its a secure hook, just bail out and dont do any unhooking -- if the hook reference doesnt exist, then its a secure hook, just bail out and dont do any unhooking
if not self.hooks[obj] or not self.hooks[obj][method] then return true end if not self.hooks[obj] or not self.hooks[obj][method] then return true end
@@ -481,12 +456,8 @@ function AceHook:Unhook(obj, method)
obj[method] = self.hooks[obj][method] obj[method] = self.hooks[obj][method]
end end
tmp = self.hooks[obj] self.hooks[obj][method] = nil
tmp[method] = nil self.hooks[obj] = next(self.hooks[obj]) and self.hooks[obj] or nil
if not next(tmp) then
del(tmp)
self.hooks[obj] = nil
end
else else
registry[self][method] = nil registry[self][method] = nil
+2 -1
View File
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceHook-3.0.lua"/> <Script file="AceHook-3.0.lua"/>
</Ui> </Ui>
@@ -97,7 +97,7 @@ function AceLocale:NewLocale(application, locale, isDefault, silent)
local app = AceLocale.apps[application] local app = AceLocale.apps[application]
if silent and app and getmetatable(app) ~= readmetasilent then if silent and app and getmetatable(app) ~= readmetasilent and not isDefault then
geterrorhandler()("Usage: NewLocale(application, locale[, isDefault[, silent]]): 'silent' must be specified for the first locale registered") geterrorhandler()("Usage: NewLocale(application, locale[, isDefault[, silent]]): 'silent' must be specified for the first locale registered")
end end
@@ -112,7 +112,7 @@ function AceLocale:NewLocale(application, locale, isDefault, silent)
end end
if locale ~= gameLocale and not isDefault then if locale ~= gameLocale and not isDefault then
return nil -- nop, we don't need these translations return -- nop, we don't need these translations
end end
registering = app -- remember globally for writeproxy and writedefaultproxy registering = app -- remember globally for writeproxy and writedefaultproxy
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceLocale-3.0.lua"/> <Script file="AceLocale-3.0.lua"/>
</Ui> </Ui>
@@ -20,7 +20,7 @@ if not AceSerializer then return end
local strbyte, strchar, gsub, gmatch, format = string.byte, string.char, string.gsub, string.gmatch, string.format local strbyte, strchar, gsub, gmatch, format = string.byte, string.char, string.gsub, string.gmatch, string.format
local assert, error, pcall = assert, error, pcall local assert, error, pcall = assert, error, pcall
local type, tostring, tonumber = type, tostring, tonumber local type, tostring, tonumber = type, tostring, tonumber
local pairs, frexp = pairs, math.frexp local pairs, select, frexp = pairs, select, math.frexp
local tconcat = table.concat local tconcat = table.concat
-- quick copies of string representations of wonky numbers -- quick copies of string representations of wonky numbers
@@ -116,8 +116,9 @@ local serializeTbl = { "^1" } -- "^1" = Hi, I'm data serialized by AceSerializer
function AceSerializer:Serialize(...) function AceSerializer:Serialize(...)
local nres = 1 local nres = 1
for i = 1, arg.n do for i=1,select("#", ...) do
nres = SerializeValue(arg[i], serializeTbl, nres) local v = select(i, ...)
nres = SerializeValue(v, serializeTbl, nres)
end end
serializeTbl[nres+1] = "^^" -- "^^" = End of serialized data serializeTbl[nres+1] = "^^" -- "^^" = End of serialized data
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceSerializer-3.0.lua"/> <Script file="AceSerializer-3.0.lua"/>
</Ui> </Ui>
+327 -231
View File
@@ -1,12 +1,12 @@
--- **AceTimer-3.0** provides a central facility for registering timers. --- **AceTimer-3.0** provides a central facility for registering timers.
-- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient -- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
-- data structure that allows easy dispatching and fast rescheduling. Timers can be registered -- data structure that allows easy dispatching and fast rescheduling. Timers can be registered, rescheduled
-- or canceled at any time, even from within a running timer, without conflict or large overhead.\\ -- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
-- AceTimer is currently limited to firing timers at a frequency of 0.01s as this is what the WoW timer API -- AceTimer is currently limited to firing timers at a frequency of 0.1s. This constant may change
-- restricts us to. -- in the future, but for now it seemed like a good compromise in efficiency and accuracy.
-- --
-- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you -- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
-- need to cancel the timer you just registered. -- need to cancel or reschedule the timer you just registered.
-- --
-- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by -- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object -- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
@@ -15,33 +15,54 @@
-- make into AceTimer. -- make into AceTimer.
-- @class file -- @class file
-- @name AceTimer-3.0 -- @name AceTimer-3.0
-- @release $Id: AceTimer-3.0.lua 1119 2014-10-14 17:23:29Z nevcairiel $ -- @release $Id: AceTimer-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
local MAJOR, MINOR = "AceTimer-3.0", 17 -- Bump minor on changes --[[
Basic assumptions:
* In a typical system, we do more re-scheduling per second than there are timer pulses per second
* Regardless of timer implementation, we cannot guarantee timely delivery due to FPS restriction (may be as low as 10)
This implementation:
CON: The smallest timer interval is constrained by HZ (currently 1/10s).
PRO: It will still correctly fire any timer slower than HZ over a length of time, e.g. 0.11s interval -> 90 times over 10 seconds
PRO: In lag bursts, the system simly skips missed timer intervals to decrease load
CON: Algorithms depending on a timer firing "N times per minute" will fail
PRO: (Re-)scheduling is O(1) with a VERY small constant. It's a simple linked list insertion in a hash bucket.
CAUTION: The BUCKETS constant constrains how many timers can be efficiently handled. With too many hash collisions, performance will decrease.
Major assumptions upheld:
- ALLOWS scheduling multiple timers with the same funcref/method
- ALLOWS scheduling more timers during OnUpdate processing
- ALLOWS unscheduling ANY timer (including the current running one) at any time, including during OnUpdate processing
]]
local MAJOR, MINOR = "AceTimer-3.0", 6
local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR) local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceTimer then return end -- No upgrade needed if not AceTimer then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0") AceTimer.hash = AceTimer.hash or {} -- Array of [0..BUCKET-1] = linked list of timers (using .next member)
local safecall = AceCore.safecall -- Linked list gets around ACE-88 and ACE-90.
AceTimer.selfs = AceTimer.selfs or {} -- Array of [self]={[handle]=timerobj, [handle2]=timerobj2, ...}
AceTimer.counter = AceTimer.counter or {}
AceTimer.hash = AceTimer.hash or {} -- Array of [1..BUCKETS] = linked list of timers (using .next member)
AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame") AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame")
local counter = AceTimer.counter
local activeTimers = AceTimer.activeTimers -- Upvalue our private data
local timerFrame = AceTimer.frame
-- Lua APIs -- Lua APIs
local type, unpack, next, error = type, unpack, next, error local assert, error, loadstring = assert, error, loadstring
local floor, max, min, mod = math.floor, math.max, math.min, math.mod local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local tostring = tostring local select, pairs, type, next, tostring = select, pairs, type, next, tostring
local floor, max, min = math.floor, math.max, math.min
local tconcat = table.concat
-- WoW APIs -- WoW APIs
local GetTime = GetTime local GetTime = GetTime
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: DEFAULT_CHAT_FRAME, geterrorhandler
-- Simple ONE-SHOT timer cache. Much more efficient than a full compost for our purposes.
local timerCache = nil
--[[ --[[
Timers will not be fired more often than HZ-1 times per second. Timers will not be fired more often than HZ-1 times per second.
Keep at intended speed PLUS ONE or we get bitten by floating point rounding errors (n.5 + 0.1 can be n.599999) Keep at intended speed PLUS ONE or we get bitten by floating point rounding errors (n.5 + 0.1 can be n.599999)
@@ -49,7 +70,6 @@ local GetTime = GetTime
If this number is ever changed, all entries need to be rehashed on lib upgrade. If this number is ever changed, all entries need to be rehashed on lib upgrade.
]] ]]
local HZ = 11 local HZ = 11
local minDelay = 1/(HZ-1)
--[[ --[[
Prime for good distribution Prime for good distribution
@@ -62,188 +82,347 @@ for i=1,BUCKETS do
hash[i] = hash[i] or false -- make it an integer-indexed array; it's faster than hashes hash[i] = hash[i] or false -- make it an integer-indexed array; it's faster than hashes
end end
local new, del --[[
do xpcall safecall implementation
local list = setmetatable({}, {__mode = "k"}) ]]
function new(self, loop, func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) local xpcall = xpcall
local name = loop and "ScheduleRepeatingTimer" or "ScheduleTimer"
if self == AceTimer then local function errorhandler(err)
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): use your own 'self'", 3) return geterrorhandler()(err)
end end
if not func or not delay then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'callback' and 'delay' must have set values.", 3) local function CreateDispatcher(argCount)
end local code = [[
if argc and (type(argc) ~= "number" or floor(argc) ~= argc) then local xpcall, eh = ... -- our arguments are received as unnamed values in "..." since we don't have a proper function declaration
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'argc' must be an integer.", 3) local method, ARGS
end local function call() return method(ARGS) end
if type(func) == "string" then
if type(self) ~= "table" then local function dispatch(func, ...)
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'self' - must be a table.", 3) method = func
elseif type(self[func]) ~= "function" then if not method then return end
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): Tried to register '"..func.."' as the callback, but it is not a method.", 3) ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {
__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end
})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
return Dispatchers[select('#', ...)](func, ...)
end
local lastint = floor(GetTime() * HZ)
-- --------------------------------------------------------------------
-- OnUpdate handler
--
-- traverse buckets, always chasing "now", and fire timers that have expired
local function OnUpdate()
local now = GetTime()
local nowint = floor(now * HZ)
-- Have we passed into a new hash bucket?
if nowint == lastint then return end
local soon = now + 1 -- +1 is safe as long as 1 < HZ < BUCKETS/2
-- Pass through each bucket at most once
-- Happens on e.g. instance loads, but COULD happen on high local load situations also
for curint = (max(lastint, nowint - BUCKETS) + 1), nowint do -- loop until we catch up with "now", usually only 1 iteration
local curbucket = (curint % BUCKETS)+1
-- Yank the list of timers out of the bucket and empty it. This allows reinsertion in the currently-processed bucket from callbacks.
local nexttimer = hash[curbucket]
hash[curbucket] = false -- false rather than nil to prevent the array from becoming a hash
while nexttimer do
local timer = nexttimer
nexttimer = timer.next
local when = timer.when
if when < soon then
-- Call the timer func, either as a method on given object, or a straight function ref
local callback = timer.callback
if type(callback) == "string" then
safecall(timer.object[callback], timer.object, timer.arg)
elseif callback then
safecall(callback, timer.arg)
else
-- probably nilled out by CancelTimer
timer.delay = nil -- don't reschedule it
end
local delay = timer.delay -- NOW make a local copy, can't do it earlier in case the timer cancelled itself in the callback
if not delay then
-- single-shot timer (or cancelled)
AceTimer.selfs[timer.object][tostring(timer)] = nil
timerCache = timer
else
-- repeating timer
local newtime = when + delay
if newtime < now then -- Keep lag from making us firing a timer unnecessarily. (Note that this still won't catch too-short-delay timers though.)
newtime = now + delay
end
timer.when = newtime
-- add next timer execution to the correct bucket
local bucket = (floor(newtime * HZ) % BUCKETS) + 1
timer.next = hash[bucket]
hash[bucket] = timer
end
else -- if when>=soon
-- reinsert (yeah, somewhat expensive, but shouldn't be happening too often either due to hash distribution)
timer.next = hash[curbucket]
hash[curbucket] = timer
end -- if when<soon ... else
end -- while nexttimer do
end -- for curint=lastint,nowint
lastint = nowint
end
-- ---------------------------------------------------------------------
-- Reg( callback, delay, arg, repeating )
--
-- callback( function or string ) - direct function ref or method name in our object for the callback
-- delay(int) - delay for the timer
-- arg(variant) - any argument to be passed to the callback function
-- repeating(boolean) - repeating timer, or oneshot
--
-- returns the handle of the timer for later processing (canceling etc)
local function Reg(self, callback, delay, arg, repeating)
if type(callback) ~= "string" and type(callback) ~= "function" then
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
error(MAJOR..": " .. error_origin .. "(callback, delay, arg): 'callback' - function or method name expected.", 3)
end
if type(callback) == "string" then
if type(self)~="table" then
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
error(MAJOR..": " .. error_origin .. "(\"methodName\", delay, arg): 'self' - must be a table.", 3)
end
if type(self[callback]) ~= "function" then
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
error(MAJOR..": " .. error_origin .. "(\"methodName\", delay, arg): 'methodName' - method not found on target object.", 3)
end end
elseif type(func) ~= "function" then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): Tried to register '"..tostring(func).."' as the callback, but it is not a function.", 3)
end end
if delay < minDelay then if delay < (1 / (HZ - 1)) then
delay = minDelay delay = 1 / (HZ - 1)
end end
-- Create and stuff timer in the correct hash bucket -- Create and stuff timer in the correct hash bucket
local now = GetTime() local now = GetTime()
local timer = next(list) or {} local timer = timerCache or {} -- Get new timer object (from cache if available)
list[timer] = nil timerCache = nil
timer.object = self timer.object = self
timer.func = func timer.callback = callback
timer.delay = delay timer.delay = (repeating and delay)
timer.status = loop and "loop" or "once" timer.arg = arg
timer.ends = now + delay timer.when = now + delay
timer.argsCount = argc or 0
timer[1] = a1
timer[2] = a2
timer[3] = a3
timer[4] = a4
timer[5] = a5
timer[6] = a6
timer[7] = a7
timer[8] = a8
timer[9] = a9
timer[10] = a10
local bucket = floor(mod((now+delay)*HZ,BUCKETS)) + 1 local bucket = (floor((now+delay)*HZ) % BUCKETS) + 1
timer.next = hash[bucket] timer.next = hash[bucket]
hash[bucket] = timer hash[bucket] = timer
local id = tostring(timer) -- user has only access to the id but not the table itself -- Insert timer in our self->handle->timer registry
activeTimers[id] = timer local handle = tostring(timer)
counter[self] = (counter[self] or 0) + 1 local selftimers = AceTimer.selfs[self]
if not selftimers then
timerFrame:Show() selftimers = {}
return id AceTimer.selfs[self] = selftimers
end
function del(t)
local id = tostring(t)
activeTimers[id] = nil
if not next(activeTimers) then
timerFrame:Hide()
end
local self = t.object
for k in pairs(t) do t[k] = nil end
list[t] = true
if counter[self] then
counter[self] = counter[self] - 1
else
counter[self] = nil
end end
selftimers[handle] = timer
selftimers.__ops = (selftimers.__ops or 0) + 1
return handle
end end
end -- new, del
--- Schedule a new one-shot timer. --- Schedule a new one-shot timer.
-- The timer will fire once in `delay` seconds, unless canceled before. -- The timer will fire once in `delay` seconds, unless canceled before.
-- @param callback Callback function for the timer pulse (funcref or method name). -- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds. -- @param delay Delay for the timer, in seconds.
-- @param argc The numbers of arguments to be passed to the callback function -- @param arg An optional argument to be passed to the callback function.
-- @param a1,...,a10 The arguments
-- @usage -- @usage
-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0") -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0")
-- --
-- function MyAddOn:OnEnable() -- function MyAddon:OnEnable()
-- self:ScheduleTimer("TimerFeedback", 5) -- self:ScheduleTimer("TimerFeedback", 5)
-- end -- end
-- --
-- function MyAddOn:TimerFeedback() -- function MyAddon:TimerFeedback()
-- print("5 seconds passed") -- print("5 seconds passed")
-- end -- end
function AceTimer:ScheduleTimer(func, delay, argc, ...) function AceTimer:ScheduleTimer(callback, delay, arg)
return new(self, nil, func, delay, argc, unpack(arg)) return Reg(self, callback, delay, arg)
end end
--- Schedule a repeating timer. --- Schedule a repeating timer.
-- The timer will fire every `delay` seconds, until canceled. -- The timer will fire every `delay` seconds, until canceled.
-- @param callback Callback function for the timer pulse (funcref or method name). -- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds. -- @param delay Delay for the timer, in seconds.
-- @param argc The numbers of arguments to be passed to the callback function -- @param arg An optional argument to be passed to the callback function.
-- @param a1,...,a10 The arguments
-- @usage -- @usage
-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0") -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0")
-- --
-- function MyAddOn:OnEnable() -- function MyAddon:OnEnable()
-- self.timerCount = 0 -- self.timerCount = 0
-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5) -- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
-- end -- end
-- --
-- function MyAddOn:TimerFeedback() -- function MyAddon:TimerFeedback()
-- self.timerCount = self.timerCount + 1 -- self.timerCount = self.timerCount + 1
-- print(format("%d seconds passed", 5 * self.timerCount)) -- print(("%d seconds passed"):format(5 * self.timerCount))
-- -- run 30 seconds in total -- -- run 30 seconds in total
-- if self.timerCount == 6 then -- if self.timerCount == 6 then
-- self:CancelTimer(self.testTimer) -- self:CancelTimer(self.testTimer)
-- end -- end
-- end -- end
function AceTimer:ScheduleRepeatingTimer(func, delay, argc, ...) function AceTimer:ScheduleRepeatingTimer(callback, delay, arg)
return new(self, true, func, delay, argc, unpack(arg)) return Reg(self, callback, delay, arg, true)
end end
--- Cancels a timer with the given id, registered by the same addon object as used for `:ScheduleTimer` --- Cancels a timer with the given handle, registered by the same addon object as used for `:ScheduleTimer`
-- Both one-shot and repeating timers can be canceled with this function, as long as the `id` is valid -- Both one-shot and repeating timers can be canceled with this function, as long as the `handle` is valid
-- and the timer has not fired yet or was canceled before. -- and the timer has not fired yet or was canceled before.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer` -- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
function AceTimer:CancelTimer(id) -- @param silent If true, no error is raised if the timer handle is invalid (expired or already canceled)
local timer = activeTimers[id] -- @return True if the timer was successfully cancelled.
function AceTimer:CancelTimer(handle, silent)
if not timer then if not handle then return end -- nil handle -> bail out without erroring
return false if type(handle) ~= "string" then
error(MAJOR..": CancelTimer(handle): 'handle' - expected a string", 2) -- for now, anyway
end
local selftimers = AceTimer.selfs[self]
local timer = selftimers and selftimers[handle]
if silent then
if timer then
timer.callback = nil -- don't run it again
timer.delay = nil -- if this is the currently-executing one: don't even reschedule
-- The timer object is removed in the OnUpdate loop
end
return not not timer -- might return "true" even if we double-cancel. we'll live.
else else
-- Ace3v: the timer will always be collected in the next update but not here if not timer then
-- this is necessary for AceBucket to determinate if the bucket has been unregistered geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - no such timer registered")
-- in the callback return false
timer.status = nil end
activeTimers[id] = nil if not timer.callback then
geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - timer already cancelled or expired")
return false
end
timer.callback = nil -- don't run it again
timer.delay = nil -- if this is the currently-executing one: don't even reschedule
return true return true
end end
end end
--- Cancels all timers registered to the current addon object ('self') --- Cancels all timers registered to the current addon object ('self')
function AceTimer:CancelAllTimers() function AceTimer:CancelAllTimers()
if type(self) ~= "table" then if not(type(self) == "string" or type(self) == "table") then
error(MAJOR..": CancelAllTimers(): 'self' - must be a table",2) error(MAJOR..": CancelAllTimers(): 'self' - must be a string or a table",2)
end end
if self == AceTimer then if self == AceTimer then
error(MAJOR..": CancelAllTimers(): supply a meaningful 'self'", 2) error(MAJOR..": CancelAllTimers(): supply a meaningful 'self'", 2)
end end
for k,v in pairs(activeTimers) do local selftimers = AceTimer.selfs[self]
if v.object == self then if selftimers then
AceTimer.CancelTimer(self, k) for handle,v in pairs(selftimers) do
if type(v) == "table" then -- avoid __ops, etc
AceTimer.CancelTimer(self, handle, true)
end
end end
end end
end end
--- Returns the time left for a timer with the given id, registered by the current addon object ('self'). --- Returns the time left for a timer with the given handle, registered by the current addon object ('self').
-- This function will return 0 when the id is invalid. -- This function will raise a warning when the handle is invalid, but not stop execution.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer` -- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @return The time left on the timer. -- @return The time left on the timer, or false if the handle is invalid.
function AceTimer:TimeLeft(id) function AceTimer:TimeLeft(handle)
local timer = activeTimers[id] if not handle then return end
if not timer then if type(handle) ~= "string" then
return 0 error(MAJOR..": TimeLeft(handle): 'handle' - expected a string", 2) -- for now, anyway
else
return timer.ends - GetTime()
end end
local selftimers = AceTimer.selfs[self]
local timer = selftimers and selftimers[handle]
if not timer then
geterrorhandler()(MAJOR..": TimeLeft(handle): '"..tostring(handle).."' - no such timer registered")
return false
end
return timer.when - GetTime()
end end
function AceTimer:TimerStatus(id)
local timer = activeTimers[id] -- ---------------------------------------------------------------------
if not timer then -- PLAYER_REGEN_ENABLED: Run through our .selfs[] array step by step
return nil -- and clean it out - otherwise the table indices can grow indefinitely
else -- if an addon starts and stops a lot of timers. AceBucket does this!
return timer.status --
-- See ACE-94 and tests/AceTimer-3.0-ACE-94.lua
local lastCleaned = nil
local function OnEvent(this, event)
if event~="PLAYER_REGEN_ENABLED" then
return
end end
-- Get the next 'self' to process
local selfs = AceTimer.selfs
local self = next(selfs, lastCleaned)
if not self then
self = next(selfs)
end
lastCleaned = self
if not self then -- should only happen if .selfs[] is empty
return
end
-- Time to clean it out?
local list = selfs[self]
if (list.__ops or 0) < 250 then -- 250 slosh indices = ~10KB wasted (worst case!). For one 'self'.
return
end
-- Create a new table and copy all members over
local newlist = {}
local n=0
for k,v in pairs(list) do
newlist[k] = v
if type(v)=="table" and v.callback then -- if the timer is actually live: count it
n=n+1
end
end
newlist.__ops = 0 -- Reset operation count
-- And since we now have a count of the number of live timers, check that it's reasonable. Emit a warning if not.
if n>BUCKETS then
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: The addon/module '"..tostring(self).."' has "..n.." live timers. Surely that's not intended?")
end
selfs[self] = newlist
end end
-- --------------------------------------------------------------------- -- ---------------------------------------------------------------------
@@ -265,115 +444,32 @@ function AceTimer:Embed(target)
return target return target
end end
-- AceTimer:OnEmbedDisable(target) -- AceTimer:OnEmbedDisable( target )
-- target (object) - target object that AceTimer is embedded in. -- target (object) - target object that AceTimer is embedded in.
-- --
-- cancel all timers registered for the object -- cancel all timers registered for the object
function AceTimer:OnEmbedDisable(target) function AceTimer:OnEmbedDisable( target )
target:CancelAllTimers() target:CancelAllTimers()
end end
for addon in pairs(AceTimer.embeds) do for addon in pairs(AceTimer.embeds) do
AceTimer:Embed(addon) AceTimer:Embed(addon)
end end
-- -------------------------------------------------------------------- -- ---------------------------------------------------------------------
-- OnUpdate handler -- Debug tools (expose copies of internals to test suites)
-- AceTimer.debug = AceTimer.debug or {}
-- traverse buckets, always chasing "now", and fire timers that have expired AceTimer.debug.HZ = HZ
local lastint = floor(GetTime() * HZ) AceTimer.debug.BUCKETS = BUCKETS
local function OnUpdate()
local now = GetTime()
local nowint = floor(now * HZ)
-- Have we passed into a new hash bucket? -- ---------------------------------------------------------------------
if nowint == lastint then return end -- Finishing touchups
local soon = now + 1 -- +1 is safe as long as 1 < HZ < BUCKETS/2 AceTimer.frame:SetScript("OnUpdate", OnUpdate)
AceTimer.frame:SetScript("OnEvent", OnEvent)
AceTimer.frame:RegisterEvent("PLAYER_REGEN_ENABLED")
-- Pass through each bucket at most once -- In theory, we could hide&show the frame based on there being timers or not.
-- Happens on e.g. instance loads, but COULD happen on high local load situations also -- However, this job is fairly expensive, and the chance that there will
for curint = (max(lastint, nowint-BUCKETS) + 1), nowint do -- loop until we catch up with "now", usually only 1 iteratio -- actually be zero timers running is diminuitive to say the least.
local curbucket = mod(curint,BUCKETS) + 1 -- Ace3v: both int so no floor here
-- Yank the list of timers out of the bucket and empty it. This allows reinsertion in the currently-processed bucket from callbacks.
local nexttimer = hash[curbucket]
hash[curbucket] = false -- false rather than nil to prevent the array from becoming a hash
while nexttimer do
local timer = nexttimer
nexttimer = timer.next
local status = timer.status
if not status then
del(timer)
else
local ends = timer.ends
if (status == "loop" or status == "once") and ends < soon then
local object = timer.object
local callback = timer.func
if type(callback) == "string" then
callback = (type(object) == "table") and object[callback]
if type(callback) == "function" then
safecall(callback, timer.argsCount+1, object,
timer[1], timer[2], timer[3], timer[4], timer[5],
timer[6], timer[7], timer[8], timer[9], timer[10])
else
status = "once"
end
elseif type(callback) == "function" then
safecall(callback, timer.argsCount,
timer[1], timer[2], timer[3], timer[4], timer[5],
timer[6], timer[7], timer[8], timer[9], timer[10])
else
-- probably nilled out by CancelTimer
status = "once" -- don't reschedule it
end
if status == "once" then
del(timer)
else
local delay = timer.delay
local newends = ends + delay
if newends < now then -- Keep lag from making us firing a timer unnecessarily. (Note that this still won't catch too-short-delay timers though.)
newends = now + delay
end
timer.ends = newends
-- add next timer execution to the correct bucket
local bucket = floor(mod(newends*HZ,BUCKETS)) + 1
timer.next = hash[bucket]
hash[bucket] = timer
end
else
-- reinsert (yeah, somewhat expensive, but shouldn't be happening too often either due to hash distribution)
timer.next = hash[curbucket]
hash[curbucket] = timer
end
end
end
end
lastint = nowint
end
local lastchecked = nil
local function OnEvent()
if event ~= "PLAYER_REGEN_ENABLED" then return end
local addon = next(counter, lastchecked)
if not addon then
addon = next(counter)
end
lastchecked = addon
if not addon then -- should only happen if counter is empty
return
end
local n = counter[addon]
if n > BUCKETS then
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: The addon/module '"..tostring(addon).."' has "..tostring(n).." live timers. Surely that's not intended?")
end
end
timerFrame:SetScript("OnUpdate", OnUpdate)
timerFrame:SetScript("OnEvent", OnEvent)
timerFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
timerFrame:Hide()
@@ -1,3 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <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="AceTimer-3.0.lua"/> <Script file="AceTimer-3.0.lua"/>
</Ui> </Ui>
@@ -10,7 +10,7 @@ local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
local tconcat = table.concat local tconcat = table.concat
local assert, error, loadstring = assert, error, loadstring local assert, error, loadstring = assert, error, loadstring
local setmetatable, rawset, rawget = setmetatable, rawset, rawget local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local next, pairs, type, tostring = next, pairs, type, tostring 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 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -24,6 +24,8 @@ end
local function CreateDispatcher(argCount) local function CreateDispatcher(argCount)
local code = [[ local code = [[
local next, xpcall, eh = ...
local method, ARGS local method, ARGS
local function call() method(ARGS) end local function call() method(ARGS) end
@@ -32,9 +34,9 @@ local function CreateDispatcher(argCount)
index, method = next(handlers) index, method = next(handlers)
if not method then return end if not method then return end
local OLD_ARGS = ARGS local OLD_ARGS = ARGS
ARGS = unpack(arg) ARGS = ...
repeat repeat
xpcall(call, function(err) return geterrorhandler()(err) end) xpcall(call, eh)
index, method = next(handlers, index) index, method = next(handlers, index)
until not method until not method
ARGS = OLD_ARGS ARGS = OLD_ARGS
@@ -45,7 +47,7 @@ local function CreateDispatcher(argCount)
local ARGS, OLD_ARGS = {}, {} local ARGS, OLD_ARGS = {}, {}
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
code = gsub(gsub(code, "OLD_ARGS", tconcat(OLD_ARGS, ", ")), "ARGS", tconcat(ARGS, ", ")) code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
end end
@@ -85,7 +87,7 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
local oldrecurse = registry.recurse local oldrecurse = registry.recurse
registry.recurse = oldrecurse + 1 registry.recurse = oldrecurse + 1
Dispatchers[getn(arg) + 1](events[eventname], eventname, unpack(arg)) Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
registry.recurse = oldrecurse registry.recurse = oldrecurse
@@ -136,10 +138,11 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
end end
if getn(arg)>=1 then -- this is not the same as testing for arg==nil! if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
regfunc = function(...) self[method](self,arg1,unpack(arg)) end local arg=select(1,...)
regfunc = function(...) self[method](self,arg,...) end
else else
regfunc = function(...) self[method](self,unpack(arg)) end regfunc = function(...) self[method](self,...) end
end end
else else
-- function ref with self=object or self="addonId" or self=thread -- function ref with self=object or self="addonId" or self=thread
@@ -147,8 +150,9 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
end end
if getn(arg)>=1 then -- this is not the same as testing for arg==nil! if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
regfunc = function(...) method(arg1,unpack(arg)) end local arg=select(1,...)
regfunc = function(...) method(arg,...) end
else else
regfunc = method regfunc = method
end end
@@ -194,16 +198,16 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
if UnregisterAllName then if UnregisterAllName then
target[UnregisterAllName] = function(...) target[UnregisterAllName] = function(...)
if getn(arg)<1 then if select("#",...)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end end
if getn(arg)==1 and arg1==target then if select("#",...)==1 and ...==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end end
for i=1,getn(arg) do for i=1,select("#",...) do
local self = arg[i] local self = select(i,...)
if registry.insertQueue then if registry.insertQueue then
for eventname, callbacks in pairs(registry.insertQueue) do for eventname, callbacks in pairs(registry.insertQueue) do
if callbacks[self] then if callbacks[self] then
+28 -10
View File
@@ -1,19 +1,25 @@
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info -- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/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_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
local _G = _G
local strfind, strfmt = string.find, string.format
local LibStub = _G[LIBSTUB_MAJOR] 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 if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or { libs = {}, minors = {} } LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub _G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR 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) function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
local _,_,num = strfind(minor, "(%d+)") minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
minor = assert(tonumber(num), "Minor version must either be a number or contain a number.")
local oldminor = self.minors[major] local oldminor = self.minors[major]
if oldminor and oldminor >= minor then return nil end if oldminor and oldminor >= minor then return nil end
@@ -21,13 +27,25 @@ if not LibStub or LibStub.minor < LIBSTUB_MINOR then
return self.libs[major], oldminor return self.libs[major], oldminor
end 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) function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then if not self.libs[major] and not silent then
error(strfmt("Cannot find a library instance of %q.", tostring(major)), 2) error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
end end
return self.libs[major], self.minors[major] return self.libs[major], self.minors[major]
end 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 }) setmetatable(LibStub, { __call = LibStub.GetLibrary })
end end
-1
View File
@@ -1,7 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="LibStub\LibStub.xml"/> <Include file="LibStub\LibStub.xml"/>
<Include file="CallbackHandler-1.0\CallbackHandler-1.0.xml"/> <Include file="CallbackHandler-1.0\CallbackHandler-1.0.xml"/>
<Include file="AceCore-3.0\AceCore-3.0.xml"/>
<Include file="AceAddon-3.0\AceAddon-3.0.xml"/> <Include file="AceAddon-3.0\AceAddon-3.0.xml"/>
<Include file="AceEvent-3.0\AceEvent-3.0.xml"/> <Include file="AceEvent-3.0\AceEvent-3.0.xml"/>
<Include file="AceConsole-3.0\AceConsole-3.0.xml"/> <Include file="AceConsole-3.0\AceConsole-3.0.xml"/>
@@ -12,15 +12,14 @@ Very light wrapper library that combines all the AceConfig subcomponents into on
]] ]]
local MAJOR, MINOR = "AceConfig-3.0", 2 local cfgreg = LibStub("AceConfigRegistry-3.0-ElvUI")
local cfgcmd = LibStub("AceConfigCmd-3.0-ElvUI")
local MAJOR, MINOR = "AceConfig-3.0-ElvUI", 3
local AceConfig = LibStub:NewLibrary(MAJOR, MINOR) local AceConfig = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfig then return end if not AceConfig then return end
AceConfig.embeds = AceConfig.embeds or {}
local cfgreg = LibStub("AceConfigRegistry-3.0")
local cfgcmd = LibStub("AceConfigCmd-3.0")
--TODO: local cfgdlg = LibStub("AceConfigDialog-3.0", true) --TODO: local cfgdlg = LibStub("AceConfigDialog-3.0", true)
--TODO: local cfgdrp = LibStub("AceConfigDropdown-3.0", true) --TODO: local cfgdrp = LibStub("AceConfigDropdown-3.0", true)
@@ -44,27 +43,16 @@ local pcall, error, type, pairs = pcall, error, type, pairs
-- local AceConfig = LibStub("AceConfig-3.0") -- local AceConfig = LibStub("AceConfig-3.0")
-- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"}) -- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"})
function AceConfig:RegisterOptionsTable(appName, options, slashcmd) function AceConfig:RegisterOptionsTable(appName, options, slashcmd)
if self == AceConfig then
error([[Usage: RegisterOptionsTable(appName, options[, slashcmd]): 'self' - use your own 'self']], 2)
end
local ok,msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options) local ok,msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options)
if not ok then error(msg, 2) end if not ok then error(msg, 2) end
if slashcmd then if slashcmd then
if type(slashcmd) == "table" then if type(slashcmd) == "table" then
for _,cmd in pairs(slashcmd) do for _,cmd in pairs(slashcmd) do
cfgcmd.CreateChatCommand(self, cmd, appName) cfgcmd:CreateChatCommand(cmd, appName)
end end
else else
cfgcmd.CreateChatCommand(self, slashcmd, appName) cfgcmd:CreateChatCommand(slashcmd, appName)
end end
end end
end end
function AceConfig:Embed(target)
target["RegisterOptionsTable"] = self["RegisterOptionsTable"]
end
for addon in pairs(AceConfig.embeds) do
AceConfig:Embed(addon)
end
@@ -3,6 +3,6 @@
<Include file="AceConfigRegistry-3.0\AceConfigRegistry-3.0.xml"/> <Include file="AceConfigRegistry-3.0\AceConfigRegistry-3.0.xml"/>
<Include file="AceConfigCmd-3.0\AceConfigCmd-3.0.xml"/> <Include file="AceConfigCmd-3.0\AceConfigCmd-3.0.xml"/>
<Include file="AceConfigDialog-3.0\AceConfigDialog-3.0.xml"/> <Include file="AceConfigDialog-3.0\AceConfigDialog-3.0.xml"/>
<Include file="AceConfigDropdown-3.0\AceConfigDropdown-3.0.xml"/> <!--<Include file="AceConfigDropdown-3.0\AceConfigDropdown-3.0.xml"/>-->
<Script file="AceConfig-3.0.lua"/> <Script file="AceConfig-3.0.lua"/>
</Ui> </Ui>
@@ -14,37 +14,28 @@ REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
-- TODO: plugin args -- TODO: plugin args
local cfgreg = LibStub("AceConfigRegistry-3.0-ElvUI")
local MAJOR, MINOR = "AceConfigCmd-3.0", 13 local MAJOR, MINOR = "AceConfigCmd-3.0-ElvUI", 14
local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR) local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigCmd then return end if not AceConfigCmd then return end
local AceCore = LibStub("AceCore-3.0")
local Dispatchers = AceCore.Dispatchers
local strtrim = AceCore.strtrim
--local strsplit = AceCore.strsplit
local new, del = AceCore.new, AceCore.del
local wipe = AceCore.wipe
AceConfigCmd.commands = AceConfigCmd.commands or {} AceConfigCmd.commands = AceConfigCmd.commands or {}
AceConfigCmd.embeds = AceConfigCmd.embeds or {}
local commands = AceConfigCmd.commands local commands = AceConfigCmd.commands
local cfgreg = LibStub("AceConfigRegistry-3.0")
local AceConsole -- LoD local AceConsole -- LoD
local AceConsoleName = "AceConsole-3.0" local AceConsoleName = "AceConsole-3.0"
-- Lua APIs -- Lua APIs
local strbyte, strsub = string.byte, string.sub local strsub, strsplit, strlower, strmatch, strtrim = string.sub, string.split, string.lower, string.match, string.trim
local strlen, strupper, strlower = string.len, string.upper, string.lower local format, tonumber, tostring = string.format, tonumber, tostring
local strfind, strgfind, strgsub = string.find, string.gfind, string.gsub local tsort, tinsert = table.sort, table.insert
local select, pairs, next, type = select, pairs, next, type
local format = string.format local error, assert = error, assert
local tsort, tinsert, tgetn, tremove = table.sort, table.insert, table.getn, table.remove
-- WoW APIs -- WoW APIs
local _G = AceCore._G local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -69,7 +60,17 @@ local handlermsg = "expected a table"
local functypes = {["function"]=true, ["string"]=true} local functypes = {["function"]=true, ["string"]=true}
local funcmsg = "expected function or member name" local funcmsg = "expected function or member name"
local pickfirstset = AceCore.pickfirstset
-- pickfirstset() - picks the first non-nil value and returns it
local function pickfirstset(...)
for i=1,select("#",...) do
if select(i,...)~=nil then
return select(i,...)
end
end
end
-- err() - produce real error() regarding malformed options tables etc -- err() - produce real error() regarding malformed options tables etc
@@ -89,26 +90,23 @@ end
-- callmethod() - call a given named method (e.g. "get", "set") with given arguments -- callmethod() - call a given named method (e.g. "get", "set") with given arguments
local function callmethod(info, inputpos, tab, methodtype, ...)
local function callmethod(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4)
local method = info[methodtype] local method = info[methodtype]
if not method then if not method then
err(info, inputpos, "'"..methodtype.."': not set") err(info, inputpos, "'"..methodtype.."': not set")
end end
argc = argc or 0
info.arg = tab.arg info.arg = tab.arg
info.option = tab info.option = tab
info.type = tab.type info.type = tab.type
if type(method)=="function" then if type(method)=="function" then
return Dispatchers[argc+1](method, info, a1, a2, a3, a4) return method(info, ...)
elseif type(method)=="string" then elseif type(method)=="string" then
if type(info.handler[method])~="function" then if type(info.handler[method])~="function" then
err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler)) err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
end end
return Dispatchers[argc+2](info.handler[method], info.handler, info, a1, a2, a3, a4) return info.handler[method](info.handler, info, ...)
else else
assert(false) -- type should have already been checked on read assert(false) -- type should have already been checked on read
end end
@@ -116,8 +114,7 @@ end
-- callfunction() - call a given named function (e.g. "name", "desc") with given arguments -- callfunction() - call a given named function (e.g. "name", "desc") with given arguments
-- Ace3v: the variable arguments are currently unused, so we removed it local function callfunction(info, tab, methodtype, ...)
local function callfunction(info, tab, methodtype)
local method = tab[methodtype] local method = tab[methodtype]
info.arg = tab.arg info.arg = tab.arg
@@ -125,18 +122,17 @@ local function callfunction(info, tab, methodtype)
info.type = tab.type info.type = tab.type
if type(method)=="function" then if type(method)=="function" then
return method(info) return method(info, ...)
else else
assert(false) -- type should have already been checked on read assert(false) -- type should have already been checked on read
end end
end end
-- do_final() - do the final step (set/execute) along with validation and confirmation -- do_final() - do the final step (set/execute) along with validation and confirmation
-- Ace3v: experimental
-- @param argc number of variable arguments local function do_final(info, inputpos, tab, methodtype, ...)
local function do_final(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4) -- currently maximum 4 arguments
if info.validate then if info.validate then
local res = callmethod(info,inputpos,tab,"validate",argc,a1,a2,a3,a4) local res = callmethod(info,inputpos,tab,"validate",...)
if type(res)=="string" then if type(res)=="string" then
usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res) usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
return return
@@ -144,7 +140,7 @@ local function do_final(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4) -
end end
-- console ignores .confirm -- console ignores .confirm
callmethod(info,inputpos,tab,methodtype,argc,a1,a2,a3,a4) callmethod(info,inputpos,tab,methodtype, ...)
end end
@@ -167,6 +163,8 @@ end
-- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.* -- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
local dummytable={}
local function iterateargs(tab) local function iterateargs(tab)
if not tab.plugins then if not tab.plugins then
return pairs(tab.args) return pairs(tab.args)
@@ -191,21 +189,17 @@ local function iterateargs(tab)
end end
end end
local function getValueFromTab(info, inputpos, tab, key)
local v = tab[key]
if type(v) == "function" or type(v) == "string" then
info[key] = v
v = callmethod(info, inputpos, tab, key)
info[key] = nil
end
return v
end
local function checkhidden(info, inputpos, tab) local function checkhidden(info, inputpos, tab)
if tab.cmdHidden~=nil then if tab.cmdHidden~=nil then
return tab.cmdHidden return tab.cmdHidden
end end
return getValueFromTab(info, inputpos, tab, "hidden") local hidden = tab.hidden
if type(hidden) == "function" or type(hidden) == "string" then
info.hidden = hidden
hidden = callmethod(info, inputpos, tab, 'hidden')
info.hidden = nil
end
return hidden
end end
local function showhelp(info, inputpos, tab, depth, noHead) local function showhelp(info, inputpos, tab, depth, noHead)
@@ -213,8 +207,8 @@ local function showhelp(info, inputpos, tab, depth, noHead)
print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":") print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":")
end end
local sortTbl = new() -- [1..n]=name local sortTbl = {} -- [1..n]=name
local refTbl = new() -- [name]=tableref local refTbl = {} -- [name]=tableref
for k,v in iterateargs(tab) do for k,v in iterateargs(tab) do
if not refTbl[k] then -- a plugin overriding something in .args if not refTbl[k] then -- a plugin overriding something in .args
@@ -228,16 +222,16 @@ local function showhelp(info, inputpos, tab, depth, noHead)
local o2 = refTbl[two].order or 100 local o2 = refTbl[two].order or 100
if type(o1) == "function" or type(o1) == "string" then if type(o1) == "function" or type(o1) == "string" then
info.order = o1 info.order = o1
tinsert(info, one) info[#info+1] = one
o1 = callmethod(info, inputpos, refTbl[one], "order") o1 = callmethod(info, inputpos, refTbl[one], "order")
tremove(info) info[#info] = nil
info.order = nil info.order = nil
end end
if type(o2) == "function" or type(o1) == "string" then if type(o2) == "function" or type(o1) == "string" then
info.order = o2 info.order = o2
tinsert(info, two) info[#info+1] = two
o2 = callmethod(info, inputpos, refTbl[two], "order") o2 = callmethod(info, inputpos, refTbl[two], "order")
tremove(info) info[#info] = nil
info.order = nil info.order = nil
end end
if o1<0 and o2<0 then return o1<o2 end if o1<0 and o2<0 then return o1<o2 end
@@ -247,7 +241,7 @@ local function showhelp(info, inputpos, tab, depth, noHead)
return o1<o2 return o1<o2
end) end)
for i = 1, tgetn(sortTbl) do for i = 1, #sortTbl do
local k = sortTbl[i] local k = sortTbl[i]
local v = refTbl[k] local v = refTbl[k]
if not checkhidden(info, inputpos, v) then if not checkhidden(info, inputpos, v) then
@@ -260,27 +254,26 @@ local function showhelp(info, inputpos, tab, depth, noHead)
if type(desc) == "function" then if type(desc) == "function" then
desc = callfunction(info, v, 'desc') desc = callfunction(info, v, 'desc')
end end
if v.type == "group" and pickfirstset(3, v.cmdInline, v.inline, false) then if v.type == "group" and pickfirstset(v.cmdInline, v.inline, false) then
print(" "..(desc or name)..":") print(" "..(desc or name)..":")
local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg) local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg)
showhelp(info, inputpos, v, depth, true) showhelp(info, inputpos, v, depth, true)
info.handler,info.handler_at = oldhandler,oldhandler_at info.handler,info.handler_at = oldhandler,oldhandler_at
else else
local key = strgsub(k, " ", "_") local key = k:gsub(" ", "_")
print(" |cffffff78"..key.."|r - "..(desc or name or "")) print(" |cffffff78"..key.."|r - "..(desc or name or ""))
end end
end end
end end
end end
del(sortTbl) -- Ace3v: release the tables
del(refTbl)
end end
local function keybindingValidateFunc(text) local function keybindingValidateFunc(text)
if text == nil or text == "NONE" then if text == nil or text == "NONE" then
return nil return nil
end end
text = strupper(text) text = text:upper()
local shift, ctrl, alt local shift, ctrl, alt
local modifier local modifier
while true do while true do
@@ -318,7 +311,7 @@ local function keybindingValidateFunc(text)
if text == "" then if text == "" then
return false return false
end end
if not strfind(text,"^F%d+$") and text ~= "CAPSLOCK" and strlen(text) ~= 1 and (strbyte(text) < 128 or strlen(text) > 4) and not _G["KEY_" .. text] then if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then
return false return false
end end
local s = text local s = text
@@ -364,7 +357,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end
-- grab next arg from input -- grab next arg from input
local _,nextpos,arg = strfind(info.input, " *([^ ]+) *", inputpos) local _,nextpos,arg = (info.input):find(" *([^ ]+) *", inputpos)
if not arg then if not arg then
showhelp(info, inputpos, tab, depth) showhelp(info, inputpos, tab, depth)
return return
@@ -376,17 +369,17 @@ local function handle(info, inputpos, tab, depth, retfalse)
if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end
-- is this child an inline group? if so, traverse into it -- is this child an inline group? if so, traverse into it
if v.type=="group" and pickfirstset(3, v.cmdInline, v.inline, false) then if v.type=="group" and pickfirstset(v.cmdInline, v.inline, false) then
tinsert(info,k) info[depth+1] = k
if handle(info, inputpos, v, depth+1, true)==false then if handle(info, inputpos, v, depth+1, true)==false then
tremove(info) info[depth+1] = nil
-- wasn't found in there, but that's ok, we just keep looking down here -- wasn't found in there, but that's ok, we just keep looking down here
else else
return -- done, name was found in inline group return -- done, name was found in inline group
end end
-- matching name and not a inline group -- matching name and not a inline group
elseif strlower(arg)==strlower(strgsub(k, " ", "_")) then elseif strlower(arg)==strlower(k:gsub(" ", "_")) then
tinsert(info,k) info[depth+1] = k
return handle(info,nextpos,v,depth+1) return handle(info,nextpos,v,depth+1)
end end
end end
@@ -419,21 +412,16 @@ local function handle(info, inputpos, tab, depth, retfalse)
elseif tab.type=="input" then elseif tab.type=="input" then
------------ input -------------------------------------------- ------------ input --------------------------------------------
if str=="" and tab.nullable == false then
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
return
end
local res = true local res = true
if tab.pattern then if tab.pattern then
if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end
if not strfind(str, tab.pattern) then if not strmatch(str, tab.pattern) then
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"]) usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
return return
end end
end end
do_final(info, inputpos, tab, "set", 1, str) do_final(info, inputpos, tab, "set", str)
@@ -472,71 +460,54 @@ local function handle(info, inputpos, tab, depth, retfalse)
return return
end end
do_final(info, inputpos, tab, "set", 1, b) do_final(info, inputpos, tab, "set", b)
elseif tab.type=="range" then elseif tab.type=="range" then
------------ range -------------------------------------------- ------------ range --------------------------------------------
local str = strtrim(strlower(str))
if str == "" then
-- TODO: Show current value
return
end
local val = tonumber(str) local val = tonumber(str)
if not val then if not val then
usererr(info, inputpos, "'"..str.."' - "..L["expected number"]) usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
return return
end end
if type(info.step)=="number" then
local step = getValueFromTab(info, inputpos, tab, "step") val = val- (val % info.step)
local min = getValueFromTab(info, inputpos, tab, "min")
if type(step)=="number" then
val = min + math.floor((val-min)/step) * step
end end
if type(info.min)=="number" and val<info.min then
if type(min)=="number" and val<min then usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(info.min)) )
usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(min)) ) return
end
if type(info.max)=="number" and val>info.max then
usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(info.max)) )
return return
end end
local max = getValueFromTab(info, inputpos, tab, "max") do_final(info, inputpos, tab, "set", val)
if type(max)=="number" and val>max then
usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(max)) )
return
end
do_final(info, inputpos, tab, "set", 1, val)
elseif tab.type=="select" then elseif tab.type=="select" then
------------ select ------------------------------------ ------------ select ------------------------------------
local str = strtrim(strlower(str)) local str = strtrim(strlower(str))
local values = getValueFromTab(info, inputpos, tab, "values") local values = tab.values
if type(values) == "function" or type(values) == "string" then
info.values = values
values = callmethod(info, inputpos, tab, "values")
info.values = nil
end
if str == "" then if str == "" then
-- Ace3v: it is possbile to not have a current value local b = callmethod(info, inputpos, tab, "get")
-- we do this only for select but not for multiselect
local b = tab.get
if type(b) == "function" or type(b) == "string" then
b = callmethod(info, inputpos, tab, "get")
else
b = nil
end
local fmt = "|cffffff78- [%s]|r %s" local fmt = "|cffffff78- [%s]|r %s"
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r" local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
print(L["Options for |cffffff78"..info[tgetn(info)].."|r:"]) print(L["Options for |cffffff78"..info[#info].."|r:"])
for k, v in pairs(values) do for k, v in pairs(values) do
if b == k then if b == k then
print(format(fmt_sel, k, v)) print(fmt_sel:format(k, v))
else else
print(format(fmt, k, v)) print(fmt:format(k, v))
end end
end end
if tab.valuesTableDestroyable then del(values) end
return return
end end
@@ -548,42 +519,45 @@ local function handle(info, inputpos, tab, depth, retfalse)
break break
end end
end end
if tab.valuesTableDestroyable then del(values) end
if not ok then if not ok then
usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"]) usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
return return
end end
do_final(info, inputpos, tab, "set", 1, str) do_final(info, inputpos, tab, "set", str)
elseif tab.type=="multiselect" then elseif tab.type=="multiselect" then
------------ multiselect ------------------------------------------- ------------ multiselect -------------------------------------------
local str = strtrim(strlower(str)) local str = strtrim(strlower(str))
local values = getValueFromTab(info, inputpos, tab, "values") local values = tab.values
if type(values) == "function" or type(values) == "string" then
info.values = values
values = callmethod(info, inputpos, tab, "values")
info.values = nil
end
if str == "" then if str == "" then
local fmt = "|cffffff78- [%s]|r %s" local fmt = "|cffffff78- [%s]|r %s"
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r" local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
print(L["Options for |cffffff78"..info[tgetn(info)].."|r (multiple possible):"]) print(L["Options for |cffffff78"..info[#info].."|r (multiple possible):"])
for k, v in pairs(values) do for k, v in pairs(values) do
if callmethod(info, inputpos, tab, "get", 1, k) then if callmethod(info, inputpos, tab, "get", k) then
print(format(fmt_sel, k, v)) print(fmt_sel:format(k, v))
else else
print(format(fmt, k, v)) print(fmt:format(k, v))
end end
end end
if tab.valuesTableDestroyable then del(values) end
return return
end end
--build a table of the selections, checking that they exist --build a table of the selections, checking that they exist
--parse for =on =off =default in the process --parse for =on =off =default in the process
--table will be key = true for options that should toggle, key = [on|off|default] for options to be set --table will be key = true for options that should toggle, key = [on|off|default] for options to be set
local sels = new() local sels = {}
for v in strgfind(str, "[^ ]+") do for v in str:gmatch("[^ ]+") do
--parse option=on etc --parse option=on etc
local _, _, opt, val = strfind(v, '(.+)=(.+)') local opt, val = v:match('(.+)=(.+)')
--get option if toggling --get option if toggling
if not opt then if not opt then
opt = v opt = v
@@ -598,7 +572,6 @@ local function handle(info, inputpos, tab, depth, retfalse)
break break
end end
end end
if tab.valuesTableDestroyable then del(values) end
if not ok then if not ok then
usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"]) usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
@@ -616,7 +589,6 @@ local function handle(info, inputpos, tab, depth, retfalse)
else else
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val)) usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
end end
del(sels)
return return
end end
else else
@@ -630,7 +602,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
if (val == true) then if (val == true) then
--toggle the option --toggle the option
local b = callmethod(info, inputpos, tab, "get", 1, opt) local b = callmethod(info, inputpos, tab, "get", opt)
if tab.tristate then if tab.tristate then
--cycle in true, nil, false order --cycle in true, nil, false order
@@ -656,9 +628,8 @@ local function handle(info, inputpos, tab, depth, retfalse)
end end
end end
do_final(info, inputpos, tab, "set", 2, opt, newval) do_final(info, inputpos, tab, "set", opt, newval)
end end
del(sels)
elseif tab.type=="color" then elseif tab.type=="color" then
@@ -669,17 +640,22 @@ local function handle(info, inputpos, tab, depth, retfalse)
return return
end end
local _, r, g, b, a local r, g, b, a
local hasAlpha = getValueFromTab(info, inputpos, tab, 'hasAlpha') local hasAlpha = tab.hasAlpha
if type(hasAlpha) == "function" or type(hasAlpha) == "string" then
info.hasAlpha = hasAlpha
hasAlpha = callmethod(info, inputpos, tab, 'hasAlpha')
info.hasAlpha = nil
end
if hasAlpha then if hasAlpha then
if strlen(str) == 8 and strfind(str, "^%x*$") then if str:len() == 8 and str:find("^%x*$") then
--parse a hex string --parse a hex string
r,g,b,a = tonumber(strsub(str, 1, 2), 16) / 255, tonumber(strsub(str, 3, 4), 16) / 255, tonumber(strsub(str, 5, 6), 16) / 255, tonumber(strsub(str, 7, 8), 16) / 255 r,g,b,a = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255, tonumber(str:sub(7, 8), 16) / 255
else else
--parse seperate values --parse seperate values
_,_,r,g,b,a = strfind(str, "^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$") r,g,b,a = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$")
r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a) r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
end end
if not (r and g and b and a) then if not (r and g and b and a) then
@@ -701,12 +677,12 @@ local function handle(info, inputpos, tab, depth, retfalse)
end end
else else
a = 1.0 a = 1.0
if strlen(str) == 6 and strfind(str, "^%x*$") then if str:len() == 6 and str:find("^%x*$") then
--parse a hex string --parse a hex string
r,g,b = tonumber(strsub(str, 1, 2), 16) / 255, tonumber(strsub(str, 3, 4), 16) / 255, tonumber(strsub(str, 5, 6), 16) / 255 r,g,b = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255
else else
--parse seperate values --parse seperate values
_,_,r,g,b = strfind(str, "^([%d%.]+) ([%d%.]+) ([%d%.]+)$") r,g,b = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+)$")
r,g,b = tonumber(r), tonumber(g), tonumber(b) r,g,b = tonumber(r), tonumber(g), tonumber(b)
end end
if not (r and g and b) then if not (r and g and b) then
@@ -726,7 +702,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
end end
end end
do_final(info, inputpos, tab, "set", 4, r,g,b,a) do_final(info, inputpos, tab, "set", r,g,b,a)
elseif tab.type=="keybinding" then elseif tab.type=="keybinding" then
------------ keybinding -------------------------------------------- ------------ keybinding --------------------------------------------
@@ -735,13 +711,13 @@ local function handle(info, inputpos, tab, depth, retfalse)
--TODO: Show current value --TODO: Show current value
return return
end end
local value = keybindingValidateFunc(strupper(str)) local value = keybindingValidateFunc(str:upper())
if value == false then if value == false then
usererr(info, inputpos, format(L["'%s' - Invalid Keybinding."], str)) usererr(info, inputpos, format(L["'%s' - Invalid Keybinding."], str))
return return
end end
do_final(info, inputpos, tab, "set", 1, value) do_final(info, inputpos, tab, "set", value)
elseif tab.type=="description" then elseif tab.type=="description" then
------------ description -------------------- ------------ description --------------------
@@ -771,9 +747,6 @@ end
-- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input) -- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
-- end -- end
-- end -- end
-- Ace3v: experimental, user should copy info table if he wanna reuse it outside
-- then handler
local info_ = {}
function AceConfigCmd:HandleCommand(slashcmd, appName, input) function AceConfigCmd:HandleCommand(slashcmd, appName, input)
local optgetter = cfgreg:GetOptionsTable(appName) local optgetter = cfgreg:GetOptionsTable(appName)
@@ -782,65 +755,32 @@ function AceConfigCmd:HandleCommand(slashcmd, appName, input)
end end
local options = assert( optgetter("cmd", MAJOR) ) local options = assert( optgetter("cmd", MAJOR) )
-- Ace3v: prevent user from using AceConfigCmd as self local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
if self == AceConfigCmd then [0] = slashcmd,
error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'self' - use your own 'self']], 2) appName = appName,
end options = options,
input = input,
self = self,
handler = self,
uiType = "cmd",
uiName = MAJOR,
}
--local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot handle(info, 1, options, 0) -- (info, inputpos, table, depth)
-- [0] = slashcmd,
-- appName = appName,
-- options = options,
-- input = input,
-- self = self,
-- handler = self,
-- uiType = "cmd",
-- uiName = MAJOR,
--}
wipe(info_)
info_[0] = slashcmd
info_.appName = appName
info_.options = options
info_.input = input
info_.self = self
info_.handler = self
info_.uiType = "cmd"
info_.uiName = MAJOR
handle(info_, 1, options, 0) -- (info, inputpos, table, depth)
end end
--- Utility function to create a slash command handler. --- Utility function to create a slash command handler.
-- Also registers tab completion with AceTab -- Also registers tab completion with AceTab
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output) -- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
-- @param appName The application name as given to `:RegisterOptionsTable()` -- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigCmd:CreateChatCommand(slashcmd, appName, func) function AceConfigCmd:CreateChatCommand(slashcmd, appName)
if not AceConsole then if not AceConsole then
AceConsole = LibStub(AceConsoleName) AceConsole = LibStub(AceConsoleName)
end end
if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
-- Ace3v: prevent user from using AceConfigCmd as self AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
if self == AceConfigCmd then end,
error([[Usage: CreateChatCommand("slashcmd", "appName"[, "func"]): 'self' - use your own 'self']], 2) true) then -- succesfully registered so lets get the command -> app table in
end
local t = type(func)
-- Ace3v: make it possible to call another function
local handler
if t == "string" then
handler = function(input) self[func](self, input, slashcmd, appName) end
elseif t ~= "function" then
handler = function(input)
AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
end
else
handler = func
end
if AceConsole.RegisterChatCommand(self, slashcmd, handler, true) then
-- succesfully registered so lets get the command -> app table in
commands[slashcmd] = appName commands[slashcmd] = appName
end end
end end
@@ -852,12 +792,3 @@ end
function AceConfigCmd:GetChatCommandOptions(slashcmd) function AceConfigCmd:GetChatCommandOptions(slashcmd)
return commands[slashcmd] return commands[slashcmd]
end end
function AceConfigCmd:Embed(target)
target["HandleCommand"] = self["HandleCommand"]
target["CreateChatCommand"] = self["CreateChatCommand"]
end
for addon in pairs(AceConfigCmd.embeds) do
AceConfigCmd:Embed(addon)
end
File diff suppressed because it is too large Load Diff
@@ -8,24 +8,24 @@
-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName". -- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
-- @class file -- @class file
-- @name AceConfigRegistry-3.0 -- @name AceConfigRegistry-3.0
-- @release $Id: AceConfigRegistry-3.0.lua 1139 2016-07-03 07:43:51Z nevcairiel $ -- @release $Id: AceConfigRegistry-3.0.lua 1105 2013-12-08 22:11:58Z nevcairiel $
local MAJOR, MINOR = "AceConfigRegistry-3.0", 16 local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
local MAJOR, MINOR = "AceConfigRegistry-3.0-ElvUI", 17
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR) local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigRegistry then return end if not AceConfigRegistry then return end
AceConfigRegistry.tables = AceConfigRegistry.tables or {} AceConfigRegistry.tables = AceConfigRegistry.tables or {}
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
if not AceConfigRegistry.callbacks then if not AceConfigRegistry.callbacks then
AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry) AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
end end
-- Lua APIs -- Lua APIs
local tinsert, tconcat, tgetn = table.insert, table.concat, table.getn local tinsert, tconcat = table.insert, table.concat
local strfind = string.find local strfind, strmatch = string.find, string.match
local type, tostring, pairs = type, tostring, pairs local type, tostring, select, pairs = type, tostring, select, pairs
local error, assert = error, assert local error, assert = error, assert
----------------------------------------------------------------------- -----------------------------------------------------------------------
@@ -40,24 +40,23 @@ AceConfigRegistry.validated = {
dialog = {}, dialog = {},
} }
local function err(msg, errlvl, ...) local function err(msg, errlvl, ...)
local l = tgetn(arg) local t = {}
local i,j = 1,l for i=select("#",...),1,-1 do
while i < j do tinsert(t, (select(i, ...)))
arg[i], arg[j] = arg[j], arg[i]
i = i+1
j = j-1
end end
error(MAJOR..":ValidateOptionsTable(): "..tconcat(arg,".")..msg, errlvl+2) error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2)
end end
local isstring={["string"]=true, _="string"} local isstring={["string"]=true, _="string"}
local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"} local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
local istable={["table"]=true, _="table"} local istable={["table"]=true, _="table"}
local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"} local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"}
local optstring={["nil"]=true,["string"]=true, _="string"} local optstring={["nil"]=true,["string"]=true, _="string"}
local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"} local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"}
local optstringnumberfunc={["nil"]=true,["string"]=true,["number"]=true,["function"]=true, _="string, number or funcref"}
local optnumber={["nil"]=true,["number"]=true, _="number"} local optnumber={["nil"]=true,["number"]=true, _="number"}
local optmethod={["nil"]=true,["string"]=true,["function"]=true, _="methodname or funcref"} local optmethod={["nil"]=true,["string"]=true,["function"]=true, _="methodname or funcref"}
local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true}, _="methodname, funcref or false"} local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true}, _="methodname, funcref or false"}
@@ -83,7 +82,7 @@ local basekeys={
dialogHidden=optmethodbool, dialogHidden=optmethodbool,
dropdownHidden=optmethodbool, dropdownHidden=optmethodbool,
cmdHidden=optmethodbool, cmdHidden=optmethodbool,
icon=optstringnumberfunc, icon=optstringfunc,
iconCoords=optmethodtable, iconCoords=optmethodtable,
handler=opttable, handler=opttable,
get=optmethodfalse, get=optmethodfalse,
@@ -91,14 +90,13 @@ local basekeys={
func=optmethodfalse, func=optmethodfalse,
arg={["*"]=true}, arg={["*"]=true},
width=optstring, width=optstring,
-- below here were created by ElvUI --
buttonElvUI=optmethodbool, buttonElvUI=optmethodbool,
} }
local typedkeys={ local typedkeys={
header={}, header={},
description={ description={
image=optstringnumberfunc, image=optstringfunc,
imageCoords=optmethodtable, imageCoords=optmethodtable,
imageHeight=optnumber, imageHeight=optnumber,
imageWidth=optnumber, imageWidth=optnumber,
@@ -115,7 +113,7 @@ local typedkeys={
childGroups=optstring, childGroups=optstring,
}, },
execute={ execute={
image=optstringnumberfunc, image=optstringfunc,
imageCoords=optmethodtable, imageCoords=optmethodtable,
imageHeight=optnumber, imageHeight=optnumber,
imageWidth=optnumber, imageWidth=optnumber,
@@ -127,11 +125,10 @@ local typedkeys={
dialogControl=optstring, dialogControl=optstring,
dropdownControl=optstring, dropdownControl=optstring,
multiline=optboolnumber, multiline=optboolnumber,
nullable=optbool,
}, },
toggle={ toggle={
tristate=optbool, tristate=optbool,
image=optstringnumberfunc, image=optstringfunc,
imageCoords=optmethodtable, imageCoords=optmethodtable,
}, },
tristate={ tristate={
@@ -147,7 +144,6 @@ local typedkeys={
}, },
select={ select={
values=ismethodtable, values=ismethodtable,
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
style={ style={
["nil"]=true, ["nil"]=true,
["string"]={dropdown=true,radio=true}, ["string"]={dropdown=true,radio=true},
@@ -160,7 +156,6 @@ local typedkeys={
}, },
multiselect={ multiselect={
values=ismethodtable, values=ismethodtable,
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
style=optstring, style=optstring,
tristate=optbool, tristate=optbool,
control=optstring, control=optstring,
@@ -169,81 +164,82 @@ local typedkeys={
}, },
color={ color={
hasAlpha=optmethodbool, hasAlpha=optmethodbool,
reset=opttable,
}, },
keybinding={ keybinding={
-- TODO -- TODO
}, },
} }
local function validateKey(k,errlvl,arg) local function validateKey(k,errlvl,...)
errlvl=(errlvl or 0)+1 errlvl=(errlvl or 0)+1
if type(k)~="string" then if type(k)~="string" then
err("["..tostring(k).."] - key is not a string", errlvl, arg) err("["..tostring(k).."] - key is not a string", errlvl,...)
end end
if strfind(k, "[%c\127]") then if strfind(k, "[%c\127]") then
err("["..tostring(k).."] - key name contained control characters", errlvl, arg) err("["..tostring(k).."] - key name contained control characters", errlvl,...)
end end
end end
local function validateVal(v, oktypes, errlvl, arg) local function validateVal(v, oktypes, errlvl,...)
errlvl=(errlvl or 0)+1 errlvl=(errlvl or 0)+1
local isok=oktypes[type(v)] or oktypes["*"] local isok=oktypes[type(v)] or oktypes["*"]
if not isok then if not isok then
err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl, arg) err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,...)
end end
if type(isok)=="table" then -- isok was a table containing specific values to be tested for! if type(isok)=="table" then -- isok was a table containing specific values to be tested for!
if not isok[v] then if not isok[v] then
err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl, arg) err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl,...)
end end
end end
end end
local function validate(options,errlvl,arg) local function validate(options,errlvl,...)
errlvl=(errlvl or 0)+1 errlvl=(errlvl or 0)+1
-- basic consistency -- basic consistency
if type(options)~="table" then if type(options)~="table" then
err(": expected a table, got a "..type(options), errlvl, arg) err(": expected a table, got a "..type(options), errlvl,...)
end end
if type(options.type)~="string" then if type(options.type)~="string" then
err(".type: expected a string, got a "..type(options.type), errlvl, arg) err(".type: expected a string, got a "..type(options.type), errlvl,...)
end end
-- get type and 'typedkeys' member -- get type and 'typedkeys' member
local tk = typedkeys[options.type] local tk = typedkeys[options.type]
if not tk then if not tk then
err(".type: unknown type '"..options.type.."'", errlvl, arg) err(".type: unknown type '"..options.type.."'", errlvl,...)
end end
-- make sure that all options[] are known parameters -- make sure that all options[] are known parameters
for k,v in pairs(options) do for k,v in pairs(options) do
if not (tk[k] or basekeys[k]) then if not (tk[k] or basekeys[k]) then
err(": unknown parameter", errlvl,tostring(k), arg) err(": unknown parameter", errlvl,tostring(k),...)
end end
end end
-- verify that required params are there, and that everything is the right type -- verify that required params are there, and that everything is the right type
for k,oktypes in pairs(basekeys) do for k,oktypes in pairs(basekeys) do
validateVal(options[k], oktypes, errlvl, k, arg) validateVal(options[k], oktypes, errlvl,k,...)
end end
for k,oktypes in pairs(tk) do for k,oktypes in pairs(tk) do
validateVal(options[k], oktypes, errlvl, k, arg) validateVal(options[k], oktypes, errlvl,k,...)
end end
-- extra logic for groups -- extra logic for groups
if options.type=="group" then if options.type=="group" then
for k,v in pairs(options.args) do for k,v in pairs(options.args) do
validateKey(k,errlvl,"args", arg) validateKey(k,errlvl,"args",...)
validate(v, errlvl,k,"args", arg) validate(v, errlvl,k,"args",...)
end end
if options.plugins then if options.plugins then
for plugname,plugin in pairs(options.plugins) do for plugname,plugin in pairs(options.plugins) do
if type(plugin)~="table" then if type(plugin)~="table" then
err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname), "plugins", arg) err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname),"plugins",...)
end end
for k,v in pairs(plugin) do for k,v in pairs(plugin) do
validateKey(k,errlvl,tostring(plugname),"plugins",arg) validateKey(k,errlvl,tostring(plugname),"plugins",...)
validate(v, errlvl,k,tostring(plugname),"plugins",arg) validate(v, errlvl,k,tostring(plugname),"plugins",...)
end end
end end
end end
@@ -271,7 +267,7 @@ end
-- @param appName The application name as given to `:RegisterOptionsTable()` -- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigRegistry:NotifyChange(appName) function AceConfigRegistry:NotifyChange(appName)
if not AceConfigRegistry.tables[appName] then return end if not AceConfigRegistry.tables[appName] then return end
AceConfigRegistry.callbacks:Fire("ConfigTableChange", 1, appName) AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName)
end end
-- ------------------------------------------------------------------- -- -------------------------------------------------------------------
@@ -285,7 +281,7 @@ local function validateGetterArgs(uiType, uiName, errlvl)
if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then
error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl) error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl)
end end
if not strfind(uiName, "[A-Za-z]+-[0-9]") then -- Expecting e.g. "MyLib-1.2" if not strmatch(uiName, "[A-Za-z]%-[0-9]") then -- Expecting e.g. "MyLib-1.2"
error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl) error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl)
end end
end end
@@ -7,9 +7,6 @@ local AceDBOptions, oldminor = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
if not AceDBOptions then return end -- No upgrade needed if not AceDBOptions then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
-- Lua APIs -- Lua APIs
local pairs, next = pairs, next local pairs, next = pairs, next
@@ -233,6 +230,7 @@ elseif LOCALE == "ptBR" then
end end
local defaultProfiles local defaultProfiles
local tmpprofiles = {}
-- Get a list of available profiles for the specified database. -- Get a list of available profiles for the specified database.
-- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below. -- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below.
@@ -241,24 +239,23 @@ local defaultProfiles
-- @param nocurrent If true, then getProfileList will not display the current profile in the list -- @param nocurrent If true, then getProfileList will not display the current profile in the list
-- @return Hashtable of all profiles with the internal name as keys and the display name as value. -- @return Hashtable of all profiles with the internal name as keys and the display name as value.
local function getProfileList(db, common, nocurrent) local function getProfileList(db, common, nocurrent)
local profiles = new() local profiles = {}
local tmpprofiles = new()
-- copy existing profiles into the table -- copy existing profiles into the table
local currentProfile = db:GetCurrentProfile() local currentProfile = db:GetCurrentProfile()
for i,v in pairs(db:GetProfiles(tmpprofiles)) do for i,v in pairs(db:GetProfiles(tmpprofiles)) do
if not (nocurrent and v == currentProfile) then if not (nocurrent and v == currentProfile) then
profiles[v] = v profiles[v] = v
end end
end end
del(tmpprofiles)
-- add our default profiles to choose from ( or rename existing profiles) -- add our default profiles to choose from ( or rename existing profiles)
for k,v in pairs(defaultProfiles) do for k,v in pairs(defaultProfiles) do
if (common or profiles[k]) and not (nocurrent and k == currentProfile) then if (common or profiles[k]) and not (nocurrent and k == currentProfile) then
profiles[k] = v profiles[k] = v
end end
end end
return profiles return profiles
end end
@@ -283,18 +280,16 @@ function OptionsHandlerPrototype:GetCurrentProfile()
return self.db:GetCurrentProfile() return self.db:GetCurrentProfile()
end end
--[[ --[[
List all active profiles List all active profiles
you can control the output with the .arg variable you can control the output with the .arg variable
currently four modes are supported currently four modes are supported
(empty) - return all available profiles (empty) - return all available profiles
"nocurrent" - returns all available profiles except the currently active profile "nocurrent" - returns all available profiles except the currently active profile
"common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default") "common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default")
"both" - common except the active profile "both" - common except the active profile
]] ]]
-- Ace3v: It is recommanded to destroy the returned table by AceCore.del
-- if it is no longer needed
function OptionsHandlerPrototype:ListProfiles(info) function OptionsHandlerPrototype:ListProfiles(info)
local arg = info.arg local arg = info.arg
local profiles local profiles
@@ -307,15 +302,13 @@ function OptionsHandlerPrototype:ListProfiles(info)
else else
profiles = getProfileList(self.db) profiles = getProfileList(self.db)
end end
return profiles return profiles
end end
function OptionsHandlerPrototype:HasNoProfiles(info) function OptionsHandlerPrototype:HasNoProfiles(info)
local profiles = self:ListProfiles(info) local profiles = self:ListProfiles(info)
local r = (not next(profiles)) and true or false return ((not next(profiles)) and true or false)
del(profiles)
return r
end end
--[[ Copy a profile ]] --[[ Copy a profile ]]
@@ -343,19 +336,19 @@ local function getOptionsHandler(db, noDefaultProfiles)
if not defaultProfiles then if not defaultProfiles then
generateDefaultProfiles(db) generateDefaultProfiles(db)
end end
local handler = AceDBOptions.handlers[db] or { db = db, noDefaultProfiles = noDefaultProfiles } local handler = AceDBOptions.handlers[db] or { db = db, noDefaultProfiles = noDefaultProfiles }
for k,v in pairs(OptionsHandlerPrototype) do for k,v in pairs(OptionsHandlerPrototype) do
handler[k] = v handler[k] = v
end end
AceDBOptions.handlers[db] = handler AceDBOptions.handlers[db] = handler
return handler return handler
end end
--[[ --[[
the real options table the real options table
]] ]]
local optionsTable = { local optionsTable = {
desc = { desc = {
@@ -393,7 +386,6 @@ local optionsTable = {
order = 30, order = 30,
get = false, get = false,
set = "SetProfile", set = "SetProfile",
nullable = false, -- Ace3v: we do not want a null or empty value
}, },
choose = { choose = {
name = L["choose"], name = L["choose"],
@@ -403,7 +395,6 @@ local optionsTable = {
get = "GetCurrentProfile", get = "GetCurrentProfile",
set = "SetProfile", set = "SetProfile",
values = "ListProfiles", values = "ListProfiles",
valuesTableDestroyable = true,
arg = "common", arg = "common",
}, },
copydesc = { copydesc = {
@@ -419,7 +410,6 @@ local optionsTable = {
get = false, get = false,
set = "CopyProfile", set = "CopyProfile",
values = "ListProfiles", values = "ListProfiles",
valuesTableDestroyable = true,
disabled = "HasNoProfiles", disabled = "HasNoProfiles",
arg = "nocurrent", arg = "nocurrent",
}, },
@@ -436,7 +426,6 @@ local optionsTable = {
get = false, get = false,
set = "DeleteProfile", set = "DeleteProfile",
values = "ListProfiles", values = "ListProfiles",
valuesTableDestroyable = true,
disabled = "HasNoProfiles", disabled = "HasNoProfiles",
arg = "nocurrent", arg = "nocurrent",
confirm = true, confirm = true,
@@ -447,7 +436,7 @@ local optionsTable = {
--- Get/Create a option table that you can use in your addon to control the profiles of AceDB-3.0. --- Get/Create a option table that you can use in your addon to control the profiles of AceDB-3.0.
-- @param db The database object to create the options table for. -- @param db The database object to create the options table for.
-- @return The options table to be used in AceConfig-3.0 -- @return The options table to be used in AceConfig-3.0
-- @usage -- @usage
-- -- Assuming `options` is your top-level options table and `self.db` is your database: -- -- Assuming `options` is your top-level options table and `self.db` is your database:
-- options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) -- options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
function AceDBOptions:GetOptionsTable(db, noDefaultProfiles) function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
@@ -456,7 +445,7 @@ function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
name = L["profiles"], name = L["profiles"],
desc = L["profiles_sub"], desc = L["profiles_sub"],
} }
tbl.handler = getOptionsHandler(db, noDefaultProfiles) tbl.handler = getOptionsHandler(db, noDefaultProfiles)
tbl.args = optionsTable tbl.args = optionsTable
@@ -6,10 +6,6 @@ local Media = LibStub("LibSharedMedia-3.0")
local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0") local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
local next, ipairs, pairs = next, ipairs, pairs
local upper = string.upper
local tinsert, sort, tremove = table.insert, table.sort, table.remove
do do
local widgetType = "LSM30_Background" local widgetType = "LSM30_Background"
local widgetVersion = 11 local widgetVersion = 11
@@ -19,12 +15,12 @@ do
self:ClearAllPoints() self:ClearAllPoints()
self:Hide() self:Hide()
self.check:Hide() self.check:Hide()
tinsert(contentFrameCache, self) table.insert(contentFrameCache, self)
end end
local function ContentOnClick(this, button) local function ContentOnClick(this, button)
local self = this.obj local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText()) self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
@@ -40,12 +36,12 @@ do
local function GetContentLine() local function GetContentLine()
local frame local frame
if next(contentFrameCache) then if next(contentFrameCache) then
frame = tremove(contentFrameCache) frame = table.remove(contentFrameCache)
else else
frame = CreateFrame("Button", nil, UIParent) frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200) --frame:SetWidth(200)
frame:SetHeight(18) frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD") frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick) frame:SetScript("OnClick", ContentOnClick)
frame:SetScript("OnEnter", ContentOnEnter) frame:SetScript("OnEnter", ContentOnEnter)
@@ -144,7 +140,7 @@ do
end end
local function textSort(a,b) local function textSort(a,b)
return upper(a) < upper(b) return string.upper(a) < string.upper(b)
end end
local sortedlist = {} local sortedlist = {}
@@ -160,18 +156,19 @@ do
self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT") self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0) self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
for k, v in pairs(self.list) do for k, v in pairs(self.list) do
tinsert(sortedlist, k) sortedlist[#sortedlist+1] = k
end end
sort(sortedlist, textSort) table.sort(sortedlist, textSort)
for i, k in ipairs(sortedlist) do for i, k in ipairs(sortedlist) do
local f = GetContentLine() local f = GetContentLine()
f.text:SetText(k) f.text:SetText(k)
--print(k)
if k == self.value then if k == self.value then
f.check:Show() f.check:Show()
end end
f.obj = self f.obj = self
f.dropdown = self.dropdown f.dropdown = self.dropdown
self.dropdown:AddFrame(f, i) self.dropdown:AddFrame(f)
end end
wipe(sortedlist) wipe(sortedlist)
end end
@@ -6,10 +6,6 @@ local Media = LibStub("LibSharedMedia-3.0")
local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0") local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
local next, ipairs, pairs = next, ipairs, pairs
local upper = string.upper
local tinsert, sort, tremove = table.insert, table.sort, table.remove
do do
local widgetType = "LSM30_Border" local widgetType = "LSM30_Border"
local widgetVersion = 11 local widgetVersion = 11
@@ -19,12 +15,12 @@ do
self:ClearAllPoints() self:ClearAllPoints()
self:Hide() self:Hide()
self.check:Hide() self.check:Hide()
tinsert(contentFrameCache, self) table.insert(contentFrameCache, self)
end end
local function ContentOnClick(this, button) local function ContentOnClick(this, button)
local self = this.obj local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText()) self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
@@ -35,7 +31,7 @@ do
local text = this.text:GetText() local text = this.text:GetText()
local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text) local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text)
this.dropdown:SetBackdrop({edgeFile = border, this.dropdown:SetBackdrop({edgeFile = border,
bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark", bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
tile = true, tileSize = 16, edgeSize = 16, tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 }}) insets = { left = 4, right = 4, top = 4, bottom = 4 }})
end end
@@ -43,12 +39,12 @@ do
local function GetContentLine() local function GetContentLine()
local frame local frame
if next(contentFrameCache) then if next(contentFrameCache) then
frame = tremove(contentFrameCache) frame = table.remove(contentFrameCache)
else else
frame = CreateFrame("Button", nil, UIParent) frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200) --frame:SetWidth(200)
frame:SetHeight(18) frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD") frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick) frame:SetScript("OnClick", ContentOnClick)
frame:SetScript("OnEnter", ContentOnEnter) frame:SetScript("OnEnter", ContentOnEnter)
local check = frame:CreateTexture("OVERLAY") local check = frame:CreateTexture("OVERLAY")
@@ -110,7 +106,7 @@ do
local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text) local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text)
self.frame.displayButton:SetBackdrop({edgeFile = border, self.frame.displayButton:SetBackdrop({edgeFile = border,
bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark", bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
tile = true, tileSize = 16, edgeSize = 16, tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 }}) insets = { left = 4, right = 4, top = 4, bottom = 4 }})
end end
@@ -139,7 +135,7 @@ do
end end
local function textSort(a,b) local function textSort(a,b)
return upper(a) < upper(b) return string.upper(a) < string.upper(b)
end end
local sortedlist = {} local sortedlist = {}
@@ -155,18 +151,19 @@ do
self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT") self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0) self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
for k, v in pairs(self.list) do for k, v in pairs(self.list) do
tinsert(sortedlist, k) sortedlist[#sortedlist+1] = k
end end
sort(sortedlist, textSort) table.sort(sortedlist, textSort)
for i, k in ipairs(sortedlist) do for i, k in ipairs(sortedlist) do
local f = GetContentLine() local f = GetContentLine()
f.text:SetText(k) f.text:SetText(k)
--print(k)
if k == self.value then if k == self.value then
f.check:Show() f.check:Show()
end end
f.obj = self f.obj = self
f.dropdown = self.dropdown f.dropdown = self.dropdown
self.dropdown:AddFrame(f, i) self.dropdown:AddFrame(f)
end end
wipe(sortedlist) wipe(sortedlist)
end end
@@ -6,10 +6,6 @@ local Media = LibStub("LibSharedMedia-3.0")
local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0") local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
local next, ipairs, pairs = next, ipairs, pairs
local upper = string.upper
local tinsert, sort, tremove = table.insert, table.sort, table.remove
do do
local widgetType = "LSM30_Font" local widgetType = "LSM30_Font"
local widgetVersion = 11 local widgetVersion = 11
@@ -19,12 +15,12 @@ do
self:ClearAllPoints() self:ClearAllPoints()
self:Hide() self:Hide()
self.check:Hide() self.check:Hide()
tinsert(contentFrameCache, self) table.insert(contentFrameCache, self)
end end
local function ContentOnClick() local function ContentOnClick(this, button)
local self = this.obj local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText()) self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
@@ -33,12 +29,12 @@ do
local function GetContentLine() local function GetContentLine()
local frame local frame
if next(contentFrameCache) then if next(contentFrameCache) then
frame = tremove(contentFrameCache) frame = table.remove(contentFrameCache)
else else
frame = CreateFrame("Button", nil, UIParent) frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200) --frame:SetWidth(200)
frame:SetHeight(18) frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD") frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick) frame:SetScript("OnClick", ContentOnClick)
local check = frame:CreateTexture("OVERLAY") local check = frame:CreateTexture("OVERLAY")
check:SetWidth(16) check:SetWidth(16)
@@ -124,11 +120,11 @@ do
end end
local function textSort(a,b) local function textSort(a,b)
return upper(a) < upper(b) return string.upper(a) < string.upper(b)
end end
local sortedlist = {} local sortedlist = {}
local function ToggleDrop() local function ToggleDrop(this)
local self = this.obj local self = this.obj
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
@@ -140,9 +136,9 @@ do
self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT") self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0) self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
for k, v in pairs(self.list) do for k, v in pairs(self.list) do
tinsert(sortedlist, k) sortedlist[#sortedlist+1] = k
end end
sort(sortedlist, textSort) table.sort(sortedlist, textSort)
for i, k in ipairs(sortedlist) do for i, k in ipairs(sortedlist) do
local f = GetContentLine() local f = GetContentLine()
local _, size, outline= f.text:GetFont() local _, size, outline= f.text:GetFont()
@@ -153,7 +149,7 @@ do
f.check:Show() f.check:Show()
end end
f.obj = self f.obj = self
self.dropdown:AddFrame(f, i) self.dropdown:AddFrame(f)
end end
wipe(sortedlist) wipe(sortedlist)
end end
@@ -165,18 +161,18 @@ do
end end
end end
local function OnHide() local function OnHide(this)
local self = this.obj local self = this.obj
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
end end
local function Drop_OnEnter() local function Drop_OnEnter(this)
this.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Drop_OnLeave() local function Drop_OnLeave(this)
this.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
@@ -6,10 +6,6 @@ local Media = LibStub("LibSharedMedia-3.0")
local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0") local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
local next, ipairs, pairs = next, ipairs, pairs
local upper = string.upper
local tinsert, sort, tremove = table.insert, table.sort, table.remove
do do
local widgetType = "LSM30_Sound" local widgetType = "LSM30_Sound"
local widgetVersion = 11 local widgetVersion = 11
@@ -19,18 +15,18 @@ do
self:ClearAllPoints() self:ClearAllPoints()
self:Hide() self:Hide()
self.check:Hide() self.check:Hide()
tinsert(contentFrameCache, self) table.insert(contentFrameCache, self)
end end
local function ContentOnClick() local function ContentOnClick(this, button)
local self = this.obj local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText()) self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
end end
local function ContentSpeakerOnClick() local function ContentSpeakerOnClick(this, button)
local self = this.frame.obj local self = this.frame.obj
local sound = this.frame.text:GetText() local sound = this.frame.text:GetText()
PlaySoundFile(self.list[sound] ~= sound and self.list[sound] or Media:Fetch('sound',sound), "Master") PlaySoundFile(self.list[sound] ~= sound and self.list[sound] or Media:Fetch('sound',sound), "Master")
@@ -39,12 +35,12 @@ do
local function GetContentLine() local function GetContentLine()
local frame local frame
if next(contentFrameCache) then if next(contentFrameCache) then
frame = tremove(contentFrameCache) frame = table.remove(contentFrameCache)
else else
frame = CreateFrame("Button", nil, UIParent) frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200) --frame:SetWidth(200)
frame:SetHeight(18) frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD") frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick) frame:SetScript("OnClick", ContentOnClick)
local check = frame:CreateTexture("OVERLAY") local check = frame:CreateTexture("OVERLAY")
check:SetWidth(16) check:SetWidth(16)
@@ -149,11 +145,11 @@ do
end end
local function textSort(a,b) local function textSort(a,b)
return upper(a) < upper(b) return string.upper(a) < string.upper(b)
end end
local sortedlist = {} local sortedlist = {}
local function ToggleDrop() local function ToggleDrop(this)
local self = this.obj local self = this.obj
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
@@ -165,9 +161,9 @@ do
self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT") self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0) self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
for k, v in pairs(self.list) do for k, v in pairs(self.list) do
tinsert(sortedlist, k) sortedlist[#sortedlist+1] = k
end end
sort(sortedlist, textSort) table.sort(sortedlist, textSort)
for i, k in ipairs(sortedlist) do for i, k in ipairs(sortedlist) do
local f = GetContentLine() local f = GetContentLine()
f.text:SetText(k) f.text:SetText(k)
@@ -175,7 +171,7 @@ do
f.check:Show() f.check:Show()
end end
f.obj = self f.obj = self
self.dropdown:AddFrame(f, i) self.dropdown:AddFrame(f)
end end
wipe(sortedlist) wipe(sortedlist)
end end
@@ -187,22 +183,22 @@ do
end end
end end
local function OnHide() local function OnHide(this)
local self = this.obj local self = this.obj
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
end end
local function Drop_OnEnter() local function Drop_OnEnter(this)
this.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Drop_OnLeave() local function Drop_OnLeave(this)
this.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function WidgetPlaySound() local function WidgetPlaySound(this)
local self = this.obj local self = this.obj
local sound = self.frame.text:GetText() local sound = self.frame.text:GetText()
PlaySoundFile(self.list[sound] ~= sound and self.list[sound] or Media:Fetch('sound',sound), "Master") PlaySoundFile(self.list[sound] ~= sound and self.list[sound] or Media:Fetch('sound',sound), "Master")
@@ -6,10 +6,6 @@ local Media = LibStub("LibSharedMedia-3.0")
local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0") local AGSMW = LibStub("AceGUISharedMediaWidgets-1.0")
local next, ipairs, pairs = next, ipairs, pairs
local upper = string.upper
local tinsert, sort, tremove = table.insert, table.sort, table.remove
do do
local widgetType = "LSM30_Statusbar" local widgetType = "LSM30_Statusbar"
local widgetVersion = 11 local widgetVersion = 11
@@ -19,12 +15,12 @@ do
self:ClearAllPoints() self:ClearAllPoints()
self:Hide() self:Hide()
self.check:Hide() self.check:Hide()
tinsert(contentFrameCache, self) table.insert(contentFrameCache, self)
end end
local function ContentOnClick() local function ContentOnClick(this, button)
local self = this.obj local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText()) self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
@@ -33,12 +29,12 @@ do
local function GetContentLine() local function GetContentLine()
local frame local frame
if next(contentFrameCache) then if next(contentFrameCache) then
frame = tremove(contentFrameCache) frame = table.remove(contentFrameCache)
else else
frame = CreateFrame("Button", nil, UIParent) frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200) --frame:SetWidth(200)
frame:SetHeight(18) frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD") frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick) frame:SetScript("OnClick", ContentOnClick)
local check = frame:CreateTexture("OVERLAY") local check = frame:CreateTexture("OVERLAY")
check:SetWidth(16) check:SetWidth(16)
@@ -133,11 +129,11 @@ do
end end
local function textSort(a,b) local function textSort(a,b)
return upper(a) < upper(b) return string.upper(a) < string.upper(b)
end end
local sortedlist = {} local sortedlist = {}
local function ToggleDrop() local function ToggleDrop(this)
local self = this.obj local self = this.obj
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
@@ -149,12 +145,13 @@ do
self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT") self.dropdown:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT")
self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0) self.dropdown:SetPoint("TOPRIGHT", self.frame, "BOTTOMRIGHT", width < 160 and (160 - width) or 0, 0)
for k, v in pairs(self.list) do for k, v in pairs(self.list) do
tinsert(sortedlist, k) sortedlist[#sortedlist+1] = k
end end
sort(sortedlist, textSort) table.sort(sortedlist, textSort)
for i, k in ipairs(sortedlist) do for i, k in ipairs(sortedlist) do
local f = GetContentLine() local f = GetContentLine()
f.text:SetText(k) f.text:SetText(k)
--print(k)
if k == self.value then if k == self.value then
f.check:Show() f.check:Show()
end end
@@ -163,7 +160,7 @@ do
f.bar:SetTexture(statusbar) f.bar:SetTexture(statusbar)
f.obj = self f.obj = self
f.dropdown = self.dropdown f.dropdown = self.dropdown
self.dropdown:AddFrame(f, i) self.dropdown:AddFrame(f)
end end
wipe(sortedlist) wipe(sortedlist)
end end
@@ -175,18 +172,18 @@ do
end end
end end
local function OnHide() local function OnHide(this)
local self = this.obj local self = this.obj
if self.dropdown then if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown) self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end end
end end
local function Drop_OnEnter() local function Drop_OnEnter(this)
this.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Drop_OnLeave() local function Drop_OnLeave(this)
this.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
@@ -16,9 +16,6 @@ local Media = LibStub("LibSharedMedia-3.0")
AGSMW = AGSMW or {} AGSMW = AGSMW or {}
local next, ipairs = next, ipairs
local tinsert, tremove = table.insert, table.remove
AceGUIWidgetLSMlists = { AceGUIWidgetLSMlists = {
['font'] = Media:HashTable("font"), ['font'] = Media:HashTable("font"),
['sound'] = Media:HashTable("sound"), ['sound'] = Media:HashTable("sound"),
@@ -140,8 +137,8 @@ end
do do
local sliderBackdrop = { local sliderBackdrop = {
["bgFile"] = "Interface\\Buttons\\UI-SliderBar-Background", ["bgFile"] = [[Interface\Buttons\UI-SliderBar-Background]],
["edgeFile"] = "Interface\\Buttons\\UI-SliderBar-Border", ["edgeFile"] = [[Interface\Buttons\UI-SliderBar-Border]],
["tile"] = true, ["tile"] = true,
["edgeSize"] = 8, ["edgeSize"] = 8,
["tileSize"] = 8, ["tileSize"] = 8,
@@ -153,8 +150,8 @@ do
}, },
} }
local frameBackdrop = { local frameBackdrop = {
bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark", bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]],
tile = true, tileSize = 32, edgeSize = 32, tile = true, tileSize = 32, edgeSize = 32,
insets = { left = 11, right = 12, top = 12, bottom = 9 }, insets = { left = 11, right = 12, top = 12, bottom = 9 },
} }
@@ -163,36 +160,38 @@ do
self.slider:SetValue(self.slider:GetValue()+(15*dir*-1)) self.slider:SetValue(self.slider:GetValue()+(15*dir*-1))
end end
local function AddFrame(self, frame, i) local function AddFrame(self, frame)
frame:SetParent(self.contentframe) frame:SetParent(self.contentframe)
frame:SetFrameStrata(self:GetFrameStrata()) frame:SetFrameStrata(self:GetFrameStrata())
frame:SetFrameLevel(self:GetFrameLevel() + 100) frame:SetFrameLevel(self:GetFrameLevel() + 100)
if next(self.contentRepo) then if next(self.contentRepo) then
frame:SetPoint("TOPLEFT", self.contentRepo[i-1], "BOTTOMLEFT", 0, 0) frame:SetPoint("TOPLEFT", self.contentRepo[#self.contentRepo], "BOTTOMLEFT", 0, 0)
frame:SetPoint("RIGHT", self.contentframe, "RIGHT", 0, 0)
self.contentframe:SetHeight(self.contentframe:GetHeight() + frame:GetHeight()) self.contentframe:SetHeight(self.contentframe:GetHeight() + frame:GetHeight())
self.contentRepo[#self.contentRepo+1] = frame
else else
self.contentframe:SetHeight(frame:GetHeight()) self.contentframe:SetHeight(frame:GetHeight())
frame:SetPoint("TOPLEFT", self.contentframe, 0, 0) frame:SetPoint("TOPLEFT", self.contentframe, "TOPLEFT", 0, 0)
frame:SetPoint("RIGHT", self.contentframe, "RIGHT", 0, 0)
self.contentRepo[1] = frame
end end
self.contentRepo[i] = frame
if self.contentframe:GetHeight() > GetScreenHeight()*2/5 - 20 then if self.contentframe:GetHeight() > UIParent:GetHeight()*2/5 - 20 then
self.scrollframe:SetWidth(128) self.scrollframe:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -28, 12)
self:SetHeight(GetScreenHeight()*2/5) self:SetHeight(UIParent:GetHeight()*2/5)
self.slider:Show() self.slider:Show()
self:SetScript("OnMouseWheel", function() OnMouseWheel(this, arg1) end) self:SetScript("OnMouseWheel", OnMouseWheel)
self.scrollframe:UpdateScrollChildRect() self.scrollframe:UpdateScrollChildRect()
self.slider:SetMinMaxValues(0, self.contentframe:GetHeight()-self.scrollframe:GetHeight()) self.slider:SetMinMaxValues(0, self.contentframe:GetHeight()-self.scrollframe:GetHeight())
else else
self.scrollframe:SetWidth(142) self.scrollframe:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -14, 12)
self:SetHeight(self.contentframe:GetHeight()+25) self:SetHeight(self.contentframe:GetHeight()+25)
self.slider:Hide() self.slider:Hide()
self:SetScript("OnMouseWheel", nil) self:SetScript("OnMouseWheel", nil)
self.scrollframe:UpdateScrollChildRect() self.scrollframe:UpdateScrollChildRect()
self.slider:SetMinMaxValues(0, 0) self.slider:SetMinMaxValues(0, 0)
end end
frame:SetWidth(self.scrollframe:GetWidth())
self.contentframe:SetWidth(self.scrollframe:GetWidth()) self.contentframe:SetWidth(self.scrollframe:GetWidth())
end end
@@ -203,15 +202,15 @@ do
end end
end end
local function slider_OnValueChanged() local function slider_OnValueChanged(self, value)
this.frame.scrollframe:SetVerticalScroll(arg1) self.frame.scrollframe:SetVerticalScroll(value)
end end
local DropDownCache = {} local DropDownCache = {}
function AGSMW:GetDropDownFrame() function AGSMW:GetDropDownFrame()
local frame local frame
if next(DropDownCache) then if next(DropDownCache) then
frame = tremove(DropDownCache) frame = table.remove(DropDownCache)
else else
frame = CreateFrame("Frame", nil, UIParent) frame = CreateFrame("Frame", nil, UIParent)
frame:SetClampedToScreen(true) frame:SetClampedToScreen(true)
@@ -226,13 +225,14 @@ do
frame.contentframe = contentframe frame.contentframe = contentframe
local scrollframe = CreateFrame("ScrollFrame", nil, frame) local scrollframe = CreateFrame("ScrollFrame", nil, frame)
scrollframe:SetWidth(128) scrollframe:SetWidth(160)
scrollframe:SetHeight((GetScreenHeight()*2/5) - 24)
scrollframe:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -13) scrollframe:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -13)
scrollframe:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 12)
scrollframe:SetScrollChild(contentframe) scrollframe:SetScrollChild(contentframe)
frame.scrollframe = scrollframe frame.scrollframe = scrollframe
contentframe:SetPoint("TOPLEFT", scrollframe) contentframe:SetPoint("TOPLEFT", scrollframe)
contentframe:SetPoint("TOPRIGHT", scrollframe)
local bgTex = frame:CreateTexture(nil, "ARTWORK") local bgTex = frame:CreateTexture(nil, "ARTWORK")
bgTex:SetAllPoints(scrollframe) bgTex:SetAllPoints(scrollframe)
@@ -247,7 +247,7 @@ do
slider:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -14, -10) slider:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -14, -10)
slider:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 10) slider:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 10)
slider:SetBackdrop(sliderBackdrop) slider:SetBackdrop(sliderBackdrop)
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") slider:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
slider:SetMinMaxValues(0, 1) slider:SetMinMaxValues(0, 1)
--slider:SetValueStep(1) --slider:SetValueStep(1)
slider:SetWidth(12) slider:SetWidth(12)
@@ -255,7 +255,7 @@ do
slider:SetScript("OnValueChanged", slider_OnValueChanged) slider:SetScript("OnValueChanged", slider_OnValueChanged)
frame.slider = slider frame.slider = slider
end end
frame:SetHeight(GetScreenHeight()*2/5) frame:SetHeight(UIParent:GetHeight()*2/5)
frame.slider:SetValue(0) frame.slider:SetValue(0)
frame:Show() frame:Show()
return frame return frame
@@ -267,7 +267,7 @@ do
frame:Hide() frame:Hide()
frame:SetBackdrop(frameBackdrop) frame:SetBackdrop(frameBackdrop)
frame.bgTex:SetTexture(nil) frame.bgTex:SetTexture(nil)
tinsert(DropDownCache, frame) table.insert(DropDownCache, frame)
return nil return nil
end end
end end
+108 -84
View File
@@ -30,17 +30,12 @@ local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
if not AceGUI then return end -- No upgrade needed if not AceGUI then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local hooksecurefunc = AceCore.hooksecurefunc
local safecall = AceCore.safecall
-- Lua APIs -- Lua APIs
local tconcat, tremove, tinsert, tgetn, tsetn = table.concat, table.remove, table.insert, table.getn, table.setn local tconcat, tremove, tinsert = table.concat, table.remove, table.insert
local pairs, next, type = pairs, next, type local select, pairs, next, type = select, pairs, next, type
local error, assert, loadstring = error, assert, loadstring local error, assert, loadstring = error, assert, loadstring
local setmetatable, rawget, rawset = setmetatable, rawget, rawset local setmetatable, rawget, rawset = setmetatable, rawget, rawset
local math_max = math.max local math_max = math.max
local strupper, strfmt = string.upper, string.format
-- WoW APIs -- WoW APIs
local UIParent = UIParent local UIParent = UIParent
@@ -56,17 +51,74 @@ AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
AceGUI.WidgetBase = AceGUI.WidgetBase or {} AceGUI.WidgetBase = AceGUI.WidgetBase or {}
AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {} AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
AceGUI.WidgetVersions = AceGUI.WidgetVersions or {} AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
AceGUI.HookedFunctions = AceGUI.HookedFunctions or {}
-- local upvalues -- local upvalues
local WidgetRegistry = AceGUI.WidgetRegistry local WidgetRegistry = AceGUI.WidgetRegistry
local LayoutRegistry = AceGUI.LayoutRegistry local LayoutRegistry = AceGUI.LayoutRegistry
local WidgetVersions = AceGUI.WidgetVersions local WidgetVersions = AceGUI.WidgetVersions
local HookedFunctions = AceGUI.HookedFunctions
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = ...
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = ...
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = code:gsub("ARGS", tconcat(ARGS, ", "))
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
end
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
local dispatcher = CreateDispatcher(argCount)
rawset(self, argCount, dispatcher)
return dispatcher
end})
Dispatchers[0] = function(func)
return xpcall(func, errorhandler)
end
local function safecall(func, ...)
return Dispatchers[select("#", ...)](func, ...)
end
-- Recycling functions -- Recycling functions
local newWidget, delWidget local newWidget, delWidget
do do
-- Version Upgrade in Minor 29
-- Internal Storage of the objects changed, from an array table
-- to a hash table, and additionally we introduced versioning on
-- the widgets which would discard all widgets from a pre-29 version
-- anyway, so we just clear the storage now, and don't try to
-- convert the storage tables to the new format.
-- This should generally not cause *many* widgets to end up in trash,
-- since once dialogs are opened, all addons should be loaded already
-- and AceGUI should be on the latest version available on the users
-- setup.
-- -- nevcairiel - Nov 2nd, 2009
if oldminor and oldminor < 29 and AceGUI.objPools then
AceGUI.objPools = nil
end
AceGUI.objPools = AceGUI.objPools or {} AceGUI.objPools = AceGUI.objPools or {}
local objPools = AceGUI.objPools local objPools = AceGUI.objPools
--Returns a new instance, if none are available either returns a new table or calls the given contructor --Returns a new instance, if none are available either returns a new table or calls the given contructor
@@ -105,16 +157,7 @@ do
end end
end end
local function fixlevels(parent,...)
local i = 1
local child = arg[i]
while child do
child:SetFrameLevel(parent:GetFrameLevel() + (parent.backdrop and -1 or 2))
fixlevels(child, child:GetChildren())
i = i + 1
child = arg[i]
end
end
------------------- -------------------
-- API Functions -- -- API Functions --
------------------- -------------------
@@ -130,15 +173,27 @@ function AceGUI:Create(type)
if WidgetRegistry[type] then if WidgetRegistry[type] then
local widget = newWidget(type) local widget = newWidget(type)
if rawget(widget, "Acquire") then
widget.OnAcquire = widget.Acquire
widget.Acquire = nil
elseif rawget(widget, "Aquire") then
widget.OnAcquire = widget.Aquire
widget.Aquire = nil
end
if rawget(widget, "Release") then
widget.OnRelease = rawget(widget, "Release")
widget.Release = nil
end
if widget.OnAcquire then if widget.OnAcquire then
widget:OnAcquire() widget:OnAcquire()
else else
error(strfmt("Widget type %s doesn't supply an OnAcquire Function", type)) error(("Widget type %s doesn't supply an OnAcquire Function"):format(type))
end end
-- Set the default Layout ("List") -- Set the default Layout ("List")
safecall(widget.SetLayout, 2, widget, "List") safecall(widget.SetLayout, widget, "List")
safecall(widget.ResumeLayout, 1, widget) safecall(widget.ResumeLayout, widget)
return widget return widget
end end
end end
@@ -149,14 +204,14 @@ end
-- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well. -- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
-- @param widget The widget to release -- @param widget The widget to release
function AceGUI:Release(widget) function AceGUI:Release(widget)
safecall(widget.PauseLayout, 1, widget) safecall(widget.PauseLayout, widget)
widget:Fire("OnRelease") widget:Fire("OnRelease")
safecall(widget.ReleaseChildren, 1, widget) safecall(widget.ReleaseChildren, widget)
if widget.OnRelease then if widget.OnRelease then
widget:OnRelease() widget:OnRelease()
-- else -- else
-- error(strfmt("Widget type %s doesn't supply an OnRelease Function", widget.type)) -- error(("Widget type %s doesn't supply an OnRelease Function"):format(widget.type))
end end
for k in pairs(widget.userdata) do for k in pairs(widget.userdata) do
widget.userdata[k] = nil widget.userdata[k] = nil
@@ -191,7 +246,7 @@ end
-- @param widget The widget that should be focused -- @param widget The widget that should be focused
function AceGUI:SetFocus(widget) function AceGUI:SetFocus(widget)
if self.FocusedWidget and self.FocusedWidget ~= widget then if self.FocusedWidget and self.FocusedWidget ~= widget then
safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget) safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
end end
self.FocusedWidget = widget self.FocusedWidget = widget
end end
@@ -201,7 +256,7 @@ end
-- e.g. titlebar of a frame being clicked -- e.g. titlebar of a frame being clicked
function AceGUI:ClearFocus() function AceGUI:ClearFocus()
if self.FocusedWidget then if self.FocusedWidget then
safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget) safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
self.FocusedWidget = nil self.FocusedWidget = nil
end end
end end
@@ -246,7 +301,6 @@ do
frame:SetParent(nil) frame:SetParent(nil)
frame:SetParent(parent.content) frame:SetParent(parent.content)
self.parent = parent self.parent = parent
fixlevels(frame, frame:GetChildren())
end end
WidgetBase.SetCallback = function(self, name, func) WidgetBase.SetCallback = function(self, name, func)
@@ -255,11 +309,9 @@ do
end end
end end
WidgetBase.Fire = function(self, name, argc, ...) WidgetBase.Fire = function(self, name, ...)
argc = arg.n if self.events[name] then
local func = self.events[name] local success, ret = safecall(self.events[name], self, name, ...)
if func then
local success, ret = safecall(func, argc+3, self, name, argc, unpack(arg))
if success then if success then
return ret return ret
end end
@@ -310,8 +362,8 @@ do
AceGUI:Release(self) AceGUI:Release(self)
end end
WidgetBase.SetPoint = function(self, a1,a2,a3,a4,a5) WidgetBase.SetPoint = function(self, ...)
return self.frame:SetPoint(a1,a2,a3,a4,a5) return self.frame:SetPoint(...)
end end
WidgetBase.ClearAllPoints = function(self) WidgetBase.ClearAllPoints = function(self)
@@ -322,8 +374,8 @@ do
return self.frame:GetNumPoints() return self.frame:GetNumPoints()
end end
WidgetBase.GetPoint = function(self, a1,a2,a3,a4,a5) WidgetBase.GetPoint = function(self, ...)
return self.frame:GetPoint(a1,a2,a3,a4,a5) return self.frame:GetPoint(...)
end end
WidgetBase.GetUserDataTable = function(self) WidgetBase.GetUserDataTable = function(self)
@@ -381,7 +433,7 @@ do
if self.LayoutPaused then if self.LayoutPaused then
return return
end end
safecall(self.LayoutFunc, 2, self.content, self.children) safecall(self.LayoutFunc, self.content, self.children)
end end
--call this function to layout, makes sure layed out objects get a frame to get sizes etc --call this function to layout, makes sure layed out objects get a frame to get sizes etc
@@ -410,51 +462,24 @@ do
self:DoLayout() self:DoLayout()
end end
do WidgetContainerBase.AddChildren = function(self, ...)
local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil} for i = 1, select("#", ...) do
WidgetContainerBase.AddChildren = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) local child = select(i, ...)
args[1] = a1
args[2] = a2
args[3] = a3
args[4] = a4
args[5] = a5
args[6] = a6
args[7] = a7
args[8] = a8
args[9] = a9
args[10] = a10
for i = 1,10 do
local child = args[i]
arg[i] = nil
if not child then break end
tinsert(self.children, child) tinsert(self.children, child)
child:SetParent(self) child:SetParent(self)
child.frame:Show() child.frame:Show()
end end
self:DoLayout() self:DoLayout()
end end
end -- WidgetContainerBase.AddChildren
WidgetContainerBase.ReleaseChildren = function(self) WidgetContainerBase.ReleaseChildren = function(self)
local children = self.children local children = self.children
for i = 1,tgetn(children) do for i = 1,#children do
AceGUI:Release(tremove(children)) AceGUI:Release(children[i])
children[i] = nil
end end
end end
--[[WidgetContainerBase.SetParent = function(self, parent)
--WidgetBase.SetParent(self, parent)
local lv = self.frame:GetFrameLevel()
self.content:SetFrameLevel(lv+1)
local children = self.children
for i = 1,tgetn(children) do
local child = children[i]
child:SetParent(self)
end
end]]
WidgetContainerBase.SetLayout = function(self, Layout) WidgetContainerBase.SetLayout = function(self, Layout)
self.LayoutFunc = AceGUI:GetLayout(Layout) self.LayoutFunc = AceGUI:GetLayout(Layout)
end end
@@ -467,7 +492,7 @@ do
end end
end end
local function FrameResize() local function FrameResize(this)
local self = this.obj local self = this.obj
if this:GetWidth() and this:GetHeight() then if this:GetWidth() and this:GetHeight() then
if self.OnWidthSet then if self.OnWidthSet then
@@ -479,7 +504,7 @@ do
end end
end end
local function ContentResize() local function ContentResize(this)
if this:GetWidth() and this:GetHeight() then if this:GetWidth() and this:GetHeight() then
this.width = this:GetWidth() this.width = this:GetWidth()
this.height = this:GetHeight() this.height = this:GetHeight()
@@ -548,7 +573,7 @@ end
function AceGUI:RegisterLayout(Name, LayoutFunc) function AceGUI:RegisterLayout(Name, LayoutFunc)
assert(type(LayoutFunc) == "function") assert(type(LayoutFunc) == "function")
if type(Name) == "string" then if type(Name) == "string" then
Name = string.upper(Name) Name = Name:upper()
end end
LayoutRegistry[Name] = LayoutFunc LayoutRegistry[Name] = LayoutFunc
end end
@@ -557,7 +582,7 @@ end
-- @param Name The name of the layout -- @param Name The name of the layout
function AceGUI:GetLayout(Name) function AceGUI:GetLayout(Name)
if type(Name) == "string" then if type(Name) == "string" then
Name = strupper(Name) Name = Name:upper()
end end
return LayoutRegistry[Name] return LayoutRegistry[Name]
end end
@@ -604,7 +629,7 @@ AceGUI:RegisterLayout("List",
function(content, children) function(content, children)
local height = 0 local height = 0
local width = content.width or content:GetWidth() or 0 local width = content.width or content:GetWidth() or 0
for i = 1, tgetn(children) do for i = 1, #children do
local child = children[i] local child = children[i]
local frame = child.frame local frame = child.frame
@@ -633,7 +658,7 @@ AceGUI:RegisterLayout("List",
height = height + (frame.height or frame:GetHeight() or 0) height = height + (frame.height or frame:GetHeight() or 0)
end end
safecall(content.obj.LayoutFinished, 3, content.obj, nil, height) safecall(content.obj.LayoutFinished, content.obj, nil, height)
end) end)
-- A single control fills the whole content area -- A single control fills the whole content area
@@ -644,15 +669,14 @@ AceGUI:RegisterLayout("Fill",
children[1]:SetHeight(content:GetHeight() or 0) children[1]:SetHeight(content:GetHeight() or 0)
children[1].frame:SetAllPoints(content) children[1].frame:SetAllPoints(content)
children[1].frame:Show() children[1].frame:Show()
safecall(content.obj.LayoutFinished, 3, content.obj, nil, children[1].frame:GetHeight()) safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight())
end end
end) end)
-- Ace3v: currently only a1 used
local layoutrecursionblock = nil local layoutrecursionblock = nil
local function safelayoutcall(object, func, a1) local function safelayoutcall(object, func, ...)
layoutrecursionblock = true layoutrecursionblock = true
object[func](object, a1) object[func](object, ...)
layoutrecursionblock = nil layoutrecursionblock = nil
end end
@@ -679,7 +703,7 @@ AceGUI:RegisterLayout("Flow",
local frameoffset local frameoffset
local lastframeoffset local lastframeoffset
local oversize local oversize
for i = 1, tgetn(children) do for i = 1, #children do
local child = children[i] local child = children[i]
oversize = nil oversize = nil
local frame = child.frame local frame = child.frame
@@ -785,5 +809,5 @@ AceGUI:RegisterLayout("Flow",
end end
height = height + rowheight + 3 height = height + rowheight + 3
safecall(content.obj.LayoutFinished, 3, content.obj, nil, height) safecall(content.obj.LayoutFinished, content.obj, nil, height)
end) end)
@@ -1,4 +1,29 @@
<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/ <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"> ..\FrameXML\UI.xsd">
<Script file="AceGUI-3.0.lua"/> <Script file="AceGUI-3.0.lua"/>
<!-- Container -->
<Script file="widgets\AceGUIContainer-BlizOptionsGroup.lua"/>
<Script file="widgets\AceGUIContainer-DropDownGroup.lua"/>
<Script file="widgets\AceGUIContainer-Frame.lua"/>
<Script file="widgets\AceGUIContainer-InlineGroup.lua"/>
<Script file="widgets\AceGUIContainer-ScrollFrame.lua"/>
<Script file="widgets\AceGUIContainer-SimpleGroup.lua"/>
<Script file="widgets\AceGUIContainer-TabGroup.lua"/>
<Script file="widgets\AceGUIContainer-TreeGroup.lua"/>
<Script file="widgets\AceGUIContainer-Window.lua"/>
<!-- Widgets -->
<Script file="widgets\AceGUIWidget-Button.lua"/>
<Script file="widgets\AceGUIWidget-Button-ElvUI.lua"/>
<Script file="widgets\AceGUIWidget-CheckBox.lua"/>
<Script file="widgets\AceGUIWidget-ColorPicker.lua"/>
<Script file="widgets\AceGUIWidget-DropDown.lua"/>
<Script file="widgets\AceGUIWidget-DropDown-Items.lua"/>
<Script file="widgets\AceGUIWidget-EditBox.lua"/>
<Script file="widgets\AceGUIWidget-Heading.lua"/>
<Script file="widgets\AceGUIWidget-Icon.lua"/>
<Script file="widgets\AceGUIWidget-InteractiveLabel.lua"/>
<Script file="widgets\AceGUIWidget-Keybinding.lua"/>
<Script file="widgets\AceGUIWidget-Label.lua"/>
<Script file="widgets\AceGUIWidget-MultiLineEditBox.lua"/>
<Script file="widgets\AceGUIWidget-Slider.lua"/>
</Ui> </Ui>
@@ -15,11 +15,11 @@ local CreateFrame = CreateFrame
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function SelectedGroup(self, event, _, value) local function SelectedGroup(self, event, value)
local group = self.parentgroup local group = self.parentgroup
local status = group.status or group.localstatus local status = group.status or group.localstatus
status.selected = value status.selected = value
self.parentgroup:Fire("OnGroupSelected", 1, value) self.parentgroup:Fire("OnGroupSelected", value)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -63,7 +63,7 @@ local methods = {
self.dropdown:SetValue(group) self.dropdown:SetValue(group)
local status = self.status or self.localstatus local status = self.status or self.localstatus
status.selected = group status.selected = group
self:Fire("OnGroupSelected", 1, group) self:Fire("OnGroupSelected", group)
end, end,
["OnWidthSet"] = function(self, width) ["OnWidthSet"] = function(self, width)
@@ -1,15 +1,13 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Frame Container Frame Container
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Frame", 24 local Type, Version = "Frame", 25
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local wipe = AceCore.wipe
-- Lua APIs -- Lua APIs
local pairs, assert, type = pairs, assert, type local pairs, assert, type = pairs, assert, type
local wipe = table.wipe
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
@@ -22,26 +20,30 @@ local CreateFrame, UIParent = CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Button_OnClick() local function Button_OnClick(frame)
PlaySound("gsTitleOptionExit") PlaySound("gsTitleOptionExit")
this.obj:Hide() frame.obj:Hide()
end end
local function Frame_OnClose() local function Frame_OnShow(frame)
this.obj:Fire("OnClose") frame.obj:Fire("OnShow")
end end
local function Frame_OnMouseDown() local function Frame_OnClose(frame)
frame.obj:Fire("OnClose")
end
local function Frame_OnMouseDown(frame)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function Title_OnMouseDown() local function Title_OnMouseDown(frame)
this:GetParent():StartMoving() frame:GetParent():StartMoving()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function MoverSizer_OnMouseUp() local function MoverSizer_OnMouseUp(mover)
local frame = this:GetParent() local frame = mover:GetParent()
frame:StopMovingOrSizing() frame:StopMovingOrSizing()
local self = frame.obj local self = frame.obj
local status = self.status or self.localstatus local status = self.status or self.localstatus
@@ -51,27 +53,27 @@ local function MoverSizer_OnMouseUp()
status.left = frame:GetLeft() status.left = frame:GetLeft()
end end
local function SizerSE_OnMouseDown() local function SizerSE_OnMouseDown(frame)
this:GetParent():StartSizing("BOTTOMRIGHT") frame:GetParent():StartSizing("BOTTOMRIGHT")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function SizerS_OnMouseDown() local function SizerS_OnMouseDown(frame)
this:GetParent():StartSizing("BOTTOM") frame:GetParent():StartSizing("BOTTOM")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function SizerE_OnMouseDown() local function SizerE_OnMouseDown(frame)
this:GetParent():StartSizing("RIGHT") frame:GetParent():StartSizing("RIGHT")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function StatusBar_OnEnter() local function StatusBar_OnEnter(frame)
this.obj:Fire("OnEnterStatusBar") frame.obj:Fire("OnEnterStatusBar")
end end
local function StatusBar_OnLeave() local function StatusBar_OnLeave(frame)
this.obj:Fire("OnLeaveStatusBar") frame.obj:Fire("OnLeaveStatusBar")
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -85,7 +87,7 @@ local methods = {
self:SetStatusText() self:SetStatusText()
self:ApplyStatus() self:ApplyStatus()
self:Show() self:Show()
self:EnableResize(true) self:EnableResize(true)
end, end,
["OnRelease"] = function(self) ["OnRelease"] = function(self)
@@ -105,7 +107,7 @@ local methods = {
["OnHeightSet"] = function(self, height) ["OnHeightSet"] = function(self, height)
local content = self.content local content = self.content
local contentheight = height - 67 local contentheight = height - 57
if contentheight < 0 then if contentheight < 0 then
contentheight = 0 contentheight = 0
end end
@@ -154,7 +156,7 @@ local methods = {
frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top) frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0) frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
else else
frame:SetPoint("CENTER", UIParent) frame:SetPoint("CENTER")
end end
end end
} }
@@ -188,6 +190,7 @@ local function Constructor()
frame:SetBackdropColor(0, 0, 0, 1) frame:SetBackdropColor(0, 0, 0, 1)
frame:SetMinResize(400, 200) frame:SetMinResize(400, 200)
frame:SetToplevel(true) frame:SetToplevel(true)
frame:SetScript("OnShow", Frame_OnShow)
frame:SetScript("OnHide", Frame_OnClose) frame:SetScript("OnHide", Frame_OnClose)
frame:SetScript("OnMouseDown", Frame_OnMouseDown) frame:SetScript("OnMouseDown", Frame_OnMouseDown)
@@ -245,9 +248,8 @@ local function Constructor()
titlebg_r:SetWidth(30) titlebg_r:SetWidth(30)
titlebg_r:SetHeight(40) titlebg_r:SetHeight(40)
-- bottom right sizer
local sizer_se = CreateFrame("Frame", nil, frame) local sizer_se = CreateFrame("Frame", nil, frame)
sizer_se:SetPoint("BOTTOMRIGHT", 0, 0) sizer_se:SetPoint("BOTTOMRIGHT")
sizer_se:SetWidth(25) sizer_se:SetWidth(25)
sizer_se:SetHeight(25) sizer_se:SetHeight(25)
sizer_se:EnableMouse() sizer_se:EnableMouse()
@@ -255,13 +257,24 @@ local function Constructor()
sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp) sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
local line1 = sizer_se:CreateTexture(nil, "BACKGROUND") local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
line1:SetPoint("BOTTOMRIGHT", -10, 10) line1:SetWidth(14)
line1:SetTexture("Interface\\Cursor\\Item") line1:SetHeight(14)
line1:SetTexCoord(1, 0, 1, 0) line1:SetPoint("BOTTOMRIGHT", -8, 8)
line1:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
local x = 0.1 * 14/17
line1:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
local line2 = sizer_se:CreateTexture(nil, "BACKGROUND")
line2:SetWidth(8)
line2:SetHeight(8)
line2:SetPoint("BOTTOMRIGHT", -8, 8)
line2:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
local x = 0.1 * 8/17
line2:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
local sizer_s = CreateFrame("Frame", nil, frame) local sizer_s = CreateFrame("Frame", nil, frame)
sizer_s:SetPoint("BOTTOMRIGHT", -25, 0) sizer_s:SetPoint("BOTTOMRIGHT", -25, 0)
sizer_s:SetPoint("BOTTOMLEFT", 0, 0) sizer_s:SetPoint("BOTTOMLEFT")
sizer_s:SetHeight(25) sizer_s:SetHeight(25)
sizer_s:EnableMouse(true) sizer_s:EnableMouse(true)
sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown) sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown)
@@ -269,7 +282,7 @@ local function Constructor()
local sizer_e = CreateFrame("Frame", nil, frame) local sizer_e = CreateFrame("Frame", nil, frame)
sizer_e:SetPoint("BOTTOMRIGHT", 0, 25) sizer_e:SetPoint("BOTTOMRIGHT", 0, 25)
sizer_e:SetPoint("TOPRIGHT", 0, 0) sizer_e:SetPoint("TOPRIGHT")
sizer_e:SetWidth(25) sizer_e:SetWidth(25)
sizer_e:EnableMouse(true) sizer_e:EnableMouse(true)
sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown) sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown)
@@ -278,7 +291,7 @@ local function Constructor()
--Container Support --Container Support
local content = CreateFrame("Frame", nil, frame) local content = CreateFrame("Frame", nil, frame)
content:SetPoint("TOPLEFT", 17, -27) content:SetPoint("TOPLEFT", 17, -27)
--content:SetPoint("BOTTOMRIGHT", -17, 40) content:SetPoint("BOTTOMRIGHT", -17, 40)
local widget = { local widget = {
localstatus = {}, localstatus = {},
@@ -2,14 +2,13 @@
ScrollFrame Container ScrollFrame Container
Plain container that scrolls its content and doesn't grow in height. Plain container that scrolls its content and doesn't grow in height.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "ScrollFrame", 24 local Type, Version = "ScrollFrame", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local pairs, assert, type = pairs, assert, type local pairs, assert, type = pairs, assert, type
local min, max, floor, abs = math.min, math.max, math.floor, math.abs local min, max, floor, abs = math.min, math.max, math.floor, math.abs
local format = string.format
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -17,24 +16,24 @@ local CreateFrame, UIParent = CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Support functions Support functions
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function FixScrollOnUpdate() local function FixScrollOnUpdate(frame)
this:SetScript("OnUpdate", nil) frame:SetScript("OnUpdate", nil)
this.obj:FixScroll() frame.obj:FixScroll()
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function ScrollFrame_OnMouseWheel() local function ScrollFrame_OnMouseWheel(frame, value)
this.obj:MoveScroll(arg1) frame.obj:MoveScroll(value)
end end
local function ScrollFrame_OnSizeChanged() local function ScrollFrame_OnSizeChanged(frame)
this:SetScript("OnUpdate", FixScrollOnUpdate) frame:SetScript("OnUpdate", FixScrollOnUpdate)
end end
local function ScrollBar_OnScrollValueChanged() local function ScrollBar_OnScrollValueChanged(frame, value)
this.obj:SetScroll(arg1) frame.obj:SetScroll(value)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -51,7 +50,7 @@ local methods = {
for k in pairs(self.localstatus) do for k in pairs(self.localstatus) do
self.localstatus[k] = nil self.localstatus[k] = nil
end end
self.scrollframe:SetPoint("BOTTOMRIGHT",0,0) self.scrollframe:SetPoint("BOTTOMRIGHT")
self.scrollbar:Hide() self.scrollbar:Hide()
self.scrollBarShown = nil self.scrollBarShown = nil
self.content.height, self.content.width = nil, nil self.content.height, self.content.width = nil, nil
@@ -90,46 +89,40 @@ local methods = {
end, end,
["FixScroll"] = function(self) ["FixScroll"] = function(self)
if self.updateLock then return end if self.updateLock then return end
self.updateLock = true self.updateLock = true
local status = self.status or self.localstatus local status = self.status or self.localstatus
local scrollframe, content, scrollbar = self.scrollframe, self.content, self.scrollbar local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
local viewheight, height = self.scrollframe:GetHeight(), self.content:GetHeight()
local offset = status.offset or 0 local offset = status.offset or 0
local curvalue = scrollbar:GetValue() local curvalue = self.scrollbar:GetValue()
-- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys -- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
-- No-one is going to miss 2 pixels at the bottom of the frame, anyhow! -- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
if viewheight < height + 2 then
if height < viewheight + 2 then
if self.scrollBarShown then if self.scrollBarShown then
self.scrollBarShown = nil self.scrollBarShown = nil
scrollbar:Hide() self.scrollbar:Hide()
scrollbar:SetValue(0) self.scrollbar:SetValue(0)
scrollframe:SetPoint("BOTTOMRIGHT",0,0) self.scrollframe:SetPoint("BOTTOMRIGHT")
self:DoLayout() self:DoLayout()
end end
offset = 0
else else
if not self.scrollBarShown then if not self.scrollBarShown then
self.scrollBarShown = true self.scrollBarShown = true
scrollbar:Show() self.scrollbar:Show()
scrollframe:SetPoint("BOTTOMRIGHT", -20, 0) self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
self:DoLayout() self:DoLayout()
end end
local value = (offset / (height - viewheight) * 1000) local value = (offset / (viewheight - height) * 1000)
if value > 1000 then if value > 1000 then value = 1000 end
value = 1000 self.scrollbar:SetValue(value)
offset = height - viewheight
end
scrollbar:SetValue(value)
self:SetScroll(value) self:SetScroll(value)
if value < 1000 then
self.content:ClearAllPoints()
self.content:SetPoint("TOPLEFT", 0, offset)
self.content:SetPoint("TOPRIGHT", 0, offset)
status.offset = offset
end
end end
status.offset = offset
scrollframe:SetScrollChild(content)
content:ClearAllPoints()
content:SetPoint("TOPLEFT", 0, offset)
content:SetPoint("TOPRIGHT", 0, offset)
self.updateLock = nil self.updateLock = nil
end, end,
@@ -148,7 +141,6 @@ local methods = {
["OnWidthSet"] = function(self, width) ["OnWidthSet"] = function(self, width)
local content = self.content local content = self.content
content:SetWidth(width)
content.width = width content.width = width
end, end,
@@ -165,13 +157,13 @@ local function Constructor()
local num = AceGUI:GetNextWidgetNum(Type) local num = AceGUI:GetNextWidgetNum(Type)
local scrollframe = CreateFrame("ScrollFrame", nil, frame) local scrollframe = CreateFrame("ScrollFrame", nil, frame)
scrollframe:SetPoint("TOPLEFT",0,0) scrollframe:SetPoint("TOPLEFT")
scrollframe:SetPoint("BOTTOMRIGHT",0,0) scrollframe:SetPoint("BOTTOMRIGHT")
scrollframe:EnableMouseWheel(true) scrollframe:EnableMouseWheel(true)
scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel) scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
-- scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged) scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
local scrollbar = CreateFrame("Slider", format("AceConfigDialogScrollFrame%dScrollBar", num), scrollframe, "UIPanelScrollBarTemplate") local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate")
scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16) scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16) scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
scrollbar:SetMinMaxValues(0, 1000) scrollbar:SetMinMaxValues(0, 1000)
@@ -188,8 +180,8 @@ local function Constructor()
--Container Support --Container Support
local content = CreateFrame("Frame", nil, scrollframe) local content = CreateFrame("Frame", nil, scrollframe)
content:SetPoint("TOPLEFT",0,0) content:SetPoint("TOPLEFT")
content:SetPoint("TOPRIGHT",0,0) content:SetPoint("TOPRIGHT")
content:SetHeight(400) content:SetHeight(400)
scrollframe:SetScrollChild(content) scrollframe:SetScrollChild(content)
@@ -2,14 +2,12 @@
TabGroup Container TabGroup Container
Container that uses tabs on top to switch between groups. Container that uses tabs on top to switch between groups.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "TabGroup-ElvUI", 31 local Type, Version = "TabGroup", 31
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe
local getn = table.getn
local format = string.format
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
@@ -54,34 +52,34 @@ local function Tab_SetDisabled(frame, disabled)
UpdateTabLook(frame) UpdateTabLook(frame)
end end
local function BuildTabsOnUpdate() local function BuildTabsOnUpdate(frame)
local self = this.obj local self = frame.obj
self:BuildTabs() self:BuildTabs()
this:SetScript("OnUpdate", nil) frame:SetScript("OnUpdate", nil)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Tab_OnClick() local function Tab_OnClick(frame)
if not (this.selected or this.disabled) then if not (frame.selected or frame.disabled) then
PlaySound("igCharacterInfoTab") PlaySound("igCharacterInfoTab")
this.obj:SelectTab(this.value) frame.obj:SelectTab(frame.value)
end end
end end
local function Tab_OnEnter() local function Tab_OnEnter(frame)
local self = this.obj local self = frame.obj
self:Fire("OnTabEnter", 2, self.tabs[this.id].value, this) self:Fire("OnTabEnter", self.tabs[frame.id].value, frame)
end end
local function Tab_OnLeave() local function Tab_OnLeave(frame)
local self = this.obj local self = frame.obj
self:Fire("OnTabLeave", 2, self.tabs[this.id].value, this) self:Fire("OnTabLeave", self.tabs[frame.id].value, frame)
end end
local function Tab_OnShow() local function Tab_OnShow(frame)
_G[this:GetName().."HighlightTexture"]:SetWidth(this:GetTextWidth() + 30) _G[frame:GetName().."HighlightTexture"]:SetWidth(frame:GetTextWidth() + 30)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -104,11 +102,10 @@ local methods = {
end, end,
["CreateTab"] = function(self, id) ["CreateTab"] = function(self, id)
local tabname = format("AceGUITabGroup%dTab%d", self.num, id) local tabname = ("AceGUITabGroup%dTab%d"):format(self.num, id)
local tab = CreateFrame("Button", tabname, self.border, "TabButtonTemplate") local tab = CreateFrame("Button", tabname, self.border, "OptionsFrameTabButtonTemplate")
tab.obj = self tab.obj = self
tab.id = id tab.id = id
tab:SetHeight(24)
tab.text = _G[tabname .. "Text"] tab.text = _G[tabname .. "Text"]
tab.text:ClearAllPoints() tab.text:ClearAllPoints()
@@ -156,7 +153,7 @@ local methods = {
end end
status.selected = value status.selected = value
if found then if found then
self:Fire("OnGroupSelected",1,value) self:Fire("OnGroupSelected",value)
end end
end, end,
@@ -196,16 +193,16 @@ local methods = {
widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text
end end
local numtabs = getn(tablist) for i = (#tablist)+1, #tabs, 1 do
for i = numtabs+1, numtabs, 1 do
tabs[i]:Hide() tabs[i]:Hide()
end end
--First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout --First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout
local numtabs = #tablist
local numrows = 1 local numrows = 1
local usedwidth = 0 local usedwidth = 0
for i = 1, numtabs do for i = 1, #tablist do
--If this is not the first tab of a row and there isn't room for it --If this is not the first tab of a row and there isn't room for it
if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
@@ -216,7 +213,7 @@ local methods = {
usedwidth = usedwidth + widths[i] usedwidth = usedwidth + widths[i]
end end
rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
rowends[numrows] = numtabs rowends[numrows] = #tablist
--Fix for single tabs being left on the last row, move a tab from the row above if applicable --Fix for single tabs being left on the last row, move a tab from the row above if applicable
if numrows > 1 then if numrows > 1 then
@@ -10,8 +10,6 @@ if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
local math_min, math_max, floor = math.min, math.max, floor local math_min, math_max, floor = math.min, math.max, floor
local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat
local tgetn = table.getn
local strfmt = string.format
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -82,11 +80,11 @@ local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
local line = button.line local line = button.line
button.level = level button.level = level
if ( level == 1 ) then if ( level == 1 ) then
button.text:SetFontObject("GameFontNormal") button:SetTextFontObject("GameFontNormal")
button:SetHighlightFontObject("GameFontHighlight") button:SetHighlightFontObject("GameFontHighlight")
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2) button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
else else
button.text:SetFontObject("GameFontHighlightSmall") button:SetTextFontObject("GameFontHighlightSmall")
button:SetHighlightFontObject("GameFontHighlightSmall") button:SetHighlightFontObject("GameFontHighlightSmall")
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2) button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
end end
@@ -156,134 +154,134 @@ local function addLine(self, v, tree, level, parent)
else else
line.hasChildren = nil line.hasChildren = nil
end end
tinsert(self.lines, line) self.lines[#self.lines+1] = line
return line return line
end end
--fire an update after one frame to catch the treeframes height --fire an update after one frame to catch the treeframes height
local function FirstFrameUpdate() local function FirstFrameUpdate(frame)
local self = this.obj local self = frame.obj
this:SetScript("OnUpdate", nil) frame:SetScript("OnUpdate", nil)
self:RefreshTree() self:RefreshTree()
end end
local function BuildUniqueValue(...) local function BuildUniqueValue(...)
local n = tgetn(arg) local n = select('#', ...)
if n == 1 then if n == 1 then
return arg[1] return ...
else else
return (unpack(arg)).."\001"..BuildUniqueValue(select(2, unpack(arg))) return (...).."\001"..BuildUniqueValue(select(2,...))
end end
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Expand_OnClick() local function Expand_OnClick(frame)
local button = this.button local button = frame.button
local self = button.obj local self = button.obj
local status = (self.status or self.localstatus).groups local status = (self.status or self.localstatus).groups
status[button.uniquevalue] = not status[button.uniquevalue] status[button.uniquevalue] = not status[button.uniquevalue]
self:RefreshTree() self:RefreshTree()
end end
local function Button_OnClick() local function Button_OnClick(frame)
local self = this.obj local self = frame.obj
self:Fire("OnClick", 2, this.uniquevalue, this.selected) self:Fire("OnClick", frame.uniquevalue, frame.selected)
if not this.selected then if not frame.selected then
self:SetSelected(this.uniquevalue) self:SetSelected(frame.uniquevalue)
this.selected = true frame.selected = true
this:LockHighlight() frame:LockHighlight()
self:RefreshTree() self:RefreshTree()
end end
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function Button_OnDoubleClick() local function Button_OnDoubleClick(button)
local self = this.obj local self = button.obj
local status = self.status or self.localstatus local status = self.status or self.localstatus
local status = (self.status or self.localstatus).groups local status = (self.status or self.localstatus).groups
status[this.uniquevalue] = not status[this.uniquevalue] status[button.uniquevalue] = not status[button.uniquevalue]
self:RefreshTree() self:RefreshTree()
end end
local function Button_OnEnter() local function Button_OnEnter(frame)
local self = this.obj local self = frame.obj
self:Fire("OnButtonEnter", 2, this.uniquevalue, this) self:Fire("OnButtonEnter", frame.uniquevalue, frame)
if self.enabletooltips then if self.enabletooltips then
GameTooltip:SetOwner(this, "ANCHOR_NONE") GameTooltip:SetOwner(frame, "ANCHOR_NONE")
GameTooltip:SetPoint("LEFT",this,"RIGHT") GameTooltip:SetPoint("LEFT",frame,"RIGHT")
GameTooltip:SetText(this.text:GetText() or "", 1, .82, 0, true) GameTooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1)
GameTooltip:Show() GameTooltip:Show()
end end
end end
local function Button_OnLeave() local function Button_OnLeave(frame)
local self = this.obj local self = frame.obj
self:Fire("OnButtonLeave", 2, this.uniquevalue, this) self:Fire("OnButtonLeave", frame.uniquevalue, frame)
if self.enabletooltips then if self.enabletooltips then
GameTooltip:Hide() GameTooltip:Hide()
end end
end end
local function OnScrollValueChanged() local function OnScrollValueChanged(frame, value)
if this.obj.noupdate then return end if frame.obj.noupdate then return end
local self = this.obj local self = frame.obj
local status = self.status or self.localstatus local status = self.status or self.localstatus
status.scrollvalue = floor(arg1 + 0.5) status.scrollvalue = value
self:RefreshTree() self:RefreshTree()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function Tree_OnSizeChanged() local function Tree_OnSizeChanged(frame)
this.obj:RefreshTree() frame.obj:RefreshTree()
end end
local function Tree_OnMouseWheel() local function Tree_OnMouseWheel(frame, delta)
local self = this.obj local self = frame.obj
if self.showscroll then if self.showscroll then
local scrollbar = self.scrollbar local scrollbar = self.scrollbar
local min, max = scrollbar:GetMinMaxValues() local min, max = scrollbar:GetMinMaxValues()
local value = scrollbar:GetValue() local value = scrollbar:GetValue()
local newvalue = math_min(max,math_max(min,value - arg1)) local newvalue = math_min(max,math_max(min,value - delta))
if value ~= newvalue then if value ~= newvalue then
scrollbar:SetValue(newvalue) scrollbar:SetValue(newvalue)
end end
end end
end end
local function Dragger_OnLeave() local function Dragger_OnLeave(frame)
this:SetBackdropColor(1, 1, 1, 0) frame:SetBackdropColor(1, 1, 1, 0)
end end
local function Dragger_OnEnter() local function Dragger_OnEnter(frame)
this:SetBackdropColor(1, 1, 1, 0.8) frame:SetBackdropColor(1, 1, 1, 0.8)
end end
local function Dragger_OnMouseDown() local function Dragger_OnMouseDown(frame)
local treeframe = this:GetParent() local treeframe = frame:GetParent()
treeframe:StartSizing("RIGHT") treeframe:StartSizing("RIGHT")
end end
local function Dragger_OnMouseUp() local function Dragger_OnMouseUp(frame)
local treeframe = this:GetParent() local treeframe = frame:GetParent()
local self = treeframe.obj local self = treeframe.obj
local this = treeframe:GetParent() local frame = treeframe:GetParent()
treeframe:StopMovingOrSizing() treeframe:StopMovingOrSizing()
--treeframe:SetScript("OnUpdate", nil) --treeframe:SetScript("OnUpdate", nil)
treeframe:SetUserPlaced(false) treeframe:SetUserPlaced(false)
--Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize --Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
treeframe:SetHeight(0) treeframe:SetHeight(0)
treeframe:SetPoint("TOPLEFT", this, "TOPLEFT",0,0) treeframe:SetPoint("TOPLEFT", frame, "TOPLEFT",0,0)
treeframe:SetPoint("BOTTOMLEFT", this, "BOTTOMLEFT",0,0) treeframe:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT",0,0)
local status = self.status or self.localstatus local status = self.status or self.localstatus
status.treewidth = treeframe:GetWidth() status.treewidth = treeframe:GetWidth()
treeframe.obj:Fire("OnTreeResize", 1, treeframe:GetWidth()) treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
-- recalculate the content width -- recalculate the content width
treeframe.obj:OnWidthSet(status.fullwidth) treeframe.obj:OnWidthSet(status.fullwidth)
-- update the layout of the content -- update the layout of the content
@@ -297,7 +295,6 @@ local methods = {
["OnAcquire"] = function(self) ["OnAcquire"] = function(self)
self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE) self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
self:EnableButtonTooltips(true) self:EnableButtonTooltips(true)
self.frame:SetScript("OnUpdate", FirstFrameUpdate)
end, end,
["OnRelease"] = function(self) ["OnRelease"] = function(self)
@@ -322,36 +319,8 @@ local methods = {
["CreateButton"] = function(self) ["CreateButton"] = function(self)
local num = AceGUI:GetNextWidgetNum("TreeGroupButton") local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), self.treeframe, "InterfaceOptionsButtonTemplate")
local button = CreateFrame("Button", strfmt("AceGUI30TreeButton%d", num), self.treeframe)
button.obj = self button.obj = self
button:SetWidth(DEFAULT_TREE_WIDTH)
button:SetHeight(18)
local toggle = CreateFrame("Button", "$parentToggle", button)
toggle:SetWidth(14)
toggle:SetHeight(14)
toggle:SetPoint("TOPRIGHT", button, "TOPRIGHT", -6, -1)
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
toggle:SetHighlightTexture("Interface\Buttons\UI-PlusButton-Hilight", "ADD")
button.toggle = toggle
local text = button:CreateFontString()
button.text = text
text:SetFontObject(GameFontNormal)
button:SetHighlightFontObject(GameFontHighlight)
text:SetPoint("RIGHT", toggle, "LEFT", -2, 0);
text:SetJustifyH("LEFT")
local highlight = button:CreateTexture(nil, "HIGHLIGHT");
button.highlight = highlight
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight")
highlight:SetBlendMode("ADD")
highlight:SetVertexColor(.196, .388, .8);
highlight:ClearAllPoints()
highlight:SetPoint("TOPLEFT",0,1)
highlight:SetPoint("BOTTOMRIGHT",0,1)
local icon = button:CreateTexture(nil, "OVERLAY") local icon = button:CreateTexture(nil, "OVERLAY")
icon:SetWidth(14) icon:SetWidth(14)
@@ -445,7 +414,7 @@ local methods = {
self:BuildLevel(tree, 1) self:BuildLevel(tree, 1)
local numlines = tgetn(lines) local numlines = #lines
local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18)) local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
if maxlines <= 0 then return end if maxlines <= 0 then return end
@@ -499,7 +468,6 @@ local methods = {
end end
local buttonnum = 1 local buttonnum = 1
local treewidth = treeframe:GetWidth()
for i = first, last do for i = first, last do
local line = lines[i] local line = lines[i]
local button = buttons[buttonnum] local button = buttons[buttonnum]
@@ -509,33 +477,33 @@ local methods = {
buttons[buttonnum] = button buttons[buttonnum] = button
button:SetParent(treeframe) button:SetParent(treeframe)
button:SetFrameLevel(treeframe:GetFrameLevel()+1) button:SetFrameLevel(treeframe:GetFrameLevel()+1)
end button:ClearAllPoints()
if buttonnum == 1 then
button:ClearAllPoints() if self.showscroll then
if buttonnum == 1 then button:SetPoint("TOPRIGHT", -22, -10)
if self.showscroll then button:SetPoint("TOPLEFT", 0, -10)
button:SetWidth(treewidth - 22) else
button:SetPoint("TOPRIGHT", -22, -10) button:SetPoint("TOPRIGHT", 0, -10)
button:SetPoint("TOPLEFT", 0, -10)
end
else else
button:SetWidth(treewidth) button:SetPoint("TOPRIGHT", buttons[buttonnum-1], "BOTTOMRIGHT",0,0)
button:SetPoint("TOPRIGHT", 0, -10) button:SetPoint("TOPLEFT", buttons[buttonnum-1], "BOTTOMLEFT",0,0)
end end
else
button:SetWidth(self.showscroll and (treewidth - 22) or treewidth)
button:SetPoint("TOPRIGHT", buttons[buttonnum-1], "BOTTOMRIGHT",0,0)
end end
UpdateButton(button, line, status.selected == line.uniquevalue, line.hasChildren, groupstatus[line.uniquevalue] ) UpdateButton(button, line, status.selected == line.uniquevalue, line.hasChildren, groupstatus[line.uniquevalue] )
button:Show() button:Show()
buttonnum = buttonnum + 1 buttonnum = buttonnum + 1
end end
end, end,
["SetSelected"] = function(self, value) ["SetSelected"] = function(self, value)
local status = self.status or self.localstatus local status = self.status or self.localstatus
if status.selected ~= value then if status.selected ~= value then
status.selected = value status.selected = value
self:Fire("OnGroupSelected", 1, value) self:Fire("OnGroupSelected", value)
end end
end, end,
@@ -543,20 +511,21 @@ local methods = {
self.filter = false self.filter = false
local status = self.status or self.localstatus local status = self.status or self.localstatus
local groups = status.groups local groups = status.groups
for i = 1, arg.n do local path = {...}
groups[tconcat(arg, "\001", 1, i)] = true for i = 1, #path do
groups[tconcat(path, "\001", 1, i)] = true
end end
status.selected = uniquevalue status.selected = uniquevalue
self:RefreshTree(true) self:RefreshTree(true)
self:Fire("OnGroupSelected", 1, uniquevalue) self:Fire("OnGroupSelected", uniquevalue)
end, end,
["SelectByPath"] = function(self, ...) ["SelectByPath"] = function(self, ...)
self:Select(BuildUniqueValue(unpack(arg)), unpack(arg)) self:Select(BuildUniqueValue(...), ...)
end, end,
["SelectByValue"] = function(self, uniquevalue) ["SelectByValue"] = function(self, uniquevalue)
self:Select(uniquevalue, strsplit("\001", uniquevalue)) self:Select(uniquevalue, ("\001"):split(uniquevalue))
end, end,
["ShowScroll"] = function(self, show) ["ShowScroll"] = function(self, show)
@@ -564,13 +533,11 @@ local methods = {
if show then if show then
self.scrollbar:Show() self.scrollbar:Show()
if self.buttons[1] then if self.buttons[1] then
self.buttons[1]:SetWidth(self.treeframe:GetWidth() - 22)
self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",-22,-10) self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",-22,-10)
end end
else else
self.scrollbar:Hide() self.scrollbar:Hide()
if self.buttons[1] then if self.buttons[1] then
self.buttons[1]:SetWidth(self.treeframe:GetWidth())
self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",0,-10) self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",0,-10)
end end
end end
@@ -665,8 +632,8 @@ local function Constructor()
local frame = CreateFrame("Frame", nil, UIParent) local frame = CreateFrame("Frame", nil, UIParent)
local treeframe = CreateFrame("Frame", nil, frame) local treeframe = CreateFrame("Frame", nil, frame)
treeframe:SetPoint("TOPLEFT", 0, 0) treeframe:SetPoint("TOPLEFT")
treeframe:SetPoint("BOTTOMLEFT", 0, 0) treeframe:SetPoint("BOTTOMLEFT")
treeframe:SetWidth(DEFAULT_TREE_WIDTH) treeframe:SetWidth(DEFAULT_TREE_WIDTH)
treeframe:EnableMouseWheel(true) treeframe:EnableMouseWheel(true)
treeframe:SetBackdrop(PaneBackdrop) treeframe:SetBackdrop(PaneBackdrop)
@@ -690,7 +657,7 @@ local function Constructor()
dragger:SetScript("OnMouseDown", Dragger_OnMouseDown) dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
dragger:SetScript("OnMouseUp", Dragger_OnMouseUp) dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
local scrollbar = CreateFrame("Slider", strfmt("AceConfigDialogTreeGroup%dScrollBar", num), treeframe, "UIPanelScrollBarTemplate") local scrollbar = CreateFrame("Slider", ("AceConfigDialogTreeGroup%dScrollBar"):format(num), treeframe, "UIPanelScrollBarTemplate")
scrollbar:SetScript("OnValueChanged", nil) scrollbar:SetScript("OnValueChanged", nil)
scrollbar:SetPoint("TOPRIGHT", -10, -26) scrollbar:SetPoint("TOPRIGHT", -10, -26)
scrollbar:SetPoint("BOTTOMRIGHT", -10, 26) scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
@@ -706,7 +673,7 @@ local function Constructor()
local border = CreateFrame("Frame",nil,frame) local border = CreateFrame("Frame",nil,frame)
border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT") border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
border:SetPoint("BOTTOMRIGHT", 0, 0) border:SetPoint("BOTTOMRIGHT")
border:SetBackdrop(PaneBackdrop) border:SetBackdrop(PaneBackdrop)
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5) border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
border:SetBackdropBorderColor(0.4, 0.4, 0.4) border:SetBackdropBorderColor(0.4, 0.4, 0.4)
@@ -739,4 +706,4 @@ local function Constructor()
return AceGUI:RegisterAsContainer(widget) return AceGUI:RegisterAsContainer(widget)
end end
AceGUI:RegisterWidgetType(Type, Constructor, Version) AceGUI:RegisterWidgetType(Type, Constructor, Version)
@@ -21,27 +21,31 @@ local CreateFrame, UIParent = CreateFrame, UIParent
]] ]]
do do
local Type = "Window" local Type = "Window"
local Version = 4 local Version = 5
local function frameOnClose() local function frameOnShow(this)
this.obj:Fire("OnShow")
end
local function frameOnClose(this)
this.obj:Fire("OnClose") this.obj:Fire("OnClose")
end end
local function closeOnClick() local function closeOnClick(this)
PlaySound("gsTitleOptionExit") PlaySound("gsTitleOptionExit")
this.obj:Hide() this.obj:Hide()
end end
local function frameOnMouseDown() local function frameOnMouseDown(this)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function titleOnMouseDown() local function titleOnMouseDown(this)
this:GetParent():StartMoving() this:GetParent():StartMoving()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function frameOnMouseUp() local function frameOnMouseUp(this)
local frame = this:GetParent() local frame = this:GetParent()
frame:StopMovingOrSizing() frame:StopMovingOrSizing()
local self = frame.obj local self = frame.obj
@@ -51,42 +55,42 @@ do
status.top = frame:GetTop() status.top = frame:GetTop()
status.left = frame:GetLeft() status.left = frame:GetLeft()
end end
local function sizerseOnMouseDown() local function sizerseOnMouseDown(this)
this:GetParent():StartSizing("BOTTOMRIGHT") this:GetParent():StartSizing("BOTTOMRIGHT")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function sizersOnMouseDown() local function sizersOnMouseDown(this)
this:GetParent():StartSizing("BOTTOM") this:GetParent():StartSizing("BOTTOM")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function sizereOnMouseDown() local function sizereOnMouseDown(this)
this:GetParent():StartSizing("RIGHT") this:GetParent():StartSizing("RIGHT")
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function sizerOnMouseUp() local function sizerOnMouseUp(this)
this:GetParent():StopMovingOrSizing() this:GetParent():StopMovingOrSizing()
end end
local function SetTitle(self,title) local function SetTitle(self,title)
self.titletext:SetText(title) self.titletext:SetText(title)
end end
local function SetStatusText(self,text) local function SetStatusText(self,text)
-- self.statustext:SetText(text) -- self.statustext:SetText(text)
end end
local function Hide(self) local function Hide(self)
self.frame:Hide() self.frame:Hide()
end end
local function Show(self) local function Show(self)
self.frame:Show() self.frame:Show()
end end
local function OnAcquire(self) local function OnAcquire(self)
self.frame:SetParent(UIParent) self.frame:SetParent(UIParent)
self.frame:SetFrameStrata("FULLSCREEN_DIALOG") self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
@@ -94,21 +98,21 @@ do
self:EnableResize(true) self:EnableResize(true)
self:Show() self:Show()
end end
local function OnRelease(self) local function OnRelease(self)
self.status = nil self.status = nil
for k in pairs(self.localstatus) do for k in pairs(self.localstatus) do
self.localstatus[k] = nil self.localstatus[k] = nil
end end
end end
-- called to set an external table to store status in -- called to set an external table to store status in
local function SetStatusTable(self, status) local function SetStatusTable(self, status)
assert(type(status) == "table") assert(type(status) == "table")
self.status = status self.status = status
self:ApplyStatus() self:ApplyStatus()
end end
local function ApplyStatus(self) local function ApplyStatus(self)
local status = self.status or self.localstatus local status = self.status or self.localstatus
local frame = self.frame local frame = self.frame
@@ -121,7 +125,7 @@ do
frame:SetPoint("CENTER",UIParent,"CENTER") frame:SetPoint("CENTER",UIParent,"CENTER")
end end
end end
local function OnWidthSet(self, width) local function OnWidthSet(self, width)
local content = self.content local content = self.content
local contentwidth = width - 34 local contentwidth = width - 34
@@ -131,8 +135,8 @@ do
content:SetWidth(contentwidth) content:SetWidth(contentwidth)
content.width = contentwidth content.width = contentwidth
end end
local function OnHeightSet(self, height) local function OnHeightSet(self, height)
local content = self.content local content = self.content
local contentheight = height - 57 local contentheight = height - 57
@@ -142,19 +146,19 @@ do
content:SetHeight(contentheight) content:SetHeight(contentheight)
content.height = contentheight content.height = contentheight
end end
local function EnableResize(self, state) local function EnableResize(self, state)
local func = state and "Show" or "Hide" local func = state and "Show" or "Hide"
self.sizer_se[func](self.sizer_se) self.sizer_se[func](self.sizer_se)
self.sizer_s[func](self.sizer_s) self.sizer_s[func](self.sizer_s)
self.sizer_e[func](self.sizer_e) self.sizer_e[func](self.sizer_e)
end end
local function Constructor() local function Constructor()
local frame = CreateFrame("Frame",nil,UIParent) local frame = CreateFrame("Frame",nil,UIParent)
local self = {} local self = {}
self.type = "Window" self.type = "Window"
self.Hide = Hide self.Hide = Hide
self.Show = Show self.Show = Show
self.SetTitle = SetTitle self.SetTitle = SetTitle
@@ -166,9 +170,9 @@ do
self.OnWidthSet = OnWidthSet self.OnWidthSet = OnWidthSet
self.OnHeightSet = OnHeightSet self.OnHeightSet = OnHeightSet
self.EnableResize = EnableResize self.EnableResize = EnableResize
self.localstatus = {} self.localstatus = {}
self.frame = frame self.frame = frame
frame.obj = self frame.obj = self
frame:SetWidth(700) frame:SetWidth(700)
@@ -179,7 +183,8 @@ do
frame:SetResizable(true) frame:SetResizable(true)
frame:SetFrameStrata("FULLSCREEN_DIALOG") frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:SetScript("OnMouseDown", frameOnMouseDown) frame:SetScript("OnMouseDown", frameOnMouseDown)
frame:SetScript("OnShow",frameOnShow)
frame:SetScript("OnHide",frameOnClose) frame:SetScript("OnHide",frameOnClose)
frame:SetMinResize(240,240) frame:SetMinResize(240,240)
frame:SetToplevel(true) frame:SetToplevel(true)
@@ -188,81 +193,81 @@ do
titlebg:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Title-Background]]) titlebg:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Title-Background]])
titlebg:SetPoint("TOPLEFT", 9, -6) titlebg:SetPoint("TOPLEFT", 9, -6)
titlebg:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -28, -24) titlebg:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -28, -24)
local dialogbg = frame:CreateTexture(nil, "BACKGROUND") local dialogbg = frame:CreateTexture(nil, "BACKGROUND")
dialogbg:SetTexture([[Interface\Tooltips\UI-Tooltip-Background]]) dialogbg:SetTexture([[Interface\Tooltips\UI-Tooltip-Background]])
dialogbg:SetPoint("TOPLEFT", 8, -24) dialogbg:SetPoint("TOPLEFT", 8, -24)
dialogbg:SetPoint("BOTTOMRIGHT", -6, 8) dialogbg:SetPoint("BOTTOMRIGHT", -6, 8)
dialogbg:SetVertexColor(0, 0, 0, .75) dialogbg:SetVertexColor(0, 0, 0, .75)
local topleft = frame:CreateTexture(nil, "BORDER") local topleft = frame:CreateTexture(nil, "BORDER")
topleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) topleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
topleft:SetWidth(64) topleft:SetWidth(64)
topleft:SetHeight(64) topleft:SetHeight(64)
topleft:SetPoint("TOPLEFT") topleft:SetPoint("TOPLEFT")
topleft:SetTexCoord(0.501953125, 0.625, 0, 1) topleft:SetTexCoord(0.501953125, 0.625, 0, 1)
local topright = frame:CreateTexture(nil, "BORDER") local topright = frame:CreateTexture(nil, "BORDER")
topright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) topright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
topright:SetWidth(64) topright:SetWidth(64)
topright:SetHeight(64) topright:SetHeight(64)
topright:SetPoint("TOPRIGHT") topright:SetPoint("TOPRIGHT")
topright:SetTexCoord(0.625, 0.75, 0, 1) topright:SetTexCoord(0.625, 0.75, 0, 1)
local top = frame:CreateTexture(nil, "BORDER") local top = frame:CreateTexture(nil, "BORDER")
top:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) top:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
top:SetHeight(64) top:SetHeight(64)
top:SetPoint("TOPLEFT", topleft, "TOPRIGHT") top:SetPoint("TOPLEFT", topleft, "TOPRIGHT")
top:SetPoint("TOPRIGHT", topright, "TOPLEFT") top:SetPoint("TOPRIGHT", topright, "TOPLEFT")
top:SetTexCoord(0.25, 0.369140625, 0, 1) top:SetTexCoord(0.25, 0.369140625, 0, 1)
local bottomleft = frame:CreateTexture(nil, "BORDER") local bottomleft = frame:CreateTexture(nil, "BORDER")
bottomleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) bottomleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
bottomleft:SetWidth(64) bottomleft:SetWidth(64)
bottomleft:SetHeight(64) bottomleft:SetHeight(64)
bottomleft:SetPoint("BOTTOMLEFT") bottomleft:SetPoint("BOTTOMLEFT")
bottomleft:SetTexCoord(0.751953125, 0.875, 0, 1) bottomleft:SetTexCoord(0.751953125, 0.875, 0, 1)
local bottomright = frame:CreateTexture(nil, "BORDER") local bottomright = frame:CreateTexture(nil, "BORDER")
bottomright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) bottomright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
bottomright:SetWidth(64) bottomright:SetWidth(64)
bottomright:SetHeight(64) bottomright:SetHeight(64)
bottomright:SetPoint("BOTTOMRIGHT") bottomright:SetPoint("BOTTOMRIGHT")
bottomright:SetTexCoord(0.875, 1, 0, 1) bottomright:SetTexCoord(0.875, 1, 0, 1)
local bottom = frame:CreateTexture(nil, "BORDER") local bottom = frame:CreateTexture(nil, "BORDER")
bottom:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) bottom:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
bottom:SetHeight(64) bottom:SetHeight(64)
bottom:SetPoint("BOTTOMLEFT", bottomleft, "BOTTOMRIGHT") bottom:SetPoint("BOTTOMLEFT", bottomleft, "BOTTOMRIGHT")
bottom:SetPoint("BOTTOMRIGHT", bottomright, "BOTTOMLEFT") bottom:SetPoint("BOTTOMRIGHT", bottomright, "BOTTOMLEFT")
bottom:SetTexCoord(0.376953125, 0.498046875, 0, 1) bottom:SetTexCoord(0.376953125, 0.498046875, 0, 1)
local left = frame:CreateTexture(nil, "BORDER") local left = frame:CreateTexture(nil, "BORDER")
left:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) left:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
left:SetWidth(64) left:SetWidth(64)
left:SetPoint("TOPLEFT", topleft, "BOTTOMLEFT") left:SetPoint("TOPLEFT", topleft, "BOTTOMLEFT")
left:SetPoint("BOTTOMLEFT", bottomleft, "TOPLEFT") left:SetPoint("BOTTOMLEFT", bottomleft, "TOPLEFT")
left:SetTexCoord(0.001953125, 0.125, 0, 1) left:SetTexCoord(0.001953125, 0.125, 0, 1)
local right = frame:CreateTexture(nil, "BORDER") local right = frame:CreateTexture(nil, "BORDER")
right:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]]) right:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
right:SetWidth(64) right:SetWidth(64)
right:SetPoint("TOPRIGHT", topright, "BOTTOMRIGHT") right:SetPoint("TOPRIGHT", topright, "BOTTOMRIGHT")
right:SetPoint("BOTTOMRIGHT", bottomright, "TOPRIGHT") right:SetPoint("BOTTOMRIGHT", bottomright, "TOPRIGHT")
right:SetTexCoord(0.1171875, 0.2421875, 0, 1) right:SetTexCoord(0.1171875, 0.2421875, 0, 1)
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton") local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
close:SetPoint("TOPRIGHT", 2, 1) close:SetPoint("TOPRIGHT", 2, 1)
close:SetScript("OnClick", closeOnClick) close:SetScript("OnClick", closeOnClick)
self.closebutton = close self.closebutton = close
close.obj = self close.obj = self
local titletext = frame:CreateFontString(nil, "ARTWORK") local titletext = frame:CreateFontString(nil, "ARTWORK")
titletext:SetFontObject(GameFontNormal) titletext:SetFontObject(GameFontNormal)
titletext:SetPoint("TOPLEFT", 12, -8) titletext:SetPoint("TOPLEFT", 12, -8)
titletext:SetPoint("TOPRIGHT", -32, -8) titletext:SetPoint("TOPRIGHT", -32, -8)
self.titletext = titletext self.titletext = titletext
local title = CreateFrame("Button", nil, frame) local title = CreateFrame("Button", nil, frame)
title:SetPoint("TOPLEFT", titlebg) title:SetPoint("TOPLEFT", titlebg)
title:SetPoint("BOTTOMRIGHT", titlebg) title:SetPoint("BOTTOMRIGHT", titlebg)
@@ -270,7 +275,7 @@ do
title:SetScript("OnMouseDown",titleOnMouseDown) title:SetScript("OnMouseDown",titleOnMouseDown)
title:SetScript("OnMouseUp", frameOnMouseUp) title:SetScript("OnMouseUp", frameOnMouseUp)
self.title = title self.title = title
local sizer_se = CreateFrame("Frame",nil,frame) local sizer_se = CreateFrame("Frame",nil,frame)
sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0) sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
sizer_se:SetWidth(25) sizer_se:SetWidth(25)
@@ -306,7 +311,7 @@ do
sizer_s:SetScript("OnMouseDown",sizersOnMouseDown) sizer_s:SetScript("OnMouseDown",sizersOnMouseDown)
sizer_s:SetScript("OnMouseUp", sizerOnMouseUp) sizer_s:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_s = sizer_s self.sizer_s = sizer_s
local sizer_e = CreateFrame("Frame",nil,frame) local sizer_e = CreateFrame("Frame",nil,frame)
sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25) sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25)
sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0) sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
@@ -315,17 +320,17 @@ do
sizer_e:SetScript("OnMouseDown",sizereOnMouseDown) sizer_e:SetScript("OnMouseDown",sizereOnMouseDown)
sizer_e:SetScript("OnMouseUp", sizerOnMouseUp) sizer_e:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_e = sizer_e self.sizer_e = sizer_e
--Container Support --Container Support
local content = CreateFrame("Frame",nil,frame) local content = CreateFrame("Frame",nil,frame)
self.content = content self.content = content
content.obj = self content.obj = self
content:SetPoint("TOPLEFT",frame,"TOPLEFT",12,-32) content:SetPoint("TOPLEFT",frame,"TOPLEFT",12,-32)
content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-12,13) content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-12,13)
AceGUI:RegisterAsContainer(self) AceGUI:RegisterAsContainer(self)
return self return self
end end
AceGUI:RegisterWidgetType(Type,Constructor,Version) AceGUI:RegisterWidgetType(Type,Constructor,Version)
end end
@@ -2,92 +2,32 @@
Button Widget (Modified to change text color on SetDisabled method) Button Widget (Modified to change text color on SetDisabled method)
Graphical Button. Graphical Button.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Button-ElvUI", 2 local Type, Version = "Button-ElvUI", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local pairs, unpack = pairs, unpack local pairs = pairs
-- WoW APIs -- WoW APIs
local _G = _G local _G = _G
local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
local IsShiftKeyDown = IsShiftKeyDown
-- GLOBALS: GameTooltip, ElvUI
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local dragdropButton local function Button_OnClick(frame, ...)
local function lockTooltip()
GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR")
GameTooltip:SetText(" ")
GameTooltip:Show()
end
local function dragdrop_OnMouseDown(...)
if this.obj.dragOnMouseDown then
dragdropButton.mouseDownFrame = this
dragdropButton:SetText(this.obj.value or "Unknown")
dragdropButton:SetWidth(this:GetWidth())
dragdropButton:SetHeight(this:SetHeight())
this.obj.dragOnMouseDown(this, unpack(arg))
end
end
local function dragdrop_OnMouseUp(...)
if this.obj.dragOnMouseUp then
this:SetAlpha(1)
GameTooltip:Hide()
dragdropButton:Hide()
if dragdropButton.enteredFrame and dragdropButton.enteredFrame ~= this and dragdropButton.enteredFrame:IsMouseOver() then
this.obj.dragOnMouseUp(this, unpack(arg))
this.obj.ActivateMultiControl(this.obj, unpack(arg))
end
dragdropButton.enteredFrame = nil
dragdropButton.mouseDownFrame = nil
end
end
local function dragdrop_OnLeave(...)
if this.obj.dragOnLeave then
if dragdropButton.mouseDownFrame then
lockTooltip()
end
if this == dragdropButton.mouseDownFrame then
this:SetAlpha(0)
dragdropButton:Show()
this.obj.dragOnLeave(this, unpack(arg))
end
end
end
local function dragdrop_OnEnter(...)
if this.obj.dragOnEnter and dragdropButton:IsShown() then
dragdropButton.enteredFrame = this
lockTooltip()
this.obj.dragOnEnter(this, unpack(arg))
end
end
local function dragdrop_OnClick()
local button = arg1
if this.obj.dragOnClick and button == "RightButton" then
this.obj.dragOnClick(this, button)
this.obj.ActivateMultiControl(this.obj, button)
elseif this.obj.stateSwitchOnClick and (button == "LeftButton") and IsShiftKeyDown() then
this.obj.stateSwitchOnClick(this, button)
this.obj.ActivateMultiControl(this.obj, button)
end
end
local function Button_OnClick()
AceGUI:ClearFocus() AceGUI:ClearFocus()
PlaySound("igMainMenuOption") PlaySound("igMainMenuOption")
this.obj:Fire("OnClick", 2, arg1) frame.obj:Fire("OnClick", ...)
end end
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -136,28 +76,14 @@ Constructor
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Constructor() local function Constructor()
local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type) local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate") local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate2")
frame:Hide() frame:Hide()
frame:EnableMouse(true) frame:EnableMouse(true)
frame:SetScript("OnClick", Button_OnClick) frame:SetScript("OnClick", Button_OnClick)
frame:SetScript("OnEnter", Control_OnEnter) frame:SetScript("OnEnter", Control_OnEnter)
frame:SetScript("OnLeave", Control_OnLeave) frame:SetScript("OnLeave", Control_OnLeave)
-- dragdrop
if not dragdropButton then
dragdropButton = CreateFrame("Button", "ElvUIAceGUI30DragDropButton", UIParent, "UIPanelButtonTemplate")
dragdropButton:SetFrameStrata("TOOLTIP")
dragdropButton:SetFrameLevel(5)
dragdropButton:SetPoint('BOTTOM', GameTooltip, "BOTTOM", 0, 10)
dragdropButton:Hide()
ElvUI[1]:GetModule('Skins'):HandleButton(dragdropButton)
end
HookScript(frame, "OnClick", dragdrop_OnClick)
HookScript(frame, "OnEnter", dragdrop_OnEnter)
HookScript(frame, "OnLeave", dragdrop_OnLeave)
HookScript(frame, "OnMouseUp", dragdrop_OnMouseUp)
HookScript(frame, "OnMouseDown", dragdrop_OnMouseDown)
local text = frame:GetFontString() local text = frame:GetFontString()
text:ClearAllPoints() text:ClearAllPoints()
text:SetPoint("TOPLEFT", 15, -1) text:SetPoint("TOPLEFT", 15, -1)
@@ -6,31 +6,28 @@ local Type, Version = "Button", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
-- Lua APIs -- Lua APIs
local pairs = pairs local pairs = pairs
-- WoW APIs -- WoW APIs
local _G = AceCore._G local _G = _G
local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
-- arg1 is the button for OnClick event local function Button_OnClick(frame, ...)
local function Button_OnClick()
AceGUI:ClearFocus() AceGUI:ClearFocus()
PlaySound("igMainMenuOption") PlaySound("igMainMenuOption")
this.obj:Fire("OnClick", 1, arg1) frame.obj:Fire("OnClick", ...)
end end
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -54,7 +51,7 @@ local methods = {
self:SetWidth(self.text:GetStringWidth() + 30) self:SetWidth(self.text:GetStringWidth() + 30)
end end
end, end,
["SetAutoWidth"] = function(self, autoWidth) ["SetAutoWidth"] = function(self, autoWidth)
self.autoWidth = autoWidth self.autoWidth = autoWidth
if self.autoWidth then if self.autoWidth then
@@ -6,7 +6,7 @@ local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local pairs = pairs local select, pairs = select, pairs
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
@@ -24,26 +24,26 @@ local function AlignImage(self)
self.text:ClearAllPoints() self.text:ClearAllPoints()
if not img then if not img then
self.text:SetPoint("LEFT", self.checkbg, "RIGHT") self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
self.text:SetPoint("RIGHT",0,0) self.text:SetPoint("RIGHT")
else else
self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0) self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0)
self.text:SetPoint("RIGHT",0,0) self.text:SetPoint("RIGHT")
end end
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function CheckBox_OnMouseDown() local function CheckBox_OnMouseDown(frame)
local self = this.obj local self = frame.obj
if not self.disabled then if not self.disabled then
if self.image:GetTexture() then if self.image:GetTexture() then
self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1) self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1)
@@ -54,9 +54,8 @@ local function CheckBox_OnMouseDown()
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function CheckBox_OnMouseUp() local function CheckBox_OnMouseUp(frame)
local self = frame.obj
local self = this.obj
if not self.disabled then if not self.disabled then
self:ToggleChecked() self:ToggleChecked()
@@ -66,7 +65,7 @@ local function CheckBox_OnMouseUp()
PlaySound("igMainMenuOptionCheckBoxOff") PlaySound("igMainMenuOptionCheckBoxOff")
end end
self:Fire("OnValueChanged", 1, self.checked) self:Fire("OnValueChanged", self.checked)
AlignImage(self) AlignImage(self)
end end
end end
@@ -173,7 +172,6 @@ local methods = {
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight") highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
highlight:SetTexCoord(0, 1, 0, 1) highlight:SetTexCoord(0, 1, 0, 1)
end end
checkbg:SetHeight(size) checkbg:SetHeight(size)
checkbg:SetWidth(size) checkbg:SetWidth(size)
end, end,
@@ -223,13 +221,14 @@ local methods = {
end end
end, end,
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8) ["SetImage"] = function(self, path, ...)
local image = self.image local image = self.image
image:SetTexture(path) image:SetTexture(path)
if image:GetTexture() then if image:GetTexture() then
if a4 or a8 then local n = select("#", ...)
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8) if n == 4 or n == 8 then
image:SetTexCoord(...)
else else
image:SetTexCoord(0, 1, 0, 1) image:SetTexCoord(0, 1, 0, 1)
end end
@@ -254,7 +253,7 @@ local function Constructor()
local checkbg = frame:CreateTexture(nil, "ARTWORK") local checkbg = frame:CreateTexture(nil, "ARTWORK")
checkbg:SetWidth(24) checkbg:SetWidth(24)
checkbg:SetHeight(24) checkbg:SetHeight(24)
checkbg:SetPoint("TOPLEFT",0,0) checkbg:SetPoint("TOPLEFT")
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up") checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
local check = frame:CreateTexture(nil, "OVERLAY") local check = frame:CreateTexture(nil, "OVERLAY")
@@ -265,7 +264,7 @@ local function Constructor()
text:SetJustifyH("LEFT") text:SetJustifyH("LEFT")
text:SetHeight(18) text:SetHeight(18)
text:SetPoint("LEFT", checkbg, "RIGHT") text:SetPoint("LEFT", checkbg, "RIGHT")
text:SetPoint("RIGHT",0,0) text:SetPoint("RIGHT")
local highlight = frame:CreateTexture(nil, "HIGHLIGHT") local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight") highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
ColorPicker Widget ColorPicker Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "ColorPicker", 23 local Type, Version = "ColorPicker-ElvUI", 22
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -25,12 +25,12 @@ local function ColorCallback(self, r, g, b, a, isAlpha)
self:SetColor(r, g, b, a) self:SetColor(r, g, b, a)
if ColorPickerFrame:IsVisible() then if ColorPickerFrame:IsVisible() then
--colorpicker is still open --colorpicker is still open
self:Fire("OnValueChanged", 4, r, g, b, a) self:Fire("OnValueChanged", r, g, b, a)
else else
--colorpicker is closed, color callback is first, ignore it, --colorpicker is closed, color callback is first, ignore it,
--alpha callback is the final call after it closes so confirm now --alpha callback is the final call after it closes so confirm now
if isAlpha then if isAlpha then
self:Fire("OnValueConfirmed", 4, r, g, b, a) self:Fire("OnValueConfirmed", r, g, b, a)
end end
end end
end end
@@ -38,19 +38,20 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function ColorSwatch_OnClick() local function ColorSwatch_OnClick(frame)
HideUIPanel(ColorPickerFrame) HideUIPanel(ColorPickerFrame)
local self = this.obj local self = frame.obj
if not self.disabled then if not self.disabled then
ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG") ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
ColorPickerFrame:SetClampedToScreen(true) ColorPickerFrame:SetClampedToScreen(true)
ColorPickerFrame.func = function() ColorPickerFrame.func = function()
@@ -66,12 +67,20 @@ local function ColorSwatch_OnClick()
ColorCallback(self, r, g, b, a, true) ColorCallback(self, r, g, b, a, true)
end end
local r, g, b, a = self.r, self.g, self.b, self.a local r, g, b, a, dR, dG, dB, dA = self.r, self.g, self.b, self.a, self.dR, self.dG, self.dB, self.dA
if self.HasAlpha then if self.HasAlpha then
ColorPickerFrame.opacity = 1 - (a or 0) ColorPickerFrame.opacity = 1 - (a or 0)
end end
ColorPickerFrame:SetColorRGB(r, g, b) ColorPickerFrame:SetColorRGB(r, g, b)
if(ColorPPDefault and self.dR and self.dG and self.dB) then
local alpha = 1
if(self.dA) then
alpha = 1 - self.dA
end
ColorPPDefault.colors = {r = self.dR, g = self.dG, b = self.dB, a = alpha}
end
ColorPickerFrame.cancelFunc = function() ColorPickerFrame.cancelFunc = function()
ColorCallback(self, r, g, b, a, true) ColorCallback(self, r, g, b, a, true)
end end
@@ -100,11 +109,15 @@ local methods = {
self.text:SetText(text) self.text:SetText(text)
end, end,
["SetColor"] = function(self, r, g, b, a) ["SetColor"] = function(self, r, g, b, a, defaultR, defaultG, defaultB, defaultA)
self.r = r self.r = r
self.g = g self.g = g
self.b = b self.b = b
self.a = a or 1 self.a = a or 1
self.dR = defaultR
self.dG = defaultG
self.dB = defaultB
self.dA = defaultA
self.colorSwatch:SetVertexColor(r, g, b, a) self.colorSwatch:SetVertexColor(r, g, b, a)
end, end,
@@ -140,7 +153,7 @@ local function Constructor()
colorSwatch:SetWidth(19) colorSwatch:SetWidth(19)
colorSwatch:SetHeight(19) colorSwatch:SetHeight(19)
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
colorSwatch:SetPoint("LEFT",0,0) colorSwatch:SetPoint("LEFT")
local texture = frame:CreateTexture(nil, "BACKGROUND") local texture = frame:CreateTexture(nil, "BACKGROUND")
texture:SetWidth(16) texture:SetWidth(16)
@@ -164,7 +177,7 @@ local function Constructor()
text:SetJustifyH("LEFT") text:SetJustifyH("LEFT")
text:SetTextColor(1, 1, 1) text:SetTextColor(1, 1, 1)
text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0) text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
text:SetPoint("RIGHT",0,0) text:SetPoint("RIGHT")
--local highlight = frame:CreateTexture(nil, "HIGHLIGHT") --local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
--highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") --highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
@@ -1,12 +1,9 @@
--[[ $Id: AceGUIWidget-DropDown-Items.lua 1137 2016-05-15 10:57:36Z nevcairiel $ ]]-- --[[ $Id: AceGUIWidget-DropDown-Items.lua 996 2010-12-01 18:34:17Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0") local AceGUI = LibStub("AceGUI-3.0")
local IsLegion = false
-- Lua APIs -- Lua APIs
local assert = assert local select, assert = select, assert
local tgetn = table.getn
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
@@ -14,12 +11,23 @@ local CreateFrame = CreateFrame
local function fixlevels(parent,...) local function fixlevels(parent,...)
local i = 1 local i = 1
local child = arg[i] local child = select(i, ...)
while child do while child do
child:SetFrameLevel(parent:GetFrameLevel()+1) child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren()) fixlevels(child, child:GetChildren())
i = i + 1 i = i + 1
child = arg[i] child = select(i, ...)
end
end
local function fixstrata(strata, parent, ...)
local i = 1
local child = select(i, ...)
parent:SetFrameStrata(strata)
while child do
fixstrata(strata, child, child:GetChildren())
i = i + 1
child = select(i, ...)
end end
end end
@@ -37,7 +45,7 @@ local ItemBase = {
counter = 0, counter = 0,
} }
function ItemBase.Frame_OnEnter() function ItemBase.Frame_OnEnter(this)
local self = this.obj local self = this.obj
if self.useHighlight then if self.useHighlight then
@@ -50,7 +58,7 @@ function ItemBase.Frame_OnEnter()
end end
end end
function ItemBase.Frame_OnLeave() function ItemBase.Frame_OnLeave(this)
local self = this.obj local self = this.obj
self.highlight:Hide() self.highlight:Hide()
@@ -83,9 +91,8 @@ function ItemBase.SetPullout(self, pullout)
self.pullout = pullout self.pullout = pullout
self.frame:SetParent(nil) self.frame:SetParent(nil)
local itemFrame = pullout.itemFrame self.frame:SetParent(pullout.itemFrame)
self.frame:SetParent(itemFrame) self.parent = pullout.itemFrame
self.parent = itemFrame
fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren()) fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren())
end end
@@ -100,8 +107,8 @@ function ItemBase.GetText(self)
end end
-- exported -- exported
function ItemBase.SetPoint(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) function ItemBase.SetPoint(self, ...)
self.frame:SetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) self.frame:SetPoint(...)
end end
-- exported -- exported
@@ -250,7 +257,7 @@ do
end end
end end
local function OnLeave() local function OnLeave(this)
local self = this.obj local self = this.obj
self:Fire("OnLeave") self:Fire("OnLeave")
@@ -331,7 +338,7 @@ do
self:SetValue(nil) self:SetValue(nil)
end end
local function Frame_OnClick() local function Frame_OnClick(this, button)
local self = this.obj local self = this.obj
if self.disabled then return end if self.disabled then return end
self.value = not self.value self.value = not self.value
@@ -341,7 +348,7 @@ do
PlaySound("igMainMenuOptionCheckBoxOff") PlaySound("igMainMenuOptionCheckBoxOff")
end end
UpdateToggle(self) UpdateToggle(self)
self:Fire("OnValueChanged", 1, self.value) self:Fire("OnValueChanged", self.value)
end end
-- exported -- exported
@@ -378,7 +385,7 @@ do
local widgetType = "Dropdown-Item-Menu" local widgetType = "Dropdown-Item-Menu"
local widgetVersion = 2 local widgetVersion = 2
local function OnEnter() local function OnEnter(this)
local self = this.obj local self = this.obj
self:Fire("OnEnter") self:Fire("OnEnter")
@@ -393,7 +400,7 @@ do
end end
end end
local function OnHide() local function OnHide(this)
local self = this.obj local self = this.obj
if self.submenu then if self.submenu then
self.submenu:Close() self.submenu:Close()
@@ -433,7 +440,7 @@ end
-- A single line to separate items -- A single line to separate items
do do
local widgetType = "Dropdown-Item-Separator" local widgetType = "Dropdown-Item-Separator"
local widgetVersion = 2 local widgetVersion = 1
-- exported, override -- exported, override
local function SetDisabled(self, disabled) local function SetDisabled(self, disabled)
@@ -449,7 +456,6 @@ do
local line = self.frame:CreateTexture(nil, "OVERLAY") local line = self.frame:CreateTexture(nil, "OVERLAY")
line:SetHeight(1) line:SetHeight(1)
line:SetTexture(.5, .5, .5) line:SetTexture(.5, .5, .5)
line:SetPoint("LEFT", self.frame, "LEFT", 10, 0) line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0) line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
@@ -1,18 +1,15 @@
--[[ $Id: AceGUIWidget-DropDown.lua 1116 2014-10-12 08:15:46Z nevcairiel $ ]]-- --[[ $Id: AceGUIWidget-DropDown.lua 1116 2014-10-12 08:15:46Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0") local AceGUI = LibStub("AceGUI-3.0")
local AceCore = LibStub("AceCore-3.0")
-- Lua APIs -- Lua APIs
local min, max, floor = math.min, math.max, math.floor local min, max, floor = math.min, math.max, math.floor
local pairs, ipairs, type = pairs, ipairs, type local select, pairs, ipairs, type = select, pairs, ipairs, type
local tsort, tinsert, tgetn, tsetn = table.sort, table.insert, table.getn, table.setn local tsort = table.sort
local format = string.format
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
local UIParent, CreateFrame = UIParent, CreateFrame local UIParent, CreateFrame = UIParent, CreateFrame
local _G = AceCore._G local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -20,23 +17,23 @@ local _G = AceCore._G
local function fixlevels(parent,...) local function fixlevels(parent,...)
local i = 1 local i = 1
local child = arg[i] local child = select(i, ...)
while child do while child do
child:SetFrameLevel(parent:GetFrameLevel()+1) child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren()) fixlevels(child, child:GetChildren())
i = i + 1 i = i + 1
child = arg[i] child = select(i, ...)
end end
end end
local function fixstrata(strata, parent, ...) local function fixstrata(strata, parent, ...)
local i = 1 local i = 1
local child = arg[i] local child = select(i, ...)
parent:SetFrameStrata(strata) parent:SetFrameStrata(strata)
while child do while child do
fixstrata(strata, child, child:GetChildren()) fixstrata(strata, child, child:GetChildren())
i = i + 1 i = i + 1
child = arg[i] child = select(i, ...)
end end
end end
@@ -79,15 +76,15 @@ do
end end
-- See the note in Constructor() for each scroll related function -- See the note in Constructor() for each scroll related function
local function OnMouseWheel() local function OnMouseWheel(this, value)
this.obj:MoveScroll(arg1) this.obj:MoveScroll(value)
end end
local function OnScrollValueChanged() local function OnScrollValueChanged(this, value)
this.obj:SetScroll(arg1) this.obj:SetScroll(value)
end end
local function OnSizeChanged() local function OnSizeChanged(this)
this.obj:FixScroll() this.obj:FixScroll()
end end
@@ -107,6 +104,7 @@ do
end end
child:ClearAllPoints() child:ClearAllPoints()
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset) child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
status.offset = offset status.offset = offset
status.scrollvalue = value status.scrollvalue = value
end end
@@ -150,6 +148,7 @@ do
if value < 1000 then if value < 1000 then
child:ClearAllPoints() child:ClearAllPoints()
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset) child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
status.offset = offset status.offset = offset
end end
end end
@@ -170,9 +169,9 @@ do
-- exported -- exported
local function AddItem(self, item) local function AddItem(self, item)
tinsert(self.items, item) self.items[#self.items + 1] = item
local h = tgetn(self.items) * 16 local h = #self.items * 16
self.itemFrame:SetHeight(h) self.itemFrame:SetHeight(h)
self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
@@ -223,7 +222,6 @@ do
AceGUI:Release(item) AceGUI:Release(item)
items[i] = nil items[i] = nil
end end
tsetn(items,0)
end end
-- exported -- exported
@@ -322,17 +320,16 @@ do
slider.obj = self slider.obj = self
scrollFrame:SetScrollChild(itemFrame) scrollFrame:SetScrollChild(itemFrame)
scrollFrame:SetWidth(defaultWidth - 12)
scrollFrame:SetHeight(self.maxHeight - 24)
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12) scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
scrollFrame:EnableMouseWheel(true) scrollFrame:EnableMouseWheel(true)
scrollFrame:SetScript("OnMouseWheel", OnMouseWheel) scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged) scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
scrollFrame:SetToplevel(true) scrollFrame:SetToplevel(true)
scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG") scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
itemFrame:SetWidth(defaultWidth - 12)
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0) itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
itemFrame:SetHeight(400) itemFrame:SetHeight(400)
itemFrame:SetToplevel(true) itemFrame:SetToplevel(true)
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG") itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
@@ -365,24 +362,24 @@ do
--[[ UI event handler ]]-- --[[ UI event handler ]]--
local function Control_OnEnter() local function Control_OnEnter(this)
this.obj.button:LockHighlight() this.obj.button:LockHighlight()
this.obj:Fire("OnEnter") this.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(this)
this.obj.button:UnlockHighlight() this.obj.button:UnlockHighlight()
this.obj:Fire("OnLeave") this.obj:Fire("OnLeave")
end end
local function Dropdown_OnHide() local function Dropdown_OnHide(this)
local self = this.obj local self = this.obj
if self.open then if self.open then
self.pullout:Close() self.pullout:Close()
end end
end end
local function Dropdown_TogglePullout() local function Dropdown_TogglePullout(this)
local self = this.obj local self = this.obj
PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound
if self.open then if self.open then
@@ -391,10 +388,7 @@ do
AceGUI:ClearFocus() AceGUI:ClearFocus()
else else
self.open = true self.open = true
local width = self.pulloutWidth or self.frame:GetWidth() self.pullout:SetWidth(self.pulloutWidth or self.frame:GetWidth())
self.pullout:SetWidth(width)
self.pullout.scrollFrame:SetWidth(width - 12)
self.pullout.itemFrame:SetWidth(width - (self.pullout.slider:IsShown() and 24 or 12))
self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0) self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
AceGUI:SetFocus(self) AceGUI:SetFocus(self)
end end
@@ -436,20 +430,17 @@ do
self:SetText(text) self:SetText(text)
end end
local function OnItemValueChanged(this, event, _, checked) local function OnItemValueChanged(this, event, checked)
local self = this.userdata.obj local self = this.userdata.obj
if self.multiselect then if self.multiselect then
self:Fire("OnValueChanged", 2, this.userdata.value, checked) self:Fire("OnValueChanged", this.userdata.value, checked)
ShowMultiText(self) ShowMultiText(self)
else else
if checked then if checked then
self:SetValue(this.userdata.value) self:SetValue(this.userdata.value)
self:Fire("OnValueChanged", 1, this.userdata.value) self:Fire("OnValueChanged", this.userdata.value)
this:SetValue(false)
else else
self:SetValue(nil)
self:Fire("OnValueChanged", 1, nil)
this:SetValue(true) this:SetValue(true)
end end
if self.open then if self.open then
@@ -468,7 +459,6 @@ do
pullout:SetCallback("OnClose", OnPulloutClose) pullout:SetCallback("OnClose", OnPulloutClose)
pullout:SetCallback("OnOpen", OnPulloutOpen) pullout:SetCallback("OnOpen", OnPulloutOpen)
self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1) self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
local frame = self.pullout.frame
fixlevels(self.pullout.frame, self.pullout.frame:GetChildren()) fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
self:SetHeight(44) self:SetHeight(44)
@@ -581,7 +571,7 @@ do
local function AddListItem(self, value, text, itemType) local function AddListItem(self, value, text, itemType)
if not itemType then itemType = "Dropdown-Item-Toggle" end if not itemType then itemType = "Dropdown-Item-Toggle" end
local exists = AceGUI:GetWidgetVersion(itemType) local exists = AceGUI:GetWidgetVersion(itemType)
if not exists then error(format("The given item type, %q, does not exist within AceGUI-3.0", tostring(itemType)), 2) end if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end
local item = AceGUI:Create(itemType) local item = AceGUI:Create(itemType)
item:SetText(text) item:SetText(text)
@@ -610,7 +600,7 @@ do
if type(order) ~= "table" then if type(order) ~= "table" then
for v in pairs(list) do for v in pairs(list) do
tinsert(sortlist, v) sortlist[#sortlist + 1] = v
end end
tsort(sortlist) tsort(sortlist)
@@ -618,7 +608,6 @@ do
AddListItem(self, key, list[key], itemType) AddListItem(self, key, list[key], itemType)
sortlist[i] = nil sortlist[i] = nil
end end
tsetn(sortlist,0)
else else
for i, key in ipairs(order) do for i, key in ipairs(order) do
AddListItem(self, key, list[key], itemType) AddListItem(self, key, list[key], itemType)
@@ -5,11 +5,6 @@ local Type, Version = "EditBox", 26
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local hooksecurefunc = AceCore.hooksecurefunc
local _G = AceCore._G
local GetCursorInfo = _G.GetCursorInfo
-- Lua APIs -- Lua APIs
local tostring, pairs = tostring, pairs local tostring, pairs = tostring, pairs
@@ -17,7 +12,7 @@ local tostring, pairs = tostring, pairs
local PlaySound = PlaySound local PlaySound = PlaySound
local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local strlen = string.len local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -28,100 +23,13 @@ Support functions
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
if not AceGUIEditBoxInsertLink then if not AceGUIEditBoxInsertLink then
-- upgradeable hook -- upgradeable hook
hooksecurefunc("BankFrameItemButtonGeneric_OnClick", hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
function(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(BANK_CONTAINER, this:GetID()))
end
end)
hooksecurefunc("ContainerFrameItemButton_OnClick",
function(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(this:GetParent():GetID(), this:GetID()))
end
end)
hooksecurefunc("KeyRingItemButton_OnClick",
function(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(KEYRING_CONTAINER, this:GetID()))
end
end)
hooksecurefunc("LootFrameItem_OnClick",
function(button)
if button == "LeftButton" and IsShiftKeyDown() then
return _G.AceGUIEditBoxInsertLink(GetLootSlotLink(this.slot))
end
end)
hooksecurefunc("SetItemRef",
function(link, text, button)
if IsShiftKeyDown() then
if strsub(link,1,6) == "player" then
local name = strsub(link,8)
if name and (strlen(name) > 0) then
return _G.AceGUIEditBoxInsertLink(name)
end
else
return _G.AceGUIEditBoxInsertLink(text)
end
end
end)
hooksecurefunc("MerchantItemButton_OnClick",
function(button, ignoreModifiers)
if MerchantFrame.selectedTab == 1 and button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIEditBoxInsertLink(GetMerchantItemLink(this:GetID()))
end
end)
hooksecurefunc("PaperDollItemSlotButton_OnClick",
function(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIEditBoxInsertLink(GetInventoryItemLink("player", this:GetID()))
end
end)
hooksecurefunc("QuestItem_OnClick",
function()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end)
hooksecurefunc("QuestRewardItem_OnClick",
function()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end)
hooksecurefunc("QuestLogTitleButton_OnClick",
function(button)
if IsShiftKeyDown() and (not this.isHeader) then
return _G.AceGUIEditBoxInsertLink(gsub(this:GetText(), " *(.*)", "%1"))
end
end)
hooksecurefunc("QuestLogRewardItem_OnClick",
function()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIEditBoxInsertLink(GetQuestLogItemLink(this.type, this:GetID()))
end
end)
hooksecurefunc("SpellButton_OnClick",
function(drag)
local id = SpellBook_GetSpellID(this:GetID())
if id <= MAX_SPELLS and (not drag) and IsShiftKeyDown() then
local spellName, subSpellName = GetSpellName(id, SpellBookFrame.bookType)
if spellName and not IsSpellPassive(id, SpellBookFrame.bookType) then
if subSpellName and (strlen(subSpellName) > 0) then
_G.AceGUIEditBoxInsertLink(spellName.."("..subSpellName..")");
else
_G.AceGUIEditBoxInsertLink(spellName);
end
end
end
end)
end end
function _G.AceGUIEditBoxInsertLink(text) function _G.AceGUIEditBoxInsertLink(text)
for i = 1, AceGUI:GetWidgetCount(Type) do for i = 1, AceGUI:GetWidgetCount(Type) do
local editbox = _G["AceGUI-3.0EditBox"..i] local editbox = _G["AceGUI-3.0EditBox"..i]
if editbox and editbox:IsVisible() and editbox.hasfocus then if editbox and editbox:IsVisible() and editbox:HasFocus() then
editbox:Insert(text) editbox:Insert(text)
return true return true
end end
@@ -143,82 +51,73 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function Frame_OnShowFocus() local function Frame_OnShowFocus(frame)
this.obj.editbox:SetFocus() frame.obj.editbox:SetFocus()
this:SetScript("OnShow", nil) frame:SetScript("OnShow", nil)
end end
local function EditBox_OnEscapePressed() local function EditBox_OnEscapePressed(frame)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function EditBox_OnEnterPressed() local function EditBox_OnEnterPressed(frame)
local self = this.obj local self = frame.obj
local value = this:GetText() local value = frame:GetText()
local cancel = self:Fire("OnEnterPressed", 1, value) local cancel = self:Fire("OnEnterPressed", value)
if not cancel then if not cancel then
PlaySound("igMainMenuOptionCheckBoxOn") PlaySound("igMainMenuOptionCheckBoxOn")
HideButton(self) HideButton(self)
end end
end end
local function EditBox_OnReceiveDrag() local function EditBox_OnReceiveDrag(frame)
if not GetCursorInfo then return end local self = frame.obj
local self = this.obj
local type, id, info = GetCursorInfo() local type, id, info = GetCursorInfo()
if type == "item" then if type == "item" then
self:SetText(info) self:SetText(info)
self:Fire("OnEnterPressed", 1, info) self:Fire("OnEnterPressed", info)
ClearCursor() ClearCursor()
elseif type == "spell" then elseif type == "spell" then
local spell, rank = GetSpellName(id, info) local name = GetSpellInfo(id, info)
if rank ~= "" then spell = spell.."("..rank..")" end self:SetText(name)
self:SetText(spell) self:Fire("OnEnterPressed", name)
self:Fire("OnEnterPressed", 1, spell)
ClearCursor() ClearCursor()
elseif type == "macro" then elseif type == "macro" then
local name = GetMacroInfo(id) local name = GetMacroInfo(id)
self:SetText(name) self:SetText(name)
self:Fire("OnEnterPressed", 1, name) self:Fire("OnEnterPressed", name)
ClearCursor() ClearCursor()
end end
HideButton(self) HideButton(self)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function EditBox_OnTextChanged(frame)
local function EditBox_OnTextChanged() local self = frame.obj
local self = this.obj local value = frame:GetText()
local value = this:GetText()
if tostring(value) ~= tostring(self.lasttext) then if tostring(value) ~= tostring(self.lasttext) then
self:Fire("OnTextChanged", 1, value) self:Fire("OnTextChanged", value)
self.lasttext = value self.lasttext = value
ShowButton(self) ShowButton(self)
end end
end end
local function EditBox_OnFocusGained() local function EditBox_OnFocusGained(frame)
this.hasfocus = true AceGUI:SetFocus(frame.obj)
AceGUI:SetFocus(this.obj)
end end
local function EditBox_OnFocusLost() local function Button_OnClick(frame)
this.hasfocus = nil local editbox = frame.obj.editbox
end
local function Button_OnClick()
local editbox = this.obj.editbox
editbox:ClearFocus() editbox:ClearFocus()
this = editbox -- Ace3v: this is kinda hack here EditBox_OnEnterPressed(editbox)
EditBox_OnEnterPressed()
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -256,7 +155,7 @@ local methods = {
["SetText"] = function(self, text) ["SetText"] = function(self, text)
self.lasttext = text or "" self.lasttext = text or ""
self.editbox:SetText(text or "") self.editbox:SetText(text or "")
self.editbox:HighlightText(0) self.editbox:SetCursorPosition(0)
HideButton(self) HideButton(self)
end, end,
@@ -327,11 +226,10 @@ local function Constructor()
editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag) editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag) editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained) editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained)
editbox:SetScript("OnEditFocusLost", EditBox_OnFocusLost)
editbox:SetTextInsets(0, 0, 3, 3) editbox:SetTextInsets(0, 0, 3, 3)
editbox:SetMaxLetters(256) editbox:SetMaxLetters(256)
editbox:SetPoint("BOTTOMLEFT", 6, 0) editbox:SetPoint("BOTTOMLEFT", 6, 0)
editbox:SetPoint("BOTTOMRIGHT", 0, 0) editbox:SetPoint("BOTTOMRIGHT")
editbox:SetHeight(19) editbox:SetHeight(19)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
@@ -43,8 +43,8 @@ local function Constructor()
frame:Hide() frame:Hide()
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal") local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
label:SetPoint("TOP",0,0) label:SetPoint("TOP")
label:SetPoint("BOTTOM",0,0) label:SetPoint("BOTTOM")
label:SetJustifyH("CENTER") label:SetJustifyH("CENTER")
local left = frame:CreateTexture(nil, "BACKGROUND") local left = frame:CreateTexture(nil, "BACKGROUND")
@@ -6,7 +6,7 @@ local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local pairs, print = pairs, print local select, pairs, print = select, pairs, print
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -14,16 +14,16 @@ local CreateFrame, UIParent = CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function Button_OnClick() local function Button_OnClick(frame, button)
this.obj:Fire("OnClick", 1, arg1) frame.obj:Fire("OnClick", button)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
@@ -53,13 +53,14 @@ local methods = {
end end
end, end,
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8) ["SetImage"] = function(self, path, ...)
local image = self.image local image = self.image
image:SetTexture(path) image:SetTexture(path)
if image:GetTexture() then if image:GetTexture() then
if a4 or a8 then local n = select("#", ...)
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8) if n == 4 or n == 8 then
image:SetTexCoord(...)
else else
image:SetTexCoord(0, 1, 0, 1) image:SetTexCoord(0, 1, 0, 1)
end end
@@ -131,7 +132,7 @@ local function Constructor()
widget[method] = func widget[method] = func
end end
widget.SetText = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) end widget.SetText = widget.SetLabel
return AceGUI:RegisterAsWidget(widget) return AceGUI:RegisterAsWidget(widget)
end end
@@ -1,12 +1,12 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
InteractiveLabel Widget InteractiveLabel Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "InteractiveLabel", 20 local Type, Version = "InteractiveLabel", 21
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local pairs = pairs local select, pairs = select, pairs
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -18,16 +18,16 @@ local CreateFrame, UIParent = CreateFrame, UIParent
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function Label_OnClick() local function Label_OnClick(frame, button)
this.obj:Fire("OnClick", 1, arg1) frame.obj:Fire("OnClick", button)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
@@ -44,13 +44,14 @@ local methods = {
-- ["OnRelease"] = nil, -- ["OnRelease"] = nil,
["SetHighlight"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) ["SetHighlight"] = function(self, ...)
self.highlight:SetTexture(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) self.highlight:SetTexture(...)
end, end,
["SetHighlightTexCoord"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8) ["SetHighlightTexCoord"] = function(self, ...)
if a4 or a8 then local c = select("#", ...)
self.highlight:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) if c == 4 or c == 8 then
self.highlight:SetTexCoord(...)
else else
self.highlight:SetTexCoord(0, 1, 0, 1) self.highlight:SetTexCoord(0, 1, 0, 1)
end end
@@ -21,32 +21,44 @@ local CreateFrame, UIParent = CreateFrame, UIParent
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function Keybinding_OnHide() local function Keybinding_OnClick(frame, button)
local self = this.obj if button == "LeftButton" or button == "RightButton" then
this:EnableKeyboard(false) local self = frame.obj
this:EnableMouseWheel(false) if self.waitingForKey then
self.msgframe:Hide() frame:EnableKeyboard(false)
this:UnlockHighlight() frame:EnableMouseWheel(false)
self.waitingForKey = nil self.msgframe:Hide()
frame:UnlockHighlight()
self.waitingForKey = nil
else
frame:EnableKeyboard(true)
frame:EnableMouseWheel(true)
self.msgframe:Show()
frame:LockHighlight()
self.waitingForKey = true
end
end
AceGUI:ClearFocus()
end end
local ignoreKeys = { local ignoreKeys = {
["BUTTON1"] = true, ["BUTTON2"] = true, ["BUTTON1"] = true, ["BUTTON2"] = true,
["UNKNOWN"] = true, ["UNKNOWN"] = true,
["SHIFT"] = true, ["CTRL"] = true, ["ALT"] = true, ["LSHIFT"] = true, ["LCTRL"] = true, ["LALT"] = true,
["RSHIFT"] = true, ["RCTRL"] = true, ["RALT"] = true,
} }
local function Keybinding_OnKeyDown() local function Keybinding_OnKeyDown(frame, key)
local self = this.obj local self = frame.obj
if self.waitingForKey then if self.waitingForKey then
local keyPressed = arg1 local keyPressed = key
if keyPressed == "ESCAPE" then if keyPressed == "ESCAPE" then
keyPressed = "" keyPressed = ""
else else
@@ -62,58 +74,40 @@ local function Keybinding_OnKeyDown()
end end
end end
this:EnableKeyboard(false) frame:EnableKeyboard(false)
this:EnableMouseWheel(false) frame:EnableMouseWheel(false)
self.msgframe:Hide() self.msgframe:Hide()
this:UnlockHighlight() frame:UnlockHighlight()
self.waitingForKey = nil self.waitingForKey = nil
if not self.disabled then if not self.disabled then
self:SetKey(keyPressed) self:SetKey(keyPressed)
self:Fire("OnKeyChanged", 1, keyPressed) self:Fire("OnKeyChanged", keyPressed)
end end
end end
end end
local function Keybinding_OnMouseDown() local function Keybinding_OnMouseDown(frame, button)
getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down"); if button == "LeftButton" or button == "RightButton" then
getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down"); return
getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down"); elseif button == "MiddleButton" then
end button = "BUTTON3"
elseif button == "Button4" then
local function Keybinding_OnMouseUp() button = "BUTTON4"
getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up"); elseif button == "Button5" then
getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up"); button = "BUTTON5"
getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
local self = this.obj
if MouseIsOver(this) and not self.disabled then
if self.waitingForKey then
if arg1 ~= "LeftButton" and arg1 ~= "RightButton" then
Keybinding_OnKeyDown()
end
this:EnableKeyboard(false)
this:EnableMouseWheel(false)
self.msgframe:Hide()
this:UnlockHighlight()
self.waitingForKey = nil
else
this:EnableKeyboard(true)
this:EnableMouseWheel(true)
self.msgframe:Show()
this:LockHighlight()
self.waitingForKey = true
end
end end
AceGUI:ClearFocus() Keybinding_OnKeyDown(frame, button)
end end
local function Keybinding_OnMouseWheel() local function Keybinding_OnMouseWheel(frame, direction)
if arg1 >= 0 then local button
arg1 = "MOUSEWHEELUP" if direction >= 0 then
button = "MOUSEWHEELUP"
else else
arg1 = "MOUSEWHEELDOWN" button = "MOUSEWHEELDOWN"
end end
Keybinding_OnKeyDown() Keybinding_OnKeyDown(frame, button)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -147,10 +141,10 @@ local methods = {
["SetKey"] = function(self, key) ["SetKey"] = function(self, key)
if (key or "") == "" then if (key or "") == "" then
self.button:SetText(NOT_BOUND) self.button:SetText(NOT_BOUND)
self.text:SetFontObject("GameFontNormal") self.button:SetNormalFontObject("GameFontNormal")
else else
self.button:SetText(key) self.button:SetText(key)
self.text:SetFontObject("GameFontHighlight") self.button:SetNormalFontObject("GameFontHighlight")
end end
end, end,
@@ -185,9 +179,9 @@ local ControlBackdrop = {
insets = { left = 3, right = 3, top = 3, bottom = 3 } insets = { left = 3, right = 3, top = 3, bottom = 3 }
} }
local function keybindingMsgFixWidth() local function keybindingMsgFixWidth(frame)
this:SetWidth(this.msg:GetWidth() + 10) frame:SetWidth(frame.msg:GetWidth() + 10)
this:SetScript("OnUpdate", nil) frame:SetScript("OnUpdate", nil)
end end
local function Constructor() local function Constructor()
@@ -198,18 +192,15 @@ local function Constructor()
button:EnableMouse(true) button:EnableMouse(true)
button:EnableMouseWheel(false) button:EnableMouseWheel(false)
button:RegisterForClicks("AnyDown")
button:SetScript("OnEnter", Control_OnEnter) button:SetScript("OnEnter", Control_OnEnter)
button:SetScript("OnLeave", Control_OnLeave) button:SetScript("OnLeave", Control_OnLeave)
button:SetScript("OnClick", Keybinding_OnClick)
button:SetScript("OnKeyDown", Keybinding_OnKeyDown) button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
button:RegisterForClicks("AnyDown","AnyUp")
-- Ace3v: RegisterForClicks means OnClick will not be triggered, so use OnKeyDown and OnKeyUp
button:SetScript("OnMouseDown", Keybinding_OnMouseDown) button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
button:SetScript("OnMouseUp", Keybinding_OnMouseUp)
button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel) button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
button:SetScript("OnHide", Keybinding_OnHide) button:SetPoint("BOTTOMLEFT")
button:SetPoint("BOTTOMLEFT",0,0) button:SetPoint("BOTTOMRIGHT")
button:SetPoint("BOTTOMRIGHT",0,0)
button:SetHeight(24) button:SetHeight(24)
button:EnableKeyboard(false) button:EnableKeyboard(false)
@@ -218,8 +209,8 @@ local function Constructor()
text:SetPoint("RIGHT", -7, 0) text:SetPoint("RIGHT", -7, 0)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
label:SetPoint("TOPLEFT",0,0) label:SetPoint("TOPLEFT")
label:SetPoint("TOPRIGHT",0,0) label:SetPoint("TOPRIGHT")
label:SetJustifyH("CENTER") label:SetJustifyH("CENTER")
label:SetHeight(18) label:SetHeight(18)
@@ -245,8 +236,7 @@ local function Constructor()
msgframe = msgframe, msgframe = msgframe,
frame = frame, frame = frame,
alignoffset = 30, alignoffset = 30,
type = Type, type = Type
text = text
} }
for method, func in pairs(methods) do for method, func in pairs(methods) do
widget[method] = func widget[method] = func
@@ -2,12 +2,12 @@
Label Widget Label Widget
Displays text and optionally an icon. Displays text and optionally an icon.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Label", 23 local Type, Version = "Label", 24
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local max, pairs = math.max, pairs local max, select, pairs = math.max, select, pairs
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
@@ -35,14 +35,14 @@ local function UpdateImageAnchor(self)
local imagewidth = image:GetWidth() local imagewidth = image:GetWidth()
if (width - imagewidth) < 200 or (label:GetText() or "") == "" then if (width - imagewidth) < 200 or (label:GetText() or "") == "" then
-- image goes on top centered when less than 200 width for the text, or if there is no text -- image goes on top centered when less than 200 width for the text, or if there is no text
image:SetPoint("TOP",0,0) image:SetPoint("TOP")
label:SetPoint("TOP", image, "BOTTOM") label:SetPoint("TOP", image, "BOTTOM")
label:SetPoint("LEFT",0,0) label:SetPoint("LEFT")
label:SetWidth(width) label:SetWidth(width)
height = image:GetHeight() + label:GetHeight() height = image:GetHeight() + label:GetHeight()
else else
-- image on the left -- image on the left
image:SetPoint("TOPLEFT",0,0) image:SetPoint("TOPLEFT")
if image:GetHeight() > label:GetHeight() then if image:GetHeight() > label:GetHeight() then
label:SetPoint("LEFT", image, "RIGHT", 4, 0) label:SetPoint("LEFT", image, "RIGHT", 4, 0)
else else
@@ -53,11 +53,11 @@ local function UpdateImageAnchor(self)
end end
else else
-- no image shown -- no image shown
label:SetPoint("TOPLEFT",0,0) label:SetPoint("TOPLEFT")
label:SetWidth(width) label:SetWidth(width)
height = label:GetHeight() height = label:GetHeight()
end end
self.resizing = true self.resizing = true
frame:SetHeight(height) frame:SetHeight(height)
frame.height = height frame.height = height
@@ -78,6 +78,8 @@ local methods = {
self:SetImageSize(16, 16) self:SetImageSize(16, 16)
self:SetColor() self:SetColor()
self:SetFontObject() self:SetFontObject()
self:SetJustifyH("LEFT")
self:SetJustifyV("TOP")
-- reset the flag -- reset the flag
self.resizing = nil self.resizing = nil
@@ -103,14 +105,15 @@ local methods = {
self.label:SetVertexColor(r, g, b) self.label:SetVertexColor(r, g, b)
end, end,
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8) ["SetImage"] = function(self, path, ...)
local image = self.image local image = self.image
image:SetTexture(path) image:SetTexture(path)
if image:GetTexture() then if image:GetTexture() then
self.imageshown = true self.imageshown = true
if a4 or a8 then local n = select("#", ...)
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8) if n == 4 or n == 8 then
image:SetTexCoord(...)
else else
image:SetTexCoord(0, 1, 0, 1) image:SetTexCoord(0, 1, 0, 1)
end end
@@ -133,6 +136,14 @@ local methods = {
self.image:SetHeight(height) self.image:SetHeight(height)
UpdateImageAnchor(self) UpdateImageAnchor(self)
end, end,
["SetJustifyH"] = function(self, justifyH)
self.label:SetJustifyH(justifyH)
end,
["SetJustifyV"] = function(self, justifyV)
self.label:SetJustifyV(justifyV)
end,
} }
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -143,9 +154,6 @@ local function Constructor()
frame:Hide() frame:Hide()
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall") local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
label:SetJustifyH("LEFT")
label:SetJustifyV("TOP")
local image = frame:CreateTexture(nil, "BACKGROUND") local image = frame:CreateTexture(nil, "BACKGROUND")
-- create widget -- create widget
@@ -2,17 +2,13 @@ local Type, Version = "MultiLineEditBox", 28
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
local hooksecurefunc = AceCore.hooksecurefunc
-- Lua APIs -- Lua APIs
local strfmt = string.format
local pairs = pairs local pairs = pairs
-- WoW APIs -- WoW APIs
local CursorHasItem, ClearCursor = CursorHasItem, ClearCursor local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local _G = AceCore._G local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script -- List them here for Mikk's FindGlobals script
@@ -21,108 +17,23 @@ local _G = AceCore._G
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Support functions Support functions
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
if not AceGUIMultiLineEditBoxInsertLink then if not AceGUIMultiLineEditBoxInsertLink then
-- upgradeable hook -- upgradeable hook
hooksecurefunc("BankFrameItemButtonGeneric_OnClick", hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
function(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(BANK_CONTAINER, this:GetID()))
end
end)
hooksecurefunc("ContainerFrameItemButton_OnClick",
function(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(this:GetParent():GetID(), this:GetID()))
end
end)
hooksecurefunc("KeyRingItemButton_OnClick",
function(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(KEYRING_CONTAINER, this:GetID()))
end
end)
hooksecurefunc("LootFrameItem_OnClick",
function(button)
if button == "LeftButton" and IsShiftKeyDown() then
return _G.AceGUIMultiLineEditBoxInsertLink(GetLootSlotLink(this.slot))
end
end)
hooksecurefunc("SetItemRef",
function(link, text, button)
if IsShiftKeyDown() then
if strsub(link,1,6) == "player" then
local name = strsub(link,8)
if name and (strlen(name) > 0) then
return _G.AceGUIMultiLineEditBoxInsertLink(name)
end
else
return _G.AceGUIMultiLineEditBoxInsertLink(text)
end
end
end)
hooksecurefunc("MerchantItemButton_OnClick",
function(button, ignoreModifiers)
if MerchantFrame.selectedTab == 1 and button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIMultiLineEditBoxInsertLink(GetMerchantItemLink(this:GetID()))
end
end)
hooksecurefunc("PaperDollItemSlotButton_OnClick",
function(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIMultiLineEditBoxInsertLink(GetInventoryItemLink("player", this:GetID()))
end
end)
hooksecurefunc("QuestItem_OnClick",
function()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end)
hooksecurefunc("QuestRewardItem_OnClick",
function()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end)
hooksecurefunc("QuestLogTitleButton_OnClick",
function(button)
if IsShiftKeyDown() and (not this.isHeader) then
return _G.AceGUIMultiLineEditBoxInsertLink(gsub(this:GetText(), " *(.*)", "%1"))
end
end)
hooksecurefunc("QuestLogRewardItem_OnClick",
function()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestLogItemLink(this.type, this:GetID()))
end
end)
hooksecurefunc("SpellButton_OnClick",
function(drag)
local id = SpellBook_GetSpellID(this:GetID())
if id <= MAX_SPELLS and (not drag) and IsShiftKeyDown() then
local spellName, subSpellName = GetSpellName(id, SpellBookFrame.bookType)
if spellName and not IsSpellPassive(id, SpellBookFrame.bookType) then
if subSpellName and (strlen(subSpellName) > 0) then
_G.AceGUIMultiLineEditBoxInsertLink(spellName.."("..subSpellName..")");
else
_G.AceGUIMultiLineEditBoxInsertLink(spellName);
end
end
end
end)
end end
function _G.AceGUIMultiLineEditBoxInsertLink(text) function _G.AceGUIMultiLineEditBoxInsertLink(text)
for i = 1, AceGUI:GetWidgetCount(Type) do for i = 1, AceGUI:GetWidgetCount(Type) do
local editbox = _G[strfmt("MultiLineEditBox%uEdit",i)] local editbox = _G[("MultiLineEditBox%uEdit"):format(i)]
if editbox and editbox:IsVisible() and editbox.hasfocus then if editbox and editbox:IsVisible() and editbox:HasFocus() then
editbox:Insert(text) editbox:Insert(text)
return true return true
end end
end end
end end
local function Layout(self) local function Layout(self)
self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight) self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
@@ -144,116 +55,109 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function OnClick() -- Button local function OnClick(self) -- Button
local self = this.obj self = self.obj
self.editBox:ClearFocus() self.editBox:ClearFocus()
if not self:Fire("OnEnterPressed", 1, self.editBox:GetText()) then if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
self.button:Disable() self.button:Disable()
end end
end end
local function OnCursorChanged() -- EditBox local function OnCursorChanged(self, _, y, _, cursorHeight) -- EditBox
self, y = self.obj.scrollFrame, -y
local self, y = this.obj.scrollFrame, -arg2
local offset = self:GetVerticalScroll() local offset = self:GetVerticalScroll()
if y < offset then if y < offset then
self:SetVerticalScroll(y) self:SetVerticalScroll(y)
else else
y = y + arg4 - self:GetHeight() y = y + cursorHeight - self:GetHeight()
if y > offset then if y > offset then
self:SetVerticalScroll(y) self:SetVerticalScroll(y)
end end
end end
end end
local function OnEditFocusLost() -- EditBox local function OnEditFocusLost(self) -- EditBox
this.hasfocus = nil self:HighlightText(0, 0)
this:HighlightText(0, 0) self.obj:Fire("OnEditFocusLost")
this.obj:Fire("OnEditFocusLost")
end end
local function OnEnter() -- EditBox / ScrollFrame local function OnEnter(self) -- EditBox / ScrollFrame
local self = this.obj self = self.obj
if not self.entered then if not self.entered then
self.entered = true self.entered = true
self:Fire("OnEnter") self:Fire("OnEnter")
end end
end end
local function OnLeave() -- EditBox / ScrollFrame local function OnLeave(self) -- EditBox / ScrollFrame
local self = this.obj self = self.obj
if self.entered then if self.entered then
self.entered = nil self.entered = nil
self:Fire("OnLeave") self:Fire("OnLeave")
end end
end end
local function OnMouseUp() -- ScrollFrame local function OnMouseUp(self) -- ScrollFrame
local self = this.obj.editBox self = self.obj.editBox
self:SetFocus() self:SetFocus()
local n = self:GetNumLetters() self:SetCursorPosition(self:GetNumLetters())
self:HighlightText(n,n)
end end
local function OnReceiveDrag() -- EditBox / ScrollFrame local function OnReceiveDrag(self) -- EditBox / ScrollFrame
if not CursorHasItem() then return end local type, id, info = GetCursorInfo()
if type == "spell" then
info = GetSpellInfo(id, info)
elseif type ~= "item" then
return
end
ClearCursor() ClearCursor()
local self = this.obj self = self.obj
local editBox = self.editBox local editBox = self.editBox
if not this.hasfocus then if not editBox:HasFocus() then
this.hasfocus = true
editBox:SetFocus() editBox:SetFocus()
local n = editBox:GetNumLetters() editBox:SetCursorPosition(editBox:GetNumLetters())
editBox:HighlightText(n,n)
end end
editBox:Insert(info) editBox:Insert(info)
self.button:Enable() self.button:Enable()
end end
local function OnSizeChanged() -- ScrollFrame local function OnSizeChanged(self, width, height) -- ScrollFrame
this:UpdateScrollChildRect() self.obj.editBox:SetWidth(width)
this:SetVerticalScroll(this:GetHeight())
this.obj.editBox:SetWidth(arg1)
end end
local function OnTextChanged() -- EditBox local function OnTextChanged(self) -- EditBox
local self = this.obj self = self.obj
local value = this:GetText() local value = self.editBox:GetText()
if tostring(value) ~= tostring(self.lasttext) then if not self.lastText or value ~= self.lastText then
self:Fire("OnTextChanged", 1, value) self:Fire("OnTextChanged", value)
self.lasttext = value self.lastText = nil
self.button:Enable() self.button:Enable()
else
self.button:Disable()
self.lastText = value
end end
end end
local function OnTextSet() -- EditBox local function OnTextSet(self) -- EditBox
this:HighlightText(0, 0) self:HighlightText(0, 0)
this.obj.button:Disable() self:SetCursorPosition(self:GetNumLetters())
self:SetCursorPosition(0)
self.obj.button:Disable()
end end
local function OnVerticalScroll() -- ScrollFrame local function OnVerticalScroll(self, offset) -- ScrollFrame
local self = this.obj local editBox = self.obj.editBox
local editBox = self.editBox editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
editBox:SetHitRectInsets(0, 0, arg1, editBox:GetHeight() - arg1 - this:GetHeight())
self.scrollFrame:SetScrollChild(self.editBox)
self.editBox:SetPoint("TOPLEFT",0,arg1)
self.editBox:SetPoint("TOPRIGHT",0,arg1)
end end
local function OnShowFocus() local function OnShowFocus(frame)
this.obj.editBox:SetFocus() frame.obj.editBox:SetFocus()
this:SetScript("OnShow", nil) frame:SetScript("OnShow", nil)
end end
local function OnEditFocusGained() local function OnEditFocusGained(frame)
this.hasfocus = true AceGUI:SetFocus(frame.obj)
AceGUI:SetFocus(this.obj) frame.obj:Fire("OnEditFocusGained")
this.obj:Fire("OnEditFocusGained")
end
local function OnEscapePressed() -- EditBox
AceGUI:ClearFocus()
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -314,10 +218,8 @@ local methods = {
end, end,
["SetText"] = function(self, text) ["SetText"] = function(self, text)
self.lasttext = text or "" self.lastText = text
self.editBox:SetText(text or "") self.editBox:SetText(text)
self.editBox:HighlightText(0)
self.button:Disable()
end, end,
["GetText"] = function(self) ["GetText"] = function(self)
@@ -353,6 +255,16 @@ local methods = {
["HighlightText"] = function(self, from, to) ["HighlightText"] = function(self, from, to)
self.editBox:HighlightText(from, to) self.editBox:HighlightText(from, to)
end, end,
["GetCursorPosition"] = function(self)
return self.editBox:GetCursorPosition()
end,
["SetCursorPosition"] = function(self, ...)
return self.editBox:SetCursorPosition(...)
end,
} }
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -377,7 +289,7 @@ local function Constructor()
label:SetText(ACCEPT) label:SetText(ACCEPT)
label:SetHeight(10) label:SetHeight(10)
local button = CreateFrame("Button", strfmt("%s%dButton", Type, widgetNum), frame, "UIPanelButtonTemplate") local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, "UIPanelButtonTemplate2")
button:SetPoint("BOTTOMLEFT", 0, 4) button:SetPoint("BOTTOMLEFT", 0, 4)
button:SetHeight(22) button:SetHeight(22)
button:SetWidth(label:GetStringWidth() + 24) button:SetWidth(label:GetStringWidth() + 24)
@@ -396,7 +308,7 @@ local function Constructor()
scrollBG:SetBackdropColor(0, 0, 0) scrollBG:SetBackdropColor(0, 0, 0)
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4) scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
local scrollFrame = CreateFrame("ScrollFrame", strfmt("%s%dScrollFrame", Type, widgetNum), frame, "UIPanelScrollFrameTemplate") local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"] local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
scrollBar:ClearAllPoints() scrollBar:ClearAllPoints()
@@ -414,17 +326,10 @@ local function Constructor()
scrollFrame:SetScript("OnMouseUp", OnMouseUp) scrollFrame:SetScript("OnMouseUp", OnMouseUp)
scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag) scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged) scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
local old = scrollFrame:GetScript("OnVerticalScroll"); scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
if old then
scrollFrame:SetScript("OnVerticalScroll", function()
old()
OnVerticalScroll()
end)
else
scrollFrame:SetScript("OnVerticalScroll", OnVerticalScroll)
end
local editBox = CreateFrame("EditBox", strfmt("%s%dEdit", Type, widgetNum), scrollFrame) local editBox = CreateFrame("EditBox", ("%s%dEdit"):format(Type, widgetNum), scrollFrame)
editBox:SetAllPoints()
editBox:SetFontObject(ChatFontNormal) editBox:SetFontObject(ChatFontNormal)
editBox:SetMultiLine(true) editBox:SetMultiLine(true)
editBox:EnableMouse(true) editBox:EnableMouse(true)
@@ -432,7 +337,7 @@ local function Constructor()
editBox:SetScript("OnCursorChanged", OnCursorChanged) editBox:SetScript("OnCursorChanged", OnCursorChanged)
editBox:SetScript("OnEditFocusLost", OnEditFocusLost) editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
editBox:SetScript("OnEnter", OnEnter) editBox:SetScript("OnEnter", OnEnter)
editBox:SetScript("OnEscapePressed", OnEscapePressed) editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
editBox:SetScript("OnLeave", OnLeave) editBox:SetScript("OnLeave", OnLeave)
editBox:SetScript("OnMouseDown", OnReceiveDrag) editBox:SetScript("OnMouseDown", OnReceiveDrag)
editBox:SetScript("OnReceiveDrag", OnReceiveDrag) editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
@@ -440,10 +345,8 @@ local function Constructor()
editBox:SetScript("OnTextSet", OnTextSet) editBox:SetScript("OnTextSet", OnTextSet)
editBox:SetScript("OnEditFocusGained", OnEditFocusGained) editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
-- Ace3v: the orders are important here
scrollFrame:SetScrollChild(editBox) scrollFrame:SetScrollChild(editBox)
editBox:SetPoint("TOPLEFT",0,0)
editBox:SetPoint("TOPRIGHT",0,0)
local widget = { local widget = {
button = button, button = button,
@@ -2,13 +2,12 @@
Slider Widget Slider Widget
Graphical Slider, like, for Range values. Graphical Slider, like, for Range values.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Slider", 21 local Type, Version = "Slider", 20
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs -- Lua APIs
local min, max, floor = math.min, math.max, math.floor local min, max, floor = math.min, math.max, math.floor
local format, gsub = string.format, string.gsub
local tonumber, pairs = tonumber, pairs local tonumber, pairs = tonumber, pairs
-- WoW APIs -- WoW APIs
@@ -25,7 +24,7 @@ Support functions
local function UpdateText(self) local function UpdateText(self)
local value = self.value or 0 local value = self.value or 0
if self.ispercent then if self.ispercent then
self.editbox:SetText(format("%s%%", floor(value * 1000 + 0.5) / 10)) self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
else else
self.editbox:SetText(floor(value * 100 + 0.5) / 100) self.editbox:SetText(floor(value * 100 + 0.5) / 100)
end end
@@ -34,8 +33,8 @@ end
local function UpdateLabels(self) local function UpdateLabels(self)
local min, max = (self.min or 0), (self.max or 100) local min, max = (self.min or 0), (self.max or 100)
if self.ispercent then if self.ispercent then
self.lowtext:SetText(format("%s%%", (min * 100))) self.lowtext:SetFormattedText("%s%%", (min * 100))
self.hightext:SetText(format("%s%%", (max * 100))) self.hightext:SetFormattedText("%s%%", (max * 100))
else else
self.lowtext:SetText(min) self.lowtext:SetText(min)
self.hightext:SetText(max) self.hightext:SetText(max)
@@ -45,30 +44,26 @@ end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Scripts Scripts
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function Control_OnEnter() local function Control_OnEnter(frame)
this.obj:Fire("OnEnter") frame.obj:Fire("OnEnter")
end end
local function Control_OnLeave() local function Control_OnLeave(frame)
this.obj:Fire("OnLeave") frame.obj:Fire("OnLeave")
end end
local function Frame_OnMouseDown() local function Frame_OnMouseDown(frame)
this.obj.slider:EnableMouseWheel(true) frame.obj.slider:EnableMouseWheel(true)
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
local function Slider_OnValueChanged() local function Slider_OnValueChanged(frame)
local self = this.obj local self = frame.obj
if not this.setup then if not frame.setup then
local newvalue = this:GetValue() local newvalue = frame:GetValue()
if self.step and self.step > 0 then
local min_value = self.min or 0
newvalue = floor((newvalue - min_value) / self.step + 0.5) * self.step + min_value
end
if newvalue ~= self.value and not self.disabled then if newvalue ~= self.value and not self.disabled then
self.value = newvalue self.value = newvalue
self:Fire("OnValueChanged", 1, newvalue) self:Fire("OnValueChanged", newvalue)
end end
if self.value then if self.value then
UpdateText(self) UpdateText(self)
@@ -76,16 +71,16 @@ local function Slider_OnValueChanged()
end end
end end
local function Slider_OnMouseUp() local function Slider_OnMouseUp(frame)
local self = this.obj local self = frame.obj
self:Fire("OnMouseUp", 1, self.value) self:Fire("OnMouseUp", self.value)
end end
local function Slider_OnMouseWheel() local function Slider_OnMouseWheel(frame, v)
local self = this.obj local self = frame.obj
if not self.disabled then if not self.disabled then
local value = self.value local value = self.value
if arg1 > 0 then if v > 0 then
value = min(value + (self.step or 1), self.max) value = min(value + (self.step or 1), self.max)
else else
value = max(value - (self.step or 1), self.min) value = max(value - (self.step or 1), self.min)
@@ -94,15 +89,15 @@ local function Slider_OnMouseWheel()
end end
end end
local function EditBox_OnEscapePressed() local function EditBox_OnEscapePressed(frame)
this:ClearFocus() frame:ClearFocus()
end end
local function EditBox_OnEnterPressed() local function EditBox_OnEnterPressed(frame)
local self = this.obj local self = frame.obj
local value = this:GetText() local value = frame:GetText()
if self.ispercent then if self.ispercent then
value = gsub(value, '%%', '') value = value:gsub('%%', '')
value = tonumber(value) / 100 value = tonumber(value) / 100
else else
value = tonumber(value) value = tonumber(value)
@@ -111,16 +106,16 @@ local function EditBox_OnEnterPressed()
if value then if value then
PlaySound("igMainMenuOptionCheckBoxOn") PlaySound("igMainMenuOptionCheckBoxOn")
self.slider:SetValue(value) self.slider:SetValue(value)
self:Fire("OnMouseUp", 1, value) self:Fire("OnMouseUp", value)
end end
end end
local function EditBox_OnEnter() local function EditBox_OnEnter(frame)
this:SetBackdropBorderColor(0.5, 0.5, 0.5, 1) frame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
end end
local function EditBox_OnLeave() local function EditBox_OnLeave(frame)
this:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8) frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
end end
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
@@ -222,9 +217,9 @@ local function Constructor()
frame:SetScript("OnMouseDown", Frame_OnMouseDown) frame:SetScript("OnMouseDown", Frame_OnMouseDown)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
label:SetPoint("TOPLEFT",0,0) label:SetPoint("TOPLEFT")
label:SetPoint("TOPRIGHT",0,0) label:SetPoint("TOPRIGHT")
label:SetJustifyH("CENTER",0,0) label:SetJustifyH("CENTER")
label:SetHeight(15) label:SetHeight(15)
local slider = CreateFrame("Slider", nil, frame) local slider = CreateFrame("Slider", nil, frame)
+1 -1
View File
@@ -1 +1 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/"> <Include file="AceGUI-3.0\AceGUI-3.0.xml"/> <Include file="AceGUI-3.0\widgets\widgets.xml"/> <Include file="AceConfig-3.0\AceConfig-3.0.xml"/> <Include file="AceDBOptions-3.0\AceDBOptions-3.0.xml"/> <Include file="AceGUI-3.0-SharedMediaWidgets\widget.xml"/> </Ui> <Ui xmlns="http://www.blizzard.com/wow/ui/"> <Include file="AceGUI-3.0\AceGUI-3.0.xml"/> <Include file="AceConfig-3.0\AceConfig-3.0.xml"/> <Include file="AceDBOptions-3.0\AceDBOptions-3.0.xml"/> <Include file="AceGUI-3.0-SharedMediaWidgets\widget.xml"/> </Ui>