Merge pull request #45 from ElvUI-Vanilla/ace3

ace3
This commit is contained in:
Loaal
2018-07-22 16:36:10 +03:00
committed by GitHub
62 changed files with 1963 additions and 1918 deletions
+75 -1
View File
@@ -7,7 +7,7 @@ local select = select
local tonumber = tonumber
local type = type
local unpack = unpack
local find, format, gmatch, gsub, lower, match, upper = string.find, string.format, string.gmatch, string.gsub, string.lower, string.match, string.upper
local find, format, gmatch, gsub, len, lower, match, upper, sub = string.find, string.format, string.gmatch, string.gsub, string.len, string.lower, string.match, string.upper, string.sub
local getn = table.getn
--WoW API
local debugstack = debugstack
@@ -412,6 +412,80 @@ function CreateStatusBarTexturePointer(statusbar)
return f
end
local function removeScript(self, script)
local func = self:GetScript(script)
if func then
self:SetScript(script, nil)
end
return func
end
local nbsp = string.char(255)
function EditBoxGetCursorPosition(self)
if self == WowLuaFrameEditBox or self == WowLuaFrameCommandEditBox then return 0 end
if self:GetText() == "" then return 0 end
local occ = removeScript(self, "OnCursorChanged")
local otc = removeScript(self, "OnTextChanged")
local ots = removeScript(self, "OnTextSet")
self:Insert(nbsp)
local pos = find(self:GetText(), nbsp)
if not pos then
pos = len(self:GetText())
print(format("CursorPosition position for `%s` not found!", self.GetName and self:GetName() or tostring(self)))
else
self:HighlightText(pos - 1, pos)
self:Insert("")
end
if occ then self:SetScript("OnCursorChanged", occ) end
if otc then self:SetScript("OnTextChanged", otc) end
if ots then self:SetScript("OnTextSet", ots) end
return pos - 1
end
function EditBoxSetCursorPosition(self, pos)
if self == WowLuaFrameEditBox or self == WowLuaFrameCommandEditBox then return end
if self:GetText() == "" then return end
local occ = removeScript(self, "OnCursorChanged")
local otc = removeScript(self, "OnTextChanged")
local ots = removeScript(self, "OnTextSet")
local text = self:GetText()
local size = len(text)
if pos < 0 then
pos = 0
elseif pos > size then
pos = size
end
if pos == 0 then
text = sub(text, 0, 1)
self:HighlightText(0, 1)
self:Insert(nbsp)
self:Insert(text)
self:HighlightText(0, 1)
self:Insert("")
else
text = sub(text, pos, pos)
self:HighlightText(pos - 1, pos)
self:Insert(text)
end
if occ then self:SetScript("OnCursorChanged", occ) end
if otc then self:SetScript("OnTextChanged", otc) end
if ots then self:SetScript("OnTextSet", ots) end
end
local threatColors = {
[0] = {0.69, 0.69, 0.69},
[1] = {1, 1, 0.47},
+1 -1
View File
@@ -590,8 +590,8 @@ function ScriptErrorsFrame_Update ()
editBox.text = text;
if (prevText ~= text) then
editBox:SetText(text);
EditBoxSetCursorPosition(editBox, 0);
editBox:HighlightText(0);
-- editBox:SetCursorPosition(0);
else
ScriptErrorsFrameScrollFrame:UpdateScrollChildRect();
end
+1 -1
View File
@@ -114,7 +114,7 @@ function E:DelayScriptCall(msg)
self:Print("usage: /in <seconds> <command>")
self:Print("example: /in 1.5 /say hi")
else
E:ScheduleTimer(OnCallback, secs, 1, command)
E:ScheduleTimer(OnCallback, secs, command)
end
end
+108 -104
View File
@@ -35,10 +35,6 @@ local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
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.addons = AceAddon.addons or {} -- addons in general
AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
@@ -47,8 +43,8 @@ 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
-- Lua APIs
local tinsert, tconcat, tremove, tgetn = table.insert, table.concat, table.remove, table.getn
local strfmt, tostring = string.format, tostring
local tinsert, tconcat, tremove, getn = table.insert, table.concat, table.remove, table.getn
local fmt, gsub, tostring = string.format, string.gsub, tostring
local pairs, next, type, unpack = pairs, next, type, unpack
local loadstring, assert, error = loadstring, assert, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
@@ -60,7 +56,51 @@ local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, r
--[[
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 = xpcall, function(err) return geterrorhandler()(err) end
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = gsub(code,"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[arg.n](func, unpack(arg))
end
end
-- local functions that will be implemented further down
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
local function queuedForInitialization(addon)
for i = 1, tgetn(AceAddon.initializequeue) do
for i = 1, getn(AceAddon.initializequeue) do
if AceAddon.initializequeue[i] == addon then
return true
end
@@ -93,34 +133,23 @@ end
-- -- Create a Addon object based on the table of a frame
-- local MyFrame = CreateFrame("Frame")
-- 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 i=1
if type(objectorname)=="table" then
object=objectorname
name=a0
name=arg[1]
i=2
else
name=objectorname
end
if type(name)~="string" then
error(strfmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2)
error(fmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2)
end
if self.addons[name] then
error(strfmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists.", name), 2)
error(fmt("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists.", name), 2)
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.name = name
@@ -137,18 +166,20 @@ function AceAddon:NewAddon(objectorname,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
object.orderedModules = {}
object.defaultModuleLibraries = {}
Embed( object ) -- embed NewModule, GetModule methods
if type(objectorname)=="table" then
self:EmbedLibraries(object,nil,args)
elseif a0 then
self:EmbedLibraries(object,a0,args)
if i == 1 then
self:EmbedLibraries(object, unpack(arg))
else
table.remove(arg, 1)
self:EmbedLibraries(object, unpack(arg))
end
del(args)
-- add to queue of addons to be initialized upon ADDON_LOADED
tinsert(self.initializequeue, object)
return object
end
--- 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).
-- @param name unique name of the addon object
@@ -158,7 +189,7 @@ end
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
function AceAddon:GetAddon(name, silent)
if not silent and not self.addons[name] then
error(strfmt("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'.", tostring(name)), 2)
error(fmt("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'.", tostring(name)), 2)
end
return self.addons[name]
end
@@ -171,12 +202,10 @@ end
-- @paramsig addon, [lib, ...]
-- @param addon addon object to embed the libs in
-- @param lib List of libraries to embed into the addon
function AceAddon:EmbedLibraries(addon,a1,arg)
if a1 then self:EmbedLibrary(addon, a1, false, 4) end
-- 10 is the max number of variable arguments in the function NewAddon and NewModule
for i=1,10 do
if not arg[i] then return end
self:EmbedLibrary(addon, arg[i], false, 4)
function AceAddon:EmbedLibraries(addon, ...)
for i=1,arg.n do
local libname = arg[i]
self:EmbedLibrary(addon, libname, false, 4)
end
end
@@ -194,13 +223,13 @@ end
function AceAddon:EmbedLibrary(addon, libname, silent, offset)
local lib = LibStub:GetLibrary(libname, true)
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(fmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q.", tostring(libname)), offset or 2)
elseif lib and type(lib.Embed) == "function" then
lib:Embed(addon)
tinsert(self.embeds[addon], libname)
return true
elseif lib then
error(strfmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable", libname), offset or 2)
error(fmt("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable", libname), offset or 2)
end
end
@@ -217,7 +246,7 @@ end
-- MyModule = MyAddon:GetModule("MyModule")
function GetModule(self, name, silent)
if not self.modules[name] and not silent then
error(strfmt("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'.", tostring(name)), 2)
error(fmt("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'.", tostring(name)), 2)
end
return self.modules[name]
end
@@ -240,39 +269,26 @@ local function IsModuleTrue(self) return true end
-- -- Create a module with a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- 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)
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(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
function NewModule(self, name, prototype, ...)
if type(name) ~= "string" then error(fmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'.", type(name)), 2) end
if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(fmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'.", 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(fmt("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists.", name), 2) end
-- 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.
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:SetEnabledState(self.defaultModuleState)
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
AceAddon:EmbedLibraries(module, prototype, args)
AceAddon:EmbedLibraries(module, prototype, unpack(arg))
else
AceAddon:EmbedLibraries(module, nil, args)
AceAddon:EmbedLibraries(module, unpack(arg))
end
del(args)
AceAddon:EmbedLibraries(module, nil, self.defaultModuleLibraries)
AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
if not prototype or type(prototype) == "string" then
prototype = self.defaultModulePrototype or nil
@@ -284,7 +300,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.
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
tinsert(self.orderedModules, module)
@@ -385,23 +401,11 @@ end
-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
-- -- Create a module
-- 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
error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
end
local args = self.defaultModuleLibraries or {}
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
self.defaultModuleLibraries = arg
end
--- Set the default state in which new modules are being created.
@@ -444,7 +448,7 @@ function SetDefaultModulePrototype(self, prototype)
error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
end
if type(prototype) ~= "table" then
error(strfmt("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'.", type(prototype)), 2)
error(fmt("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'.", type(prototype)), 2)
end
self.defaultModulePrototype = prototype
end
@@ -528,12 +532,12 @@ end
-- **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
function AceAddon:InitializeAddon(addon)
safecall(addon.OnInitialize, 1, addon)
safecall(addon.OnInitialize, addon)
local embeds = self.embeds[addon]
for i = 1, tgetn(embeds) do
for i = 1, getn(embeds) do
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
-- we don't call InitializeAddon on modules specifically, this is handled
@@ -557,19 +561,19 @@ function AceAddon:EnableAddon(addon)
-- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
self.statuses[addon.name] = true
safecall(addon.OnEnable, 1, addon)
safecall(addon.OnEnable, addon)
-- make sure we're still enabled before continueing
if self.statuses[addon.name] then
local embeds = self.embeds[addon]
for i = 1, tgetn(embeds) do
for i = 1, getn(embeds) do
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
-- enable possible modules.
local modules = addon.orderedModules
for i = 1, tgetn(modules) do
for i = 1, getn(modules) do
self:EnableAddon(modules[i])
end
end
@@ -592,18 +596,18 @@ function AceAddon:DisableAddon(addon)
-- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
self.statuses[addon.name] = false
safecall(addon.OnDisable, 1, addon)
safecall( addon.OnDisable, addon )
-- make sure we're still disabling...
if not self.statuses[addon.name] then
local embeds = self.embeds[addon]
for i = 1, tgetn(embeds) do
for i = 1, getn(embeds) do
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
-- disable possible modules.
local modules = addon.orderedModules
for i = 1, tgetn(modules) do
for i = 1, getn(modules) do
self:DisableAddon(modules[i])
end
end
@@ -634,22 +638,13 @@ function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
local onEvent
do
local IsLoggedIn = false
-- Event Handling
function onEvent()
-- 2011-08-17 nevcairiel - ignore the load event of Blizzard_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
-- 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
local IsLoggedIn
local function onEvent()
-- 2011-08-17 nevcairiel - ignore the load event of !DebugTools, so a potential startup error isn't swallowed up
if (event == "ADDON_LOADED" and arg1 ~= "!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
-- Ace3v: When an Ace3 addons is loaded, then he initializeque should not be empty unless
-- 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
while(getn(AceAddon.initializequeue) > 0) do
local addon = tremove(AceAddon.initializequeue, 1)
-- this might be an issue with recursion - TODO: validate
if event == "ADDON_LOADED" then addon.baseName = arg1 end
@@ -662,14 +657,13 @@ function onEvent()
end
if IsLoggedIn then
while(tgetn(AceAddon.enablequeue) > 0) do
while(getn(AceAddon.enablequeue) > 0) do
local addon = tremove(AceAddon.enablequeue, 1)
AceAddon:EnableAddon(addon)
end
end
end
end
end -- onEvent
AceAddon.frame:RegisterEvent("ADDON_LOADED")
AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
@@ -679,3 +673,13 @@ AceAddon.frame:SetScript("OnEvent", onEvent)
for name, addon in pairs(AceAddon.addons) do
Embed(addon, true)
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"/>
</Ui>
+67 -65
View File
@@ -9,7 +9,7 @@
-- make into AceComm.
-- @class file
-- @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
@@ -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)
if not AceComm then return end
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib")
-- Lua APIs
local type, next, pairs, tostring = type, next, pairs, tostring
local strlen, strsub, strfind = string.len, string.sub, string.find
local tinsert, tconcat, tgetn, tremove = table.insert, table.concat, table.getn, table.remove
local type, next, pairs, tostring, unpack = type, next, pairs, tostring, unpack
local strsub, strfind, strlen = string.sub, string.find, string.len
local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
local error, assert = error, assert
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- 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 {}
@@ -43,27 +41,21 @@ AceComm.embeds = AceComm.embeds or {}
local MSG_MULTI_FIRST = "\001"
local MSG_MULTI_NEXT = "\002"
local MSG_MULTI_LAST = "\003"
local MSG_ESCAPE = "\004"
-- remove old structures (pre WoW 4.0)
AceComm.multipart_origprefixes = nil
AceComm.multipart_reassemblers = nil
AceComm.multipart_origprefixes = AceComm.multipart_origprefixes or {} -- e.g. "Prefix\001"="Prefix", "Prefix\002"="Prefix"
AceComm.multipart_reassemblers = AceComm.multipart_reassemblers or {} -- e.g. "Prefix\001"="OnReceiveMultipartFirst"
-- the multipart message spool: indexed by a combination of sender+distribution+
AceComm.multipart_spool = AceComm.multipart_spool or {}
--- 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"
function AceComm:RegisterComm(prefix, method)
if method == nil then
method = "OnCommReceived"
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
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)
end
if strfind(prefix, "[\001-\009]") then
if strfind(prefix, "[\001-\003]") then
error("SendCommMessage: Characters \\001--\\003 in prefix are reserved for AceComm metadata", 2)
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 = strlen(text)
-- Yes, the max is 255 even if the dev post said 256. I tested. Char 256+ get silently truncated. /Mikk, 20110327
-- Ace3v: substract the prefix length
local maxtextlen = 254 - strlen(prefix)
local maxtextlen = 254 - strlen(prefix) -- 254 is the max length of prefix + text that can be sent in one message
local queueName = prefix..distribution..(target or "")
local ctlCallback = nil
@@ -101,38 +102,29 @@ function AceComm:SendCommMessage(prefix, text, distribution, target, prio, callb
end
end
local forceMultipart
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
if textlen <= maxtextlen then
-- fits all in one message
CTL:SendAddonMessage(prio, prefix, text, distribution, target, queueName, ctlCallback, textlen)
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
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
local pos = 1+maxtextlen
local prefix2 = prefix..MSG_MULTI_NEXT
while pos+maxtextlen <= textlen do
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
end
-- final part
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
@@ -147,8 +139,8 @@ do
local t = next(compost)
if t then
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
tremove(t) -- Ace3v: t[i] = nil wont affect the tgetn return value
for i=getn(t),3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten
tremove(t, i)
end
return t
end
@@ -210,11 +202,11 @@ do
if type(olddata) == "table" then
-- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat
tinsert(olddata, message)
AceComm.callbacks:Fire(prefix, 3, tconcat(olddata, ""), distribution, sender)
AceComm.callbacks:Fire(prefix, tconcat(olddata, ""), distribution, sender)
compost[olddata] = true
else
-- 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
@@ -229,40 +221,50 @@ end
----------------------------------------
if not AceComm.callbacks then
-- ensure that 'prefix to watch' table is consistent with registered
-- callbacks
AceComm.__prefixes = {}
AceComm.callbacks = CallbackHandler:New(AceComm,
"_RegisterComm",
"UnregisterComm",
"UnregisterAllComm")
end
AceComm.callbacks.OnUsed = nil
AceComm.callbacks.OnUnused = nil
function AceComm.callbacks:OnUsed(target, prefix)
AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = prefix
AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = "OnReceiveMultipartFirst"
AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = prefix
AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = "OnReceiveMultipartNext"
AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = prefix
AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = "OnReceiveMultipartLast"
end
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
-- Ace3v: in vanilla, global vars:
-- event -> event type
-- arg1 -> prefix
-- arg2 -> message
-- arg3 -> channel
-- arg4 -> sender
local function OnEvent()
local prefix, message, distribution, sender = arg1, arg2, arg3, arg4
if event == "CHAT_MSG_ADDON" then
local _, _, control, rest = strfind(message, "^([\001-\009])(.*)")
if control then
if control==MSG_MULTI_FIRST then
AceComm:OnReceiveMultipartFirst(prefix, rest, distribution, sender)
elseif control==MSG_MULTI_NEXT then
AceComm:OnReceiveMultipartNext(prefix, rest, distribution, sender)
elseif control==MSG_MULTI_LAST then
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
local prefix,message,distribution,sender = unpack(arg)
local reassemblername = AceComm.multipart_reassemblers[prefix]
if reassemblername then
-- multipart: reassemble
local aceCommReassemblerFunc = AceComm[reassemblername]
local origprefix = AceComm.multipart_origprefixes[prefix]
aceCommReassemblerFunc(AceComm, origprefix, message, distribution, sender)
else
-- 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
else
assert(false, "Received "..tostring(event).." event?!")
@@ -303,4 +305,4 @@ end
-- Update embeds
for target, v in pairs(AceComm.embeds) do
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="AceComm-3.0.lua"/>
</Ui>
+33 -56
View File
@@ -20,15 +20,10 @@
--
-- 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 = AceCore._G
local hooksecurefunc = AceCore.hooksecurefunc
local wipe = AceCore.wipe
local _G = _G
if _G.ChatThrottleLib then
if _G.ChatThrottleLib.version >= CTL_VERSION then
@@ -69,8 +64,8 @@ ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) i
local setmetatable = setmetatable
local table_insert = table.insert
local table_remove = table.remove
local tinsert = table.insert
local tostring = tostring
local GetTime = GetTime
local math_min = math.min
@@ -78,9 +73,7 @@ local math_max = math.max
local next = next
local strlen = string.len
local GetFramerate = GetFramerate
local strlower = string.lower
local unpack,type,pairs,wipe = unpack,type,pairs,wipe
local UnitInRaid,UnitInParty = UnitInRaid,UnitInParty
-----------------------------------------------------------------------
@@ -123,20 +116,24 @@ end
-----------------------------------------------------------------------
-- Recycling bin for pipes
-- A pipe is a plain integer-indexed queue of messages
-- Pipes normally live in Rings of pipes (3 rings total, one per priority)
-- A pipe is a plain integer-indexed queue, which also happens to be a ring member
ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different
local PipeBin = setmetatable({}, {__mode="k"})
local function DelPipe(pipe)
for i = getn(pipe), 1, -1 do
pipe[i] = nil
end
pipe.prev = nil
pipe.next = nil
PipeBin[pipe] = true
end
local function NewPipe()
local pipe = next(PipeBin)
if pipe then
wipe(pipe)
PipeBin[pipe] = nil
return pipe
end
@@ -230,7 +227,7 @@ end
local bMyTraffic = false
function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination)
function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...)
if bMyTraffic then
return
end
@@ -239,7 +236,7 @@ function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destinat
self.avail = self.avail - size
self.nBypass = self.nBypass + size -- just a statistic
end
function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination)
function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...)
if bMyTraffic then
return
end
@@ -266,7 +263,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
avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5)
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)
self.bChoking = true -- just a statistic
else
@@ -285,16 +282,12 @@ end
-----------------------------------------------------------------------
-- 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)
local ring = Prio.Ring
while ring.pos and Prio.avail > ring.pos[1].nSize do
local msg = table_remove(ring.pos, 1)
if not ring.pos[1] then -- did we remove last msg in this pipe?
local msg = table_remove(Prio.Ring.pos, 1)
if not Prio.Ring.pos[1] then
local pipe = Prio.Ring.pos
Prio.Ring:Remove(pipe)
Prio.ByName[pipe.name] = nil
@@ -302,26 +295,15 @@ function ChatThrottleLib:Despool(Prio)
else
Prio.Ring.pos = Prio.Ring.pos.next
end
local didSend=false
local lowerDest = strlower(msg[3] or "")
if lowerDest == "raid" and not UnitInRaid("player") then
-- do nothing
elseif lowerDest == "party" and not UnitInParty("player") then
-- do nothing
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)
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)
if msg.callbackFn then
msg.callbackFn (msg.callbackArg, didSend)
msg.callbackFn (msg.callbackArg)
end
-- USER CALLBACK MAY ERROR
end
end
@@ -393,6 +375,7 @@ end
-----------------------------------------------------------------------
-- Spooling logic
function ChatThrottleLib:Enqueue(prioname, pipename, msg)
local Prio = self.Prio[prioname]
local pipe = Prio.ByName[pipename]
@@ -404,11 +387,13 @@ function ChatThrottleLib:Enqueue(prioname, pipename, msg)
Prio.Ring:Add(pipe)
end
tinsert(pipe,msg)
table_insert(pipe, msg)
self.bQueueing = true
end
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
error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2)
@@ -433,9 +418,8 @@ function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, languag
bMyTraffic = false
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
if callbackFn then
callbackFn (callbackArg, true)
callbackFn (callbackArg)
end
-- USER CALLBACK MAY ERROR
return
end
@@ -463,17 +447,10 @@ function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target,
error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
end
local nSize = strlen(text);
local nSize = strlen(prefix) + 1 + strlen(text);
if RegisterAddonMessagePrefix then
if nSize>255 then
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
if nSize>255 then
error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2)
end
nSize = nSize + self.MSG_OVERHEAD;
@@ -486,9 +463,8 @@ function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target,
bMyTraffic = false
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
if callbackFn then
callbackFn (callbackArg, true)
callbackFn (callbackArg)
end
-- USER CALLBACK MAY ERROR
return
end
@@ -525,3 +501,4 @@ if(WOWB_VER) then
end
]]
@@ -16,49 +16,36 @@ local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
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.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
-- Lua APIs
local tinsert, tconcat, tgetn, tsetn = table.insert, table.concat, table.getn, table.setn
local tostring = tostring
local tconcat, tostring = table.concat, tostring
local type, pairs, error = type, pairs, error
local format, strfind, strsub = string.format, string.find, string.sub
local format, strfind, strsub, upper, lower = string.format, string.find, string.sub, string.upper, string.lower
local max = math.max
local strupper, strlower = string.upper, string.lower
-- WoW APIs
local _G = AceCore._G
local _G = _G
-- 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, SlashCmdList, hash_SlashCmdList
local Print
do
local tmp = {}
function Print(self, frame, arg)
local tmp={}
local function Print(self,frame,...)
local n=0
if self ~= AceConsole then
tmp[1] = "|cff33ff99"..tostring(self).."|r:"
else
tmp[1] = ''
n=n+1
tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
end
if type(arg) == "string" then
frame:AddMessage(tmp[1]..arg)
else -- arg is table and may contain frame as first element if argument frame is nil
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
for i=1, arg.n do
n=n+1
tmp[n] = tostring(arg[i])
end
frame:AddMessage( tconcat(tmp," ",1,n) )
end
end -- Print
--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] ...
@@ -67,59 +54,50 @@ end -- Print
function AceConsole:Print(...)
local frame = arg[1]
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
return Print(self, nil, arg)
return Print(self, unpack(arg))
else
return Print(self, DEFAULT_CHAT_FRAME, arg)
return Print(self, DEFAULT_CHAT_FRAME, unpack(arg))
end
end
--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
-- @paramsig [chatframe ,] "format"[, ...]
-- @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 ... Arguments to the format string
function AceConsole:Printf(a1, ...)
local frame, succ, s
if type(a1) == "table" and a1.AddMessage then -- Is first argument something with an .AddMessage member?
frame, succ, s = a1, pcall(format, unpack(arg))
function AceConsole:Printf(...)
local frame = arg[1]
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
tremove(arg, 1)
return Print(self, frame, format(unpack(arg)))
else
frame, succ, s = DEFAULT_CHAT_FRAME, pcall(format, a1, unpack(arg))
return Print(self, DEFAULT_CHAT_FRAME, format(unpack(arg)))
end
if not succ then error(s,2) end
return Print(self, frame, s)
end
--- Register a simple chat command
-- @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 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 )
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
local name = "ACECONSOLE_"..strupper(command)
local name = "ACECONSOLE_"..upper(command)
local t = type(func)
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
if type( func ) == "string" then
SlashCmdList[name] = function(input, editBox)
self[func](self, input, editBox)
end
elseif t == "function" then
SlashCmdList[name] = func
else
error([[Usage: AceConsole:RegisterChatCommand(command, func[, persist ]): 'func' - expected a string or a function]], 2)
SlashCmdList[name] = func
end
_G["SLASH_"..name.."1"] = "/"..strlower(command)
_G["SLASH_"..name.."1"] = "/"..lower(command)
AceConsole.commands[command] = name
-- non-persisting commands are registered for enabling disabling
if not persist then
@@ -136,6 +114,7 @@ function AceConsole:UnregisterChatCommand( command )
if name then
SlashCmdList[name] = nil
_G["SLASH_" .. name .. "1"] = nil
hash_SlashCmdList["/" .. upper(command)] = nil
AceConsole.commands[command] = nil
end
end
@@ -144,16 +123,18 @@ end
-- @return Iterator (pairs) over all commands
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
return nil, nils(n-1,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
elseif not argc or argc == 0 then
return
local function nils(n, ...)
if n>1 then
return nil, nils(n-1, unpack(arg))
elseif n==1 then
return nil, unpack(arg)
else
return a1, nils(0,argc-1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
return unpack(arg)
end
end
--- Retreive one or more space-separated arguments from a string.
-- Treats quoted strings and itemlinks as non-spaced.
-- @param str The raw argument string
@@ -170,7 +151,7 @@ function AceConsole:GetArgs(str, numargs, startpos)
-- find start of new arg
pos = strfind(str, "[^ ]", pos)
if not pos then -- whoops, end of string
return nils(numargs, 1, 1e9)
return nils(numargs, 1e9)
end
if numargs<1 then
@@ -225,7 +206,7 @@ function AceConsole:GetArgs(str, numargs, startpos)
end
-- 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
@@ -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"/>
</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>
+43 -50
View File
@@ -40,22 +40,19 @@
-- end
-- @class file
-- @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, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
if not AceDB then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
-- Lua APIs
local type, pairs, next, error = type, pairs, next, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
local format, lower = string.format, string.lower
local format = string.format
-- WoW APIs
local _G = AceCore._G
local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
@@ -69,13 +66,6 @@ local CallbackDummy = { Fire = function() end }
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
---------------------------------------------------------------------------]]
@@ -220,35 +210,36 @@ end
-- Metatable to handle the dynamic creation of sections and copying of sections.
local dbmt = {
__index = function(t, section)
local keys = rawget(t, "keys")
local key = keys[section]
if key then
local defaultTbl = rawget(t, "defaults")
local defaults = defaultTbl and defaultTbl[section]
local keys = rawget(t, "keys")
local key = keys[section]
if key then
local defaultTbl = rawget(t, "defaults")
local defaults = defaultTbl and defaultTbl[section]
if section == "profile" then
if initSection(t, section, "profiles", key, defaults) then
-- Callback: OnNewProfile, database, newProfileKey
t.callbacks:Fire("OnNewProfile", 2, t, key)
if section == "profile" then
local new = initSection(t, section, "profiles", key, defaults)
if new then
-- 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
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
return rawget(t, section)
end
return rawget(t, section)
end
}
local function validateDefaults(defaults, keyTbl, offset)
@@ -273,10 +264,11 @@ local realmKey = GetRealmName()
local charKey = UnitName("player") .. " - " .. realmKey
local _, classKey = UnitClass("player")
local _, raceKey = UnitRace("player")
local _, factionKey = UnitFactionGroup("player")
-- Ace3v: the faction key may error when in GM mode
local factionKey = UnitFactionGroup("player")
factionKey = factionKey or "Others"
local localeKey = lower(GetLocale())
local factionrealmKey = factionKey .. " - " .. realmKey
local factionrealmregionKey = factionrealmKey .. " - " .. string.upper(string.sub(GetCVar("realmList"), 1, 2))
local localeKey = string.lower(GetLocale())
-- Actual database initialization function
local function initdb(sv, defaults, defaultProfile, olddb, parent)
@@ -312,7 +304,8 @@ local function initdb(sv, defaults, defaultProfile, olddb, parent)
["class"] = classKey,
["race"] = raceKey,
["faction"] = factionKey,
["factionrealm"] = factionKey .. " - " .. realmKey,
["factionrealm"] = factionrealmKey,
["factionrealmregion"] = factionrealmregionKey,
["profile"] = profileKey,
["locale"] = localeKey,
["global"] = true,
@@ -369,7 +362,7 @@ end
local function logoutHandler()
if event == "PLAYER_LOGOUT" then
for db in pairs(AceDB.db_registry) do
db.callbacks:Fire("OnDatabaseShutdown", 1, db)
db.callbacks:Fire("OnDatabaseShutdown", db)
db:RegisterDefaults(nil)
-- cleanup sections that are empty without defaults
@@ -449,7 +442,7 @@ function DBObjectLib:SetProfile(name)
local defaults = self.defaults and self.defaults.profile
-- Callback: OnProfileShutdown, database
self.callbacks:Fire("OnProfileShutdown", 1, self)
self.callbacks:Fire("OnProfileShutdown", self)
if oldProfile and defaults then
-- Remove the defaults from the old profile
@@ -473,7 +466,7 @@ function DBObjectLib:SetProfile(name)
end
-- Callback: OnProfileChanged, database, newProfileKey
self.callbacks:Fire("OnProfileChanged", 2, self, name)
self.callbacks:Fire("OnProfileChanged", self, name)
end
--- Returns a table with the names of the existing profiles in the database.
@@ -549,7 +542,7 @@ function DBObjectLib:DeleteProfile(name, silent)
end
-- Callback: OnProfileDeleted, database, profileKey
self.callbacks:Fire("OnProfileDeleted", 2, self, name)
self.callbacks:Fire("OnProfileDeleted", self, name)
end
--- Copies a named profile into the current profile, overwriting any conflicting
@@ -585,7 +578,7 @@ function DBObjectLib:CopyProfile(name, silent)
end
-- Callback: OnProfileCopied, database, sourceProfileKey
self.callbacks:Fire("OnProfileCopied", 2, self, name)
self.callbacks:Fire("OnProfileCopied", self, name)
end
--- Resets the current profile to the default values (if specified).
@@ -612,7 +605,7 @@ function DBObjectLib:ResetProfile(noChildren, noCallbacks)
-- Callback: OnProfileReset, database
if not noCallbacks then
self.callbacks:Fire("OnProfileReset", 2, self, self.keys["profile"])
self.callbacks:Fire("OnProfileReset", self)
end
end
@@ -643,9 +636,9 @@ function DBObjectLib:ResetDB(defaultProfile)
end
-- Callback: OnDatabaseReset, database
self.callbacks:Fire("OnDatabaseReset", 1, self)
self.callbacks:Fire("OnDatabaseReset", self)
-- Callback: OnProfileChanged, database, profileKey
self.callbacks:Fire("OnProfileChanged", 2, self, self.keys["profile"])
self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
return self
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"/>
</Ui>
+8 -11
View File
@@ -2,7 +2,7 @@
-- 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.
--
-- **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
-- 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
@@ -10,7 +10,9 @@
-- @class file
-- @name AceEvent-3.0
-- @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)
if not AceEvent then return end
@@ -18,29 +20,27 @@ if not AceEvent then return end
-- Lua APIs
local pairs = pairs
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
-- APIs and registry for blizzard events, using CallbackHandler lib
if not AceEvent.events then
AceEvent.events = CallbackHandler:New(AceEvent,
AceEvent.events = CallbackHandler:New(AceEvent,
"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
end
function AceEvent.events:OnUsed(target, eventname)
function AceEvent.events:OnUsed(target, eventname)
AceEvent.frame:RegisterEvent(eventname)
end
function AceEvent.events:OnUnused(target, eventname)
function AceEvent.events:OnUnused(target, eventname)
AceEvent.frame:UnregisterEvent(eventname)
end
-- APIs and registry for IPC messages, using CallbackHandler lib
if not AceEvent.messages then
AceEvent.messages = CallbackHandler:New(AceEvent,
AceEvent.messages = CallbackHandler:New(AceEvent,
"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
)
AceEvent.SendMessage = AceEvent.messages.Fire
@@ -115,9 +115,6 @@ function AceEvent:OnEmbedDisable(target)
end
-- 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
AceEvent.frame:SetScript("OnEvent", function()
events:Fire(event)
@@ -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"/>
</Ui>
+18 -46
View File
@@ -15,9 +15,6 @@ local AceHook, oldminor = LibStub:NewLibrary(ACEHOOK_MAJOR, ACEHOOK_MINOR)
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.registry = AceHook.registry or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end })
AceHook.handlers = AceHook.handlers or {}
@@ -34,14 +31,17 @@ local scripts = AceHook.scripts
local onceSecure = AceHook.onceSecure
-- Lua APIs
local pairs, next, type = pairs, next, type
local pairs, next, type, unpack = pairs, next, type, unpack
local format = string.format
local assert, error = assert, error
-- WoW APIs
local hooksecurefunc, issecurevariable = AceCore.hooksecurefunc, AceCore.issecurevariable
local HookScript = HookScript
local issecurevariable, hooksecurefunc = issecurevariable, hooksecurefunc
local _G = _G
local _G = AceCore._G
-- functions for later definition
local donothing, createHook, hook
local protectedScripts = {
OnClick = true,
@@ -80,20 +80,15 @@ function AceHook:OnEmbedDisable( target )
target:UnhookAll()
end
-- failsafe means even the hooking method fails, the original method will
-- always be called
local function createHook(self, handler, orig, secure, failsafe)
function createHook(self, handler, orig, secure, failsafe)
local uid
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
-- failsafe hook creation
uid = function(...)
if actives[uid] then
if method then
self[handler](self,unpack(arg))
self[handler](self, unpack(arg))
else
handler(unpack(arg))
end
@@ -106,7 +101,7 @@ local function createHook(self, handler, orig, secure, failsafe)
uid = function(...)
if actives[uid] then
if method then
return self[handler](self,unpack(arg))
return self[handler](self, unpack(arg))
else
return handler(unpack(arg))
end
@@ -119,18 +114,9 @@ local function createHook(self, handler, orig, secure, failsafe)
return uid
end
local function donothing() end
function donothing() end
-- @param self
-- @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)
function hook(self, obj, method, handler, script, secure, raw, forceSecure, usage)
if not handler then handler = method end
-- These asserts make sure AceHooks's devs play by the rules.
@@ -215,7 +201,6 @@ local function hook(self, obj, method, handler, script, secure, raw, forceSecure
local orig
if script then
-- Sometimes there is not a original function for a script.
orig = obj:GetScript(method) or donothing
elseif obj then
orig = obj[method]
@@ -230,11 +215,11 @@ local function hook(self, obj, method, handler, script, secure, raw, forceSecure
uid = createHook(self, handler, orig, secure, not (raw or secure))
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
if not secure then
self.hooks[obj] = self.hooks[obj] or new()
self.hooks[obj][method] = orig
end
@@ -242,12 +227,7 @@ local function hook(self, obj, method, handler, script, secure, raw, forceSecure
if not secure then
obj:SetScript(method, uid)
else
obj:SetScript(method, function(...)
local tmp = {orig(unpack(arg))}
uid(unpack(arg))
return unpack(tmp)
end)
--obj:HookScript(method, uid) -- Ace3v: vanilla frame has no HookScript
HookScript(obj, method, uid)
end
else
if not secure then
@@ -464,12 +444,8 @@ function AceHook:Unhook(obj, method)
actives[uid], handlers[uid] = nil, nil
if obj then
local tmp = registry[self][obj]
tmp[method] = nil
if not next(tmp) then
del(tmp)
registry[self][obj] = nil
end
registry[self][obj][method] = nil
registry[self][obj] = next(registry[self][obj]) and registry[self][obj] or nil
-- 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
@@ -481,12 +457,8 @@ function AceHook:Unhook(obj, method)
obj[method] = self.hooks[obj][method]
end
tmp = self.hooks[obj]
tmp[method] = nil
if not next(tmp) then
del(tmp)
self.hooks[obj] = nil
end
self.hooks[obj][method] = nil
self.hooks[obj] = next(self.hooks[obj]) and self.hooks[obj] or nil
else
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"/>
</Ui>
@@ -97,7 +97,7 @@ function AceLocale:NewLocale(application, locale, isDefault, silent)
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")
end
@@ -112,7 +112,7 @@ function AceLocale:NewLocale(application, locale, isDefault, silent)
end
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
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"/>
</Ui>
@@ -116,8 +116,9 @@ local serializeTbl = { "^1" } -- "^1" = Hi, I'm data serialized by AceSerializer
function AceSerializer:Serialize(...)
local nres = 1
for i = 1, arg.n do
nres = SerializeValue(arg[i], serializeTbl, nres)
for i=1,arg.n do
local v = arg[i]
nres = SerializeValue(v, serializeTbl, nres)
end
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"/>
</Ui>
+327 -230
View File
@@ -1,12 +1,12 @@
--- **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
-- 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.\\
-- AceTimer is currently limited to firing timers at a frequency of 0.01s as this is what the WoW timer API
-- restricts us to.
-- AceTimer is currently limited to firing timers at a frequency of 0.1s. This constant may change
-- 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
-- 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
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
@@ -15,33 +15,55 @@
-- make into AceTimer.
-- @class file
-- @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)
if not AceTimer then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local safecall = AceCore.safecall
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.hash = AceTimer.hash or {} -- Array of [0..BUCKET-1] = linked list of timers (using .next member)
-- Linked list gets around ACE-88 and ACE-90.
AceTimer.selfs = AceTimer.selfs or {} -- Array of [self]={[handle]=timerobj, [handle2]=timerobj2, ...}
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
local type, unpack, next, error = type, unpack, next, error
local floor, max, min, mod = math.floor, math.max, math.min, math.mod
local tostring = tostring
local assert, error, loadstring = assert, error, loadstring
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local pairs, type, next, tostring, unpack = pairs, type, next, tostring, unpack
local gsub = string.gsub
local floor, max, min, fmod = math.floor, math.max, math.min, math.fmod
local tconcat = table.concat
-- WoW APIs
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.
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 +71,6 @@ local GetTime = GetTime
If this number is ever changed, all entries need to be rehashed on lib upgrade.
]]
local HZ = 11
local minDelay = 1/(HZ-1)
--[[
Prime for good distribution
@@ -62,122 +83,215 @@ for i=1,BUCKETS do
hash[i] = hash[i] or false -- make it an integer-indexed array; it's faster than hashes
end
local new, del
do
local list = setmetatable({}, {__mode = "k"})
function new(self, loop, func, delay, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local name = loop and "ScheduleRepeatingTimer" or "ScheduleTimer"
if self == AceTimer then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): use your own 'self'", 3)
end
if not func or not delay then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'callback' and 'delay' must have set values.", 3)
end
if argc and (type(argc) ~= "number" or floor(argc) ~= argc) then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'argc' must be an integer.", 3)
end
if type(func) == "string" then
if type(self) ~= "table" then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): 'self' - must be a table.", 3)
elseif type(self[func]) ~= "function" then
error(MAJOR..": " .. name .. "(callback, delay, argc, args...): Tried to register '"..func.."' as the callback, but it is not a method.", 3)
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = xpcall, function(err) return geterrorhandler()(err) end -- our arguments are received as unnamed values in "..." since we don't have a proper function declaration
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = gsub(code, "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[arg.n](func, unpack(arg))
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 = (fmod(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 = (fmod(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, argument, 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
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
if delay < minDelay then
delay = minDelay
if delay < (1 / (HZ - 1)) then
delay = 1 / (HZ - 1)
end
-- Create and stuff timer in the correct hash bucket
local now = GetTime()
local timer = next(list) or {}
list[timer] = nil
local timer = timerCache or {} -- Get new timer object (from cache if available)
timerCache = nil
timer.object = self
timer.func = func
timer.delay = delay
timer.status = loop and "loop" or "once"
timer.ends = 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
timer.callback = callback
timer.delay = (repeating and delay)
timer.arg = argument
timer.when = now + delay
local bucket = floor(mod((now+delay)*HZ,BUCKETS)) + 1
local bucket = (fmod(floor((now+delay)*HZ), BUCKETS)) + 1
timer.next = hash[bucket]
hash[bucket] = timer
local id = tostring(timer) -- user has only access to the id but not the table itself
activeTimers[id] = timer
-- Insert timer in our self->handle->timer registry
local handle = tostring(timer)
counter[self] = (counter[self] or 0) + 1
timerFrame:Show()
return id
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
local selftimers = AceTimer.selfs[self]
if not selftimers then
selftimers = {}
AceTimer.selfs[self] = selftimers
end
selftimers[handle] = timer
selftimers.__ops = (selftimers.__ops or 0) + 1
return handle
end
end -- new, del
--- Schedule a new one-shot timer.
-- The timer will fire once in `delay` seconds, unless canceled before.
-- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds.
-- @param argc The numbers of arguments to be passed to the callback function
-- @param a1,...,a10 The arguments
-- @param arg An optional argument to be passed to the callback function.
-- @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)
-- end
--
-- function MyAddOn:TimerFeedback()
-- function MyAddon:TimerFeedback()
-- print("5 seconds passed")
-- end
function AceTimer:ScheduleTimer(func, delay, argc, ...)
return new(self, nil, func, delay, argc, unpack(arg))
function AceTimer:ScheduleTimer(callback, delay, argument)
return Reg(self, callback, delay, argument)
end
--- Schedule a repeating timer.
-- The timer will fire every `delay` seconds, until canceled.
-- @param callback Callback function for the timer pulse (funcref or method name).
-- @param delay Delay for the timer, in seconds.
-- @param argc The numbers of arguments to be passed to the callback function
-- @param a1,...,a10 The arguments
-- @param arg An optional argument to be passed to the callback function.
-- @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.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
-- end
--
-- function MyAddOn:TimerFeedback()
-- function MyAddon:TimerFeedback()
-- self.timerCount = self.timerCount + 1
-- print(format("%d seconds passed", 5 * self.timerCount))
-- -- run 30 seconds in total
@@ -185,65 +299,131 @@ end
-- self:CancelTimer(self.testTimer)
-- end
-- end
function AceTimer:ScheduleRepeatingTimer(func, delay, argc, ...)
return new(self, true, func, delay, argc, unpack(arg))
function AceTimer:ScheduleRepeatingTimer(callback, delay, argument)
return Reg(self, callback, delay, argument, true)
end
--- Cancels a timer with the given id, 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
--- 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 `handle` is valid
-- and the timer has not fired yet or was canceled before.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
function AceTimer:CancelTimer(id)
local timer = activeTimers[id]
if not timer then
return false
-- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @param silent If true, no error is raised if the timer handle is invalid (expired or already canceled)
-- @return True if the timer was successfully cancelled.
function AceTimer:CancelTimer(handle, silent)
if not handle then return end -- nil handle -> bail out without erroring
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
-- Ace3v: the timer will always be collected in the next update but not here
-- this is necessary for AceBucket to determinate if the bucket has been unregistered
-- in the callback
timer.status = nil
activeTimers[id] = nil
if not timer then
geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - no such timer registered")
return false
end
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
end
end
--- Cancels all timers registered to the current addon object ('self')
function AceTimer:CancelAllTimers()
if type(self) ~= "table" then
error(MAJOR..": CancelAllTimers(): 'self' - must be a table",2)
if not(type(self) == "string" or type(self) == "table") then
error(MAJOR..": CancelAllTimers(): 'self' - must be a string or a table",2)
end
if self == AceTimer then
error(MAJOR..": CancelAllTimers(): supply a meaningful 'self'", 2)
end
for k,v in pairs(activeTimers) do
if v.object == self then
AceTimer.CancelTimer(self, k)
local selftimers = AceTimer.selfs[self]
if selftimers then
for handle,v in pairs(selftimers) do
if type(v) == "table" then -- avoid __ops, etc
AceTimer.CancelTimer(self, handle, true)
end
end
end
end
--- Returns the time left for a timer with the given id, registered by the current addon object ('self').
-- This function will return 0 when the id is invalid.
-- @param id The id of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @return The time left on the timer.
function AceTimer:TimeLeft(id)
local timer = activeTimers[id]
if not timer then
return 0
else
return timer.ends - GetTime()
--- Returns the time left for a timer with the given handle, registered by the current addon object ('self').
-- This function will raise a warning when the handle is invalid, but not stop execution.
-- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
-- @return The time left on the timer, or false if the handle is invalid.
function AceTimer:TimeLeft(handle)
if not handle then return end
if type(handle) ~= "string" then
error(MAJOR..": TimeLeft(handle): 'handle' - expected a string", 2) -- for now, anyway
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
function AceTimer:TimerStatus(id)
local timer = activeTimers[id]
if not timer then
return nil
else
return timer.status
-- ---------------------------------------------------------------------
-- PLAYER_REGEN_ENABLED: Run through our .selfs[] array step by step
-- and clean it out - otherwise the table indices can grow indefinitely
-- if an addon starts and stops a lot of timers. AceBucket does this!
--
-- See ACE-94 and tests/AceTimer-3.0-ACE-94.lua
local lastCleaned = nil
local function OnEvent()
if event~="PLAYER_REGEN_ENABLED" then
return
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
-- ---------------------------------------------------------------------
@@ -265,115 +445,32 @@ function AceTimer:Embed(target)
return target
end
-- AceTimer:OnEmbedDisable(target)
-- AceTimer:OnEmbedDisable( target )
-- target (object) - target object that AceTimer is embedded in.
--
-- cancel all timers registered for the object
function AceTimer:OnEmbedDisable(target)
function AceTimer:OnEmbedDisable( target )
target:CancelAllTimers()
end
for addon in pairs(AceTimer.embeds) do
AceTimer:Embed(addon)
end
-- --------------------------------------------------------------------
-- OnUpdate handler
--
-- traverse buckets, always chasing "now", and fire timers that have expired
local lastint = floor(GetTime() * HZ)
local function OnUpdate()
local now = GetTime()
local nowint = floor(now * HZ)
-- ---------------------------------------------------------------------
-- Debug tools (expose copies of internals to test suites)
AceTimer.debug = AceTimer.debug or {}
AceTimer.debug.HZ = HZ
AceTimer.debug.BUCKETS = BUCKETS
-- 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
-- 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 iteratio
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()
-- In theory, we could hide&show the frame based on there being timers or not.
-- However, this job is fairly expensive, and the chance that there will
-- actually be zero timers running is diminuitive to say the least.
@@ -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"/>
</Ui>
@@ -1,4 +1,4 @@
--[[ $Id: CallbackHandler-1.0.lua 18 2014-10-16 02:52:20Z mikk $ ]]
--[[ $Id: CallbackHandler-1.0.lua 1131 2015-06-04 07:29:24Z nevcairiel $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 6
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
@@ -7,7 +7,7 @@ if not CallbackHandler then return end -- No upgrade needed
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-- Lua APIs
local tconcat = table.concat
local tconcat, getn = table.concat, table.getn
local assert, error, loadstring = assert, error, loadstring
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local next, pairs, type, tostring = next, pairs, type, tostring
@@ -24,6 +24,8 @@ end
local function CreateDispatcher(argCount)
local code = [[
local next, xpcall, eh = next, xpcall, function(err) return geterrorhandler()(err) end
local method, ARGS
local function call() method(ARGS) end
@@ -34,7 +36,7 @@ local function CreateDispatcher(argCount)
local OLD_ARGS = ARGS
ARGS = unpack(arg)
repeat
xpcall(call, function(err) return geterrorhandler()(err) end)
xpcall(call, eh)
index, method = next(handlers, index)
until not method
ARGS = OLD_ARGS
@@ -137,7 +139,8 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
end
if getn(arg)>=1 then -- this is not the same as testing for arg==nil!
regfunc = function(...) self[method](self,arg1,unpack(arg)) end
local a1=arg[1]
regfunc = function(...) self[method](self,a1,unpack(arg)) end
else
regfunc = function(...) self[method](self,unpack(arg)) end
end
@@ -148,7 +151,8 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
end
if getn(arg)>=1 then -- this is not the same as testing for arg==nil!
regfunc = function(...) method(arg1,unpack(arg)) end
local a1=arg[1]
regfunc = function(...) method(arg,unpack(arg)) end
else
regfunc = method
end
@@ -197,7 +201,7 @@ function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAll
if getn(arg)<1 then
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
end
if getn(arg)==1 and arg1==target then
if getn(arg)==1 and arg[1]==target then
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
end
+5 -5
View File
@@ -2,17 +2,17 @@
-- 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 _G = _G
local strfind, strfmt = string.find, string.format
local find, format = string.find, string.format
local LibStub = _G[LIBSTUB_MAJOR]
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
LibStub = LibStub or { libs = {}, minors = {} }
LibStub = LibStub or {libs = {}, minors = {} }
_G[LIBSTUB_MAJOR] = LibStub
LibStub.minor = LIBSTUB_MINOR
function LibStub:NewLibrary(major, minor)
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
local _,_,num = strfind(minor, "(%d+)")
local _, _, num = find(minor, "(%d+)")
minor = assert(tonumber(num), "Minor version must either be a number or contain a number.")
local oldminor = self.minors[major]
@@ -23,11 +23,11 @@ if not LibStub or LibStub.minor < LIBSTUB_MINOR then
function LibStub:GetLibrary(major, silent)
if not self.libs[major] and not silent then
error(strfmt("Cannot find a library instance of %q.", tostring(major)), 2)
error(format("Cannot find a library instance of %q.", tostring(major)), 2)
end
return self.libs[major], self.minors[major]
end
function LibStub:IterateLibraries() return pairs(self.libs) end
setmetatable(LibStub, { __call = LibStub.GetLibrary })
end
end
-1
View File
@@ -1,7 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="LibStub\LibStub.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="AceEvent-3.0\AceEvent-3.0.xml"/>
<Include file="AceConsole-3.0\AceConsole-3.0.xml"/>
+2 -2
View File
@@ -107,7 +107,7 @@ local function ChatFrame_OnMouseScroll()
CH:CancelTimer(this.ScrollTimer, true)
end
this.ScrollTimer = CH:ScheduleTimer("ScrollToBottom", CH.db.scrollDownInterval, 1, this)
this.ScrollTimer = CH:ScheduleTimer("ScrollToBottom", CH.db.scrollDownInterval, this)
end
end
else
@@ -133,7 +133,7 @@ local function ChatFrame_OnMouseScroll()
CH:CancelTimer(this.ScrollTimer, true)
end
this.ScrollTimer = CH:ScheduleTimer("ScrollToBottom", CH.db.scrollDownInterval, 1, this)
this.ScrollTimer = CH:ScheduleTimer("ScrollToBottom", CH.db.scrollDownInterval, this)
end
end
end
+1 -1
View File
@@ -467,7 +467,7 @@ function mod:UpdateElement_All(frame, noTargetFrame)
self:UpdateElement_Level(frame)
if not noTargetFrame then
mod:ScheduleTimer("ForEachPlate", 0.25, 1, "SetTargetFrame")
mod:ScheduleTimer("ForEachPlate", 0.25, "SetTargetFrame")
end
end
+4 -4
View File
@@ -311,7 +311,7 @@ function S:SkinAce3()
if TYPE == "ScrollFrame" then
local frame = widget.scrollbar
SkinScrollBar(frame)
elseif TYPE == "InlineGroup" or TYPE == "TreeGroup" or TYPE == "TabGroup-ElvUI" or TYPE == "Frame" or TYPE == "DropdownGroup" or TYPE == "Window" then
elseif TYPE == "InlineGroup" or TYPE == "TreeGroup" or TYPE == "TabGroup" or TYPE == "Frame" or TYPE == "DropdownGroup" or TYPE == "Window" then
local frame = widget.content:GetParent()
if TYPE == "Frame" then
E:StripTextures(frame)
@@ -378,16 +378,16 @@ function S:SkinAce3()
end
end
if TYPE == "TabGroup-ElvUI" then
if TYPE == "TabGroup" then
local oldCreateTab = widget.CreateTab
widget.CreateTab = function(self, id)
local tab = oldCreateTab(self, id)
E:StripTextures(tab)
tab.backdrop = CreateFrame("Frame", nil, tab)
--[[tab.backdrop = CreateFrame("Frame", nil, tab)
E:SetTemplate(tab.backdrop, "Transparent")
tab.backdrop:SetFrameLevel(tab:GetFrameLevel() - 1)
E:Point(tab.backdrop, "TOPLEFT", 10, -3)
E:Point(tab.backdrop, "BOTTOMRIGHT", -10, 0)
E:Point(tab.backdrop, "BOTTOMRIGHT", -10, 0)]]
return tab
end
end
@@ -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")
local cfgcmd = LibStub("AceConfigCmd-3.0")
local MAJOR, MINOR = "AceConfig-3.0", 3
local AceConfig = LibStub:NewLibrary(MAJOR, MINOR)
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 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")
-- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"})
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)
if not ok then error(msg, 2) end
if slashcmd then
if type(slashcmd) == "table" then
for _,cmd in pairs(slashcmd) do
cfgcmd.CreateChatCommand(self, cmd, appName)
cfgcmd:CreateChatCommand(cmd, appName)
end
else
cfgcmd.CreateChatCommand(self, slashcmd, appName)
cfgcmd:CreateChatCommand(slashcmd, appName)
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="AceConfigCmd-3.0\AceConfigCmd-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"/>
</Ui>
@@ -14,37 +14,30 @@ REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
-- TODO: plugin args
local cfgreg = LibStub("AceConfigRegistry-3.0")
local MAJOR, MINOR = "AceConfigCmd-3.0", 13
local MAJOR, MINOR = "AceConfigCmd-3.0", 14
local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
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.embeds = AceConfigCmd.embeds or {}
local commands = AceConfigCmd.commands
local cfgreg = LibStub("AceConfigRegistry-3.0")
local AceConsole -- LoD
local AceConsoleName = "AceConsole-3.0"
-- Lua APIs
local strbyte, strsub = string.byte, string.sub
local strlen, strupper, strlower = string.len, string.upper, string.lower
local strfind, strgfind, strgsub = string.find, string.gfind, string.gsub
local format = string.format
local tsort, tinsert, tgetn, tremove = table.sort, table.insert, table.getn, table.remove
local strsub, strsplit, strlower, strmatch, strtrim = string.sub, string.split, string.lower, string.match, string.trim
local strgsub, strupper, strfind, strlen, strbyte, strgmatch = string.gsub, string.upper, string.find, string.len, string.byte, string.gmatch
local format, tonumber, tostring = string.format, tonumber, tostring
local tsort, tinsert, getn = table.sort, table.insert, table.getn
local fmod = math.fmod
local select, pairs, next, type = select, pairs, next, type
local error, assert = error, assert
-- WoW APIs
local _G = AceCore._G
local _G = _G
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
@@ -69,7 +62,17 @@ local handlermsg = "expected a table"
local functypes = {["function"]=true, ["string"]=true}
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,arg.n do
if arg[i]~=nil then
return arg[i]
end
end
end
-- err() - produce real error() regarding malformed options tables etc
@@ -89,26 +92,23 @@ end
-- callmethod() - call a given named method (e.g. "get", "set") with given arguments
local function callmethod(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4)
local function callmethod(info, inputpos, tab, methodtype, ...)
local method = info[methodtype]
if not method then
err(info, inputpos, "'"..methodtype.."': not set")
end
argc = argc or 0
info.arg = tab.arg
info.option = tab
info.type = tab.type
if type(method)=="function" then
return Dispatchers[argc+1](method, info, a1, a2, a3, a4)
return method(info, unpack(arg))
elseif type(method)=="string" then
if type(info.handler[method])~="function" then
err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
end
return Dispatchers[argc+2](info.handler[method], info.handler, info, a1, a2, a3, a4)
return info.handler[method](info.handler, info, unpack(arg))
else
assert(false) -- type should have already been checked on read
end
@@ -116,8 +116,7 @@ end
-- 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]
info.arg = tab.arg
@@ -125,18 +124,21 @@ local function callfunction(info, tab, methodtype)
info.type = tab.type
if type(method)=="function" then
return method(info)
if arg.n > 0 then
return method(info, unpack(arg))
else
return method(info)
end
else
assert(false) -- type should have already been checked on read
end
end
-- 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, argc, a1, a2, a3, a4) -- currently maximum 4 arguments
local function do_final(info, inputpos, tab, methodtype, ...)
if info.validate then
local res = callmethod(info,inputpos,tab,"validate",argc,a1,a2,a3,a4)
local res = callmethod(info,inputpos,tab,"validate",unpack(arg))
if type(res)=="string" then
usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
return
@@ -144,7 +146,7 @@ local function do_final(info, inputpos, tab, methodtype, argc, a1, a2, a3, a4) -
end
-- console ignores .confirm
callmethod(info,inputpos,tab,methodtype,argc,a1,a2,a3,a4)
callmethod(info,inputpos,tab,methodtype, unpack(arg))
end
@@ -167,6 +169,8 @@ end
-- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
local dummytable={}
local function iterateargs(tab)
if not tab.plugins then
return pairs(tab.args)
@@ -191,21 +195,17 @@ local function iterateargs(tab)
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)
if tab.cmdHidden~=nil then
return tab.cmdHidden
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
local function showhelp(info, inputpos, tab, depth, noHead)
@@ -213,8 +213,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)..":")
end
local sortTbl = new() -- [1..n]=name
local refTbl = new() -- [name]=tableref
local sortTbl = {} -- [1..n]=name
local refTbl = {} -- [name]=tableref
for k,v in iterateargs(tab) do
if not refTbl[k] then -- a plugin overriding something in .args
@@ -247,7 +247,7 @@ local function showhelp(info, inputpos, tab, depth, noHead)
return o1<o2
end)
for i = 1, tgetn(sortTbl) do
for i = 1, getn(sortTbl) do
local k = sortTbl[i]
local v = refTbl[k]
if not checkhidden(info, inputpos, v) then
@@ -260,7 +260,7 @@ local function showhelp(info, inputpos, tab, depth, noHead)
if type(desc) == "function" then
desc = callfunction(info, v, 'desc')
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)..":")
local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg)
showhelp(info, inputpos, v, depth, true)
@@ -272,10 +272,9 @@ local function showhelp(info, inputpos, tab, depth, noHead)
end
end
end
del(sortTbl) -- Ace3v: release the tables
del(refTbl)
end
local function keybindingValidateFunc(text)
if text == nil or text == "NONE" then
return nil
@@ -376,7 +375,7 @@ 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
-- 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)
if handle(info, inputpos, v, depth+1, true)==false then
tremove(info)
@@ -419,21 +418,16 @@ local function handle(info, inputpos, tab, depth, retfalse)
elseif tab.type=="input" then
------------ input --------------------------------------------
if str=="" and tab.nullable == false then
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
return
end
local res = true
if tab.pattern then
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"])
return
end
end
do_final(info, inputpos, tab, "set", 1, str)
do_final(info, inputpos, tab, "set", str)
@@ -472,63 +466,47 @@ local function handle(info, inputpos, tab, depth, retfalse)
return
end
do_final(info, inputpos, tab, "set", 1, b)
do_final(info, inputpos, tab, "set", b)
elseif tab.type=="range" then
------------ range --------------------------------------------
local str = strtrim(strlower(str))
if str == "" then
-- TODO: Show current value
return
end
local val = tonumber(str)
if not val then
usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
return
end
local step = getValueFromTab(info, inputpos, tab, "step")
local min = getValueFromTab(info, inputpos, tab, "min")
if type(step)=="number" then
val = min + math.floor((val-min)/step) * step
if type(info.step)=="number" then
val = val- fmod(val, info.step)
end
if type(min)=="number" and val<min then
usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(min)) )
if type(info.min)=="number" and val<info.min then
usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(info.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
end
local max = getValueFromTab(info, inputpos, tab, "max")
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)
do_final(info, inputpos, tab, "set", val)
elseif tab.type=="select" then
------------ select ------------------------------------
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
-- Ace3v: it is possbile to not have a current value
-- 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 b = callmethod(info, inputpos, tab, "get")
local fmt = "|cffffff78- [%s]|r %s"
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
print(L["Options for |cffffff78"..info[tgetn(info)].."|r:"])
print(L["Options for |cffffff78"..info[getn(info)].."|r:"])
for k, v in pairs(values) do
if b == k then
print(format(fmt_sel, k, v))
@@ -536,7 +514,6 @@ local function handle(info, inputpos, tab, depth, retfalse)
print(format(fmt, k, v))
end
end
if tab.valuesTableDestroyable then del(values) end
return
end
@@ -548,39 +525,42 @@ local function handle(info, inputpos, tab, depth, retfalse)
break
end
end
if tab.valuesTableDestroyable then del(values) end
if not ok then
usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
return
end
do_final(info, inputpos, tab, "set", 1, str)
do_final(info, inputpos, tab, "set", str)
elseif tab.type=="multiselect" then
------------ multiselect -------------------------------------------
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
local fmt = "|cffffff78- [%s]|r %s"
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[getn(info)].."|r (multiple possible):"])
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))
else
print(format(fmt, k, v))
end
end
if tab.valuesTableDestroyable then del(values) end
return
end
--build a table of the selections, checking that they exist
--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
local sels = new()
local sels = {}
for v in strgfind(str, "[^ ]+") do
--parse option=on etc
local _, _, opt, val = strfind(v, '(.+)=(.+)')
@@ -598,7 +578,6 @@ local function handle(info, inputpos, tab, depth, retfalse)
break
end
end
if tab.valuesTableDestroyable then del(values) end
if not ok then
usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
@@ -616,7 +595,6 @@ local function handle(info, inputpos, tab, depth, retfalse)
else
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
end
del(sels)
return
end
else
@@ -630,7 +608,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
if (val == true) then
--toggle the option
local b = callmethod(info, inputpos, tab, "get", 1, opt)
local b = callmethod(info, inputpos, tab, "get", opt)
if tab.tristate then
--cycle in true, nil, false order
@@ -656,9 +634,8 @@ local function handle(info, inputpos, tab, depth, retfalse)
end
end
do_final(info, inputpos, tab, "set", 2, opt, newval)
do_final(info, inputpos, tab, "set", opt, newval)
end
del(sels)
elseif tab.type=="color" then
@@ -671,7 +648,12 @@ local function handle(info, inputpos, tab, depth, retfalse)
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 strlen(str) == 8 and strfind(str, "^%x*$") then
@@ -726,7 +708,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
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
------------ keybinding --------------------------------------------
@@ -741,7 +723,7 @@ local function handle(info, inputpos, tab, depth, retfalse)
return
end
do_final(info, inputpos, tab, "set", 1, value)
do_final(info, inputpos, tab, "set", value)
elseif tab.type=="description" then
------------ description --------------------
@@ -765,15 +747,12 @@ end
-- -- Show the GUI if no input is supplied, otherwise handle the chat input.
-- function MyAddon:ChatCommand(input)
-- -- Assuming "MyOptions" is the appName of a valid options table
-- if not input or input:trim() == "" then
-- if not input or trim(input) == "" then
-- LibStub("AceConfigDialog-3.0"):Open("MyOptions")
-- else
-- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
-- 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)
local optgetter = cfgreg:GetOptionsTable(appName)
@@ -782,65 +761,32 @@ function AceConfigCmd:HandleCommand(slashcmd, appName, input)
end
local options = assert( optgetter("cmd", MAJOR) )
-- Ace3v: prevent user from using AceConfigCmd as self
if self == AceConfigCmd then
error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'self' - use your own 'self']], 2)
end
local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
[0] = slashcmd,
appName = appName,
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
-- [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)
handle(info, 1, options, 0) -- (info, inputpos, table, depth)
end
--- Utility function to create a slash command handler.
-- Also registers tab completion with AceTab
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
-- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigCmd:CreateChatCommand(slashcmd, appName, func)
function AceConfigCmd:CreateChatCommand(slashcmd, appName)
if not AceConsole then
AceConsole = LibStub(AceConsoleName)
end
-- Ace3v: prevent user from using AceConfigCmd as self
if self == AceConfigCmd then
error([[Usage: CreateChatCommand("slashcmd", "appName"[, "func"]): 'self' - use your own 'self']], 2)
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
if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
end,
true) then -- succesfully registered so lets get the command -> app table in
commands[slashcmd] = appName
end
end
@@ -852,12 +798,3 @@ end
function AceConfigCmd:GetChatCommandOptions(slashcmd)
return commands[slashcmd]
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
@@ -1,20 +1,17 @@
--- AceConfigDialog-3.0 generates AceGUI-3.0 based windows based on option tables.
-- @class file
-- @name AceConfigDialog-3.0
-- @release $Id: AceConfigDialog-3.0.lua 1139 2016-07-03 07:43:51Z nevcairiel $
-- @release $Id: AceConfigDialog-3.0.lua 1168 2017-10-01 08:05:04Z nevcairiel $
local LibStub = LibStub
local MAJOR, MINOR = "AceConfigDialog-3.0", 61
local gui = LibStub("AceGUI-3.0")
local reg = LibStub("AceConfigRegistry-3.0")
local MAJOR, MINOR = "AceConfigDialog-3.0", 65
local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigDialog then return end
local AceCore = LibStub("AceCore-3.0")
local wipe = AceCore.wipe
local safecall = AceCore.safecall
local Dispatchers = AceCore.Dispatchers
local countargs = AceCore.countargs
AceConfigDialog.OpenFrames = AceConfigDialog.OpenFrames or {}
AceConfigDialog.Status = AceConfigDialog.Status or {}
AceConfigDialog.frame = AceConfigDialog.frame or CreateFrame("Frame")
@@ -23,14 +20,11 @@ AceConfigDialog.frame.apps = AceConfigDialog.frame.apps or {}
AceConfigDialog.frame.closing = AceConfigDialog.frame.closing or {}
AceConfigDialog.frame.closeAllOverride = AceConfigDialog.frame.closeAllOverride or {}
local gui = LibStub("AceGUI-3.0")
local reg = LibStub("AceConfigRegistry-3.0")
-- Lua APIs
local tconcat, tinsert, tsort, tremove, tgetn, tsetn = table.concat, table.insert, table.sort, table.remove, table.getn, table.setn
local format, strfind, strupper = string.format, string.find, string.upper
local tconcat, tinsert, tsort, tremove, tsort, getn, setn = table.concat, table.insert, table.sort, table.remove, table.sort, table.getn, table.setn
local gsub, format, upper, find = string.gsub, string.format, string.upper, string.find
local assert, loadstring, error = assert, loadstring, error
local pairs, next, type, unpack, ipairs = pairs, next, type, unpack, ipairs
local pairs, next, type, unpack, wipe, ipairs = pairs, next, type, unpack, wipe, ipairs
local rawset, tostring, tonumber = rawset, tostring, tonumber
local math_min, math_max, math_floor = math.min, math.max, math.floor
@@ -42,23 +36,67 @@ local math_min, math_max, math_floor = math.min, math.max, math.floor
local emptyTbl = {}
--[[
xpcall safecall implementation
]]
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function CreateDispatcher(argCount)
local code = [[
local xpcall, eh = xpcall, function(err) return geterrorhandler()(err) end
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = gsub(code, "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[arg.n](func, unpack(arg))
end
local width_multiplier = 170
--[[
Group Types
Tree - All Descendant Groups will all become nodes on the tree, direct child options will appear above the tree
- Descendant Groups with inline=true and thier children will not become nodes
- Descendant Groups with inline=true and thier children will not become nodes
Tab - Direct Child Groups will become tabs, direct child options will appear above the tab control
- Grandchild groups will default to inline unless specified otherwise
- Grandchild groups will default to inline unless specified otherwise
Select- Same as Tab but with entries in a dropdown rather than tabs
Inline Groups
- Will not become nodes of a select group, they will be effectivly part of thier parent group seperated by a border
- If declared on a direct child of a root node of a select group, they will appear above the group container control
- When a group is displayed inline, all descendants will also be inline members of the group
- Will not become nodes of a select group, they will be effectivly part of thier parent group seperated by a border
- If declared on a direct child of a root node of a select group, they will appear above the group container control
- When a group is displayed inline, all descendants will also be inline members of the group
]]
@@ -83,7 +121,7 @@ do
for k, v in pairs(t) do
c[k] = v
end
tsetn(c, tgetn(t))
setn(c, getn(t))
return c
end
function del(t)
@@ -101,7 +139,13 @@ do
end
-- picks the first non-nil value and returns it
local pickfirstset = AceCore.pickfirstset
local function pickfirstset(...)
for i=1,arg.n do
if arg[i]~=nil then
return arg[i]
end
end
end
--gets an option from a given group, checking plugins
local function GetSubOption(group, key)
@@ -151,10 +195,11 @@ local allIsLiteral = {
--gets the value for a member that could be a function
--function refs are called with an info arg
--every other type is returned
local function GetOptionsMemberValue(membername, option, options, path, appName, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local function GetOptionsMemberValue(membername, option, options, path, appName, ...)
--get definition for the member
local inherits = isInherited[membername]
--get the member of the option, traversing the tree if it can be inherited
local member
@@ -163,13 +208,13 @@ local function GetOptionsMemberValue(membername, option, options, path, appName,
if group[membername] ~= nil then
member = group[membername]
end
for i = 1, tgetn(path) do
for i = 1, getn(path) do
group = GetSubOption(group, path[i])
if group[membername] ~= nil then
member = group[membername]
end
end
elseif option then
else
member = option[membername]
end
@@ -182,13 +227,13 @@ local function GetOptionsMemberValue(membername, option, options, path, appName,
local group = options
handler = group.handler or handler
local l = tgetn(path)
for i = 1, l do
local x = getn(path)
for i = 1, x do
group = GetSubOption(group, path[i])
info[i] = path[i]
handler = group.handler or handler
end
tsetn(info, l)
setn(info, x)
info.options = options
info.appName = appName
@@ -200,16 +245,15 @@ local function GetOptionsMemberValue(membername, option, options, path, appName,
info.uiType = "dialog"
info.uiName = MAJOR
argc = argc or 0
local a, b, c ,d
--using 4 returns for the get of a color type, increase if a type needs more
if type(member) == "function" then
--Call the function
a,b,c,d = Dispatchers[argc+1](member,info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
a,b,c,d = member(info, unpack(arg))
else
--Call the method
if handler and handler[member] then
a,b,c,d = Dispatchers[argc+2](handler[member],handler,info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
a,b,c,d = handler[member](handler, info, unpack(arg))
else
error(format("Method %s doesn't exist in handler for type %s", member, membername))
end
@@ -281,7 +325,7 @@ local function compareOptions(a,b)
if OrderA == OrderB then
local NameA = (type(tempNames[a]) == "string") and tempNames[a] or ""
local NameB = (type(tempNames[b]) == "string") and tempNames[b] or ""
return strupper(NameA) < strupper(NameB)
return upper(NameA) < upper(NameB)
end
if OrderA < 0 then
if OrderB > 0 then
@@ -341,7 +385,7 @@ end
local function DelTree(tree)
if tree.children then
local childs = tree.children
for i = 1, tgetn(childs) do
for i = 1, getn(childs) do
DelTree(childs[i])
del(childs[i])
end
@@ -361,7 +405,7 @@ local function CleanUserData(widget, event)
local tree = user.tree
widget:SetTree(nil)
if tree then
for i = 1, tgetn(tree) do
for i = 1, getn(tree) do
DelTree(tree[i])
del(tree[i])
end
@@ -369,7 +413,7 @@ local function CleanUserData(widget, event)
end
end
if widget.type == "TabGroup-ElvUI" then
if widget.type == "TabGroup" then
widget:SetTabs(nil)
if user.tablist then
del(user.tablist)
@@ -403,7 +447,7 @@ function AceConfigDialog:GetStatusTable(appName, path)
status = status[appName]
if path then
for i = 1, tgetn(path) do
for i = 1, getn(path) do
local v = path[i]
if not status.children[v] then
status.children[v] = {}
@@ -421,11 +465,10 @@ end
-- The path specified has to match the keys of the groups in the table.
-- @param appName The application name as given to `:RegisterOptionsTable()`
-- @param ... The path to the key that should be selected
do
local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
function AceConfigDialog:SelectGroup(appName, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
function AceConfigDialog:SelectGroup(appName, ...)
local path = new()
local app = reg:GetOptionsTable(appName)
if not app then
error(format("%s isn't registed with AceConfigRegistry, unable to open config", appName), 2)
@@ -440,21 +483,8 @@ function AceConfigDialog:SelectGroup(appName, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local treevalue
local treestatus
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 n = 1, 10 do
local key = args[n]
args[n] = nil
if not key then break end
for n = 1, arg.n do
local key = arg[n]
if group.childGroups == "tab" or group.childGroups == "select" then
--if this is a tab or select group, select the group
@@ -498,7 +528,6 @@ function AceConfigDialog:SelectGroup(appName, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
del(path)
reg:NotifyChange(appName)
end
end -- AceConfigDialog:SelectGroup
local function OptionOnMouseOver(widget, event)
--show a tooltip/set the status bar to the desc text
@@ -516,16 +545,16 @@ local function OptionOnMouseOver(widget, event)
if descStyle and descStyle ~= "tooltip" then return end
GameTooltip:SetText(name, 1, .82, 0, true)
GameTooltip:SetText(name, 1, .82, 0, 1)
if opt.type == "multiselect" then
GameTooltip:AddLine(user.text, 0.5, 0.5, 0.8, true)
GameTooltip:AddLine(user.text,0.5, 0.5, 0.8, 1)
end
if type(desc) == "string" then
GameTooltip:AddLine(desc, 1, 1, 1, true)
GameTooltip:AddLine(desc, 1, 1, 1, 1)
end
if type(usage) == "string" then
GameTooltip:AddLine("Usage: "..usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
GameTooltip:AddLine("Usage: "..usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
end
GameTooltip:Show()
@@ -543,7 +572,7 @@ local function GetFuncName(option)
return "set"
end
end
local function confirmPopup(appName, rootframe, basepath, info, message, func, argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local function confirmPopup(appName, rootframe, basepath, info, message, func, ...)
if not StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] then
StaticPopupDialogs["ACECONFIGDIALOG30_CONFIRM_DIALOG"] = {}
end
@@ -557,7 +586,7 @@ local function confirmPopup(appName, rootframe, basepath, info, message, func, a
t.preferredIndex = STATICPOPUP_NUMDIALOGS
local dialog, oldstrata
t.OnAccept = function()
safecall(func, tgetn(t), unpack(t))
safecall(func, unpack(t))
if dialog and oldstrata then
dialog:SetFrameStrata(oldstrata)
end
@@ -571,23 +600,11 @@ local function confirmPopup(appName, rootframe, basepath, info, message, func, a
AceConfigDialog:Open(appName, rootframe, unpack(basepath or emptyTbl))
del(info)
end
t[1] = a1
t[2] = a2
t[3] = a3
t[4] = a4
t[5] = a5
t[6] = a6
t[7] = a7
t[8] = a8
t[9] = a9
t[10] = a10
for i=1,argc do
t[i] = t[i] or false
local x = arg.n
for i = 1, x do
t[i] = arg[i] or false
end
for i=argc+1,10 do
t[i] = nil
end
tsetn(t,argc)
setn(t, x)
t.timeout = 0
t.whileDead = 1
t.hideOnEscape = 1
@@ -599,7 +616,32 @@ local function confirmPopup(appName, rootframe, basepath, info, message, func, a
end
end
local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local function validationErrorPopup(message)
if not StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"] then
StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"] = {}
end
local t = StaticPopupDialogs["ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG"]
t.text = message
t.button1 = OKAY
t.preferredIndex = STATICPOPUP_NUMDIALOGS
local dialog, oldstrata
t.OnAccept = function()
if dialog and oldstrata then
dialog:SetFrameStrata(oldstrata)
end
end
t.timeout = 0
t.whileDead = 1
t.hideOnEscape = 1
dialog = StaticPopup_Show("ACECONFIGDIALOG30_VALIDATION_ERROR_DIALOG")
if dialog then
oldstrata = dialog:GetFrameStrata()
dialog:SetFrameStrata("TOOLTIP")
end
end
local function ActivateControl(widget, event, ...)
--This function will call the set / execute handler for the widget
--widget:GetUserDataTable() contains the needed info
local user = widget:GetUserDataTable()
@@ -622,9 +664,8 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
handler = group.handler or handler
confirm = group.confirm
validate = group.validate
local l = tgetn(path)
for i = 1, l do
local x = getn(path)
for i = 1, x do
local v = path[i]
group = GetSubOption(group, v)
info[i] = v
@@ -639,7 +680,7 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
validate = group.validate
end
end
tsetn(info, l)
setn(info, x)
info.options = options
info.appName = user.appName
@@ -651,7 +692,6 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
info.uiName = MAJOR
local name
if type(option.name) == "function" then
name = option.name(info)
elseif type(option.name) == "string" then
@@ -666,7 +706,7 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
if option.type == "input" then
if type(pattern)=="string" then
if not strfind(a1, pattern) then
if not find(arg[1], pattern) then
validated = false
end
end
@@ -676,42 +716,36 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
if validated and option.type ~= "execute" then
if type(validate) == "string" then
if handler and handler[validate] then
success, validated = safecall(handler[validate], argc+2, handler, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
success, validated = safecall(handler[validate], handler, info, unpack(arg))
if not success then validated = false end
else
error(format("Method %s doesn't exist in handler for type execute", validate))
end
elseif type(validate) == "function" then
success, validated = safecall(validate, argc+1, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
success, validated = safecall(validate, info, unpack(arg))
if not success then validated = false end
end
end
local rootframe = user.rootframe
if type(validated) == "string" then
--validate function returned a message to display
if not validated or type(validated) == "string" then
if not validated then
if usage then
validated = name..": "..usage
else
if pattern then
validated = name..": Expected "..pattern
else
validated = name..": Invalid Value"
end
end
end
-- show validate message
if rootframe.SetStatusText then
rootframe:SetStatusText(validated)
else
-- TODO: do something else.
end
PlaySound("igPlayerInviteDecline")
del(info)
return true
elseif not validated then
--validate returned false
if rootframe.SetStatusText then
if usage then
rootframe:SetStatusText(name..": "..usage)
else
if pattern then
rootframe:SetStatusText(name..": Expected "..pattern)
else
rootframe:SetStatusText(name..": Invalid Value")
end
end
else
-- TODO: do something else
validationErrorPopup(validated)
end
PlaySound("igPlayerInviteDecline")
del(info)
@@ -722,7 +756,7 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
--call confirm func/method
if type(confirm) == "string" then
if handler and handler[confirm] then
success, confirm = safecall(handler[confirm], argc+2, handler, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
success, confirm = safecall(handler[confirm], handler, info, unpack(arg))
if success and type(confirm) == "string" then
confirmText = confirm
confirm = true
@@ -733,7 +767,7 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
error(format("Method %s doesn't exist in handler for type confirm", confirm))
end
elseif type(confirm) == "function" then
success, confirm = safecall(confirm, argc+1, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
success, confirm = safecall(confirm, info, unpack(arg))
if success and type(confirm) == "string" then
confirmText = confirm
confirm = true
@@ -768,12 +802,12 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
local basepath = user.rootframe:GetUserData("basepath")
if type(func) == "string" then
if handler and handler[func] then
confirmPopup(user.appName, rootframe, basepath, info, confirmText, handler[func], argc+2, handler, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
confirmPopup(user.appName, rootframe, basepath, info, confirmText, handler[func], handler, info, unpack(arg))
else
error(format("Method %s doesn't exist in handler for type func", func))
end
elseif type(func) == "function" then
confirmPopup(user.appName, rootframe, basepath, info, confirmText, func, argc+1, info,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
confirmPopup(user.appName, rootframe, basepath, info, confirmText, func, info, unpack(arg))
end
--func will be called and info deleted when the confirm dialog is responded to
return
@@ -783,14 +817,16 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
--call the function
if type(func) == "string" then
if handler and handler[func] then
safecall(handler[func], argc+2, handler, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
safecall(handler[func],handler, info, unpack(arg))
else
error(format("Method %s doesn't exist in handler for type func", func))
end
elseif type(func) == "function" then
safecall(func, argc+1, info, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
safecall(func,info, unpack(arg))
end
local iscustom = user.rootframe:GetUserData("iscustom")
local basepath = user.rootframe:GetUserData("basepath") or emptyTbl
--full refresh of the frame, some controls dont cause this on all events
@@ -826,7 +862,7 @@ local function ActivateControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a
del(info)
end
local function ActivateSlider(widget, event, _, value)
local function ActivateSlider(widget, event, value)
local option = widget:GetUserData("option")
local min, max, step = option.min or (not option.softMin and 0 or nil), option.max or (not option.softMax and 100 or nil), option.step
if min then
@@ -838,13 +874,13 @@ local function ActivateSlider(widget, event, _, value)
if max then
value = math_min(value, max)
end
ActivateControl(widget,event,1,value)
ActivateControl(widget,event,value)
end
--called from a checkbox that is part of an internally created multiselect group
--this type is safe to refresh on activation of one control
local function ActivateMultiControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
ActivateControl(widget, event, argc+1, widget:GetUserData("value"), a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local function ActivateMultiControl(widget, event, ...)
ActivateControl(widget, event, widget:GetUserData("value"), unpack(arg))
local user = widget:GetUserDataTable()
local iscustom = user.rootframe:GetUserData("iscustom")
local basepath = user.rootframe:GetUserData("basepath") or emptyTbl
@@ -855,7 +891,7 @@ local function ActivateMultiControl(widget, event, argc, a1,a2,a3,a4,a5,a6,a7,a8
end
end
local function MultiControlOnClosed(widget, event)
local function MultiControlOnClosed(widget, event, ...)
local user = widget:GetUserDataTable()
if user.valuechanged then
local iscustom = user.rootframe:GetUserData("iscustom")
@@ -876,7 +912,7 @@ end
local function CheckOptionHidden(option, options, path, appName)
--check for a specific boolean option
local hidden = pickfirstset(2,option.dialogHidden,option.guiHidden)
local hidden = pickfirstset(option.dialogHidden,option.guiHidden)
if hidden ~= nil then
return hidden
end
@@ -886,7 +922,7 @@ end
local function CheckOptionDisabled(option, options, path, appName)
--check for a specific boolean option
local disabled = pickfirstset(2,option.dialogDisabled,option.guiDisabled)
local disabled = pickfirstset(option.dialogDisabled,option.guiDisabled)
if disabled ~= nil then
return disabled
end
@@ -907,7 +943,7 @@ local function BuildTabs(group, options, path, appName)
local v = opts[k]
if v.type == "group" then
path[#path+1] = k
local inline = pickfirstset(4,v.dialogInline,v.guiInline,v.inline, false)
local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
local hidden = CheckOptionHidden(v, options, path, appName)
if not inline and not hidden then
tinsert(tabs, k)
@@ -931,12 +967,12 @@ local function BuildSelect(group, options, path, appName)
BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
for i = 1, tgetn(keySort) do
for i = 1, getn(keySort) do
local k = keySort[i]
local v = opts[k]
if v.type == "group" then
tinsert(path,k)
local inline = pickfirstset(4,v.dialogInline,v.guiInline,v.inline, false)
tinsert(path, k)
local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
local hidden = CheckOptionHidden(v, options, path, appName)
if not inline and not hidden then
groups[k] = GetOptionsMemberValue("name", v, options, path, appName)
@@ -958,12 +994,12 @@ local function BuildSubGroups(group, tree, options, path, appName)
BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
for i = 1, tgetn(keySort) do
for i = 1, getn(keySort) do
local k = keySort[i]
local v = opts[k]
if v.type == "group" then
tinsert(path,k)
local inline = pickfirstset(4,v.dialogInline,v.guiInline,v.inline, false)
tinsert(path, k)
local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
local hidden = CheckOptionHidden(v, options, path, appName)
if not inline and not hidden then
local entry = new()
@@ -993,18 +1029,19 @@ local function BuildGroups(group, options, path, appName, recurse)
BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
for i = 1, tgetn(keySort) do
for i = 1, getn(keySort) do
local k = keySort[i]
local v = opts[k]
if v.type == "group" then
tinsert(path,k)
local inline = pickfirstset(4,v.dialogInline,v.guiInline,v.inline, false)
local inline = pickfirstset(v.dialogInline,v.guiInline,v.inline, false)
local hidden = CheckOptionHidden(v, options, path, appName)
if not inline and not hidden then
local entry = new()
entry.value = k
entry.text = GetOptionsMemberValue("name", v, options, path, appName)
entry.icon = GetOptionsMemberValue("icon", v, options, path, appName)
entry.iconCoords = GetOptionsMemberValue("iconCoords", v, options, path, appName)
entry.disabled = CheckOptionDisabled(v, options, path, appName)
tinsert(tree,entry)
if recurse and (v.childGroups or "tree") == "tree" then
@@ -1021,12 +1058,11 @@ end
local function InjectInfo(control, options, option, path, rootframe, appName)
local user = control:GetUserDataTable()
local l = tgetn(path)
for i = 1, l do
local x = getn(path)
for i = 1, x do
user[i] = path[i]
end
tsetn(user,l)
setn(user, x)
user.rootframe = rootframe
user.option = option
user.options = options
@@ -1051,7 +1087,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
BuildSortedOptionsTable(group, keySort, opts, options, path, appName)
for i = 1, tgetn(keySort) do
for i = 1, getn(keySort) do
local k = keySort[i]
local v = opts[k]
tinsert(path, k)
@@ -1059,7 +1095,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local name = GetOptionsMemberValue("name", v, options, path, appName)
if not hidden then
if v.type == "group" then
if inline or pickfirstset(4, v.dialogInline,v.guiInline,v.inline, false) then
if inline or pickfirstset(v.dialogInline,v.guiInline,v.inline, false) then
--Inline group
local GroupContainer
if name and name ~= "" then
@@ -1085,7 +1121,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
if type(image) == "string" or type(image) == "number" then
if type(image) == "string" then
control = gui:Create("Icon")
if not width then
width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
@@ -1148,7 +1184,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local image = GetOptionsMemberValue("image", v, options, path, appName)
local imageCoords = GetOptionsMemberValue("imageCoords", v, options, path, appName)
if type(image) == "string" or type(image) == "number" then
if type(image) == "string" then
if type(imageCoords) == "table" then
control:SetImage(image, unpack(imageCoords))
else
@@ -1182,7 +1218,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local optionValue = GetOptionsMemberValue("get",v, options, path, appName)
local t = {}
for value, text in pairs(values) do
tinsert(t,value)
tinsert(t, value)
end
tsort(t)
for k, value in ipairs(t) do
@@ -1215,7 +1251,6 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
if not control then
geterrorhandler()(format("Invalid Custom Control Type - %s", tostring(controlType)))
control = gui:Create("Dropdown")
end
local itemType = v.itemControl
if itemType and not gui:GetWidgetVersion(itemType) then
@@ -1234,7 +1269,6 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
elseif v.type == "multiselect" then
local values = GetOptionsMemberValue("values", v, options, path, appName)
local disabled = CheckOptionDisabled(v, options, path, appName)
local controlType = v.dialogControl or v.control
@@ -1271,9 +1305,9 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
control:SetWidth(width_multiplier)
end
--check:SetTriState(v.tristate)
for i = 1, tgetn(valuesort) do
for i = 1, getn(valuesort) do
local key = valuesort[i]
local value = GetOptionsMemberValue("get", v, options, path, appName, 1, key)
local value = GetOptionsMemberValue("get",v, options, path, appName, key)
control:SetItemValue(key,value)
end
else
@@ -1284,7 +1318,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
control:PauseLayout()
local width = GetOptionsMemberValue("width",v,options,path,appName)
for i = 1, tgetn(valuesort) do
for i = 1, getn(valuesort) do
local value = valuesort[i]
local text = values[value]
local check = gui:Create("CheckBox")
@@ -1293,7 +1327,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
check:SetUserData("text", text)
check:SetDisabled(disabled)
check:SetTriState(v.tristate)
check:SetValue(GetOptionsMemberValue("get",v, options, path, appName, 1, value))
check:SetValue(GetOptionsMemberValue("get",v, options, path, appName, value))
check:SetCallback("OnValueChanged",ActivateMultiControl)
InjectInfo(check, options, v, path, rootframe, appName)
control:AddChild(check)
@@ -1350,7 +1384,7 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
local imageCoords = GetOptionsMemberValue("imageCoords",v, options, path, appName)
local image, width, height = GetOptionsMemberValue("image",v, options, path, appName)
if type(image) == "string" or type(image) == "number" then
if type(image) == "string" then
if not width then
width = GetOptionsMemberValue("imageWidth",v, options, path, appName)
end
@@ -1407,15 +1441,14 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
del(opts)
end
-- Ace3v: recursive
local function BuildPath(path, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if a1 then
tinsert(path,a1)
BuildPath(path,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local function BuildPath(path, ...)
for i = 1, arg.n do
tinsert(path, arg[i])
end
end
local function TreeOnButtonEnter(widget, event, _, uniquevalue, button)
local function TreeOnButtonEnter(widget, event, uniquevalue, button)
local user = widget:GetUserDataTable()
if not user then return end
local options = user.options
@@ -1424,13 +1457,15 @@ local function TreeOnButtonEnter(widget, event, _, uniquevalue, button)
local appName = user.appName
local feedpath = new()
for i = 1, tgetn(path) do
local x = getn(path)
for i = 1, x do
feedpath[i] = path[i]
end
setn(feedpath, x)
BuildPath(feedpath, strsplit("\001", uniquevalue))
local group = options
for i = 1, tgetn(feedpath) do
for i = 1, getn(feedpath) do
if not group then return end
group = GetSubOption(group, feedpath[i])
end
@@ -1439,43 +1474,41 @@ local function TreeOnButtonEnter(widget, event, _, uniquevalue, button)
local desc = GetOptionsMemberValue("desc", group, options, feedpath, appName)
GameTooltip:SetOwner(button, "ANCHOR_NONE")
if widget.type == "TabGroup-ElvUI" then
if widget.type == "TabGroup" then
GameTooltip:SetPoint("BOTTOM",button,"TOP")
else
GameTooltip:SetPoint("LEFT",button,"RIGHT")
end
if name then
GameTooltip:SetText(name, 1, .82, 0, true)
end
GameTooltip:SetText(name, 1, .82, 0, 1)
if type(desc) == "string" then
GameTooltip:AddLine(desc, 1, 1, 1, true)
GameTooltip:AddLine(desc, 1, 1, 1, 1)
end
GameTooltip:Show()
end
local function TreeOnButtonLeave(widget, event, _, value, button)
local function TreeOnButtonLeave(widget, event, value, button)
GameTooltip:Hide()
end
local function GroupExists(appName, options, path, uniquevalue)
if not uniquevalue then return false end
local feedpath = new()
local temppath = new()
local l = tgetn(path)
for i = 1, l do
local x = getn(path)
for i = 1, x do
feedpath[i] = path[i]
end
tsetn(feedpath,l)
setn(feedpath, x)
BuildPath(feedpath, strsplit("\001", uniquevalue))
local group = options
for i = 1, tgetn(feedpath) do
for i = 1, getn(feedpath) do
local v = feedpath[i]
temppath[i] = v
group = GetSubOption(group, v)
@@ -1491,8 +1524,7 @@ local function GroupExists(appName, options, path, uniquevalue)
return true
end
local function GroupSelected(widget, event, _, uniquevalue)
if not uniquevalue then widget:ReleaseChildren() return end
local function GroupSelected(widget, event, uniquevalue)
local user = widget:GetUserDataTable()
@@ -1502,19 +1534,18 @@ local function GroupSelected(widget, event, _, uniquevalue)
local rootframe = user.rootframe
local feedpath = new()
local l = tgetn(path)
for i = 1, l do
local x = getn(path)
for i = 1, x do
feedpath[i] = path[i]
end
tsetn(feedpath,l)
setn(feedpath, x)
BuildPath(feedpath, strsplit("\001", uniquevalue))
local group = options
for i = 1, tgetn(feedpath) do
for i = 1, getn(feedpath) do
group = GetSubOption(group, feedpath[i])
end
widget:ReleaseChildren()
AceConfigDialog:FeedGroup(user.appName,options,widget,rootframe,feedpath)
del(feedpath)
@@ -1539,16 +1570,16 @@ Rules:
--]]
function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isRoot)
local group = options
--follow the path to get to the curent group
local inline
local grouptype, parenttype = options.childGroups, "none"
for i = 1, tgetn(path) do
for i = 1, getn(path) do
local v = path[i]
group = GetSubOption(group, v)
inline = inline or pickfirstset(4,group.dialogInline,group.guiInline,group.inline, false)
inline = inline or pickfirstset(group.dialogInline,group.guiInline,group.inline, false)
parenttype = grouptype
grouptype = group.childGroups
end
@@ -1560,14 +1591,14 @@ function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isR
--check if the group has child groups
local hasChildGroups
for k, v in pairs(group.args) do
if v.type == "group" and not pickfirstset(4,v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
if v.type == "group" and not pickfirstset(v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
hasChildGroups = true
end
end
if group.plugins then
for plugin, t in pairs(group.plugins) do
for k, v in pairs(t) do
if v.type == "group" and not pickfirstset(4,v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
if v.type == "group" and not pickfirstset(v.dialogInline,v.guiInline,v.inline, false) and not CheckOptionHidden(v, options, path, appName) then
hasChildGroups = true
end
end
@@ -1605,7 +1636,7 @@ function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isR
local name = GetOptionsMemberValue("name", group, options, path, appName)
if grouptype == "tab" then
local tab = gui:Create("TabGroup-ElvUI")
local tab = gui:Create("TabGroup")
InjectInfo(tab, options, group, path, rootframe, appName)
tab:SetCallback("OnGroupSelected", GroupSelected)
tab:SetCallback("OnTabEnter", TreeOnButtonEnter)
@@ -1623,7 +1654,7 @@ function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isR
tab:SetTabs(tabs)
tab:SetUserData("tablist", tabs)
for i = 1, tgetn(tabs) do
for i = 1, getn(tabs) do
local entry = tabs[i]
if not entry.disabled then
tab:SelectTab((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or entry.value)
@@ -1683,7 +1714,7 @@ function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isR
tree:SetTree(treedefinition)
tree:SetUserData("tree",treedefinition)
for i = 1, tgetn(treedefinition) do
for i = 1, getn(treedefinition) do
local entry = treedefinition[i]
if not entry.disabled then
tree:SelectByValue((GroupExists(appName, options, path,status.groups.selected) and status.groups.selected) or entry.value)
@@ -1696,7 +1727,7 @@ function AceConfigDialog:FeedGroup(appName,options,container,rootframe,path, isR
end
end
local old_CloseSpecialWindows
local old_CloseWindows
local function RefreshOnUpdate()
@@ -1793,11 +1824,11 @@ end
-- @param appName The application name as given to `:RegisterOptionsTable()`
-- @param container An optional container frame to feed the options into
-- @param ... The path to open after creating the options window (see `:SelectGroup` for details)
function AceConfigDialog:Open(appName, container, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if not old_CloseSpecialWindows then
old_CloseSpecialWindows = CloseSpecialWindows
CloseSpecialWindows = function()
local found = old_CloseSpecialWindows()
function AceConfigDialog:Open(appName, container, ...)
if not old_CloseWindows then
old_CloseWindows = CloseWindows
CloseWindows = function(ignoreCenter)
local found = old_CloseWindows(ignoreCenter)
return self:CloseAll() or found
end
end
@@ -1818,11 +1849,13 @@ function AceConfigDialog:Open(appName, container, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
tinsert(path, container)
container = nil
end
BuildPath(path, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
for n = 1, arg.n do
tinsert(path, arg[n])
end
local option = options
if type(container) == "table" and container.type == "BlizOptionsGroup" and tgetn(path) > 0 then
for i = 1, tgetn(path) do
if type(container) == "table" and container.type == "BlizOptionsGroup" and getn(path) > 0 then
for i = 1, getn(path) do
option = options.args[path[i]]
end
name = format("%s - %s", name, GetOptionsMemberValue("name", option, options, path, appName))
@@ -1834,7 +1867,7 @@ function AceConfigDialog:Open(appName, container, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
f:ReleaseChildren()
f:SetUserData("appName", appName)
f:SetUserData("iscustom", true)
if tgetn(path) > 0 then
if getn(path) > 0 then
f:SetUserData("basepath", copy(path))
end
local status = AceConfigDialog:GetStatusTable(appName)
@@ -1860,7 +1893,7 @@ function AceConfigDialog:Open(appName, container, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
f:ReleaseChildren()
f:SetCallback("OnClose", FrameOnClose)
f:SetUserData("appName", appName)
if tgetn(path) > 0 then
if getn(path) > 0 then
f:SetUserData("basepath", copy(path))
end
f:SetTitle(name or "")
@@ -1926,9 +1959,8 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
local BlizOptions = AceConfigDialog.BlizOptions
local key = appName
local l = tgetn(arg)
for n = 1, l do
key = key .. "\001" .. arg[n]
for n = 1, arg.n do
key = key.."\001"..arg[n]
end
if not BlizOptions[appName] then
@@ -1942,10 +1974,10 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
group:SetTitle(name or appName)
group:SetUserData("appName", appName)
if l > 0 then
if arg.n > 0 then
local path = {}
for n = 1, l do
tinsert(path, args[n])
for n = 1, arg.n do
tinsert(path, arg[n])
end
group:SetUserData("path", path)
end
@@ -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".
-- @class file
-- @name AceConfigRegistry-3.0
-- @release $Id: AceConfigRegistry-3.0.lua 1139 2016-07-03 07:43:51Z nevcairiel $
local MAJOR, MINOR = "AceConfigRegistry-3.0", 16
-- @release $Id: AceConfigRegistry-3.0.lua 1105 2013-12-08 22:11:58Z nevcairiel $
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
local MAJOR, MINOR = "AceConfigRegistry-3.0", 17
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigRegistry then return end
AceConfigRegistry.tables = AceConfigRegistry.tables or {}
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
if not AceConfigRegistry.callbacks then
AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
end
-- Lua APIs
local tinsert, tconcat, tgetn = table.insert, table.concat, table.getn
local strfind = string.find
local type, tostring, pairs = type, tostring, pairs
local tinsert, tconcat = table.insert, table.concat
local strfind, strmatch = string.find, string.match
local type, tostring, pairs, unpack = type, tostring, pairs, unpack
local error, assert = error, assert
-----------------------------------------------------------------------
@@ -40,24 +40,23 @@ AceConfigRegistry.validated = {
dialog = {},
}
local function err(msg, errlvl, ...)
local l = tgetn(arg)
local i,j = 1,l
while i < j do
arg[i], arg[j] = arg[j], arg[i]
i = i+1
j = j-1
local t = {}
for i=arg.n,1,-1 do
tinsert(t, arg[i])
end
error(MAJOR..":ValidateOptionsTable(): "..tconcat(arg,".")..msg, errlvl+2)
error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2)
end
local isstring={["string"]=true, _="string"}
local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
local istable={["table"]=true, _="table"}
local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"}
local optstring={["nil"]=true,["string"]=true, _="string"}
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 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"}
@@ -83,7 +82,7 @@ local basekeys={
dialogHidden=optmethodbool,
dropdownHidden=optmethodbool,
cmdHidden=optmethodbool,
icon=optstringnumberfunc,
icon=optstringfunc,
iconCoords=optmethodtable,
handler=opttable,
get=optmethodfalse,
@@ -98,7 +97,7 @@ local basekeys={
local typedkeys={
header={},
description={
image=optstringnumberfunc,
image=optstringfunc,
imageCoords=optmethodtable,
imageHeight=optnumber,
imageWidth=optnumber,
@@ -115,7 +114,7 @@ local typedkeys={
childGroups=optstring,
},
execute={
image=optstringnumberfunc,
image=optstringfunc,
imageCoords=optmethodtable,
imageHeight=optnumber,
imageWidth=optnumber,
@@ -127,11 +126,10 @@ local typedkeys={
dialogControl=optstring,
dropdownControl=optstring,
multiline=optboolnumber,
nullable=optbool,
},
toggle={
tristate=optbool,
image=optstringnumberfunc,
image=optstringfunc,
imageCoords=optmethodtable,
},
tristate={
@@ -147,7 +145,6 @@ local typedkeys={
},
select={
values=ismethodtable,
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
style={
["nil"]=true,
["string"]={dropdown=true,radio=true},
@@ -160,7 +157,6 @@ local typedkeys={
},
multiselect={
values=ismethodtable,
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
style=optstring,
tristate=optbool,
control=optstring,
@@ -175,75 +171,75 @@ local typedkeys={
},
}
local function validateKey(k,errlvl,arg)
local function validateKey(k,errlvl,...)
errlvl=(errlvl or 0)+1
if type(k)~="string" then
err("["..tostring(k).."] - key is not a string", errlvl, arg)
err("["..tostring(k).."] - key is not a string", errlvl,unpack(arg))
end
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,unpack(arg))
end
end
local function validateVal(v, oktypes, errlvl, arg)
local function validateVal(v, oktypes, errlvl,...)
errlvl=(errlvl or 0)+1
local isok=oktypes[type(v)] or oktypes["*"]
if not isok then
err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl, arg)
err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,unpack(arg))
end
if type(isok)=="table" then -- isok was a table containing specific values to be tested for!
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,unpack(arg))
end
end
end
local function validate(options,errlvl,arg)
local function validate(options,errlvl,...)
errlvl=(errlvl or 0)+1
-- basic consistency
if type(options)~="table" then
err(": expected a table, got a "..type(options), errlvl, arg)
err(": expected a table, got a "..type(options), errlvl,unpack(arg))
end
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,unpack(arg))
end
-- get type and 'typedkeys' member
local tk = typedkeys[options.type]
if not tk then
err(".type: unknown type '"..options.type.."'", errlvl, arg)
err(".type: unknown type '"..options.type.."'", errlvl,unpack(arg))
end
-- make sure that all options[] are known parameters
for k,v in pairs(options) do
if not (tk[k] or basekeys[k]) then
err(": unknown parameter", errlvl,tostring(k), arg)
err(": unknown parameter", errlvl,tostring(k),unpack(arg))
end
end
-- verify that required params are there, and that everything is the right type
for k,oktypes in pairs(basekeys) do
validateVal(options[k], oktypes, errlvl, k, arg)
validateVal(options[k], oktypes, errlvl,k,unpack(arg))
end
for k,oktypes in pairs(tk) do
validateVal(options[k], oktypes, errlvl, k, arg)
validateVal(options[k], oktypes, errlvl,k,unpack(arg))
end
-- extra logic for groups
if options.type=="group" then
for k,v in pairs(options.args) do
validateKey(k,errlvl,"args", arg)
validate(v, errlvl,k,"args", arg)
validateKey(k,errlvl,"args",unpack(arg))
validate(v, errlvl,k,"args",unpack(arg))
end
if options.plugins then
for plugname,plugin in pairs(options.plugins) do
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",unpack(arg))
end
for k,v in pairs(plugin) do
validateKey(k,errlvl,tostring(plugname),"plugins",arg)
validate(v, errlvl,k,tostring(plugname),"plugins",arg)
validateKey(k,errlvl,tostring(plugname),"plugins",unpack(arg))
validate(v, errlvl,k,tostring(plugname),"plugins",unpack(arg))
end
end
end
@@ -271,7 +267,7 @@ end
-- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigRegistry:NotifyChange(appName)
if not AceConfigRegistry.tables[appName] then return end
AceConfigRegistry.callbacks:Fire("ConfigTableChange", 1, appName)
AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName)
end
-- -------------------------------------------------------------------
@@ -285,7 +281,7 @@ local function validateGetterArgs(uiType, uiName, errlvl)
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)
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)
end
end
@@ -7,9 +7,6 @@ local AceDBOptions, oldminor = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
if not AceDBOptions then return end -- No upgrade needed
local AceCore = LibStub("AceCore-3.0")
local new, del = AceCore.new, AceCore.del
-- Lua APIs
local pairs, next = pairs, next
@@ -233,6 +230,7 @@ elseif LOCALE == "ptBR" then
end
local defaultProfiles
local tmpprofiles = {}
-- 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.
@@ -241,24 +239,23 @@ local defaultProfiles
-- @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.
local function getProfileList(db, common, nocurrent)
local profiles = new()
local tmpprofiles = new()
local profiles = {}
-- copy existing profiles into the table
local currentProfile = db:GetCurrentProfile()
for i,v in pairs(db:GetProfiles(tmpprofiles)) do
if not (nocurrent and v == currentProfile) then
profiles[v] = v
end
for i,v in pairs(db:GetProfiles(tmpprofiles)) do
if not (nocurrent and v == currentProfile) then
profiles[v] = v
end
end
del(tmpprofiles)
-- add our default profiles to choose from ( or rename existing profiles)
for k,v in pairs(defaultProfiles) do
if (common or profiles[k]) and not (nocurrent and k == currentProfile) then
profiles[k] = v
end
end
return profiles
end
@@ -283,18 +280,16 @@ function OptionsHandlerPrototype:GetCurrentProfile()
return self.db:GetCurrentProfile()
end
--[[
--[[
List all active profiles
you can control the output with the .arg variable
currently four modes are supported
(empty) - return all available profiles
"nocurrent" - returns all available profiles except the currently active profile
"common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default")
"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)
local arg = info.arg
local profiles
@@ -307,15 +302,13 @@ function OptionsHandlerPrototype:ListProfiles(info)
else
profiles = getProfileList(self.db)
end
return profiles
end
function OptionsHandlerPrototype:HasNoProfiles(info)
local profiles = self:ListProfiles(info)
local r = (not next(profiles)) and true or false
del(profiles)
return r
return ((not next(profiles)) and true or false)
end
--[[ Copy a profile ]]
@@ -343,19 +336,19 @@ local function getOptionsHandler(db, noDefaultProfiles)
if not defaultProfiles then
generateDefaultProfiles(db)
end
local handler = AceDBOptions.handlers[db] or { db = db, noDefaultProfiles = noDefaultProfiles }
for k,v in pairs(OptionsHandlerPrototype) do
handler[k] = v
end
AceDBOptions.handlers[db] = handler
return handler
end
--[[
the real options table
the real options table
]]
local optionsTable = {
desc = {
@@ -393,7 +386,6 @@ local optionsTable = {
order = 30,
get = false,
set = "SetProfile",
nullable = false, -- Ace3v: we do not want a null or empty value
},
choose = {
name = L["choose"],
@@ -403,7 +395,6 @@ local optionsTable = {
get = "GetCurrentProfile",
set = "SetProfile",
values = "ListProfiles",
valuesTableDestroyable = true,
arg = "common",
},
copydesc = {
@@ -419,7 +410,6 @@ local optionsTable = {
get = false,
set = "CopyProfile",
values = "ListProfiles",
valuesTableDestroyable = true,
disabled = "HasNoProfiles",
arg = "nocurrent",
},
@@ -436,7 +426,6 @@ local optionsTable = {
get = false,
set = "DeleteProfile",
values = "ListProfiles",
valuesTableDestroyable = true,
disabled = "HasNoProfiles",
arg = "nocurrent",
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.
-- @param db The database object to create the options table for.
-- @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:
-- options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
@@ -456,7 +445,7 @@ function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
name = L["profiles"],
desc = L["profiles_sub"],
}
tbl.handler = getOptionsHandler(db, noDefaultProfiles)
tbl.args = optionsTable
@@ -8,7 +8,7 @@ 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
local tinsert, tremove, sort = table.insert, table.remove, table.sort
do
local widgetType = "LSM30_Background"
@@ -22,15 +22,15 @@ do
tinsert(contentFrameCache, self)
end
local function ContentOnClick(this, button)
local function ContentOnClick()
local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText())
self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end
end
local function ContentOnEnter(this, button)
local function ContentOnEnter()
local self = this.obj
local text = this.text:GetText()
local background = self.list[text] ~= text and self.list[text] or Media:Fetch('background',text)
@@ -45,7 +45,7 @@ do
frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200)
frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick)
frame:SetScript("OnEnter", ContentOnEnter)
@@ -166,12 +166,13 @@ do
for i, k in ipairs(sortedlist) do
local f = GetContentLine()
f.text:SetText(k)
--print(k)
if k == self.value then
f.check:Show()
end
f.obj = self
f.dropdown = self.dropdown
self.dropdown:AddFrame(f, i)
self.dropdown:AddFrame(f)
end
wipe(sortedlist)
end
@@ -183,18 +184,18 @@ do
end
end
local function OnHide(this)
local function OnHide()
local self = this.obj
if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end
end
local function Drop_OnEnter(this)
local function Drop_OnEnter()
this.obj:Fire("OnEnter")
end
local function Drop_OnLeave(this)
local function Drop_OnLeave()
this.obj:Fire("OnLeave")
end
@@ -8,7 +8,7 @@ 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
local tinsert, tremove, sort = table.insert, table.remove, table.sort
do
local widgetType = "LSM30_Border"
@@ -24,7 +24,7 @@ do
local function ContentOnClick(this, button)
local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText())
self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end
@@ -35,7 +35,7 @@ do
local text = this.text:GetText()
local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text)
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,
insets = { left = 4, right = 4, top = 4, bottom = 4 }})
end
@@ -48,7 +48,7 @@ do
frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200)
frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick)
frame:SetScript("OnEnter", ContentOnEnter)
local check = frame:CreateTexture("OVERLAY")
@@ -110,7 +110,7 @@ do
local border = self.list[text] ~= text and self.list[text] or Media:Fetch('border',text)
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,
insets = { left = 4, right = 4, top = 4, bottom = 4 }})
end
@@ -161,12 +161,13 @@ do
for i, k in ipairs(sortedlist) do
local f = GetContentLine()
f.text:SetText(k)
--print(k)
if k == self.value then
f.check:Show()
end
f.obj = self
f.dropdown = self.dropdown
self.dropdown:AddFrame(f, i)
self.dropdown:AddFrame(f)
end
wipe(sortedlist)
end
@@ -8,7 +8,7 @@ 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
local tinsert, tremove, sort = table.insert, table.remove, table.sort
do
local widgetType = "LSM30_Font"
@@ -24,7 +24,7 @@ do
local function ContentOnClick()
local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText())
self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end
@@ -38,7 +38,7 @@ do
frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200)
frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick)
local check = frame:CreateTexture("OVERLAY")
check:SetWidth(16)
@@ -153,7 +153,7 @@ do
f.check:Show()
end
f.obj = self
self.dropdown:AddFrame(f, i)
self.dropdown:AddFrame(f)
end
wipe(sortedlist)
end
@@ -8,7 +8,7 @@ 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
local tinsert, tremove, sort = table.insert, table.remove, table.sort
do
local widgetType = "LSM30_Sound"
@@ -24,7 +24,7 @@ do
local function ContentOnClick()
local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText())
self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end
@@ -44,7 +44,7 @@ do
frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200)
frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick)
local check = frame:CreateTexture("OVERLAY")
check:SetWidth(16)
@@ -175,7 +175,7 @@ do
f.check:Show()
end
f.obj = self
self.dropdown:AddFrame(f, i)
self.dropdown:AddFrame(f)
end
wipe(sortedlist)
end
@@ -8,7 +8,7 @@ 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
local tinsert, tremove, sort = table.insert, table.remove, table.sort
do
local widgetType = "LSM30_Statusbar"
@@ -24,7 +24,7 @@ do
local function ContentOnClick()
local self = this.obj
self:Fire("OnValueChanged", 1, this.text:GetText())
self:Fire("OnValueChanged", this.text:GetText())
if self.dropdown then
self.dropdown = AGSMW:ReturnDropDownFrame(self.dropdown)
end
@@ -38,7 +38,7 @@ do
frame = CreateFrame("Button", nil, UIParent)
--frame:SetWidth(200)
frame:SetHeight(18)
frame:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight", "ADD")
frame:SetHighlightTexture([[Interface\QuestFrame\UI-QuestTitleHighlight]], "ADD")
frame:SetScript("OnClick", ContentOnClick)
local check = frame:CreateTexture("OVERLAY")
check:SetWidth(16)
@@ -155,6 +155,7 @@ do
for i, k in ipairs(sortedlist) do
local f = GetContentLine()
f.text:SetText(k)
--print(k)
if k == self.value then
f.check:Show()
end
@@ -163,7 +164,7 @@ do
f.bar:SetTexture(statusbar)
f.obj = self
f.dropdown = self.dropdown
self.dropdown:AddFrame(f, i)
self.dropdown:AddFrame(f)
end
wipe(sortedlist)
end
@@ -19,6 +19,8 @@ AGSMW = AGSMW or {}
local next, ipairs = next, ipairs
local tinsert, tremove = table.insert, table.remove
local GetScreenHeight = GetScreenHeight
AceGUIWidgetLSMlists = {
['font'] = Media:HashTable("font"),
['sound'] = Media:HashTable("sound"),
@@ -140,8 +142,8 @@ end
do
local sliderBackdrop = {
["bgFile"] = "Interface\\Buttons\\UI-SliderBar-Background",
["edgeFile"] = "Interface\\Buttons\\UI-SliderBar-Border",
["bgFile"] = [[Interface\Buttons\UI-SliderBar-Background]],
["edgeFile"] = [[Interface\Buttons\UI-SliderBar-Border]],
["tile"] = true,
["edgeSize"] = 8,
["tileSize"] = 8,
@@ -153,38 +155,42 @@ do
},
}
local frameBackdrop = {
bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
bgFile=[[Interface\DialogFrame\UI-DialogBox-Background-Dark]],
edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]],
tile = true, tileSize = 32, edgeSize = 32,
insets = { left = 11, right = 12, top = 12, bottom = 9 },
}
local function OnMouseWheel(self, dir)
self.slider:SetValue(self.slider:GetValue()+(15*dir*-1))
local function OnMouseWheel()
this.slider:SetValue(this.slider:GetValue()+(15*arg1*-1))
end
local function AddFrame(self, frame, i)
local function AddFrame(self, frame)
frame:SetParent(self.contentframe)
frame:SetFrameStrata(self:GetFrameStrata())
frame:SetFrameLevel(self:GetFrameLevel() + 100)
if next(self.contentRepo) then
frame:SetPoint("TOPLEFT", self.contentRepo[i-1], "BOTTOMLEFT", 0, 0)
frame:SetPoint("TOPLEFT", self.contentRepo[getn(self.contentRepo)], "BOTTOMLEFT", 0, 0)
-- frame:SetPoint("RIGHT", self.contentframe, "RIGHT", 0, 0)
self.contentframe:SetHeight(self.contentframe:GetHeight() + frame:GetHeight())
else
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)
end
self.contentRepo[i] = frame
tinsert(self.contentRepo, frame)
if self.contentframe:GetHeight() > GetScreenHeight()*2/5 - 20 then
-- self.scrollframe:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -28, 12)
self.scrollframe:SetWidth(128)
self:SetHeight(GetScreenHeight()*2/5)
self.slider:Show()
self:SetScript("OnMouseWheel", function() OnMouseWheel(this, arg1) end)
self:SetScript("OnMouseWheel", OnMouseWheel)
self.scrollframe:UpdateScrollChildRect()
self.slider:SetMinMaxValues(0, self.contentframe:GetHeight()-self.scrollframe:GetHeight())
else
-- self.scrollframe:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -14, 12)
self.scrollframe:SetWidth(142)
self:SetHeight(self.contentframe:GetHeight()+25)
self.slider:Hide()
@@ -229,10 +235,12 @@ do
scrollframe:SetWidth(128)
scrollframe:SetHeight((GetScreenHeight()*2/5) - 24)
scrollframe:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -13)
-- scrollframe:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 12)
scrollframe:SetScrollChild(contentframe)
frame.scrollframe = scrollframe
contentframe:SetPoint("TOPLEFT", scrollframe)
-- contentframe:SetPoint("TOPRIGHT", scrollframe)
local bgTex = frame:CreateTexture(nil, "ARTWORK")
bgTex:SetAllPoints(scrollframe)
@@ -247,7 +255,7 @@ do
slider:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -14, -10)
slider:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -14, 10)
slider:SetBackdrop(sliderBackdrop)
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
slider:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
slider:SetMinMaxValues(0, 1)
--slider:SetValueStep(1)
slider:SetWidth(12)
+122 -73
View File
@@ -30,17 +30,13 @@ local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
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
local tconcat, tremove, tinsert, tgetn, tsetn = table.concat, table.remove, table.insert, table.getn, table.setn
local pairs, next, type = pairs, next, type
local tconcat, tremove, tinsert, getn = table.concat, table.remove, table.insert, table.getn
local format, gsub, upper = string.format, string.gsub, string.upper
local pairs, next, type, unpack = pairs, next, type, unpack
local error, assert, loadstring = error, assert, loadstring
local setmetatable, rawget, rawset = setmetatable, rawget, rawset
local math_max = math.max
local strupper, strfmt = string.upper, string.format
-- WoW APIs
local UIParent = UIParent
@@ -56,17 +52,74 @@ AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
AceGUI.WidgetBase = AceGUI.WidgetBase or {}
AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
AceGUI.HookedFunctions = AceGUI.HookedFunctions or {}
-- local upvalues
local WidgetRegistry = AceGUI.WidgetRegistry
local LayoutRegistry = AceGUI.LayoutRegistry
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 = xpcall, function(err) return geterrorhandler()(err) end
local method, ARGS
local function call() return method(ARGS) end
local function dispatch(func, ...)
method = func
if not method then return end
ARGS = unpack(arg)
return xpcall(call, eh)
end
return dispatch
]]
local ARGS = {}
for i = 1, argCount do ARGS[i] = "arg"..i end
code = gsub(code, "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[arg.n](func, unpack(arg))
end
-- Recycling functions
local newWidget, delWidget
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 {}
local objPools = AceGUI.objPools
--Returns a new instance, if none are available either returns a new table or calls the given contructor
@@ -105,16 +158,19 @@ do
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]
local function fixlevels(parent)
local child
local childList = {parent:GetChildren()}
local level = parent:GetFrameLevel() + 1
for i = 1, getn(childList) do
child = childList[i]
child:SetFrameLevel(level)
fixlevels(child)
end
end
-------------------
-- API Functions --
-------------------
@@ -130,15 +186,27 @@ function AceGUI:Create(type)
if WidgetRegistry[type] then
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
widget:OnAcquire()
else
error(strfmt("Widget type %s doesn't supply an OnAcquire Function", type))
error(format("Widget type %s doesn't supply an OnAcquire Function", type))
end
-- Set the default Layout ("List")
safecall(widget.SetLayout, 2, widget, "List")
safecall(widget.ResumeLayout, 1, widget)
safecall(widget.SetLayout, widget, "List")
safecall(widget.ResumeLayout, widget)
return widget
end
end
@@ -149,14 +217,14 @@ end
-- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
-- @param widget The widget to release
function AceGUI:Release(widget)
safecall(widget.PauseLayout, 1, widget)
safecall(widget.PauseLayout, widget)
widget:Fire("OnRelease")
safecall(widget.ReleaseChildren, 1, widget)
safecall(widget.ReleaseChildren, widget)
if widget.OnRelease then
widget:OnRelease()
-- else
-- error(strfmt("Widget type %s doesn't supply an OnRelease Function", widget.type))
-- error(format("Widget type %s doesn't supply an OnRelease Function", widget.type))
end
for k in pairs(widget.userdata) do
widget.userdata[k] = nil
@@ -191,7 +259,7 @@ end
-- @param widget The widget that should be focused
function AceGUI:SetFocus(widget)
if self.FocusedWidget and self.FocusedWidget ~= widget then
safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget)
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
end
self.FocusedWidget = widget
end
@@ -201,7 +269,7 @@ end
-- e.g. titlebar of a frame being clicked
function AceGUI:ClearFocus()
if self.FocusedWidget then
safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget)
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
self.FocusedWidget = nil
end
end
@@ -246,7 +314,7 @@ do
frame:SetParent(nil)
frame:SetParent(parent.content)
self.parent = parent
fixlevels(frame, frame:GetChildren())
fixlevels(frame)
end
WidgetBase.SetCallback = function(self, name, func)
@@ -255,11 +323,9 @@ do
end
end
WidgetBase.Fire = function(self, name, argc, ...)
argc = arg.n
local func = self.events[name]
if func then
local success, ret = safecall(func, argc+3, self, name, argc, unpack(arg))
WidgetBase.Fire = function(self, name, ...)
if self.events[name] then
local success, ret = safecall(self.events[name], self, name, unpack(arg))
if success then
return ret
end
@@ -310,8 +376,8 @@ do
AceGUI:Release(self)
end
WidgetBase.SetPoint = function(self, a1,a2,a3,a4,a5)
return self.frame:SetPoint(a1,a2,a3,a4,a5)
WidgetBase.SetPoint = function(self, ...)
return self.frame:SetPoint(unpack(arg))
end
WidgetBase.ClearAllPoints = function(self)
@@ -322,8 +388,8 @@ do
return self.frame:GetNumPoints()
end
WidgetBase.GetPoint = function(self, a1,a2,a3,a4,a5)
return self.frame:GetPoint(a1,a2,a3,a4,a5)
WidgetBase.GetPoint = function(self, ...)
return self.frame:GetPoint(unpack(arg))
end
WidgetBase.GetUserDataTable = function(self)
@@ -381,7 +447,7 @@ do
if self.LayoutPaused then
return
end
safecall(self.LayoutFunc, 2, self.content, self.children)
safecall(self.LayoutFunc, self.content, self.children)
end
--call this function to layout, makes sure layed out objects get a frame to get sizes etc
@@ -410,50 +476,34 @@ do
self:DoLayout()
end
do
local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
WidgetContainerBase.AddChildren = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
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
WidgetContainerBase.AddChildren = function(self, ...)
for i = 1, arg.n do
local child = arg[i]
tinsert(self.children, child)
child:SetParent(self)
child.frame:Show()
end
self:DoLayout()
end
end -- WidgetContainerBase.AddChildren
WidgetContainerBase.ReleaseChildren = function(self)
local children = self.children
for i = 1,tgetn(children) do
for i = 1,getn(children) do
AceGUI:Release(tremove(children))
end
end
--[[WidgetContainerBase.SetParent = function(self, parent)
--WidgetBase.SetParent(self, parent)
WidgetContainerBase.SetParent = function(self, parent)
WidgetBase.SetParent(self, parent)
local lv = self.frame:GetFrameLevel()
self.content:SetFrameLevel(lv+1)
local level = self.frame:GetFrameLevel()
self.content:SetFrameLevel(level + 1)
local children = self.children
for i = 1,tgetn(children) do
for i = 1,getn(children) do
local child = children[i]
child:SetParent(self)
end
end]]
end
WidgetContainerBase.SetLayout = function(self, Layout)
self.LayoutFunc = AceGUI:GetLayout(Layout)
@@ -548,7 +598,7 @@ end
function AceGUI:RegisterLayout(Name, LayoutFunc)
assert(type(LayoutFunc) == "function")
if type(Name) == "string" then
Name = string.upper(Name)
Name = upper(Name)
end
LayoutRegistry[Name] = LayoutFunc
end
@@ -557,7 +607,7 @@ end
-- @param Name The name of the layout
function AceGUI:GetLayout(Name)
if type(Name) == "string" then
Name = strupper(Name)
Name = upper(Name)
end
return LayoutRegistry[Name]
end
@@ -604,7 +654,7 @@ AceGUI:RegisterLayout("List",
function(content, children)
local height = 0
local width = content.width or content:GetWidth() or 0
for i = 1, tgetn(children) do
for i = 1, getn(children) do
local child = children[i]
local frame = child.frame
@@ -633,7 +683,7 @@ AceGUI:RegisterLayout("List",
height = height + (frame.height or frame:GetHeight() or 0)
end
safecall(content.obj.LayoutFinished, 3, content.obj, nil, height)
safecall(content.obj.LayoutFinished, content.obj, nil, height)
end)
-- A single control fills the whole content area
@@ -644,15 +694,14 @@ AceGUI:RegisterLayout("Fill",
children[1]:SetHeight(content:GetHeight() or 0)
children[1].frame:SetAllPoints(content)
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)
-- Ace3v: currently only a1 used
local layoutrecursionblock = nil
local function safelayoutcall(object, func, a1)
local function safelayoutcall(object, func, ...)
layoutrecursionblock = true
object[func](object, a1)
object[func](object, unpack(arg))
layoutrecursionblock = nil
end
@@ -679,7 +728,7 @@ AceGUI:RegisterLayout("Flow",
local frameoffset
local lastframeoffset
local oversize
for i = 1, tgetn(children) do
for i = 1, getn(children) do
local child = children[i]
oversize = nil
local frame = child.frame
@@ -785,5 +834,5 @@ AceGUI:RegisterLayout("Flow",
end
height = height + rowheight + 3
safecall(content.obj.LayoutFinished, 3, content.obj, nil, height)
safecall(content.obj.LayoutFinished, content.obj, nil, height)
end)
@@ -15,11 +15,11 @@ local CreateFrame = CreateFrame
--[[-----------------------------------------------------------------------------
Scripts
-------------------------------------------------------------------------------]]
local function SelectedGroup(self, event, _, value)
local function SelectedGroup(self, event, value)
local group = self.parentgroup
local status = group.status or group.localstatus
status.selected = value
self.parentgroup:Fire("OnGroupSelected", 1, value)
self.parentgroup:Fire("OnGroupSelected", value)
end
--[[-----------------------------------------------------------------------------
@@ -63,7 +63,7 @@ local methods = {
self.dropdown:SetValue(group)
local status = self.status or self.localstatus
status.selected = group
self:Fire("OnGroupSelected", 1, group)
self:Fire("OnGroupSelected", group)
end,
["OnWidthSet"] = function(self, width)
@@ -1,15 +1,13 @@
--[[-----------------------------------------------------------------------------
Frame Container
-------------------------------------------------------------------------------]]
local Type, Version = "Frame", 24
local Type, Version = "Frame", 25
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
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
local pairs, assert, type = pairs, assert, type
local wipe = table.wipe
-- WoW APIs
local PlaySound = PlaySound
@@ -27,6 +25,10 @@ local function Button_OnClick()
this.obj:Hide()
end
local function Frame_OnShow()
this.obj:Fire("OnShow")
end
local function Frame_OnClose()
this.obj:Fire("OnClose")
end
@@ -85,7 +87,7 @@ local methods = {
self:SetStatusText()
self:ApplyStatus()
self:Show()
self:EnableResize(true)
self:EnableResize(true)
end,
["OnRelease"] = function(self)
@@ -154,7 +156,7 @@ local methods = {
frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
else
frame:SetPoint("CENTER", UIParent)
frame:SetPoint("CENTER", 0, 0)
end
end
}
@@ -188,6 +190,7 @@ local function Constructor()
frame:SetBackdropColor(0, 0, 0, 1)
frame:SetMinResize(400, 200)
frame:SetToplevel(true)
frame:SetScript("OnShow", Frame_OnShow)
frame:SetScript("OnHide", Frame_OnClose)
frame:SetScript("OnMouseDown", Frame_OnMouseDown)
@@ -245,7 +248,6 @@ local function Constructor()
titlebg_r:SetWidth(30)
titlebg_r:SetHeight(40)
-- bottom right sizer
local sizer_se = CreateFrame("Frame", nil, frame)
sizer_se:SetPoint("BOTTOMRIGHT", 0, 0)
sizer_se:SetWidth(25)
@@ -255,9 +257,20 @@ local function Constructor()
sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
line1:SetPoint("BOTTOMRIGHT", -10, 10)
line1:SetTexture("Interface\\Cursor\\Item")
line1:SetTexCoord(1, 0, 1, 0)
line1:SetWidth(14)
line1:SetHeight(14)
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)
sizer_s:SetPoint("BOTTOMRIGHT", -25, 0)
@@ -278,7 +291,6 @@ local function Constructor()
--Container Support
local content = CreateFrame("Frame", nil, frame)
content:SetPoint("TOPLEFT", 17, -27)
--content:SetPoint("BOTTOMRIGHT", -17, 40)
local widget = {
localstatus = {},
@@ -2,7 +2,7 @@
ScrollFrame Container
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)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -51,7 +51,7 @@ local methods = {
for k in pairs(self.localstatus) do
self.localstatus[k] = nil
end
self.scrollframe:SetPoint("BOTTOMRIGHT",0,0)
self.scrollframe:SetPoint("BOTTOMRIGHT", 0, 0)
self.scrollbar:Hide()
self.scrollBarShown = nil
self.content.height, self.content.width = nil, nil
@@ -90,7 +90,6 @@ local methods = {
end,
["FixScroll"] = function(self)
if self.updateLock then return end
self.updateLock = true
local status = self.status or self.localstatus
@@ -153,6 +152,13 @@ local methods = {
end,
["OnHeightSet"] = function(self, height)
local parent = self.parent
if parent and height then
height = (parent.content.height or 0) or height
self.frame.height = parent.content.height or 0
end
self.scrollframe:SetHeight(height)
local content = self.content
content.height = height
end
@@ -165,11 +171,11 @@ local function Constructor()
local num = AceGUI:GetNextWidgetNum(Type)
local scrollframe = CreateFrame("ScrollFrame", nil, frame)
scrollframe:SetPoint("TOPLEFT",0,0)
scrollframe:SetPoint("BOTTOMRIGHT",0,0)
scrollframe:SetPoint("TOPLEFT", 0, 0)
scrollframe:SetPoint("BOTTOMRIGHT", 0, 0)
scrollframe:EnableMouseWheel(true)
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")
scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
@@ -188,8 +194,8 @@ local function Constructor()
--Container Support
local content = CreateFrame("Frame", nil, scrollframe)
content:SetPoint("TOPLEFT",0,0)
content:SetPoint("TOPRIGHT",0,0)
content:SetPoint("TOPLEFT", 0, 0)
content:SetPoint("TOPRIGHT", 0, 0)
content:SetHeight(400)
scrollframe:SetScrollChild(content)
@@ -2,14 +2,14 @@
TabGroup Container
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)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs
local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe
local getn = table.getn
local format = string.format
local getn = table.getn
-- WoW APIs
local PlaySound = PlaySound
@@ -72,12 +72,12 @@ end
local function Tab_OnEnter()
local self = this.obj
self:Fire("OnTabEnter", 2, self.tabs[this.id].value, this)
self:Fire("OnTabEnter", self.tabs[this.id].value, this)
end
local function Tab_OnLeave()
local self = this.obj
self:Fire("OnTabLeave", 2, self.tabs[this.id].value, this)
self:Fire("OnTabLeave", self.tabs[this.id].value, this)
end
local function Tab_OnShow()
@@ -110,6 +110,21 @@ local methods = {
tab.id = id
tab:SetHeight(24)
-- Normal texture
local texture = _G[tabname.."Left"]
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture = _G[tabname.."Middle"]
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture = _G[tabname.."Right"]
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
-- Disabled texture
texture = _G[tabname.."LeftDisabled"]
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture = _G[tabname.."MiddleDisabled"]
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
texture = _G[tabname.."RightDisabled"]
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
tab.text = _G[tabname .. "Text"]
tab.text:ClearAllPoints()
tab.text:SetPoint("LEFT", 14, -3)
@@ -156,7 +171,7 @@ local methods = {
end
status.selected = value
if found then
self:Fire("OnGroupSelected",1,value)
self:Fire("OnGroupSelected",value)
end
end,
@@ -189,19 +204,24 @@ local methods = {
end
tab:Show()
tab:SetText(v.text)
tab:SetDisabled(v.disabled)
tab.value = v.value
if type(v) == "table" then
tab:SetText(v.text)
tab:SetDisabled(v.disabled)
tab.value = v.value
elseif type(v) == "string" then
tab:SetText(v)
tab.value = v
end
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
local numtabs = getn(tablist)
for i = numtabs+1, numtabs, 1 do
for i = getn(tablist)+1, getn(tabs), 1 do
tabs[i]:Hide()
end
--First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout
local numtabs = getn(tablist)
local numrows = 1
local usedwidth = 0
@@ -281,6 +301,14 @@ local methods = {
end,
["OnHeightSet"] = function(self, height)
local parent = self.parent
if parent and height then
local _, _, _, _, offset = self:GetPoint()
height = (parent.content.height or 0) + (offset or 0) or height
self.frame.height = (parent.content.height or 0) + (offset or 0)
end
--self.frame:SetHeight(height)
local content = self.content
local contentheight = height - (self.borderoffset + 23)
if contentheight < 0 then
@@ -9,9 +9,8 @@ if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs
local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
local math_min, math_max, floor = math.min, math.max, floor
local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat
local tgetn = table.getn
local strfmt = string.format
local tremove, unpack, tconcat, getn = table.remove, unpack, table.concat, getn
local format, split = string.format, string.split
-- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent
@@ -168,12 +167,7 @@ local function FirstFrameUpdate()
end
local function BuildUniqueValue(...)
local n = tgetn(arg)
if n == 1 then
return arg[1]
else
return (unpack(arg)).."\001"..BuildUniqueValue(select(2, unpack(arg)))
end
return tconcat(arg, "\001", 1, arg.n)
end
--[[-----------------------------------------------------------------------------
@@ -189,7 +183,7 @@ end
local function Button_OnClick()
local self = this.obj
self:Fire("OnClick", 2, this.uniquevalue, this.selected)
self:Fire("OnClick", this.uniquevalue, this.selected)
if not this.selected then
self:SetSelected(this.uniquevalue)
this.selected = true
@@ -209,12 +203,12 @@ end
local function Button_OnEnter()
local self = this.obj
self:Fire("OnButtonEnter", 2, this.uniquevalue, this)
self:Fire("OnButtonEnter", this.uniquevalue, this)
if self.enabletooltips then
GameTooltip:SetOwner(this, "ANCHOR_NONE")
GameTooltip:SetPoint("LEFT",this,"RIGHT")
GameTooltip:SetText(this.text:GetText() or "", 1, .82, 0, true)
GameTooltip:SetText(this.text:GetText() or "", 1, .82, 0, 1)
GameTooltip:Show()
end
@@ -222,7 +216,7 @@ end
local function Button_OnLeave()
local self = this.obj
self:Fire("OnButtonLeave", 2, this.uniquevalue, this)
self:Fire("OnButtonLeave", this.uniquevalue, this)
if self.enabletooltips then
GameTooltip:Hide()
@@ -233,7 +227,7 @@ local function OnScrollValueChanged()
if this.obj.noupdate then return end
local self = this.obj
local status = self.status or self.localstatus
status.scrollvalue = floor(arg1 + 0.5)
status.scrollvalue = arg1
self:RefreshTree()
AceGUI:ClearFocus()
end
@@ -271,19 +265,19 @@ end
local function Dragger_OnMouseUp()
local treeframe = this:GetParent()
local self = treeframe.obj
local this = treeframe:GetParent()
local frame = treeframe:GetParent()
treeframe:StopMovingOrSizing()
--treeframe:SetScript("OnUpdate", nil)
treeframe:SetUserPlaced(false)
--Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
treeframe:SetHeight(0)
treeframe:SetPoint("TOPLEFT", this, "TOPLEFT",0,0)
treeframe:SetPoint("BOTTOMLEFT", this, "BOTTOMLEFT",0,0)
treeframe:SetPoint("TOPLEFT", frame, "TOPLEFT",0,0)
treeframe:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT",0,0)
local status = self.status or self.localstatus
status.treewidth = treeframe:GetWidth()
treeframe.obj:Fire("OnTreeResize", 1, treeframe:GetWidth())
treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
-- recalculate the content width
treeframe.obj:OnWidthSet(status.fullwidth)
-- update the layout of the content
@@ -297,7 +291,6 @@ local methods = {
["OnAcquire"] = function(self)
self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
self:EnableButtonTooltips(true)
self.frame:SetScript("OnUpdate", FirstFrameUpdate)
end,
["OnRelease"] = function(self)
@@ -322,36 +315,38 @@ local methods = {
["CreateButton"] = function(self)
local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
local button = CreateFrame("Button", strfmt("AceGUI30TreeButton%d", num), self.treeframe)
local button = CreateFrame("Button", format("AceGUI30TreeButton%d", num), self.treeframe)
button.obj = self
button:SetWidth(DEFAULT_TREE_WIDTH)
button:SetWidth(175)
button:SetHeight(18)
local toggle = CreateFrame("Button", "$parentToggle", button)
local toggle = CreateFrame("Button", nil, button)
toggle:SetWidth(14)
toggle:SetHeight(14)
toggle:ClearAllPoints()
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")
toggle:SetScript("OnClick", Button_OnClick)
button.toggle = toggle
toggle.obj = button
local text = button:CreateFontString()
button.text = text
text:SetFontObject(GameFontNormal)
button:SetHighlightFontObject(GameFontHighlight)
text:SetPoint("RIGHT", toggle, "LEFT", -2, 0);
text:SetPoint("RIGHT", toggle, "LEFT", -2, 0)
text:SetJustifyH("LEFT")
button:SetHighlightFontObject(GameFontHighlight)
button.text = text
local highlight = button:CreateTexture(nil, "HIGHLIGHT");
button.highlight = highlight
local highlight = button:CreateTexture(nil, "HIGHLIGHT")
highlight:SetPoint("TOPLEFT", 0, 1)
highlight:SetPoint("BOTTOMRIGHT", 0, 1)
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)
highlight:SetVertexColor(.196, .388, .8)
button.highlight = highlight
local icon = button:CreateTexture(nil, "OVERLAY")
icon:SetWidth(14)
@@ -445,7 +440,7 @@ local methods = {
self:BuildLevel(tree, 1)
local numlines = tgetn(lines)
local numlines = getn(lines)
local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
if maxlines <= 0 then return end
@@ -529,13 +524,14 @@ local methods = {
button:Show()
buttonnum = buttonnum + 1
end
end,
["SetSelected"] = function(self, value)
local status = self.status or self.localstatus
if status.selected ~= value then
status.selected = value
self:Fire("OnGroupSelected", 1, value)
self:Fire("OnGroupSelected", value)
end
end,
@@ -548,7 +544,7 @@ local methods = {
end
status.selected = uniquevalue
self:RefreshTree(true)
self:Fire("OnGroupSelected", 1, uniquevalue)
self:Fire("OnGroupSelected", uniquevalue)
end,
["SelectByPath"] = function(self, ...)
@@ -556,7 +552,7 @@ local methods = {
end,
["SelectByValue"] = function(self, uniquevalue)
self:Select(uniquevalue, strsplit("\001", uniquevalue))
self:Select(uniquevalue, split("\001", uniquevalue))
end,
["ShowScroll"] = function(self, show)
@@ -598,6 +594,14 @@ local methods = {
end,
["OnHeightSet"] = function(self, height)
local parent = self.parent
if parent and height then
local _, _, _, _, offset = self:GetPoint()
height = (parent.content.height or 0) + (offset or 0) or height
self.frame.height = (parent.content.height or 0) + (offset or 0)
end
self.treeframe:SetHeight(height)
local content = self.content
local contentheight = height - 20
if contentheight < 0 then
@@ -666,7 +670,6 @@ local function Constructor()
local treeframe = CreateFrame("Frame", nil, frame)
treeframe:SetPoint("TOPLEFT", 0, 0)
treeframe:SetPoint("BOTTOMLEFT", 0, 0)
treeframe:SetWidth(DEFAULT_TREE_WIDTH)
treeframe:EnableMouseWheel(true)
treeframe:SetBackdrop(PaneBackdrop)
@@ -690,7 +693,7 @@ local function Constructor()
dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
local scrollbar = CreateFrame("Slider", strfmt("AceConfigDialogTreeGroup%dScrollBar", num), treeframe, "UIPanelScrollBarTemplate")
local scrollbar = CreateFrame("Slider", format("AceConfigDialogTreeGroup%dScrollBar", num), treeframe, "UIPanelScrollBarTemplate")
scrollbar:SetScript("OnValueChanged", nil)
scrollbar:SetPoint("TOPRIGHT", -10, -26)
scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
@@ -714,7 +717,7 @@ local function Constructor()
--Container Support
local content = CreateFrame("Frame", nil, border)
content:SetPoint("TOPLEFT", 10, -10)
content:SetPoint("BOTTOMRIGHT", -10, 10)
--content:SetPoint("BOTTOMRIGHT", -10, 10)
local widget = {
frame = frame,
@@ -739,4 +742,4 @@ local function Constructor()
return AceGUI:RegisterAsContainer(widget)
end
AceGUI:RegisterWidgetType(Type, Constructor, Version)
AceGUI:RegisterWidgetType(Type, Constructor, Version)
@@ -21,26 +21,30 @@ local CreateFrame, UIParent = CreateFrame, UIParent
]]
do
local Type = "Window"
local Version = 4
local Version = 5
local function frameOnShow()
this.obj:Fire("OnShow")
end
local function frameOnClose()
this.obj:Fire("OnClose")
end
local function closeOnClick()
PlaySound("gsTitleOptionExit")
this.obj:Hide()
end
local function frameOnMouseDown()
AceGUI:ClearFocus()
end
local function titleOnMouseDown()
this:GetParent():StartMoving()
AceGUI:ClearFocus()
end
local function frameOnMouseUp()
local frame = this:GetParent()
frame:StopMovingOrSizing()
@@ -51,22 +55,22 @@ do
status.top = frame:GetTop()
status.left = frame:GetLeft()
end
local function sizerseOnMouseDown()
this:GetParent():StartSizing("BOTTOMRIGHT")
AceGUI:ClearFocus()
end
local function sizersOnMouseDown()
this:GetParent():StartSizing("BOTTOM")
AceGUI:ClearFocus()
end
local function sizereOnMouseDown()
this:GetParent():StartSizing("RIGHT")
AceGUI:ClearFocus()
end
local function sizerOnMouseUp()
this:GetParent():StopMovingOrSizing()
end
@@ -74,19 +78,19 @@ do
local function SetTitle(self,title)
self.titletext:SetText(title)
end
local function SetStatusText(self,text)
-- self.statustext:SetText(text)
end
local function Hide(self)
self.frame:Hide()
end
local function Show(self)
self.frame:Show()
end
local function OnAcquire(self)
self.frame:SetParent(UIParent)
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
@@ -94,21 +98,21 @@ do
self:EnableResize(true)
self:Show()
end
local function OnRelease(self)
self.status = nil
for k in pairs(self.localstatus) do
self.localstatus[k] = nil
end
end
-- called to set an external table to store status in
local function SetStatusTable(self, status)
assert(type(status) == "table")
self.status = status
self:ApplyStatus()
end
local function ApplyStatus(self)
local status = self.status or self.localstatus
local frame = self.frame
@@ -121,7 +125,7 @@ do
frame:SetPoint("CENTER",UIParent,"CENTER")
end
end
local function OnWidthSet(self, width)
local content = self.content
local contentwidth = width - 34
@@ -131,8 +135,8 @@ do
content:SetWidth(contentwidth)
content.width = contentwidth
end
local function OnHeightSet(self, height)
local content = self.content
local contentheight = height - 57
@@ -142,19 +146,19 @@ do
content:SetHeight(contentheight)
content.height = contentheight
end
local function EnableResize(self, state)
local func = state and "Show" or "Hide"
self.sizer_se[func](self.sizer_se)
self.sizer_s[func](self.sizer_s)
self.sizer_e[func](self.sizer_e)
end
local function Constructor()
local frame = CreateFrame("Frame",nil,UIParent)
local self = {}
self.type = "Window"
self.Hide = Hide
self.Show = Show
self.SetTitle = SetTitle
@@ -166,9 +170,9 @@ do
self.OnWidthSet = OnWidthSet
self.OnHeightSet = OnHeightSet
self.EnableResize = EnableResize
self.localstatus = {}
self.frame = frame
frame.obj = self
frame:SetWidth(700)
@@ -179,7 +183,8 @@ do
frame:SetResizable(true)
frame:SetFrameStrata("FULLSCREEN_DIALOG")
frame:SetScript("OnMouseDown", frameOnMouseDown)
frame:SetScript("OnShow",frameOnShow)
frame:SetScript("OnHide",frameOnClose)
frame:SetMinResize(240,240)
frame:SetToplevel(true)
@@ -188,81 +193,81 @@ do
titlebg:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Title-Background]])
titlebg:SetPoint("TOPLEFT", 9, -6)
titlebg:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -28, -24)
local dialogbg = frame:CreateTexture(nil, "BACKGROUND")
dialogbg:SetTexture([[Interface\Tooltips\UI-Tooltip-Background]])
dialogbg:SetPoint("TOPLEFT", 8, -24)
dialogbg:SetPoint("BOTTOMRIGHT", -6, 8)
dialogbg:SetVertexColor(0, 0, 0, .75)
local topleft = frame:CreateTexture(nil, "BORDER")
topleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
topleft:SetWidth(64)
topleft:SetHeight(64)
topleft:SetPoint("TOPLEFT")
topleft:SetTexCoord(0.501953125, 0.625, 0, 1)
local topright = frame:CreateTexture(nil, "BORDER")
topright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
topright:SetWidth(64)
topright:SetHeight(64)
topright:SetPoint("TOPRIGHT")
topright:SetTexCoord(0.625, 0.75, 0, 1)
local top = frame:CreateTexture(nil, "BORDER")
top:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
top:SetHeight(64)
top:SetPoint("TOPLEFT", topleft, "TOPRIGHT")
top:SetPoint("TOPRIGHT", topright, "TOPLEFT")
top:SetTexCoord(0.25, 0.369140625, 0, 1)
local bottomleft = frame:CreateTexture(nil, "BORDER")
bottomleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
bottomleft:SetWidth(64)
bottomleft:SetHeight(64)
bottomleft:SetPoint("BOTTOMLEFT")
bottomleft:SetTexCoord(0.751953125, 0.875, 0, 1)
local bottomright = frame:CreateTexture(nil, "BORDER")
bottomright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
bottomright:SetWidth(64)
bottomright:SetHeight(64)
bottomright:SetPoint("BOTTOMRIGHT")
bottomright:SetTexCoord(0.875, 1, 0, 1)
local bottom = frame:CreateTexture(nil, "BORDER")
bottom:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
bottom:SetHeight(64)
bottom:SetPoint("BOTTOMLEFT", bottomleft, "BOTTOMRIGHT")
bottom:SetPoint("BOTTOMRIGHT", bottomright, "BOTTOMLEFT")
bottom:SetTexCoord(0.376953125, 0.498046875, 0, 1)
local left = frame:CreateTexture(nil, "BORDER")
left:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
left:SetWidth(64)
left:SetPoint("TOPLEFT", topleft, "BOTTOMLEFT")
left:SetPoint("BOTTOMLEFT", bottomleft, "TOPLEFT")
left:SetTexCoord(0.001953125, 0.125, 0, 1)
local right = frame:CreateTexture(nil, "BORDER")
right:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
right:SetWidth(64)
right:SetPoint("TOPRIGHT", topright, "BOTTOMRIGHT")
right:SetPoint("BOTTOMRIGHT", bottomright, "TOPRIGHT")
right:SetTexCoord(0.1171875, 0.2421875, 0, 1)
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
close:SetPoint("TOPRIGHT", 2, 1)
close:SetScript("OnClick", closeOnClick)
self.closebutton = close
close.obj = self
local titletext = frame:CreateFontString(nil, "ARTWORK")
titletext:SetFontObject(GameFontNormal)
titletext:SetPoint("TOPLEFT", 12, -8)
titletext:SetPoint("TOPRIGHT", -32, -8)
self.titletext = titletext
local title = CreateFrame("Button", nil, frame)
title:SetPoint("TOPLEFT", titlebg)
title:SetPoint("BOTTOMRIGHT", titlebg)
@@ -270,7 +275,7 @@ do
title:SetScript("OnMouseDown",titleOnMouseDown)
title:SetScript("OnMouseUp", frameOnMouseUp)
self.title = title
local sizer_se = CreateFrame("Frame",nil,frame)
sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
sizer_se:SetWidth(25)
@@ -306,7 +311,7 @@ do
sizer_s:SetScript("OnMouseDown",sizersOnMouseDown)
sizer_s:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_s = sizer_s
local sizer_e = CreateFrame("Frame",nil,frame)
sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25)
sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
@@ -315,17 +320,17 @@ do
sizer_e:SetScript("OnMouseDown",sizereOnMouseDown)
sizer_e:SetScript("OnMouseUp", sizerOnMouseUp)
self.sizer_e = sizer_e
--Container Support
local content = CreateFrame("Frame",nil,frame)
self.content = content
content.obj = self
content:SetPoint("TOPLEFT",frame,"TOPLEFT",12,-32)
content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-12,13)
AceGUI:RegisterAsContainer(self)
return self
return self
end
AceGUI:RegisterWidgetType(Type,Constructor,Version)
end
@@ -6,23 +6,20 @@ local Type, Version = "Button", 23
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local AceCore = LibStub("AceCore-3.0")
-- Lua APIs
local pairs = pairs
-- WoW APIs
local _G = AceCore._G
local _G = _G
local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
--[[-----------------------------------------------------------------------------
Scripts
-------------------------------------------------------------------------------]]
-- arg1 is the button for OnClick event
local function Button_OnClick()
AceGUI:ClearFocus()
PlaySound("igMainMenuOption")
this.obj:Fire("OnClick", 1, arg1)
this.obj:Fire("OnClick", arg1)
end
local function Control_OnEnter()
@@ -54,7 +51,7 @@ local methods = {
self:SetWidth(self.text:GetStringWidth() + 30)
end
end,
["SetAutoWidth"] = function(self, autoWidth)
self.autoWidth = autoWidth
if self.autoWidth then
@@ -7,6 +7,7 @@ if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs
local pairs = pairs
local unpack = unpack
-- WoW APIs
local PlaySound = PlaySound
@@ -24,10 +25,10 @@ local function AlignImage(self)
self.text:ClearAllPoints()
if not img then
self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
self.text:SetPoint("RIGHT",0,0)
self.text:SetPoint("RIGHT", 0, 0)
else
self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0)
self.text:SetPoint("RIGHT",0,0)
self.text:SetPoint("RIGHT", 0, 0)
end
end
@@ -55,7 +56,6 @@ local function CheckBox_OnMouseDown()
end
local function CheckBox_OnMouseUp()
local self = this.obj
if not self.disabled then
self:ToggleChecked()
@@ -66,7 +66,7 @@ local function CheckBox_OnMouseUp()
PlaySound("igMainMenuOptionCheckBoxOff")
end
self:Fire("OnValueChanged", 1, self.checked)
self:Fire("OnValueChanged", self.checked)
AlignImage(self)
end
end
@@ -173,7 +173,6 @@ local methods = {
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
highlight:SetTexCoord(0, 1, 0, 1)
end
checkbg:SetHeight(size)
checkbg:SetWidth(size)
end,
@@ -223,13 +222,14 @@ local methods = {
end
end,
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
["SetImage"] = function(self, path, ...)
local image = self.image
image:SetTexture(path)
if image:GetTexture() then
if a4 or a8 then
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
local n = arg.n
if n == 4 or n == 8 then
image:SetTexCoord(unpack(arg))
else
image:SetTexCoord(0, 1, 0, 1)
end
@@ -254,7 +254,7 @@ local function Constructor()
local checkbg = frame:CreateTexture(nil, "ARTWORK")
checkbg:SetWidth(24)
checkbg:SetHeight(24)
checkbg:SetPoint("TOPLEFT",0,0)
checkbg:SetPoint("TOPLEFT", 0, 0)
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
local check = frame:CreateTexture(nil, "OVERLAY")
@@ -265,7 +265,7 @@ local function Constructor()
text:SetJustifyH("LEFT")
text:SetHeight(18)
text:SetPoint("LEFT", checkbg, "RIGHT")
text:SetPoint("RIGHT",0,0)
text:SetPoint("RIGHT", 0, 0)
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
@@ -1,7 +1,7 @@
--[[-----------------------------------------------------------------------------
ColorPicker Widget
-------------------------------------------------------------------------------]]
local Type, Version = "ColorPicker", 23
local Type, Version = "ColorPicker", 22
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
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)
if ColorPickerFrame:IsVisible() then
--colorpicker is still open
self:Fire("OnValueChanged", 4, r, g, b, a)
self:Fire("OnValueChanged", r, g, b, a)
else
--colorpicker is closed, color callback is first, ignore it,
--alpha callback is the final call after it closes so confirm now
if isAlpha then
self:Fire("OnValueConfirmed", 4, r, g, b, a)
self:Fire("OnValueConfirmed", r, g, b, a)
end
end
end
@@ -51,6 +51,7 @@ local function ColorSwatch_OnClick()
local self = this.obj
if not self.disabled then
ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
ColorPickerFrame:SetFrameLevel(this:GetFrameLevel() + 10)
ColorPickerFrame:SetClampedToScreen(true)
ColorPickerFrame.func = function()
@@ -140,7 +141,7 @@ local function Constructor()
colorSwatch:SetWidth(19)
colorSwatch:SetHeight(19)
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
colorSwatch:SetPoint("LEFT",0,0)
colorSwatch:SetPoint("LEFT", 0, 0)
local texture = frame:CreateTexture(nil, "BACKGROUND")
texture:SetWidth(16)
@@ -164,7 +165,7 @@ local function Constructor()
text:SetJustifyH("LEFT")
text:SetTextColor(1, 1, 1)
text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
text:SetPoint("RIGHT",0,0)
text:SetPoint("RIGHT", 0, 0)
--local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
--highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
@@ -1,25 +1,32 @@
--[[ $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 IsLegion = false
-- Lua APIs
local assert = assert
local tgetn = table.getn
local assert, unpack = assert, unpack
-- WoW APIs
local PlaySound = PlaySound
local CreateFrame = CreateFrame
local function fixlevels(parent,...)
local i = 1
local child = arg[i]
while child do
child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren())
i = i + 1
local function fixlevels(parent, ...)
local child
local level = parent:GetFrameLevel() + 1
for i = 1, arg.n do
child = arg[i]
child:SetFrameLevel(level)
fixlevels(child)
end
end
local function fixstrata(strata, parent, ...)
local child
parent:SetFrameStrata(strata)
for i = 1, arg.n do
child = arg[i]
fixstrata(strata, child)
end
end
@@ -83,9 +90,8 @@ function ItemBase.SetPullout(self, pullout)
self.pullout = pullout
self.frame:SetParent(nil)
local itemFrame = pullout.itemFrame
self.frame:SetParent(itemFrame)
self.parent = itemFrame
self.frame:SetParent(pullout.itemFrame)
self.parent = pullout.itemFrame
fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren())
end
@@ -100,8 +106,8 @@ function ItemBase.GetText(self)
end
-- exported
function ItemBase.SetPoint(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self.frame:SetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
function ItemBase.SetPoint(self, ...)
self.frame:SetPoint(unpack(arg))
end
-- exported
@@ -241,7 +247,7 @@ do
local widgetType = "Dropdown-Item-Header"
local widgetVersion = 1
local function OnEnter(this)
local function OnEnter()
local self = this.obj
self:Fire("OnEnter")
@@ -290,7 +296,7 @@ do
local widgetType = "Dropdown-Item-Execute"
local widgetVersion = 1
local function Frame_OnClick(this, button)
local function Frame_OnClick()
local self = this.obj
if self.disabled then return end
self:Fire("OnClick")
@@ -341,7 +347,7 @@ do
PlaySound("igMainMenuOptionCheckBoxOff")
end
UpdateToggle(self)
self:Fire("OnValueChanged", 1, self.value)
self:Fire("OnValueChanged", self.value)
end
-- exported
@@ -433,7 +439,7 @@ end
-- A single line to separate items
do
local widgetType = "Dropdown-Item-Separator"
local widgetVersion = 2
local widgetVersion = 1
-- exported, override
local function SetDisabled(self, disabled)
@@ -449,7 +455,6 @@ do
local line = self.frame:CreateTexture(nil, "OVERLAY")
line:SetHeight(1)
line:SetTexture(.5, .5, .5)
line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
@@ -1,42 +1,39 @@
--[[ $Id: AceGUIWidget-DropDown.lua 1116 2014-10-12 08:15:46Z nevcairiel $ ]]--
local AceGUI = LibStub("AceGUI-3.0")
local AceCore = LibStub("AceCore-3.0")
-- Lua APIs
local min, max, floor = math.min, math.max, math.floor
local pairs, ipairs, type = pairs, ipairs, type
local tsort, tinsert, tgetn, tsetn = table.sort, table.insert, table.getn, table.setn
local tsort, tinsert, getn, setn = table.sort, table.insert, table.getn, table.setn
local format = string.format
-- WoW APIs
local PlaySound = PlaySound
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
-- List them here for Mikk's FindGlobals script
-- GLOBALS: CLOSE
local function fixlevels(parent,...)
local i = 1
local child = arg[i]
while child do
child:SetFrameLevel(parent:GetFrameLevel()+1)
fixlevels(child, child:GetChildren())
i = i + 1
local function fixlevels(parent, ...)
local child
local level = parent:GetFrameLevel() + 1
for i = 1, arg.n do
child = arg[i]
child:SetFrameLevel(level)
fixlevels(child)
end
end
local function fixstrata(strata, parent, ...)
local i = 1
local child = arg[i]
local child
parent:SetFrameStrata(strata)
while child do
fixstrata(strata, child, child:GetChildren())
i = i + 1
for i = 1, arg.n do
child = arg[i]
fixstrata(strata, child)
end
end
@@ -107,6 +104,7 @@ do
end
child:ClearAllPoints()
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
-- child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
status.offset = offset
status.scrollvalue = value
end
@@ -150,6 +148,7 @@ do
if value < 1000 then
child:ClearAllPoints()
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
-- child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
status.offset = offset
end
end
@@ -172,7 +171,7 @@ do
local function AddItem(self, item)
tinsert(self.items, item)
local h = tgetn(self.items) * 16
local h = getn(self.items) * 16
self.itemFrame:SetHeight(h)
self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
@@ -223,7 +222,7 @@ do
AceGUI:Release(item)
items[i] = nil
end
tsetn(items,0)
setn(items, 0)
end
-- exported
@@ -325,6 +324,7 @@ do
scrollFrame:SetWidth(defaultWidth - 12)
scrollFrame:SetHeight(self.maxHeight - 24)
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
-- scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
scrollFrame:EnableMouseWheel(true)
scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
@@ -333,6 +333,7 @@ do
itemFrame:SetWidth(defaultWidth - 12)
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
-- itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
itemFrame:SetHeight(400)
itemFrame:SetToplevel(true)
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
@@ -436,20 +437,17 @@ do
self:SetText(text)
end
local function OnItemValueChanged(this, event, _, checked)
local function OnItemValueChanged(this, event, checked)
local self = this.userdata.obj
if self.multiselect then
self:Fire("OnValueChanged", 2, this.userdata.value, checked)
self:Fire("OnValueChanged", this.userdata.value, checked)
ShowMultiText(self)
else
if checked then
self:SetValue(this.userdata.value)
self:Fire("OnValueChanged", 1, this.userdata.value)
this:SetValue(false)
self:Fire("OnValueChanged", this.userdata.value)
else
self:SetValue(nil)
self:Fire("OnValueChanged", 1, nil)
this:SetValue(true)
end
if self.open then
@@ -468,7 +466,6 @@ do
pullout:SetCallback("OnClose", OnPulloutClose)
pullout:SetCallback("OnOpen", OnPulloutOpen)
self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
local frame = self.pullout.frame
fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
self:SetHeight(44)
@@ -618,7 +615,7 @@ do
AddListItem(self, key, list[key], itemType)
sortlist[i] = nil
end
tsetn(sortlist,0)
setn(sortlist, 0)
else
for i, key in ipairs(order) do
AddListItem(self, key, list[key], itemType)
@@ -5,19 +5,29 @@ local Type, Version = "EditBox", 26
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
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
local tostring, pairs = tostring, pairs
local gsub, sub = string.gsub, string.sub
-- WoW APIs
local PlaySound = PlaySound
local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
local GetCursorInfo, ClearCursor, GetSpellName = GetCursorInfo, ClearCursor, GetSpellName
local CreateFrame, UIParent = CreateFrame, UIParent
local strlen = string.len
local _G = _G
local GetContainerItemLink = GetContainerItemLink
local GetInventoryItemLink = GetInventoryItemLink
local GetLootSlotLink = GetLootSlotLink
local GetMerchantItemLink = GetMerchantItemLink
local GetQuestItemLink = GetQuestItemLink
local GetQuestLogItemLink = GetQuestLogItemLink
local GetSpellName = GetSpellName
local IsShiftKeyDown = IsShiftKeyDown
local IsSpellPassive = IsSpellPassive
local SpellBook_GetSpellID = SpellBook_GetSpellID
local BANK_CONTAINER = BANK_CONTAINER
local KEYRING_CONTAINER = KEYRING_CONTAINER
local MAX_SPELLS = MAX_SPELLS
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
@@ -28,94 +38,104 @@ Support functions
-------------------------------------------------------------------------------]]
if not AceGUIEditBoxInsertLink then
-- upgradeable hook
hooksecurefunc("BankFrameItemButtonGeneric_OnClick",
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)
local orig_BankFrameItemButtonGeneric_OnClick = BankFrameItemButtonGeneric_OnClick
function BankFrameItemButtonGeneric_OnClick(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(BANK_CONTAINER, 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()))
local orig_ContainerFrameItemButton_OnClick = ContainerFrameItemButton_OnClick
function ContainerFrameItemButton_OnClick(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(this:GetParent():GetID(), this:GetID()))
end
end
local orig_KeyRingItemButton_OnClick = KeyRingItemButton_OnClick
function KeyRingItemButton_OnClick(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(KEYRING_CONTAINER, this:GetID()))
end
end
local orig_LootFrameItem_OnClick = LootFrameItem_OnClick
function LootFrameItem_OnClick(button)
if button == "LeftButton" and IsShiftKeyDown() then
return _G.AceGUIEditBoxInsertLink(GetLootSlotLink(this.slot))
end
end
local orig_SetItemRef = SetItemRef
function SetItemRef(link, text, button)
if IsShiftKeyDown() then
if sub(link, 1, 6) == "player" then
local name = sub(link, 8)
if name and name ~= "" then
return _G.AceGUIEditBoxInsertLink(name)
end
else
return _G.AceGUIEditBoxInsertLink(text)
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
end
end
local orig_MerchantItemButton_OnClick = MerchantItemButton_OnClick
function MerchantItemButton_OnClick(button, ignoreModifiers)
if MerchantFrame.selectedTab == 1 and button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIEditBoxInsertLink(GetMerchantItemLink(this:GetID()))
end
end
local orig_PaperDollItemSlotButton_OnClick = PaperDollItemSlotButton_OnClick
function PaperDollItemSlotButton_OnClick(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIEditBoxInsertLink(GetInventoryItemLink("player", this:GetID()))
end
end
local orig_QuestItem_OnClick = QuestItem_OnClick
function QuestItem_OnClick()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end
local orig_QuestRewardItem_OnClick = QuestRewardItem_OnClick
function QuestRewardItem_OnClick()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end
local orig_QuestLogTitleButton_OnClick = QuestLogTitleButton_OnClick
function QuestLogTitleButton_OnClick(button)
if IsShiftKeyDown() and (not this.isHeader) then
return _G.AceGUIEditBoxInsertLink(gsub(this:GetText(), " *(.*)", "%1"))
end
end
local orig_QuestLogRewardItem_OnClick = QuestLogRewardItem_OnClick
function QuestLogRewardItem_OnClick()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIEditBoxInsertLink(GetQuestLogItemLink(this.type, this:GetID()))
end
end
local orig_SpellButton_OnClick = SpellButton_OnClick
function SpellButton_OnClick(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 subSpellName ~= "" then
_G.AceGUIEditBoxInsertLink(spellName.."("..subSpellName..")")
else
return _G.AceGUIEditBoxInsertLink(text)
_G.AceGUIEditBoxInsertLink(spellName)
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
end
function _G.AceGUIEditBoxInsertLink(text)
@@ -163,7 +183,7 @@ end
local function EditBox_OnEnterPressed()
local self = this.obj
local value = this:GetText()
local cancel = self:Fire("OnEnterPressed", 1, value)
local cancel = self:Fire("OnEnterPressed", value)
if not cancel then
PlaySound("igMainMenuOptionCheckBoxOn")
HideButton(self)
@@ -172,34 +192,36 @@ end
local function EditBox_OnReceiveDrag()
if not GetCursorInfo then return end
local self = this.obj
local type, id, info = GetCursorInfo()
if type == "item" then
self:SetText(info)
self:Fire("OnEnterPressed", 1, info)
self:Fire("OnEnterPressed", info)
ClearCursor()
elseif type == "spell" then
local spell, rank = GetSpellName(id, info)
if rank ~= "" then spell = spell.."("..rank..")" end
self:SetText(spell)
self:Fire("OnEnterPressed", 1, spell)
local name, rank = GetSpellName(id, info)
if rank ~= "" then
name = name.."("..rank..")"
end
self:SetText(name)
self:Fire("OnEnterPressed", name)
ClearCursor()
elseif type == "macro" then
local name = GetMacroInfo(id)
self:SetText(name)
self:Fire("OnEnterPressed", 1, name)
self:Fire("OnEnterPressed", name)
ClearCursor()
end
HideButton(self)
AceGUI:ClearFocus()
end
local function EditBox_OnTextChanged()
local self = this.obj
local value = this:GetText()
if tostring(value) ~= tostring(self.lasttext) then
self:Fire("OnTextChanged", 1, value)
self:Fire("OnTextChanged", value)
self.lasttext = value
ShowButton(self)
end
@@ -217,7 +239,7 @@ end
local function Button_OnClick()
local editbox = this.obj.editbox
editbox:ClearFocus()
this = editbox -- Ace3v: this is kinda hack here
this = editbox
EditBox_OnEnterPressed()
end
@@ -256,7 +278,7 @@ local methods = {
["SetText"] = function(self, text)
self.lasttext = text or ""
self.editbox:SetText(text or "")
self.editbox:HighlightText(0)
EditBoxSetCursorPosition(self.editbox, 0)
HideButton(self)
end,
@@ -43,8 +43,8 @@ local function Constructor()
frame:Hide()
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
label:SetPoint("TOP",0,0)
label:SetPoint("BOTTOM",0,0)
label:SetPoint("TOP", 0, 0)
label:SetPoint("BOTTOM", 0, 0)
label:SetJustifyH("CENTER")
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
-- Lua APIs
local pairs, print = pairs, print
local pairs, print, unpack = pairs, print, unpack
-- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent
@@ -23,7 +23,7 @@ local function Control_OnLeave()
end
local function Button_OnClick()
this.obj:Fire("OnClick", 1, arg1)
this.obj:Fire("OnClick", arg1)
AceGUI:ClearFocus()
end
@@ -53,13 +53,14 @@ local methods = {
end
end,
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
["SetImage"] = function(self, path, ...)
local image = self.image
image:SetTexture(path)
if image:GetTexture() then
if a4 or a8 then
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
local n = arg.n
if n == 4 or n == 8 then
image:SetTexCoord(unpack(arg))
else
image:SetTexCoord(0, 1, 0, 1)
end
@@ -131,7 +132,7 @@ local function Constructor()
widget[method] = func
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)
end
@@ -1,12 +1,12 @@
--[[-----------------------------------------------------------------------------
InteractiveLabel Widget
-------------------------------------------------------------------------------]]
local Type, Version = "InteractiveLabel", 20
local Type, Version = "InteractiveLabel", 21
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs
local pairs = pairs
local pairs, unpack = pairs, unpack
-- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent
@@ -27,7 +27,7 @@ local function Control_OnLeave()
end
local function Label_OnClick()
this.obj:Fire("OnClick", 1, arg1)
this.obj:Fire("OnClick", arg1)
AceGUI:ClearFocus()
end
@@ -44,13 +44,14 @@ local methods = {
-- ["OnRelease"] = nil,
["SetHighlight"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
self.highlight:SetTexture(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
["SetHighlight"] = function(self, ...)
self.highlight:SetTexture(unpack(arg))
end,
["SetHighlightTexCoord"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8)
if a4 or a8 then
self.highlight:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
["SetHighlightTexCoord"] = function(self, ...)
local c = arg.n
if c == 4 or c == 8 then
self.highlight:SetTexCoord(unpack(arg))
else
self.highlight:SetTexCoord(0, 1, 0, 1)
end
@@ -38,10 +38,31 @@ local function Keybinding_OnHide()
self.waitingForKey = nil
end
local function Keybinding_OnClick()
if arg1 == "LeftButton" or arg1 == "RightButton" then
local self = this.obj
if self.waitingForKey then
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
AceGUI:ClearFocus()
end
local ignoreKeys = {
["BUTTON1"] = true, ["BUTTON2"] = 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 self = this.obj
@@ -70,23 +91,14 @@ local function Keybinding_OnKeyDown()
if not self.disabled then
self:SetKey(keyPressed)
self:Fire("OnKeyChanged", 1, keyPressed)
self:Fire("OnKeyChanged", keyPressed)
end
end
end
local function Keybinding_OnMouseDown()
getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
end
local function Keybinding_OnMouseUp()
getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
local self = this.obj
if MouseIsOver(this) and not self.disabled then
local self = this.obj
if self.waitingForKey then
if arg1 ~= "LeftButton" and arg1 ~= "RightButton" then
Keybinding_OnKeyDown()
@@ -107,6 +119,19 @@ local function Keybinding_OnMouseUp()
AceGUI:ClearFocus()
end
local function Keybinding_OnMouseDown()
if arg1 == "LeftButton" or arg1 == "RightButton" then
return
elseif arg1 == "MiddleButton" then
arg1 = "BUTTON3"
elseif arg1 == "Button4" then
arg1 = "BUTTON4"
elseif arg1 == "Button5" then
arg1 = "BUTTON5"
end
Keybinding_OnKeyDown()
end
local function Keybinding_OnMouseWheel()
if arg1 >= 0 then
arg1 = "MOUSEWHEELUP"
@@ -198,18 +223,17 @@ local function Constructor()
button:EnableMouse(true)
button:EnableMouseWheel(false)
button:RegisterForClicks("AnyDown")
button:SetScript("OnEnter", Control_OnEnter)
button:SetScript("OnLeave", Control_OnLeave)
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("OnClick", Keybinding_OnClick)
button:SetScript("OnMouseUp", Keybinding_OnMouseUp)
button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
button:SetScript("OnHide", Keybinding_OnHide)
button:SetPoint("BOTTOMLEFT",0,0)
button:SetPoint("BOTTOMRIGHT",0,0)
button:SetPoint("BOTTOMLEFT", 0, 0)
button:SetPoint("BOTTOMRIGHT", 0, 0)
button:SetHeight(24)
button:EnableKeyboard(false)
@@ -218,8 +242,8 @@ local function Constructor()
text:SetPoint("RIGHT", -7, 0)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
label:SetPoint("TOPLEFT",0,0)
label:SetPoint("TOPRIGHT",0,0)
label:SetPoint("TOPLEFT", 0, 0)
label:SetPoint("TOPRIGHT", 0, 0)
label:SetJustifyH("CENTER")
label:SetHeight(18)
@@ -2,12 +2,12 @@
Label Widget
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)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs
local max, pairs = math.max, pairs
local max, pairs, unpack = math.max, pairs, unpack
-- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent
@@ -35,14 +35,14 @@ local function UpdateImageAnchor(self)
local imagewidth = image:GetWidth()
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:SetPoint("TOP",0,0)
image:SetPoint("TOP", 0, 0)
label:SetPoint("TOP", image, "BOTTOM")
label:SetPoint("LEFT",0,0)
label:SetPoint("LEFT", 0, 0)
label:SetWidth(width)
height = image:GetHeight() + label:GetHeight()
else
-- image on the left
image:SetPoint("TOPLEFT",0,0)
image:SetPoint("TOPLEFT", 0, 0)
if image:GetHeight() > label:GetHeight() then
label:SetPoint("LEFT", image, "RIGHT", 4, 0)
else
@@ -53,11 +53,11 @@ local function UpdateImageAnchor(self)
end
else
-- no image shown
label:SetPoint("TOPLEFT",0,0)
label:SetPoint("TOPLEFT", 0, 0)
label:SetWidth(width)
height = label:GetHeight()
end
self.resizing = true
frame:SetHeight(height)
frame.height = height
@@ -78,6 +78,8 @@ local methods = {
self:SetImageSize(16, 16)
self:SetColor()
self:SetFontObject()
self:SetJustifyH("LEFT")
self:SetJustifyV("TOP")
-- reset the flag
self.resizing = nil
@@ -103,14 +105,15 @@ local methods = {
self.label:SetVertexColor(r, g, b)
end,
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
["SetImage"] = function(self, path, ...)
local image = self.image
image:SetTexture(path)
if image:GetTexture() then
self.imageshown = true
if a4 or a8 then
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
local n = arg.n
if n == 4 or n == 8 then
image:SetTexCoord(unpack(arg))
else
image:SetTexCoord(0, 1, 0, 1)
end
@@ -133,6 +136,14 @@ local methods = {
self.image:SetHeight(height)
UpdateImageAnchor(self)
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()
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
label:SetJustifyH("LEFT")
label:SetJustifyV("TOP")
local image = frame:CreateTexture(nil, "BACKGROUND")
-- create widget
@@ -2,17 +2,28 @@ local Type, Version = "MultiLineEditBox", 28
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
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
local strfmt = string.format
local pairs = pairs
local format, gsub, sub = string.format, string.gsub, string.sub
-- WoW APIs
local CursorHasItem, ClearCursor = CursorHasItem, ClearCursor
local GetCursorInfo, GetSpellName, ClearCursor = GetCursorInfo, GetSpellName, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent
local _G = AceCore._G
local _G = _G
local GetContainerItemLink = GetContainerItemLink
local GetInventoryItemLink = GetInventoryItemLink
local GetLootSlotLink = GetLootSlotLink
local GetMerchantItemLink = GetMerchantItemLink
local GetQuestItemLink = GetQuestItemLink
local GetQuestLogItemLink = GetQuestLogItemLink
local GetSpellName = GetSpellName
local IsShiftKeyDown = IsShiftKeyDown
local IsSpellPassive = IsSpellPassive
local SpellBook_GetSpellID = SpellBook_GetSpellID
local BANK_CONTAINER = BANK_CONTAINER
local KEYRING_CONTAINER = KEYRING_CONTAINER
local MAX_SPELLS = MAX_SPELLS
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
@@ -21,101 +32,112 @@ local _G = AceCore._G
--[[-----------------------------------------------------------------------------
Support functions
-------------------------------------------------------------------------------]]
if not AceGUIMultiLineEditBoxInsertLink then
-- upgradeable hook
hooksecurefunc("BankFrameItemButtonGeneric_OnClick",
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)
local orig_BankFrameItemButtonGeneric_OnClick = BankFrameItemButtonGeneric_OnClick
function BankFrameItemButtonGeneric_OnClick(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(BANK_CONTAINER, 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()))
local orig_ContainerFrameItemButton_OnClick = ContainerFrameItemButton_OnClick
function ContainerFrameItemButton_OnClick(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(this:GetParent():GetID(), this:GetID()))
end
end
local orig_KeyRingItemButton_OnClick = KeyRingItemButton_OnClick
function KeyRingItemButton_OnClick(button)
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(KEYRING_CONTAINER, this:GetID()))
end
end
local orig_LootFrameItem_OnClick = LootFrameItem_OnClick
function LootFrameItem_OnClick(button)
if button == "LeftButton" and IsShiftKeyDown() then
return _G.AceGUIMultiLineEditBoxInsertLink(GetLootSlotLink(this.slot))
end
end
local orig_SetItemRef = SetItemRef
function SetItemRef(link, text, button)
if IsShiftKeyDown() then
if sub(link, 1, 6) == "player" then
local name = sub(link, 8)
if name and name ~= "" then
return _G.AceGUIMultiLineEditBoxInsertLink(name)
end
else
return _G.AceGUIMultiLineEditBoxInsertLink(text)
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
end
end
local orig_MerchantItemButton_OnClick = MerchantItemButton_OnClick
function MerchantItemButton_OnClick(button, ignoreModifiers)
if MerchantFrame.selectedTab == 1 and button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIMultiLineEditBoxInsertLink(GetMerchantItemLink(this:GetID()))
end
end
local orig_PaperDollItemSlotButton_OnClick = PaperDollItemSlotButton_OnClick
function PaperDollItemSlotButton_OnClick(button, ignoreModifiers)
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
return _G.AceGUIMultiLineEditBoxInsertLink(GetInventoryItemLink("player", this:GetID()))
end
end
local orig_QuestItem_OnClick = QuestItem_OnClick
function QuestItem_OnClick()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end
local orig_QuestRewardItem_OnClick = QuestRewardItem_OnClick
function QuestRewardItem_OnClick()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
end
end
local orig_QuestLogTitleButton_OnClick = QuestLogTitleButton_OnClick
function QuestLogTitleButton_OnClick(button)
if IsShiftKeyDown() and (not this.isHeader) then
return _G.AceGUIMultiLineEditBoxInsertLink(gsub(this:GetText(), " *(.*)", "%1"))
end
end
local orig_QuestLogRewardItem_OnClick = QuestLogRewardItem_OnClick
function QuestLogRewardItem_OnClick()
if IsShiftKeyDown() and this.rewardType ~= "spell" then
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestLogItemLink(this.type, this:GetID()))
end
end
local orig_SpellButton_OnClick = SpellButton_OnClick
function SpellButton_OnClick(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 subSpellName ~= "" then
_G.AceGUIMultiLineEditBoxInsertLink(spellName.."("..subSpellName..")")
else
return _G.AceGUIMultiLineEditBoxInsertLink(text)
_G.AceGUIMultiLineEditBoxInsertLink(spellName)
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
end
function _G.AceGUIMultiLineEditBoxInsertLink(text)
for i = 1, AceGUI:GetWidgetCount(Type) do
local editbox = _G[strfmt("MultiLineEditBox%uEdit",i)]
local editbox = _G[format("MultiLineEditBox%uEdit",i)]
if editbox and editbox:IsVisible() and editbox.hasfocus then
editbox:Insert(text)
return true
@@ -123,6 +145,7 @@ function _G.AceGUIMultiLineEditBoxInsertLink(text)
end
end
local function Layout(self)
self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
@@ -144,16 +167,15 @@ end
--[[-----------------------------------------------------------------------------
Scripts
-------------------------------------------------------------------------------]]
local function OnClick() -- Button
local function OnClick() -- Button
local self = this.obj
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()
end
end
local function OnCursorChanged() -- EditBox
local function OnCursorChanged() -- EditBox
local self, y = this.obj.scrollFrame, -arg2
local offset = self:GetVerticalScroll()
if y < offset then
@@ -166,13 +188,13 @@ local function OnCursorChanged() -- EditBox
end
end
local function OnEditFocusLost() -- EditBox
local function OnEditFocusLost() -- EditBox
this.hasfocus = nil
this:HighlightText(0, 0)
this.obj:Fire("OnEditFocusLost")
end
local function OnEnter() -- EditBox / ScrollFrame
local function OnEnter() -- EditBox / ScrollFrame
local self = this.obj
if not self.entered then
self.entered = true
@@ -180,7 +202,7 @@ local function OnEnter() -- EditBox / ScrollFrame
end
end
local function OnLeave() -- EditBox / ScrollFrame
local function OnLeave() -- EditBox / ScrollFrame
local self = this.obj
if self.entered then
self.entered = nil
@@ -188,57 +210,64 @@ local function OnLeave() -- EditBox / ScrollFrame
end
end
local function OnMouseUp() -- ScrollFrame
local function OnMouseUp() -- ScrollFrame
local self = this.obj.editBox
self:SetFocus()
local n = self:GetNumLetters()
self:HighlightText(n,n)
EditBoxSetCursorPosition(self, self:GetNumLetters())
end
local function OnReceiveDrag() -- EditBox / ScrollFrame
if not CursorHasItem() then return end
local function OnReceiveDrag() -- EditBox / ScrollFrame
if not GetCursorInfo then return end
local type, id, info = GetCursorInfo()
if type == "spell" then
local name, rank = GetSpellName(id, info)
if rank ~= "" then
name = name.."("..rank..")"
end
info = name
elseif type ~= "item" then
return
end
ClearCursor()
local self = this.obj
local editBox = self.editBox
if not this.hasfocus then
this.hasfocus = true
editBox:SetFocus()
local n = editBox:GetNumLetters()
editBox:HighlightText(n,n)
EditBoxSetCursorPosition(editBox, editBox:GetNumLetters())
end
editBox:Insert(info)
self.button:Enable()
end
local function OnSizeChanged() -- ScrollFrame
this:UpdateScrollChildRect()
this:SetVerticalScroll(this:GetHeight())
this.obj.editBox:SetWidth(arg1)
local function OnSizeChanged() -- ScrollFrame
this.obj.editBox:SetWidth(this.obj.editBox:GetWidth())
end
local function OnTextChanged() -- EditBox
local function OnTextChanged() -- EditBox
local self = this.obj
local value = this:GetText()
if tostring(value) ~= tostring(self.lasttext) then
self:Fire("OnTextChanged", 1, value)
self.lasttext = value
local value = self.editBox:GetText()
if not self.lastText or value ~= self.lastText then
self:Fire("OnTextChanged", value)
self.lastText = nil
self.button:Enable()
else
self.button:Disable()
self.lastText = value
end
end
local function OnTextSet() -- EditBox
local function OnTextSet() -- EditBox
this:HighlightText(0, 0)
EditBoxSetCursorPosition(this, this:GetNumLetters())
EditBoxSetCursorPosition(this, 0)
this.obj.button:Disable()
end
local function OnVerticalScroll() -- ScrollFrame
local self = this.obj
local editBox = self.editBox
local function OnVerticalScroll() -- ScrollFrame
local editBox = this.obj.editBox
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
local function OnShowFocus()
@@ -252,7 +281,7 @@ local function OnEditFocusGained()
this.obj:Fire("OnEditFocusGained")
end
local function OnEscapePressed() -- EditBox
local function OnEscapePressed()
AceGUI:ClearFocus()
end
@@ -314,10 +343,8 @@ local methods = {
end,
["SetText"] = function(self, text)
self.lasttext = text or ""
self.editBox:SetText(text or "")
self.editBox:HighlightText(0)
self.button:Disable()
self.lastText = text
self.editBox:SetText(text)
end,
["GetText"] = function(self)
@@ -353,6 +380,22 @@ local methods = {
["HighlightText"] = function(self, from, to)
self.editBox:HighlightText(from, to)
end,
["GetCursorPosition"] = function(self)
return EditBoxGetCursorPosition(self.editBox)
end,
["SetCursorPosition"] = function(self, pos)
return EditBoxSetCursorPosition(self.editBox, pos)
end,
["OnWidthSet"] = function(self, width)
self.scrollFrame:SetWidth(width)
end,
["OnHeightSet"] = function(self, height)
self.scrollFrame:SetHeight(height)
end
}
--[[-----------------------------------------------------------------------------
@@ -377,7 +420,7 @@ local function Constructor()
label:SetText(ACCEPT)
label:SetHeight(10)
local button = CreateFrame("Button", strfmt("%s%dButton", Type, widgetNum), frame, "UIPanelButtonTemplate")
local button = CreateFrame("Button", format("%s%dButton", Type, widgetNum), frame, "UIPanelButtonTemplate")
button:SetPoint("BOTTOMLEFT", 0, 4)
button:SetHeight(22)
button:SetWidth(label:GetStringWidth() + 24)
@@ -396,7 +439,7 @@ local function Constructor()
scrollBG:SetBackdropColor(0, 0, 0)
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
local scrollFrame = CreateFrame("ScrollFrame", strfmt("%s%dScrollFrame", Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
local scrollFrame = CreateFrame("ScrollFrame", format("%s%dScrollFrame", Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
scrollBar:ClearAllPoints()
@@ -414,17 +457,9 @@ local function Constructor()
scrollFrame:SetScript("OnMouseUp", OnMouseUp)
scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
local old = scrollFrame:GetScript("OnVerticalScroll");
if old then
scrollFrame:SetScript("OnVerticalScroll", function()
old()
OnVerticalScroll()
end)
else
scrollFrame:SetScript("OnVerticalScroll", OnVerticalScroll)
end
HookScript(scrollFrame, "OnVerticalScroll", OnVerticalScroll)
local editBox = CreateFrame("EditBox", strfmt("%s%dEdit", Type, widgetNum), scrollFrame)
local editBox = CreateFrame("EditBox", format("%s%dEdit", Type, widgetNum), scrollFrame)
editBox:SetFontObject(ChatFontNormal)
editBox:SetMultiLine(true)
editBox:EnableMouse(true)
@@ -440,10 +475,9 @@ local function Constructor()
editBox:SetScript("OnTextSet", OnTextSet)
editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
-- Ace3v: the orders are important here
scrollFrame:SetScrollChild(editBox)
editBox:SetPoint("TOPLEFT",0,0)
editBox:SetPoint("TOPRIGHT",0,0)
editBox:SetAllPoints()
local widget = {
button = button,
@@ -2,14 +2,14 @@
Slider Widget
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)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
-- Lua APIs
local min, max, floor = math.min, math.max, math.floor
local format, gsub = string.format, string.gsub
local tonumber, pairs = tonumber, pairs
local format, gsub = string.format, string.gsub
-- WoW APIs
local PlaySound = PlaySound
@@ -62,13 +62,9 @@ local function Slider_OnValueChanged()
local self = this.obj
if not this.setup then
local newvalue = this: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
self.value = newvalue
self:Fire("OnValueChanged", 1, newvalue)
self:Fire("OnValueChanged", newvalue)
end
if self.value then
UpdateText(self)
@@ -78,7 +74,7 @@ end
local function Slider_OnMouseUp()
local self = this.obj
self:Fire("OnMouseUp", 1, self.value)
self:Fire("OnMouseUp", self.value)
end
local function Slider_OnMouseWheel()
@@ -111,7 +107,7 @@ local function EditBox_OnEnterPressed()
if value then
PlaySound("igMainMenuOptionCheckBoxOn")
self.slider:SetValue(value)
self:Fire("OnMouseUp", 1, value)
self:Fire("OnMouseUp", value)
end
end
@@ -222,9 +218,9 @@ local function Constructor()
frame:SetScript("OnMouseDown", Frame_OnMouseDown)
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
label:SetPoint("TOPLEFT",0,0)
label:SetPoint("TOPRIGHT",0,0)
label:SetJustifyH("CENTER",0,0)
label:SetPoint("TOPLEFT", 0, 0)
label:SetPoint("TOPRIGHT", 0, 0)
label:SetJustifyH("CENTER")
label:SetHeight(15)
local slider = CreateFrame("Slider", nil, frame)