diff --git a/Libs/AceAddon-3.0/AceAddon-3.0.lua b/Libs/AceAddon-3.0/AceAddon-3.0.lua
index 0ea93d1..f392a21 100755
--- a/Libs/AceAddon-3.0/AceAddon-3.0.lua
+++ b/Libs/AceAddon-3.0/AceAddon-3.0.lua
@@ -1,649 +1,649 @@
---- **AceAddon-3.0** provides a template for creating addon objects.
--- It'll provide you with a set of callback functions that allow you to simplify the loading
--- process of your addon.\\
--- Callbacks provided are:\\
--- * **OnInitialize**, which is called directly after the addon is fully loaded.
--- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
--- * **OnDisable**, which is only called when your addon is manually being disabled.
--- @usage
--- -- A small (but complete) addon, that doesn't do anything,
--- -- but shows usage of the callbacks.
--- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
---
--- function MyAddon:OnInitialize()
--- -- do init tasks here, like loading the Saved Variables,
--- -- or setting up slash commands.
--- end
---
--- function MyAddon:OnEnable()
--- -- Do more initialization here, that really enables the use of your addon.
--- -- Register Events, Hook functions, Create Frames, Get information from
--- -- the game that wasn't available in OnInitialize
--- end
---
--- function MyAddon:OnDisable()
--- -- Unhook, Unregister Events, Hide frames that you created.
--- -- You would probably only use an OnDisable if you want to
--- -- build a "standby" mode, or be able to toggle modules on/off.
--- end
--- @class file
--- @name AceAddon-3.0.lua
--- @release $Id: AceAddon-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-
-local MAJOR, MINOR = "AceAddon-3.0", 13
-local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceAddon then return end -- No Upgrade needed.
-
-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.
-AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
-AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
-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 = table.insert, table.concat, table.remove
-local fmt, tostring = string.format, tostring
-local select, pairs, next, type, unpack = select, pairs, next, type, unpack
-local loadstring, assert, error = loadstring, assert, error
-local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
-
---[[
- xpcall safecall implementation
-]]
-local xpcall = xpcall
-
-local function errorhandler(err)
- return geterrorhandler()(err)
-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 xpcall(func, errorhandler, ...)
- end
-end
-
--- local functions that will be implemented further down
-local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
-
--- used in the addon metatable
-local function addontostring( self ) return self.name end
-
--- Check if the addon is queued for initialization
-local function queuedForInitialization(addon)
- for i = 1, #AceAddon.initializequeue do
- if AceAddon.initializequeue[i] == addon then
- return true
- end
- end
- return false
-end
-
---- Create a new AceAddon-3.0 addon.
--- Any libraries you specified will be embeded, and the addon will be scheduled for
--- its OnInitialize and OnEnable callbacks.
--- The final addon object, with all libraries embeded, will be returned.
--- @paramsig [object ,]name[, lib, ...]
--- @param object Table to use as a base for the addon (optional)
--- @param name Name of the addon object to create
--- @param lib List of libraries to embed into the addon
--- @usage
--- -- Create a simple addon object
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
---
--- -- 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, ...)
- local object,name
- local i=1
- if type(objectorname)=="table" then
- object=objectorname
- name=...
- i=2
- else
- name=objectorname
- end
- if type(name)~="string" then
- error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
- end
- if self.addons[name] then
- error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
- end
-
- object = object or {}
- object.name = name
-
- local addonmeta = {}
- local oldmeta = getmetatable(object)
- if oldmeta then
- for k, v in pairs(oldmeta) do addonmeta[k] = v end
- end
- addonmeta.__tostring = addontostring
-
- setmetatable( object, addonmeta )
- self.addons[name] = object
- object.modules = {}
- object.orderedModules = {}
- object.defaultModuleLibraries = {}
- Embed( object ) -- embed NewModule, GetModule methods
- self:EmbedLibraries(object, select(i,...))
-
- -- 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
--- @param silent if true, the addon is optional, silently return nil if its not found
--- @usage
--- -- Get the Addon
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-function AceAddon:GetAddon(name, silent)
- if not silent and not self.addons[name] then
- error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
- end
- return self.addons[name]
-end
-
--- - Embed a list of libraries into the specified addon.
--- This function will try to embed all of the listed libraries into the addon
--- and error if a single one fails.
---
--- **Note:** This function is for internal use by :NewAddon/:NewModule
--- @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, ...)
- for i=1,select("#", ... ) do
- local libname = select(i, ...)
- self:EmbedLibrary(addon, libname, false, 4)
- end
-end
-
--- - Embed a library into the addon object.
--- This function will check if the specified library is registered with LibStub
--- and if it has a :Embed function to call. It'll error if any of those conditions
--- fails.
---
--- **Note:** This function is for internal use by :EmbedLibraries
--- @paramsig addon, libname[, silent[, offset]]
--- @param addon addon object to embed the library in
--- @param libname name of the library to embed
--- @param silent marks an embed to fail silently if the library doesn't exist (optional)
--- @param offset will push the error messages back to said offset, defaults to 2 (optional)
-function AceAddon:EmbedLibrary(addon, libname, silent, offset)
- local lib = LibStub:GetLibrary(libname, true)
- if not lib and not silent then
- error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
- elseif lib and type(lib.Embed) == "function" then
- lib:Embed(addon)
- tinsert(self.embeds[addon], libname)
- return true
- elseif lib then
- error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
- end
-end
-
---- Return the specified module from an addon object.
--- Throws an error if the addon object cannot be found (except if silent is set)
--- @name //addon//:GetModule
--- @paramsig name[, silent]
--- @param name unique name of the module
--- @param silent if true, the module is optional, silently return nil if its not found (optional)
--- @usage
--- -- Get the Addon
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- -- Get the Module
--- MyModule = MyAddon:GetModule("MyModule")
-function GetModule(self, name, silent)
- if not self.modules[name] and not silent then
- error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
- end
- return self.modules[name]
-end
-
-local function IsModuleTrue(self) return true end
-
---- Create a new module for the addon.
--- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
--- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
--- an addon object.
--- @name //addon//:NewModule
--- @paramsig name[, prototype|lib[, lib, ...]]
--- @param name unique name of the module
--- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
--- @param lib List of libraries to embed into the addon
--- @usage
--- -- Create a module with some embeded libraries
--- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
---
--- -- 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, ...)
- if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
- if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
-
- if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
-
- -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
- -- 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(fmt("%s_%s", self.name or tostring(self), name))
-
- module.IsModule = IsModuleTrue
- module:SetEnabledState(self.defaultModuleState)
- module.moduleName = name
-
- if type(prototype) == "string" then
- AceAddon:EmbedLibraries(module, prototype, ...)
- else
- AceAddon:EmbedLibraries(module, ...)
- end
- AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
-
- if not prototype or type(prototype) == "string" then
- prototype = self.defaultModulePrototype or nil
- end
-
- if type(prototype) == "table" then
- local mt = getmetatable(module)
- mt.__index = prototype
- setmetatable(module, mt) -- More of a Base class type feel.
- end
-
- 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)
-
- return module
-end
-
---- Returns the real name of the addon or module, without any prefix.
--- @name //addon//:GetName
--- @paramsig
--- @usage
--- print(MyAddon:GetName())
--- -- prints "MyAddon"
-function GetName(self)
- return self.moduleName or self.name
-end
-
---- Enables the Addon, if possible, return true or false depending on success.
--- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
--- and enabling all modules of the addon (unless explicitly disabled).\\
--- :Enable() also sets the internal `enableState` variable to true
--- @name //addon//:Enable
--- @paramsig
--- @usage
--- -- Enable MyModule
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyModule = MyAddon:GetModule("MyModule")
--- MyModule:Enable()
-function Enable(self)
- self:SetEnabledState(true)
-
- -- nevcairiel 2013-04-27: don't enable an addon/module if its queued for init still
- -- it'll be enabled after the init process
- if not queuedForInitialization(self) then
- return AceAddon:EnableAddon(self)
- end
-end
-
---- Disables the Addon, if possible, return true or false depending on success.
--- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
--- and disabling all modules of the addon.\\
--- :Disable() also sets the internal `enableState` variable to false
--- @name //addon//:Disable
--- @paramsig
--- @usage
--- -- Disable MyAddon
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyAddon:Disable()
-function Disable(self)
- self:SetEnabledState(false)
- return AceAddon:DisableAddon(self)
-end
-
---- Enables the Module, if possible, return true or false depending on success.
--- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
--- @name //addon//:EnableModule
--- @paramsig name
--- @usage
--- -- Enable MyModule using :GetModule
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyModule = MyAddon:GetModule("MyModule")
--- MyModule:Enable()
---
--- -- Enable MyModule using the short-hand
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyAddon:EnableModule("MyModule")
-function EnableModule(self, name)
- local module = self:GetModule( name )
- return module:Enable()
-end
-
---- Disables the Module, if possible, return true or false depending on success.
--- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
--- @name //addon//:DisableModule
--- @paramsig name
--- @usage
--- -- Disable MyModule using :GetModule
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyModule = MyAddon:GetModule("MyModule")
--- MyModule:Disable()
---
--- -- Disable MyModule using the short-hand
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyAddon:DisableModule("MyModule")
-function DisableModule(self, name)
- local module = self:GetModule( name )
- return module:Disable()
-end
-
---- Set the default libraries to be mixed into all modules created by this object.
--- Note that you can only change the default module libraries before any module is created.
--- @name //addon//:SetDefaultModuleLibraries
--- @paramsig lib[, lib, ...]
--- @param lib List of libraries to embed into the addon
--- @usage
--- -- Create the addon object
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
--- -- Configure default libraries for modules (all modules need AceEvent-3.0)
--- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
--- -- Create a module
--- MyModule = MyAddon:NewModule("MyModule")
-function SetDefaultModuleLibraries(self, ...)
- if next(self.modules) then
- error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
- end
- self.defaultModuleLibraries = {...}
-end
-
---- Set the default state in which new modules are being created.
--- Note that you can only change the default state before any module is created.
--- @name //addon//:SetDefaultModuleState
--- @paramsig state
--- @param state Default state for new modules, true for enabled, false for disabled
--- @usage
--- -- Create the addon object
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
--- -- Set the default state to "disabled"
--- MyAddon:SetDefaultModuleState(false)
--- -- Create a module and explicilty enable it
--- MyModule = MyAddon:NewModule("MyModule")
--- MyModule:Enable()
-function SetDefaultModuleState(self, state)
- if next(self.modules) then
- error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
- end
- self.defaultModuleState = state
-end
-
---- Set the default prototype to use for new modules on creation.
--- Note that you can only change the default prototype before any module is created.
--- @name //addon//:SetDefaultModulePrototype
--- @paramsig prototype
--- @param prototype Default prototype for the new modules (table)
--- @usage
--- -- Define a prototype
--- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
--- -- Set the default prototype
--- MyAddon:SetDefaultModulePrototype(prototype)
--- -- Create a module and explicitly Enable it
--- MyModule = MyAddon:NewModule("MyModule")
--- MyModule:Enable()
--- -- should print "OnEnable called!" now
--- @see NewModule
-function SetDefaultModulePrototype(self, prototype)
- if next(self.modules) then
- error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
- end
- if type(prototype) ~= "table" then
- error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
- end
- self.defaultModulePrototype = prototype
-end
-
---- Set the state of an addon or module
--- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
--- @name //addon//:SetEnabledState
--- @paramsig state
--- @param state the state of an addon or module (enabled=true, disabled=false)
-function SetEnabledState(self, state)
- self.enabledState = state
-end
-
-
---- Return an iterator of all modules associated to the addon.
--- @name //addon//:IterateModules
--- @paramsig
--- @usage
--- -- Enable all modules
--- for name, module in MyAddon:IterateModules() do
--- module:Enable()
--- end
-local function IterateModules(self) return pairs(self.modules) end
-
--- Returns an iterator of all embeds in the addon
--- @name //addon//:IterateEmbeds
--- @paramsig
-local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
-
---- Query the enabledState of an addon.
--- @name //addon//:IsEnabled
--- @paramsig
--- @usage
--- if MyAddon:IsEnabled() then
--- MyAddon:Disable()
--- end
-local function IsEnabled(self) return self.enabledState end
-local mixins = {
- NewModule = NewModule,
- GetModule = GetModule,
- Enable = Enable,
- Disable = Disable,
- EnableModule = EnableModule,
- DisableModule = DisableModule,
- IsEnabled = IsEnabled,
- SetDefaultModuleLibraries = SetDefaultModuleLibraries,
- SetDefaultModuleState = SetDefaultModuleState,
- SetDefaultModulePrototype = SetDefaultModulePrototype,
- SetEnabledState = SetEnabledState,
- IterateModules = IterateModules,
- IterateEmbeds = IterateEmbeds,
- GetName = GetName,
-}
-local function IsModule(self) return false end
-local pmixins = {
- defaultModuleState = true,
- enabledState = true,
- IsModule = IsModule,
-}
--- Embed( target )
--- target (object) - target object to embed aceaddon in
---
--- this is a local function specifically since it's meant to be only called internally
-function Embed(target, skipPMixins)
- for k, v in pairs(mixins) do
- target[k] = v
- end
- if not skipPMixins then
- for k, v in pairs(pmixins) do
- target[k] = target[k] or v
- end
- end
-end
-
-
--- - Initialize the addon after creation.
--- This function is only used internally during the ADDON_LOADED event
--- It will call the **OnInitialize** function on the addon object (if present),
--- and the **OnEmbedInitialize** function on all embeded libraries.
---
--- **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, addon)
-
- local embeds = self.embeds[addon]
- for i = 1, #embeds do
- local lib = LibStub:GetLibrary(embeds[i], true)
- if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
- end
-
- -- we don't call InitializeAddon on modules specifically, this is handled
- -- from the event handler and only done _once_
-end
-
--- - Enable the addon after creation.
--- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
--- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
--- It will call the **OnEnable** function on the addon object (if present),
--- and the **OnEmbedEnable** function on all embeded libraries.\\
--- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
---
--- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
--- Use :Enable on the addon itself instead.
--- @param addon addon object to enable
-function AceAddon:EnableAddon(addon)
- if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
- if self.statuses[addon.name] or not addon.enabledState then return false end
-
- -- 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, addon)
-
- -- make sure we're still enabled before continueing
- if self.statuses[addon.name] then
- local embeds = self.embeds[addon]
- for i = 1, #embeds do
- local lib = LibStub:GetLibrary(embeds[i], true)
- if lib then safecall(lib.OnEmbedEnable, lib, addon) end
- end
-
- -- enable possible modules.
- local modules = addon.orderedModules
- for i = 1, #modules do
- self:EnableAddon(modules[i])
- end
- end
- return self.statuses[addon.name] -- return true if we're disabled
-end
-
--- - Disable the addon
--- Note: This function is only used internally.
--- It will call the **OnDisable** function on the addon object (if present),
--- and the **OnEmbedDisable** function on all embeded libraries.\\
--- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
---
--- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
--- Use :Disable on the addon itself instead.
--- @param addon addon object to enable
-function AceAddon:DisableAddon(addon)
- if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
- if not self.statuses[addon.name] then return false end
-
- -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
- self.statuses[addon.name] = false
-
- 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, #embeds do
- local lib = LibStub:GetLibrary(embeds[i], true)
- if lib then safecall(lib.OnEmbedDisable, lib, addon) end
- end
- -- disable possible modules.
- local modules = addon.orderedModules
- for i = 1, #modules do
- self:DisableAddon(modules[i])
- end
- end
-
- return not self.statuses[addon.name] -- return true if we're disabled
-end
-
---- Get an iterator over all registered addons.
--- @usage
--- -- Print a list of all installed AceAddon's
--- for name, addon in AceAddon:IterateAddons() do
--- print("Addon: " .. name)
--- end
-function AceAddon:IterateAddons() return pairs(self.addons) end
-
---- Get an iterator over the internal status registry.
--- @usage
--- -- Print a list of all enabled addons
--- for name, status in AceAddon:IterateAddonStatus() do
--- if status then
--- print("EnabledAddon: " .. name)
--- end
--- end
-function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
-
--- Following Iterators are deprecated, and their addon specific versions should be used
--- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
-function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
-function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
-
--- Blizzard AddOns which can load very early in the loading process and mess with Ace3 addon loading
-local BlizzardEarlyLoadAddons = {
- Blizzard_DebugTools = true,
- Blizzard_TimeManager = true,
- Blizzard_BattlefieldMap = true,
- Blizzard_MapCanvas = true,
- Blizzard_SharedMapDataProviders = true,
- Blizzard_CombatLog = true,
-}
-
--- Event Handling
-local function onEvent(this, event, arg1)
- -- 2020-08-28 nevcairiel - ignore the load event of Blizzard addons which occur early in the loading process
- if (event == "ADDON_LOADED" and (arg1 == nil or not BlizzardEarlyLoadAddons[arg1])) 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
- while(#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
- AceAddon:InitializeAddon(addon)
- tinsert(AceAddon.enablequeue, addon)
- end
-
- if IsLoggedIn() then
- while(#AceAddon.enablequeue > 0) do
- local addon = tremove(AceAddon.enablequeue, 1)
- AceAddon:EnableAddon(addon)
- end
- end
- end
-end
-
-AceAddon.frame:RegisterEvent("ADDON_LOADED")
-AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
-AceAddon.frame:SetScript("OnEvent", onEvent)
-
--- upgrade embeded
-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
+--- **AceAddon-3.0** provides a template for creating addon objects.
+-- It'll provide you with a set of callback functions that allow you to simplify the loading
+-- process of your addon.\\
+-- Callbacks provided are:\\
+-- * **OnInitialize**, which is called directly after the addon is fully loaded.
+-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
+-- * **OnDisable**, which is only called when your addon is manually being disabled.
+-- @usage
+-- -- A small (but complete) addon, that doesn't do anything,
+-- -- but shows usage of the callbacks.
+-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
+--
+-- function MyAddon:OnInitialize()
+-- -- do init tasks here, like loading the Saved Variables,
+-- -- or setting up slash commands.
+-- end
+--
+-- function MyAddon:OnEnable()
+-- -- Do more initialization here, that really enables the use of your addon.
+-- -- Register Events, Hook functions, Create Frames, Get information from
+-- -- the game that wasn't available in OnInitialize
+-- end
+--
+-- function MyAddon:OnDisable()
+-- -- Unhook, Unregister Events, Hide frames that you created.
+-- -- You would probably only use an OnDisable if you want to
+-- -- build a "standby" mode, or be able to toggle modules on/off.
+-- end
+-- @class file
+-- @name AceAddon-3.0.lua
+-- @release $Id: AceAddon-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+
+local MAJOR, MINOR = "AceAddon-3.0", 13
+local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceAddon then return end -- No Upgrade needed.
+
+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.
+AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
+AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
+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 = table.insert, table.concat, table.remove
+local fmt, tostring = string.format, tostring
+local select, pairs, next, type, unpack = select, pairs, next, type, unpack
+local loadstring, assert, error = loadstring, assert, error
+local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
+
+--[[
+ xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+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 xpcall(func, errorhandler, ...)
+ end
+end
+
+-- local functions that will be implemented further down
+local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
+
+-- used in the addon metatable
+local function addontostring( self ) return self.name end
+
+-- Check if the addon is queued for initialization
+local function queuedForInitialization(addon)
+ for i = 1, #AceAddon.initializequeue do
+ if AceAddon.initializequeue[i] == addon then
+ return true
+ end
+ end
+ return false
+end
+
+--- Create a new AceAddon-3.0 addon.
+-- Any libraries you specified will be embeded, and the addon will be scheduled for
+-- its OnInitialize and OnEnable callbacks.
+-- The final addon object, with all libraries embeded, will be returned.
+-- @paramsig [object ,]name[, lib, ...]
+-- @param object Table to use as a base for the addon (optional)
+-- @param name Name of the addon object to create
+-- @param lib List of libraries to embed into the addon
+-- @usage
+-- -- Create a simple addon object
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
+--
+-- -- 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, ...)
+ local object,name
+ local i=1
+ if type(objectorname)=="table" then
+ object=objectorname
+ name=...
+ i=2
+ else
+ name=objectorname
+ end
+ if type(name)~="string" then
+ error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
+ end
+ if self.addons[name] then
+ error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
+ end
+
+ object = object or {}
+ object.name = name
+
+ local addonmeta = {}
+ local oldmeta = getmetatable(object)
+ if oldmeta then
+ for k, v in pairs(oldmeta) do addonmeta[k] = v end
+ end
+ addonmeta.__tostring = addontostring
+
+ setmetatable( object, addonmeta )
+ self.addons[name] = object
+ object.modules = {}
+ object.orderedModules = {}
+ object.defaultModuleLibraries = {}
+ Embed( object ) -- embed NewModule, GetModule methods
+ self:EmbedLibraries(object, select(i,...))
+
+ -- 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
+-- @param silent if true, the addon is optional, silently return nil if its not found
+-- @usage
+-- -- Get the Addon
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+function AceAddon:GetAddon(name, silent)
+ if not silent and not self.addons[name] then
+ error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
+ end
+ return self.addons[name]
+end
+
+-- - Embed a list of libraries into the specified addon.
+-- This function will try to embed all of the listed libraries into the addon
+-- and error if a single one fails.
+--
+-- **Note:** This function is for internal use by :NewAddon/:NewModule
+-- @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, ...)
+ for i=1,select("#", ... ) do
+ local libname = select(i, ...)
+ self:EmbedLibrary(addon, libname, false, 4)
+ end
+end
+
+-- - Embed a library into the addon object.
+-- This function will check if the specified library is registered with LibStub
+-- and if it has a :Embed function to call. It'll error if any of those conditions
+-- fails.
+--
+-- **Note:** This function is for internal use by :EmbedLibraries
+-- @paramsig addon, libname[, silent[, offset]]
+-- @param addon addon object to embed the library in
+-- @param libname name of the library to embed
+-- @param silent marks an embed to fail silently if the library doesn't exist (optional)
+-- @param offset will push the error messages back to said offset, defaults to 2 (optional)
+function AceAddon:EmbedLibrary(addon, libname, silent, offset)
+ local lib = LibStub:GetLibrary(libname, true)
+ if not lib and not silent then
+ error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
+ elseif lib and type(lib.Embed) == "function" then
+ lib:Embed(addon)
+ tinsert(self.embeds[addon], libname)
+ return true
+ elseif lib then
+ error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
+ end
+end
+
+--- Return the specified module from an addon object.
+-- Throws an error if the addon object cannot be found (except if silent is set)
+-- @name //addon//:GetModule
+-- @paramsig name[, silent]
+-- @param name unique name of the module
+-- @param silent if true, the module is optional, silently return nil if its not found (optional)
+-- @usage
+-- -- Get the Addon
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- -- Get the Module
+-- MyModule = MyAddon:GetModule("MyModule")
+function GetModule(self, name, silent)
+ if not self.modules[name] and not silent then
+ error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
+ end
+ return self.modules[name]
+end
+
+local function IsModuleTrue(self) return true end
+
+--- Create a new module for the addon.
+-- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
+-- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
+-- an addon object.
+-- @name //addon//:NewModule
+-- @paramsig name[, prototype|lib[, lib, ...]]
+-- @param name unique name of the module
+-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
+-- @param lib List of libraries to embed into the addon
+-- @usage
+-- -- Create a module with some embeded libraries
+-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
+--
+-- -- 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, ...)
+ if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
+ if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
+
+ if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
+
+ -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
+ -- 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(fmt("%s_%s", self.name or tostring(self), name))
+
+ module.IsModule = IsModuleTrue
+ module:SetEnabledState(self.defaultModuleState)
+ module.moduleName = name
+
+ if type(prototype) == "string" then
+ AceAddon:EmbedLibraries(module, prototype, ...)
+ else
+ AceAddon:EmbedLibraries(module, ...)
+ end
+ AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
+
+ if not prototype or type(prototype) == "string" then
+ prototype = self.defaultModulePrototype or nil
+ end
+
+ if type(prototype) == "table" then
+ local mt = getmetatable(module)
+ mt.__index = prototype
+ setmetatable(module, mt) -- More of a Base class type feel.
+ end
+
+ 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)
+
+ return module
+end
+
+--- Returns the real name of the addon or module, without any prefix.
+-- @name //addon//:GetName
+-- @paramsig
+-- @usage
+-- print(MyAddon:GetName())
+-- -- prints "MyAddon"
+function GetName(self)
+ return self.moduleName or self.name
+end
+
+--- Enables the Addon, if possible, return true or false depending on success.
+-- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
+-- and enabling all modules of the addon (unless explicitly disabled).\\
+-- :Enable() also sets the internal `enableState` variable to true
+-- @name //addon//:Enable
+-- @paramsig
+-- @usage
+-- -- Enable MyModule
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyModule = MyAddon:GetModule("MyModule")
+-- MyModule:Enable()
+function Enable(self)
+ self:SetEnabledState(true)
+
+ -- nevcairiel 2013-04-27: don't enable an addon/module if its queued for init still
+ -- it'll be enabled after the init process
+ if not queuedForInitialization(self) then
+ return AceAddon:EnableAddon(self)
+ end
+end
+
+--- Disables the Addon, if possible, return true or false depending on success.
+-- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
+-- and disabling all modules of the addon.\\
+-- :Disable() also sets the internal `enableState` variable to false
+-- @name //addon//:Disable
+-- @paramsig
+-- @usage
+-- -- Disable MyAddon
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyAddon:Disable()
+function Disable(self)
+ self:SetEnabledState(false)
+ return AceAddon:DisableAddon(self)
+end
+
+--- Enables the Module, if possible, return true or false depending on success.
+-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
+-- @name //addon//:EnableModule
+-- @paramsig name
+-- @usage
+-- -- Enable MyModule using :GetModule
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyModule = MyAddon:GetModule("MyModule")
+-- MyModule:Enable()
+--
+-- -- Enable MyModule using the short-hand
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyAddon:EnableModule("MyModule")
+function EnableModule(self, name)
+ local module = self:GetModule( name )
+ return module:Enable()
+end
+
+--- Disables the Module, if possible, return true or false depending on success.
+-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
+-- @name //addon//:DisableModule
+-- @paramsig name
+-- @usage
+-- -- Disable MyModule using :GetModule
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyModule = MyAddon:GetModule("MyModule")
+-- MyModule:Disable()
+--
+-- -- Disable MyModule using the short-hand
+-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
+-- MyAddon:DisableModule("MyModule")
+function DisableModule(self, name)
+ local module = self:GetModule( name )
+ return module:Disable()
+end
+
+--- Set the default libraries to be mixed into all modules created by this object.
+-- Note that you can only change the default module libraries before any module is created.
+-- @name //addon//:SetDefaultModuleLibraries
+-- @paramsig lib[, lib, ...]
+-- @param lib List of libraries to embed into the addon
+-- @usage
+-- -- Create the addon object
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
+-- -- Configure default libraries for modules (all modules need AceEvent-3.0)
+-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
+-- -- Create a module
+-- MyModule = MyAddon:NewModule("MyModule")
+function SetDefaultModuleLibraries(self, ...)
+ if next(self.modules) then
+ error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
+ end
+ self.defaultModuleLibraries = {...}
+end
+
+--- Set the default state in which new modules are being created.
+-- Note that you can only change the default state before any module is created.
+-- @name //addon//:SetDefaultModuleState
+-- @paramsig state
+-- @param state Default state for new modules, true for enabled, false for disabled
+-- @usage
+-- -- Create the addon object
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
+-- -- Set the default state to "disabled"
+-- MyAddon:SetDefaultModuleState(false)
+-- -- Create a module and explicilty enable it
+-- MyModule = MyAddon:NewModule("MyModule")
+-- MyModule:Enable()
+function SetDefaultModuleState(self, state)
+ if next(self.modules) then
+ error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
+ end
+ self.defaultModuleState = state
+end
+
+--- Set the default prototype to use for new modules on creation.
+-- Note that you can only change the default prototype before any module is created.
+-- @name //addon//:SetDefaultModulePrototype
+-- @paramsig prototype
+-- @param prototype Default prototype for the new modules (table)
+-- @usage
+-- -- Define a prototype
+-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
+-- -- Set the default prototype
+-- MyAddon:SetDefaultModulePrototype(prototype)
+-- -- Create a module and explicitly Enable it
+-- MyModule = MyAddon:NewModule("MyModule")
+-- MyModule:Enable()
+-- -- should print "OnEnable called!" now
+-- @see NewModule
+function SetDefaultModulePrototype(self, prototype)
+ if next(self.modules) then
+ error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
+ end
+ if type(prototype) ~= "table" then
+ error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
+ end
+ self.defaultModulePrototype = prototype
+end
+
+--- Set the state of an addon or module
+-- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
+-- @name //addon//:SetEnabledState
+-- @paramsig state
+-- @param state the state of an addon or module (enabled=true, disabled=false)
+function SetEnabledState(self, state)
+ self.enabledState = state
+end
+
+
+--- Return an iterator of all modules associated to the addon.
+-- @name //addon//:IterateModules
+-- @paramsig
+-- @usage
+-- -- Enable all modules
+-- for name, module in MyAddon:IterateModules() do
+-- module:Enable()
+-- end
+local function IterateModules(self) return pairs(self.modules) end
+
+-- Returns an iterator of all embeds in the addon
+-- @name //addon//:IterateEmbeds
+-- @paramsig
+local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
+
+--- Query the enabledState of an addon.
+-- @name //addon//:IsEnabled
+-- @paramsig
+-- @usage
+-- if MyAddon:IsEnabled() then
+-- MyAddon:Disable()
+-- end
+local function IsEnabled(self) return self.enabledState end
+local mixins = {
+ NewModule = NewModule,
+ GetModule = GetModule,
+ Enable = Enable,
+ Disable = Disable,
+ EnableModule = EnableModule,
+ DisableModule = DisableModule,
+ IsEnabled = IsEnabled,
+ SetDefaultModuleLibraries = SetDefaultModuleLibraries,
+ SetDefaultModuleState = SetDefaultModuleState,
+ SetDefaultModulePrototype = SetDefaultModulePrototype,
+ SetEnabledState = SetEnabledState,
+ IterateModules = IterateModules,
+ IterateEmbeds = IterateEmbeds,
+ GetName = GetName,
+}
+local function IsModule(self) return false end
+local pmixins = {
+ defaultModuleState = true,
+ enabledState = true,
+ IsModule = IsModule,
+}
+-- Embed( target )
+-- target (object) - target object to embed aceaddon in
+--
+-- this is a local function specifically since it's meant to be only called internally
+function Embed(target, skipPMixins)
+ for k, v in pairs(mixins) do
+ target[k] = v
+ end
+ if not skipPMixins then
+ for k, v in pairs(pmixins) do
+ target[k] = target[k] or v
+ end
+ end
+end
+
+
+-- - Initialize the addon after creation.
+-- This function is only used internally during the ADDON_LOADED event
+-- It will call the **OnInitialize** function on the addon object (if present),
+-- and the **OnEmbedInitialize** function on all embeded libraries.
+--
+-- **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, addon)
+
+ local embeds = self.embeds[addon]
+ for i = 1, #embeds do
+ local lib = LibStub:GetLibrary(embeds[i], true)
+ if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
+ end
+
+ -- we don't call InitializeAddon on modules specifically, this is handled
+ -- from the event handler and only done _once_
+end
+
+-- - Enable the addon after creation.
+-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
+-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
+-- It will call the **OnEnable** function on the addon object (if present),
+-- and the **OnEmbedEnable** function on all embeded libraries.\\
+-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
+--
+-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
+-- Use :Enable on the addon itself instead.
+-- @param addon addon object to enable
+function AceAddon:EnableAddon(addon)
+ if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
+ if self.statuses[addon.name] or not addon.enabledState then return false end
+
+ -- 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, addon)
+
+ -- make sure we're still enabled before continueing
+ if self.statuses[addon.name] then
+ local embeds = self.embeds[addon]
+ for i = 1, #embeds do
+ local lib = LibStub:GetLibrary(embeds[i], true)
+ if lib then safecall(lib.OnEmbedEnable, lib, addon) end
+ end
+
+ -- enable possible modules.
+ local modules = addon.orderedModules
+ for i = 1, #modules do
+ self:EnableAddon(modules[i])
+ end
+ end
+ return self.statuses[addon.name] -- return true if we're disabled
+end
+
+-- - Disable the addon
+-- Note: This function is only used internally.
+-- It will call the **OnDisable** function on the addon object (if present),
+-- and the **OnEmbedDisable** function on all embeded libraries.\\
+-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
+--
+-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
+-- Use :Disable on the addon itself instead.
+-- @param addon addon object to enable
+function AceAddon:DisableAddon(addon)
+ if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
+ if not self.statuses[addon.name] then return false end
+
+ -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
+ self.statuses[addon.name] = false
+
+ 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, #embeds do
+ local lib = LibStub:GetLibrary(embeds[i], true)
+ if lib then safecall(lib.OnEmbedDisable, lib, addon) end
+ end
+ -- disable possible modules.
+ local modules = addon.orderedModules
+ for i = 1, #modules do
+ self:DisableAddon(modules[i])
+ end
+ end
+
+ return not self.statuses[addon.name] -- return true if we're disabled
+end
+
+--- Get an iterator over all registered addons.
+-- @usage
+-- -- Print a list of all installed AceAddon's
+-- for name, addon in AceAddon:IterateAddons() do
+-- print("Addon: " .. name)
+-- end
+function AceAddon:IterateAddons() return pairs(self.addons) end
+
+--- Get an iterator over the internal status registry.
+-- @usage
+-- -- Print a list of all enabled addons
+-- for name, status in AceAddon:IterateAddonStatus() do
+-- if status then
+-- print("EnabledAddon: " .. name)
+-- end
+-- end
+function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
+
+-- Following Iterators are deprecated, and their addon specific versions should be used
+-- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
+function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
+function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
+
+-- Blizzard AddOns which can load very early in the loading process and mess with Ace3 addon loading
+local BlizzardEarlyLoadAddons = {
+ Blizzard_DebugTools = true,
+ Blizzard_TimeManager = true,
+ Blizzard_BattlefieldMap = true,
+ Blizzard_MapCanvas = true,
+ Blizzard_SharedMapDataProviders = true,
+ Blizzard_CombatLog = true,
+}
+
+-- Event Handling
+local function onEvent(this, event, arg1)
+ -- 2020-08-28 nevcairiel - ignore the load event of Blizzard addons which occur early in the loading process
+ if (event == "ADDON_LOADED" and (arg1 == nil or not BlizzardEarlyLoadAddons[arg1])) 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
+ while(#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
+ AceAddon:InitializeAddon(addon)
+ tinsert(AceAddon.enablequeue, addon)
+ end
+
+ if IsLoggedIn() then
+ while(#AceAddon.enablequeue > 0) do
+ local addon = tremove(AceAddon.enablequeue, 1)
+ AceAddon:EnableAddon(addon)
+ end
+ end
+ end
+end
+
+AceAddon.frame:RegisterEvent("ADDON_LOADED")
+AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
+AceAddon.frame:SetScript("OnEvent", onEvent)
+
+-- upgrade embeded
+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
diff --git a/Libs/AceAddon-3.0/AceAddon-3.0.xml b/Libs/AceAddon-3.0/AceAddon-3.0.xml
index c607008..dcf24c7 100755
--- a/Libs/AceAddon-3.0/AceAddon-3.0.xml
+++ b/Libs/AceAddon-3.0/AceAddon-3.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/AceConsole-3.0/AceConsole-3.0.lua b/Libs/AceConsole-3.0/AceConsole-3.0.lua
index 8ce5f8b..2361a3b 100644
--- a/Libs/AceConsole-3.0/AceConsole-3.0.lua
+++ b/Libs/AceConsole-3.0/AceConsole-3.0.lua
@@ -1,246 +1,246 @@
---- **AceConsole-3.0** provides registration facilities for slash commands.
--- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
--- to your addons individual needs.
---
--- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole: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 AceConsole itself.\\
--- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
--- make into AceConsole.
--- @class file
--- @name AceConsole-3.0
--- @release $Id: AceConsole-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-local MAJOR,MINOR = "AceConsole-3.0", 7
-
-local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceConsole then return end -- No upgrade needed
-
-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 tconcat, tostring, select = table.concat, tostring, select
-local type, pairs, error = type, pairs, error
-local format, strfind, strsub = string.format, string.find, string.sub
-local max = math.max
-
--- WoW APIs
-local _G = _G
-
-local tmp={}
-local function Print(self,frame,...)
- local n=0
- if self ~= AceConsole then
- n=n+1
- tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
- end
- for i=1, select("#", ...) do
- n=n+1
- tmp[n] = tostring(select(i, ...))
- end
- frame:AddMessage( tconcat(tmp," ",1,n) )
-end
-
---- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
--- @paramsig [chatframe ,] ...
--- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
--- @param ... List of any values to be printed
-function AceConsole:Print(...)
- local frame = ...
- if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
- return Print(self, frame, select(2,...))
- else
- return Print(self, DEFAULT_CHAT_FRAME, ...)
- 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(...)
- local frame = ...
- if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
- return Print(self, frame, format(select(2,...)))
- else
- return Print(self, DEFAULT_CHAT_FRAME, format(...))
- end
-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 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_"..command:upper()
-
- if type( func ) == "string" then
- SlashCmdList[name] = function(input, editBox)
- self[func](self, input, editBox)
- end
- else
- SlashCmdList[name] = func
- end
- _G["SLASH_"..name.."1"] = "/"..command:lower()
- AceConsole.commands[command] = name
- -- non-persisting commands are registered for enabling disabling
- if not persist then
- if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end
- AceConsole.weakcommands[self][command] = func
- end
- return true
-end
-
---- Unregister a chatcommand
--- @param command Chat command to be unregistered WITHOUT leading "/"
-function AceConsole:UnregisterChatCommand( command )
- local name = AceConsole.commands[command]
- if name then
- SlashCmdList[name] = nil
- _G["SLASH_" .. name .. "1"] = nil
- hash_SlashCmdList["/" .. command:upper()] = nil
- AceConsole.commands[command] = nil
- end
-end
-
---- Get an iterator over all Chat Commands registered with AceConsole
--- @return Iterator (pairs) over all commands
-function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
-
-
-local function nils(n, ...)
- if n>1 then
- return nil, nils(n-1, ...)
- elseif n==1 then
- return nil, ...
- else
- return ...
- 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
--- @param numargs How many arguments to get (default 1)
--- @param startpos Where in the string to start scanning (default 1)
--- @return Returns arg1, arg2, ..., nextposition\\
--- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string.
-function AceConsole:GetArgs(str, numargs, startpos)
- numargs = numargs or 1
- startpos = max(startpos or 1, 1)
-
- local pos=startpos
-
- -- find start of new arg
- pos = strfind(str, "[^ ]", pos)
- if not pos then -- whoops, end of string
- return nils(numargs, 1e9)
- end
-
- if numargs<1 then
- return pos
- end
-
- -- quoted or space separated? find out which pattern to use
- local delim_or_pipe
- local ch = strsub(str, pos, pos)
- if ch=='"' then
- pos = pos + 1
- delim_or_pipe='([|"])'
- elseif ch=="'" then
- pos = pos + 1
- delim_or_pipe="([|'])"
- else
- delim_or_pipe="([| ])"
- end
-
- startpos = pos
-
- while true do
- -- find delimiter or hyperlink
- local _
- pos,_,ch = strfind(str, delim_or_pipe, pos)
-
- if not pos then break end
-
- if ch=="|" then
- -- some kind of escape
-
- if strsub(str,pos,pos+1)=="|H" then
- -- It's a |H....|hhyper link!|h
- pos=strfind(str, "|h", pos+2) -- first |h
- if not pos then break end
-
- pos=strfind(str, "|h", pos+2) -- second |h
- if not pos then break end
- elseif strsub(str,pos, pos+1) == "|T" then
- -- It's a |T....|t texture
- pos=strfind(str, "|t", pos+2)
- if not pos then break end
- end
-
- pos=pos+2 -- skip past this escape (last |h if it was a hyperlink)
-
- else
- -- found delimiter, done with this arg
- return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1)
- end
-
- end
-
- -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
- return strsub(str, startpos), nils(numargs-1, 1e9)
-end
-
-
---- embedding and embed handling
-
-local mixins = {
- "Print",
- "Printf",
- "RegisterChatCommand",
- "UnregisterChatCommand",
- "GetArgs",
-}
-
--- Embeds AceConsole into the target object making the functions from the mixins list available on target:..
--- @param target target object to embed AceBucket in
-function AceConsole:Embed( target )
- for k, v in pairs( mixins ) do
- target[v] = self[v]
- end
- self.embeds[target] = true
- return target
-end
-
-function AceConsole:OnEmbedEnable( target )
- if AceConsole.weakcommands[target] then
- for command, func in pairs( AceConsole.weakcommands[target] ) do
- target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry
- end
- end
-end
-
-function AceConsole:OnEmbedDisable( target )
- if AceConsole.weakcommands[target] then
- for command, func in pairs( AceConsole.weakcommands[target] ) do
- target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care?
- end
- end
-end
-
-for addon in pairs(AceConsole.embeds) do
- AceConsole:Embed(addon)
-end
+--- **AceConsole-3.0** provides registration facilities for slash commands.
+-- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
+-- to your addons individual needs.
+--
+-- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole: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 AceConsole itself.\\
+-- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceConsole.
+-- @class file
+-- @name AceConsole-3.0
+-- @release $Id: AceConsole-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+local MAJOR,MINOR = "AceConsole-3.0", 7
+
+local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceConsole then return end -- No upgrade needed
+
+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 tconcat, tostring, select = table.concat, tostring, select
+local type, pairs, error = type, pairs, error
+local format, strfind, strsub = string.format, string.find, string.sub
+local max = math.max
+
+-- WoW APIs
+local _G = _G
+
+local tmp={}
+local function Print(self,frame,...)
+ local n=0
+ if self ~= AceConsole then
+ n=n+1
+ tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
+ end
+ for i=1, select("#", ...) do
+ n=n+1
+ tmp[n] = tostring(select(i, ...))
+ end
+ frame:AddMessage( tconcat(tmp," ",1,n) )
+end
+
+--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
+-- @paramsig [chatframe ,] ...
+-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
+-- @param ... List of any values to be printed
+function AceConsole:Print(...)
+ local frame = ...
+ if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
+ return Print(self, frame, select(2,...))
+ else
+ return Print(self, DEFAULT_CHAT_FRAME, ...)
+ 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(...)
+ local frame = ...
+ if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
+ return Print(self, frame, format(select(2,...)))
+ else
+ return Print(self, DEFAULT_CHAT_FRAME, format(...))
+ end
+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 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_"..command:upper()
+
+ if type( func ) == "string" then
+ SlashCmdList[name] = function(input, editBox)
+ self[func](self, input, editBox)
+ end
+ else
+ SlashCmdList[name] = func
+ end
+ _G["SLASH_"..name.."1"] = "/"..command:lower()
+ AceConsole.commands[command] = name
+ -- non-persisting commands are registered for enabling disabling
+ if not persist then
+ if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end
+ AceConsole.weakcommands[self][command] = func
+ end
+ return true
+end
+
+--- Unregister a chatcommand
+-- @param command Chat command to be unregistered WITHOUT leading "/"
+function AceConsole:UnregisterChatCommand( command )
+ local name = AceConsole.commands[command]
+ if name then
+ SlashCmdList[name] = nil
+ _G["SLASH_" .. name .. "1"] = nil
+ hash_SlashCmdList["/" .. command:upper()] = nil
+ AceConsole.commands[command] = nil
+ end
+end
+
+--- Get an iterator over all Chat Commands registered with AceConsole
+-- @return Iterator (pairs) over all commands
+function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
+
+
+local function nils(n, ...)
+ if n>1 then
+ return nil, nils(n-1, ...)
+ elseif n==1 then
+ return nil, ...
+ else
+ return ...
+ 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
+-- @param numargs How many arguments to get (default 1)
+-- @param startpos Where in the string to start scanning (default 1)
+-- @return Returns arg1, arg2, ..., nextposition\\
+-- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string.
+function AceConsole:GetArgs(str, numargs, startpos)
+ numargs = numargs or 1
+ startpos = max(startpos or 1, 1)
+
+ local pos=startpos
+
+ -- find start of new arg
+ pos = strfind(str, "[^ ]", pos)
+ if not pos then -- whoops, end of string
+ return nils(numargs, 1e9)
+ end
+
+ if numargs<1 then
+ return pos
+ end
+
+ -- quoted or space separated? find out which pattern to use
+ local delim_or_pipe
+ local ch = strsub(str, pos, pos)
+ if ch=='"' then
+ pos = pos + 1
+ delim_or_pipe='([|"])'
+ elseif ch=="'" then
+ pos = pos + 1
+ delim_or_pipe="([|'])"
+ else
+ delim_or_pipe="([| ])"
+ end
+
+ startpos = pos
+
+ while true do
+ -- find delimiter or hyperlink
+ local _
+ pos,_,ch = strfind(str, delim_or_pipe, pos)
+
+ if not pos then break end
+
+ if ch=="|" then
+ -- some kind of escape
+
+ if strsub(str,pos,pos+1)=="|H" then
+ -- It's a |H....|hhyper link!|h
+ pos=strfind(str, "|h", pos+2) -- first |h
+ if not pos then break end
+
+ pos=strfind(str, "|h", pos+2) -- second |h
+ if not pos then break end
+ elseif strsub(str,pos, pos+1) == "|T" then
+ -- It's a |T....|t texture
+ pos=strfind(str, "|t", pos+2)
+ if not pos then break end
+ end
+
+ pos=pos+2 -- skip past this escape (last |h if it was a hyperlink)
+
+ else
+ -- found delimiter, done with this arg
+ return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1)
+ end
+
+ end
+
+ -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
+ return strsub(str, startpos), nils(numargs-1, 1e9)
+end
+
+
+--- embedding and embed handling
+
+local mixins = {
+ "Print",
+ "Printf",
+ "RegisterChatCommand",
+ "UnregisterChatCommand",
+ "GetArgs",
+}
+
+-- Embeds AceConsole into the target object making the functions from the mixins list available on target:..
+-- @param target target object to embed AceBucket in
+function AceConsole:Embed( target )
+ for k, v in pairs( mixins ) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+function AceConsole:OnEmbedEnable( target )
+ if AceConsole.weakcommands[target] then
+ for command, func in pairs( AceConsole.weakcommands[target] ) do
+ target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry
+ end
+ end
+end
+
+function AceConsole:OnEmbedDisable( target )
+ if AceConsole.weakcommands[target] then
+ for command, func in pairs( AceConsole.weakcommands[target] ) do
+ target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care?
+ end
+ end
+end
+
+for addon in pairs(AceConsole.embeds) do
+ AceConsole:Embed(addon)
+end
diff --git a/Libs/AceConsole-3.0/AceConsole-3.0.xml b/Libs/AceConsole-3.0/AceConsole-3.0.xml
index f6ae8a6..4f4699a 100644
--- a/Libs/AceConsole-3.0/AceConsole-3.0.xml
+++ b/Libs/AceConsole-3.0/AceConsole-3.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/AceDB-3.0/AceDB-3.0.lua b/Libs/AceDB-3.0/AceDB-3.0.lua
index 9e84705..1e25429 100644
--- a/Libs/AceDB-3.0/AceDB-3.0.lua
+++ b/Libs/AceDB-3.0/AceDB-3.0.lua
@@ -1,740 +1,740 @@
---- **AceDB-3.0** manages the SavedVariables of your addon.
--- It offers profile management, smart defaults and namespaces for modules.\\
--- Data can be saved in different data-types, depending on its intended usage.
--- The most common data-type is the `profile` type, which allows the user to choose
--- the active profile, and manage the profiles of all of his characters.\\
--- The following data types are available:
--- * **char** Character-specific data. Every character has its own database.
--- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
--- * **class** Class-specific data. All of the players characters of the same class share this database.
--- * **race** Race-specific data. All of the players characters of the same race share this database.
--- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
--- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
--- * **locale** Locale specific data, based on the locale of the players game client.
--- * **global** Global Data. All characters on the same account share this database.
--- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
---
--- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
--- of the DBObjectLib listed here. \\
--- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
--- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
--- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
---
--- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
---
--- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
---
--- @usage
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
---
--- -- declare defaults to be used in the DB
--- local defaults = {
--- profile = {
--- setting = true,
--- }
--- }
---
--- function MyAddon:OnInitialize()
--- -- Assuming the .toc says ## SavedVariables: MyAddonDB
--- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
--- end
--- @class file
--- @name AceDB-3.0.lua
--- @release $Id: AceDB-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 27
-local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
-
-if not AceDB then return end -- No upgrade needed
-
--- Lua APIs
-local type, pairs, next, error = type, pairs, next, error
-local setmetatable, rawset, rawget = setmetatable, rawset, rawget
-
--- WoW APIs
-local _G = _G
-
-AceDB.db_registry = AceDB.db_registry or {}
-AceDB.frame = AceDB.frame or CreateFrame("Frame")
-
-local CallbackHandler
-local CallbackDummy = { Fire = function() end }
-
-local DBObjectLib = {}
-
---[[-------------------------------------------------------------------------
- AceDB Utility Functions
----------------------------------------------------------------------------]]
-
--- Simple shallow copy for copying defaults
-local function copyTable(src, dest)
- if type(dest) ~= "table" then dest = {} end
- if type(src) == "table" then
- for k,v in pairs(src) do
- if type(v) == "table" then
- -- try to index the key first so that the metatable creates the defaults, if set, and use that table
- v = copyTable(v, dest[k])
- end
- dest[k] = v
- end
- end
- return dest
-end
-
--- Called to add defaults to a section of the database
---
--- When a ["*"] default section is indexed with a new key, a table is returned
--- and set in the host table. These tables must be cleaned up by removeDefaults
--- in order to ensure we don't write empty default tables.
-local function copyDefaults(dest, src)
- -- this happens if some value in the SV overwrites our default value with a non-table
- --if type(dest) ~= "table" then return end
- for k, v in pairs(src) do
- if k == "*" or k == "**" then
- if type(v) == "table" then
- -- This is a metatable used for table defaults
- local mt = {
- -- This handles the lookup and creation of new subtables
- __index = function(t,k2)
- if k2 == nil then return nil end
- local tbl = {}
- copyDefaults(tbl, v)
- rawset(t, k2, tbl)
- return tbl
- end,
- }
- setmetatable(dest, mt)
- -- handle already existing tables in the SV
- for dk, dv in pairs(dest) do
- if not rawget(src, dk) and type(dv) == "table" then
- copyDefaults(dv, v)
- end
- end
- else
- -- Values are not tables, so this is just a simple return
- local mt = {__index = function(t,k2) return k2~=nil and v or nil end}
- setmetatable(dest, mt)
- end
- elseif type(v) == "table" then
- if not rawget(dest, k) then rawset(dest, k, {}) end
- if type(dest[k]) == "table" then
- copyDefaults(dest[k], v)
- if src['**'] then
- copyDefaults(dest[k], src['**'])
- end
- end
- else
- if rawget(dest, k) == nil then
- rawset(dest, k, v)
- end
- end
- end
-end
-
--- Called to remove all defaults in the default table from the database
-local function removeDefaults(db, defaults, blocker)
- -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
- setmetatable(db, nil)
- -- loop through the defaults and remove their content
- for k,v in pairs(defaults) do
- if k == "*" or k == "**" then
- if type(v) == "table" then
- -- Loop through all the actual k,v pairs and remove
- for key, value in pairs(db) do
- if type(value) == "table" then
- -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
- if defaults[key] == nil and (not blocker or blocker[key] == nil) then
- removeDefaults(value, v)
- -- if the table is empty afterwards, remove it
- if next(value) == nil then
- db[key] = nil
- end
- -- if it was specified, only strip ** content, but block values which were set in the key table
- elseif k == "**" then
- removeDefaults(value, v, defaults[key])
- end
- end
- end
- elseif k == "*" then
- -- check for non-table default
- for key, value in pairs(db) do
- if defaults[key] == nil and v == value then
- db[key] = nil
- end
- end
- end
- elseif type(v) == "table" and type(db[k]) == "table" then
- -- if a blocker was set, dive into it, to allow multi-level defaults
- removeDefaults(db[k], v, blocker and blocker[k])
- if next(db[k]) == nil then
- db[k] = nil
- end
- else
- -- check if the current value matches the default, and that its not blocked by another defaults table
- if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
- db[k] = nil
- end
- end
- end
-end
-
--- This is called when a table section is first accessed, to set up the defaults
-local function initSection(db, section, svstore, key, defaults)
- local sv = rawget(db, "sv")
-
- local tableCreated
- if not sv[svstore] then sv[svstore] = {} end
- if not sv[svstore][key] then
- sv[svstore][key] = {}
- tableCreated = true
- end
-
- local tbl = sv[svstore][key]
-
- if defaults then
- copyDefaults(tbl, defaults)
- end
- rawset(db, section, tbl)
-
- return tableCreated, tbl
-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]
-
- 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
- end
-
- return rawget(t, section)
- end
-}
-
-local function validateDefaults(defaults, keyTbl, offset)
- if not defaults then return end
- offset = offset or 0
- for k in pairs(defaults) do
- if not keyTbl[k] or k == "profiles" then
- error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
- end
- end
-end
-
-local preserve_keys = {
- ["callbacks"] = true,
- ["RegisterCallback"] = true,
- ["UnregisterCallback"] = true,
- ["UnregisterAllCallbacks"] = true,
- ["children"] = true,
-}
-
-local realmKey = GetRealmName()
-local charKey = UnitName("player") .. " - " .. realmKey
-local _, classKey = UnitClass("player")
-local _, raceKey = UnitRace("player")
-local factionKey = UnitFactionGroup("player")
-local factionrealmKey = factionKey .. " - " .. realmKey
-local localeKey = GetLocale():lower()
-
-local regionTable = { "US", "KR", "EU", "TW", "CN" }
-local regionKey = regionTable[GetCurrentRegion()]
-local factionrealmregionKey = factionrealmKey .. " - " .. regionKey
-
--- Actual database initialization function
-local function initdb(sv, defaults, defaultProfile, olddb, parent)
- -- Generate the database keys for each section
-
- -- map "true" to our "Default" profile
- if defaultProfile == true then defaultProfile = "Default" end
-
- local profileKey
- if not parent then
- -- Make a container for profile keys
- if not sv.profileKeys then sv.profileKeys = {} end
-
- -- Try to get the profile selected from the char db
- profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
-
- -- save the selected profile for later
- sv.profileKeys[charKey] = profileKey
- else
- -- Use the profile of the parents DB
- profileKey = parent.keys.profile or defaultProfile or charKey
-
- -- clear the profileKeys in the DB, namespaces don't need to store them
- sv.profileKeys = nil
- end
-
- -- This table contains keys that enable the dynamic creation
- -- of each section of the table. The 'global' and 'profiles'
- -- have a key of true, since they are handled in a special case
- local keyTbl= {
- ["char"] = charKey,
- ["realm"] = realmKey,
- ["class"] = classKey,
- ["race"] = raceKey,
- ["faction"] = factionKey,
- ["factionrealm"] = factionrealmKey,
- ["factionrealmregion"] = factionrealmregionKey,
- ["profile"] = profileKey,
- ["locale"] = localeKey,
- ["global"] = true,
- ["profiles"] = true,
- }
-
- validateDefaults(defaults, keyTbl, 1)
-
- -- This allows us to use this function to reset an entire database
- -- Clear out the old database
- if olddb then
- for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
- end
-
- -- Give this database the metatable so it initializes dynamically
- local db = setmetatable(olddb or {}, dbmt)
-
- if not rawget(db, "callbacks") then
- -- try to load CallbackHandler-1.0 if it loaded after our library
- if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
- db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
- end
-
- -- Copy methods locally into the database object, to avoid hitting
- -- the metatable when calling methods
-
- if not parent then
- for name, func in pairs(DBObjectLib) do
- db[name] = func
- end
- else
- -- hack this one in
- db.RegisterDefaults = DBObjectLib.RegisterDefaults
- db.ResetProfile = DBObjectLib.ResetProfile
- end
-
- -- Set some properties in the database object
- db.profiles = sv.profiles
- db.keys = keyTbl
- db.sv = sv
- --db.sv_name = name
- db.defaults = defaults
- db.parent = parent
-
- -- store the DB in the registry
- AceDB.db_registry[db] = true
-
- return db
-end
-
--- handle PLAYER_LOGOUT
--- strip all defaults from all databases
--- and cleans up empty sections
-local function logoutHandler(frame, event)
- if event == "PLAYER_LOGOUT" then
- for db in pairs(AceDB.db_registry) do
- db.callbacks:Fire("OnDatabaseShutdown", db)
- db:RegisterDefaults(nil)
-
- -- cleanup sections that are empty without defaults
- local sv = rawget(db, "sv")
- for section in pairs(db.keys) do
- if rawget(sv, section) then
- -- global is special, all other sections have sub-entrys
- -- also don't delete empty profiles on main dbs, only on namespaces
- if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
- for key in pairs(sv[section]) do
- if not next(sv[section][key]) then
- sv[section][key] = nil
- end
- end
- end
- if not next(sv[section]) then
- sv[section] = nil
- end
- end
- end
- end
- end
-end
-
-AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
-AceDB.frame:SetScript("OnEvent", logoutHandler)
-
-
---[[-------------------------------------------------------------------------
- AceDB Object Method Definitions
----------------------------------------------------------------------------]]
-
---- Sets the defaults table for the given database object by clearing any
--- that are currently set, and then setting the new defaults.
--- @param defaults A table of defaults for this database
-function DBObjectLib:RegisterDefaults(defaults)
- if defaults and type(defaults) ~= "table" then
- error(("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
- end
-
- validateDefaults(defaults, self.keys)
-
- -- Remove any currently set defaults
- if self.defaults then
- for section,key in pairs(self.keys) do
- if self.defaults[section] and rawget(self, section) then
- removeDefaults(self[section], self.defaults[section])
- end
- end
- end
-
- -- Set the DBObject.defaults table
- self.defaults = defaults
-
- -- Copy in any defaults, only touching those sections already created
- if defaults then
- for section,key in pairs(self.keys) do
- if defaults[section] and rawget(self, section) then
- copyDefaults(self[section], defaults[section])
- end
- end
- end
-end
-
---- Changes the profile of the database and all of it's namespaces to the
--- supplied named profile
--- @param name The name of the profile to set as the current profile
-function DBObjectLib:SetProfile(name)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
-
- -- changing to the same profile, dont do anything
- if name == self.keys.profile then return end
-
- local oldProfile = self.profile
- local defaults = self.defaults and self.defaults.profile
-
- -- Callback: OnProfileShutdown, database
- self.callbacks:Fire("OnProfileShutdown", self)
-
- if oldProfile and defaults then
- -- Remove the defaults from the old profile
- removeDefaults(oldProfile, defaults)
- end
-
- self.profile = nil
- self.keys["profile"] = name
-
- -- if the storage exists, save the new profile
- -- this won't exist on namespaces.
- if self.sv.profileKeys then
- self.sv.profileKeys[charKey] = name
- end
-
- -- populate to child namespaces
- if self.children then
- for _, db in pairs(self.children) do
- DBObjectLib.SetProfile(db, name)
- end
- end
-
- -- Callback: OnProfileChanged, database, newProfileKey
- self.callbacks:Fire("OnProfileChanged", self, name)
-end
-
---- Returns a table with the names of the existing profiles in the database.
--- You can optionally supply a table to re-use for this purpose.
--- @param tbl A table to store the profile names in (optional)
-function DBObjectLib:GetProfiles(tbl)
- if tbl and type(tbl) ~= "table" then
- error(("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected, got %q."):format(type(tbl)), 2)
- end
-
- -- Clear the container table
- if tbl then
- for k,v in pairs(tbl) do tbl[k] = nil end
- else
- tbl = {}
- end
-
- local curProfile = self.keys.profile
-
- local i = 0
- for profileKey in pairs(self.profiles) do
- i = i + 1
- tbl[i] = profileKey
- if curProfile and profileKey == curProfile then curProfile = nil end
- end
-
- -- Add the current profile, if it hasn't been created yet
- if curProfile then
- i = i + 1
- tbl[i] = curProfile
- end
-
- return tbl, i
-end
-
---- Returns the current profile name used by the database
-function DBObjectLib:GetCurrentProfile()
- return self.keys.profile
-end
-
---- Deletes a named profile. This profile must not be the active profile.
--- @param name The name of the profile to be deleted
--- @param silent If true, do not raise an error when the profile does not exist
-function DBObjectLib:DeleteProfile(name, silent)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
-
- if self.keys.profile == name then
- error(("Cannot delete the active profile (%q) in an AceDBObject."):format(name), 2)
- end
-
- if not rawget(self.profiles, name) and not silent then
- error(("Cannot delete profile %q as it does not exist."):format(name), 2)
- end
-
- self.profiles[name] = nil
-
- -- populate to child namespaces
- if self.children then
- for _, db in pairs(self.children) do
- DBObjectLib.DeleteProfile(db, name, true)
- end
- end
-
- -- switch all characters that use this profile back to the default
- if self.sv.profileKeys then
- for key, profile in pairs(self.sv.profileKeys) do
- if profile == name then
- self.sv.profileKeys[key] = nil
- end
- end
- end
-
- -- Callback: OnProfileDeleted, database, profileKey
- self.callbacks:Fire("OnProfileDeleted", self, name)
-end
-
---- Copies a named profile into the current profile, overwriting any conflicting
--- settings.
--- @param name The name of the profile to be copied into the current profile
--- @param silent If true, do not raise an error when the profile does not exist
-function DBObjectLib:CopyProfile(name, silent)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:CopyProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
-
- if name == self.keys.profile then
- error(("Cannot have the same source and destination profiles (%q)."):format(name), 2)
- end
-
- if not rawget(self.profiles, name) and not silent then
- error(("Cannot copy profile %q as it does not exist."):format(name), 2)
- end
-
- -- Reset the profile before copying
- DBObjectLib.ResetProfile(self, nil, true)
-
- local profile = self.profile
- local source = self.profiles[name]
-
- copyTable(source, profile)
-
- -- populate to child namespaces
- if self.children then
- for _, db in pairs(self.children) do
- DBObjectLib.CopyProfile(db, name, true)
- end
- end
-
- -- Callback: OnProfileCopied, database, sourceProfileKey
- self.callbacks:Fire("OnProfileCopied", self, name)
-end
-
---- Resets the current profile to the default values (if specified).
--- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
--- @param noCallbacks if set to true, won't fire the OnProfileReset callback
-function DBObjectLib:ResetProfile(noChildren, noCallbacks)
- local profile = self.profile
-
- for k,v in pairs(profile) do
- profile[k] = nil
- end
-
- local defaults = self.defaults and self.defaults.profile
- if defaults then
- copyDefaults(profile, defaults)
- end
-
- -- populate to child namespaces
- if self.children and not noChildren then
- for _, db in pairs(self.children) do
- DBObjectLib.ResetProfile(db, nil, noCallbacks)
- end
- end
-
- -- Callback: OnProfileReset, database
- if not noCallbacks then
- self.callbacks:Fire("OnProfileReset", self)
- end
-end
-
---- Resets the entire database, using the string defaultProfile as the new default
--- profile.
--- @param defaultProfile The profile name to use as the default
-function DBObjectLib:ResetDB(defaultProfile)
- if defaultProfile and type(defaultProfile) ~= "string" then
- error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected, got %q."):format(type(defaultProfile)), 2)
- end
-
- local sv = self.sv
- for k,v in pairs(sv) do
- sv[k] = nil
- end
-
- initdb(sv, self.defaults, defaultProfile, self)
-
- -- fix the child namespaces
- if self.children then
- if not sv.namespaces then sv.namespaces = {} end
- for name, db in pairs(self.children) do
- if not sv.namespaces[name] then sv.namespaces[name] = {} end
- initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
- end
- end
-
- -- Callback: OnDatabaseReset, database
- self.callbacks:Fire("OnDatabaseReset", self)
- -- Callback: OnProfileChanged, database, profileKey
- self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
-
- return self
-end
-
---- Creates a new database namespace, directly tied to the database. This
--- is a full scale database in it's own rights other than the fact that
--- it cannot control its profile individually
--- @param name The name of the new namespace
--- @param defaults A table of values to use as defaults
-function DBObjectLib:RegisterNamespace(name, defaults)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected, got %q."):format(type(name)), 2)
- end
- if defaults and type(defaults) ~= "table" then
- error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
- end
- if self.children and self.children[name] then
- error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace called %q already exists."):format(name), 2)
- end
-
- local sv = self.sv
- if not sv.namespaces then sv.namespaces = {} end
- if not sv.namespaces[name] then
- sv.namespaces[name] = {}
- end
-
- local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
-
- if not self.children then self.children = {} end
- self.children[name] = newDB
- return newDB
-end
-
---- Returns an already existing namespace from the database object.
--- @param name The name of the new namespace
--- @param silent if true, the addon is optional, silently return nil if its not found
--- @usage
--- local namespace = self.db:GetNamespace('namespace')
--- @return the namespace object if found
-function DBObjectLib:GetNamespace(name, silent)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:GetNamespace(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
- if not silent and not (self.children and self.children[name]) then
- error(("Usage: AceDBObject:GetNamespace(name): 'name' - namespace %q does not exist."):format(name), 2)
- end
- if not self.children then self.children = {} end
- return self.children[name]
-end
-
---[[-------------------------------------------------------------------------
- AceDB Exposed Methods
----------------------------------------------------------------------------]]
-
---- Creates a new database object that can be used to handle database settings and profiles.
--- By default, an empty DB is created, using a character specific profile.
---
--- You can override the default profile used by passing any profile name as the third argument,
--- or by passing //true// as the third argument to use a globally shared profile called "Default".
---
--- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
--- will use a profile named "char", and not a character-specific profile.
--- @param tbl The name of variable, or table to use for the database
--- @param defaults A table of database defaults
--- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
--- You can also pass //true// to use a shared global profile called "Default".
--- @usage
--- -- Create an empty DB using a character-specific default profile.
--- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
--- @usage
--- -- Create a DB using defaults and using a shared default profile
--- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
-function AceDB:New(tbl, defaults, defaultProfile)
- if type(tbl) == "string" then
- local name = tbl
- tbl = _G[name]
- if not tbl then
- tbl = {}
- _G[name] = tbl
- end
- end
-
- if type(tbl) ~= "table" then
- error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected, got %q."):format(type(tbl)), 2)
- end
-
- if defaults and type(defaults) ~= "table" then
- error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2)
- end
-
- if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
- error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
- end
-
- return initdb(tbl, defaults, defaultProfile)
-end
-
--- upgrade existing databases
-for db in pairs(AceDB.db_registry) do
- if not db.parent then
- for name,func in pairs(DBObjectLib) do
- db[name] = func
- end
- else
- db.RegisterDefaults = DBObjectLib.RegisterDefaults
- db.ResetProfile = DBObjectLib.ResetProfile
- end
-end
+--- **AceDB-3.0** manages the SavedVariables of your addon.
+-- It offers profile management, smart defaults and namespaces for modules.\\
+-- Data can be saved in different data-types, depending on its intended usage.
+-- The most common data-type is the `profile` type, which allows the user to choose
+-- the active profile, and manage the profiles of all of his characters.\\
+-- The following data types are available:
+-- * **char** Character-specific data. Every character has its own database.
+-- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
+-- * **class** Class-specific data. All of the players characters of the same class share this database.
+-- * **race** Race-specific data. All of the players characters of the same race share this database.
+-- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
+-- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
+-- * **locale** Locale specific data, based on the locale of the players game client.
+-- * **global** Global Data. All characters on the same account share this database.
+-- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
+--
+-- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
+-- of the DBObjectLib listed here. \\
+-- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
+-- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
+-- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
+--
+-- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
+--
+-- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
+--
+-- @usage
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
+--
+-- -- declare defaults to be used in the DB
+-- local defaults = {
+-- profile = {
+-- setting = true,
+-- }
+-- }
+--
+-- function MyAddon:OnInitialize()
+-- -- Assuming the .toc says ## SavedVariables: MyAddonDB
+-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
+-- end
+-- @class file
+-- @name AceDB-3.0.lua
+-- @release $Id: AceDB-3.0.lua 1328 2024-03-20 22:36:27Z nevcairiel $
+local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 29
+local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
+
+if not AceDB then return end -- No upgrade needed
+
+-- Lua APIs
+local type, pairs, next, error = type, pairs, next, error
+local setmetatable, rawset, rawget = setmetatable, rawset, rawget
+
+-- WoW APIs
+local _G = _G
+
+AceDB.db_registry = AceDB.db_registry or {}
+AceDB.frame = AceDB.frame or CreateFrame("Frame")
+
+local CallbackHandler
+local CallbackDummy = { Fire = function() end }
+
+local DBObjectLib = {}
+
+--[[-------------------------------------------------------------------------
+ AceDB Utility Functions
+---------------------------------------------------------------------------]]
+
+-- Simple shallow copy for copying defaults
+local function copyTable(src, dest)
+ if type(dest) ~= "table" then dest = {} end
+ if type(src) == "table" then
+ for k,v in pairs(src) do
+ if type(v) == "table" then
+ -- try to index the key first so that the metatable creates the defaults, if set, and use that table
+ v = copyTable(v, dest[k])
+ end
+ dest[k] = v
+ end
+ end
+ return dest
+end
+
+-- Called to add defaults to a section of the database
+--
+-- When a ["*"] default section is indexed with a new key, a table is returned
+-- and set in the host table. These tables must be cleaned up by removeDefaults
+-- in order to ensure we don't write empty default tables.
+local function copyDefaults(dest, src)
+ -- this happens if some value in the SV overwrites our default value with a non-table
+ --if type(dest) ~= "table" then return end
+ for k, v in pairs(src) do
+ if k == "*" or k == "**" then
+ if type(v) == "table" then
+ -- This is a metatable used for table defaults
+ local mt = {
+ -- This handles the lookup and creation of new subtables
+ __index = function(t,k2)
+ if k2 == nil then return nil end
+ local tbl = {}
+ copyDefaults(tbl, v)
+ rawset(t, k2, tbl)
+ return tbl
+ end,
+ }
+ setmetatable(dest, mt)
+ -- handle already existing tables in the SV
+ for dk, dv in pairs(dest) do
+ if not rawget(src, dk) and type(dv) == "table" then
+ copyDefaults(dv, v)
+ end
+ end
+ else
+ -- Values are not tables, so this is just a simple return
+ local mt = {__index = function(t,k2) return k2~=nil and v or nil end}
+ setmetatable(dest, mt)
+ end
+ elseif type(v) == "table" then
+ if not rawget(dest, k) then rawset(dest, k, {}) end
+ if type(dest[k]) == "table" then
+ copyDefaults(dest[k], v)
+ if src['**'] then
+ copyDefaults(dest[k], src['**'])
+ end
+ end
+ else
+ if rawget(dest, k) == nil then
+ rawset(dest, k, v)
+ end
+ end
+ end
+end
+
+-- Called to remove all defaults in the default table from the database
+local function removeDefaults(db, defaults, blocker)
+ -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
+ setmetatable(db, nil)
+ -- loop through the defaults and remove their content
+ for k,v in pairs(defaults) do
+ if k == "*" or k == "**" then
+ if type(v) == "table" then
+ -- Loop through all the actual k,v pairs and remove
+ for key, value in pairs(db) do
+ if type(value) == "table" then
+ -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
+ if defaults[key] == nil and (not blocker or blocker[key] == nil) then
+ removeDefaults(value, v)
+ -- if the table is empty afterwards, remove it
+ if next(value) == nil then
+ db[key] = nil
+ end
+ -- if it was specified, only strip ** content, but block values which were set in the key table
+ elseif k == "**" then
+ removeDefaults(value, v, defaults[key])
+ end
+ end
+ end
+ elseif k == "*" then
+ -- check for non-table default
+ for key, value in pairs(db) do
+ if defaults[key] == nil and v == value then
+ db[key] = nil
+ end
+ end
+ end
+ elseif type(v) == "table" and type(db[k]) == "table" then
+ -- if a blocker was set, dive into it, to allow multi-level defaults
+ removeDefaults(db[k], v, blocker and blocker[k])
+ if next(db[k]) == nil then
+ db[k] = nil
+ end
+ else
+ -- check if the current value matches the default, and that its not blocked by another defaults table
+ if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
+ db[k] = nil
+ end
+ end
+ end
+end
+
+-- This is called when a table section is first accessed, to set up the defaults
+local function initSection(db, section, svstore, key, defaults)
+ local sv = rawget(db, "sv")
+
+ local tableCreated
+ if not sv[svstore] then sv[svstore] = {} end
+ if not sv[svstore][key] then
+ sv[svstore][key] = {}
+ tableCreated = true
+ end
+
+ local tbl = sv[svstore][key]
+
+ if defaults then
+ copyDefaults(tbl, defaults)
+ end
+ rawset(db, section, tbl)
+
+ return tableCreated, tbl
+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]
+
+ 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
+ end
+
+ return rawget(t, section)
+ end
+}
+
+local function validateDefaults(defaults, keyTbl, offset)
+ if not defaults then return end
+ offset = offset or 0
+ for k in pairs(defaults) do
+ if not keyTbl[k] or k == "profiles" then
+ error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
+ end
+ end
+end
+
+local preserve_keys = {
+ ["callbacks"] = true,
+ ["RegisterCallback"] = true,
+ ["UnregisterCallback"] = true,
+ ["UnregisterAllCallbacks"] = true,
+ ["children"] = true,
+}
+
+local realmKey = GetRealmName()
+local charKey = UnitName("player") .. " - " .. realmKey
+local _, classKey = UnitClass("player")
+local _, raceKey = UnitRace("player")
+local factionKey = UnitFactionGroup("player")
+local factionrealmKey = factionKey .. " - " .. realmKey
+local localeKey = GetLocale():lower()
+
+local regionTable = { "US", "KR", "EU", "TW", "CN" }
+local regionKey = regionTable[GetCurrentRegion()] or GetCurrentRegionName() or "TR"
+local factionrealmregionKey = factionrealmKey .. " - " .. regionKey
+
+-- Actual database initialization function
+local function initdb(sv, defaults, defaultProfile, olddb, parent)
+ -- Generate the database keys for each section
+
+ -- map "true" to our "Default" profile
+ if defaultProfile == true then defaultProfile = "Default" end
+
+ local profileKey
+ if not parent then
+ -- Make a container for profile keys
+ if not sv.profileKeys then sv.profileKeys = {} end
+
+ -- Try to get the profile selected from the char db
+ profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
+
+ -- save the selected profile for later
+ sv.profileKeys[charKey] = profileKey
+ else
+ -- Use the profile of the parents DB
+ profileKey = parent.keys.profile or defaultProfile or charKey
+
+ -- clear the profileKeys in the DB, namespaces don't need to store them
+ sv.profileKeys = nil
+ end
+
+ -- This table contains keys that enable the dynamic creation
+ -- of each section of the table. The 'global' and 'profiles'
+ -- have a key of true, since they are handled in a special case
+ local keyTbl= {
+ ["char"] = charKey,
+ ["realm"] = realmKey,
+ ["class"] = classKey,
+ ["race"] = raceKey,
+ ["faction"] = factionKey,
+ ["factionrealm"] = factionrealmKey,
+ ["factionrealmregion"] = factionrealmregionKey,
+ ["profile"] = profileKey,
+ ["locale"] = localeKey,
+ ["global"] = true,
+ ["profiles"] = true,
+ }
+
+ validateDefaults(defaults, keyTbl, 1)
+
+ -- This allows us to use this function to reset an entire database
+ -- Clear out the old database
+ if olddb then
+ for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
+ end
+
+ -- Give this database the metatable so it initializes dynamically
+ local db = setmetatable(olddb or {}, dbmt)
+
+ if not rawget(db, "callbacks") then
+ -- try to load CallbackHandler-1.0 if it loaded after our library
+ if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
+ db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
+ end
+
+ -- Copy methods locally into the database object, to avoid hitting
+ -- the metatable when calling methods
+
+ if not parent then
+ for name, func in pairs(DBObjectLib) do
+ db[name] = func
+ end
+ else
+ -- hack this one in
+ db.RegisterDefaults = DBObjectLib.RegisterDefaults
+ db.ResetProfile = DBObjectLib.ResetProfile
+ end
+
+ -- Set some properties in the database object
+ db.profiles = sv.profiles
+ db.keys = keyTbl
+ db.sv = sv
+ --db.sv_name = name
+ db.defaults = defaults
+ db.parent = parent
+
+ -- store the DB in the registry
+ AceDB.db_registry[db] = true
+
+ return db
+end
+
+-- handle PLAYER_LOGOUT
+-- strip all defaults from all databases
+-- and cleans up empty sections
+local function logoutHandler(frame, event)
+ if event == "PLAYER_LOGOUT" then
+ for db in pairs(AceDB.db_registry) do
+ db.callbacks:Fire("OnDatabaseShutdown", db)
+ db:RegisterDefaults(nil)
+
+ -- cleanup sections that are empty without defaults
+ local sv = rawget(db, "sv")
+ for section in pairs(db.keys) do
+ if rawget(sv, section) then
+ -- global is special, all other sections have sub-entrys
+ -- also don't delete empty profiles on main dbs, only on namespaces
+ if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
+ for key in pairs(sv[section]) do
+ if not next(sv[section][key]) then
+ sv[section][key] = nil
+ end
+ end
+ end
+ if not next(sv[section]) then
+ sv[section] = nil
+ end
+ end
+ end
+ end
+ end
+end
+
+AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
+AceDB.frame:SetScript("OnEvent", logoutHandler)
+
+
+--[[-------------------------------------------------------------------------
+ AceDB Object Method Definitions
+---------------------------------------------------------------------------]]
+
+--- Sets the defaults table for the given database object by clearing any
+-- that are currently set, and then setting the new defaults.
+-- @param defaults A table of defaults for this database
+function DBObjectLib:RegisterDefaults(defaults)
+ if defaults and type(defaults) ~= "table" then
+ error(("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
+ end
+
+ validateDefaults(defaults, self.keys)
+
+ -- Remove any currently set defaults
+ if self.defaults then
+ for section,key in pairs(self.keys) do
+ if self.defaults[section] and rawget(self, section) then
+ removeDefaults(self[section], self.defaults[section])
+ end
+ end
+ end
+
+ -- Set the DBObject.defaults table
+ self.defaults = defaults
+
+ -- Copy in any defaults, only touching those sections already created
+ if defaults then
+ for section,key in pairs(self.keys) do
+ if defaults[section] and rawget(self, section) then
+ copyDefaults(self[section], defaults[section])
+ end
+ end
+ end
+end
+
+--- Changes the profile of the database and all of it's namespaces to the
+-- supplied named profile
+-- @param name The name of the profile to set as the current profile
+function DBObjectLib:SetProfile(name)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+
+ -- changing to the same profile, dont do anything
+ if name == self.keys.profile then return end
+
+ local oldProfile = self.profile
+ local defaults = self.defaults and self.defaults.profile
+
+ -- Callback: OnProfileShutdown, database
+ self.callbacks:Fire("OnProfileShutdown", self)
+
+ if oldProfile and defaults then
+ -- Remove the defaults from the old profile
+ removeDefaults(oldProfile, defaults)
+ end
+
+ self.profile = nil
+ self.keys["profile"] = name
+
+ -- if the storage exists, save the new profile
+ -- this won't exist on namespaces.
+ if self.sv.profileKeys then
+ self.sv.profileKeys[charKey] = name
+ end
+
+ -- populate to child namespaces
+ if self.children then
+ for _, db in pairs(self.children) do
+ DBObjectLib.SetProfile(db, name)
+ end
+ end
+
+ -- Callback: OnProfileChanged, database, newProfileKey
+ self.callbacks:Fire("OnProfileChanged", self, name)
+end
+
+--- Returns a table with the names of the existing profiles in the database.
+-- You can optionally supply a table to re-use for this purpose.
+-- @param tbl A table to store the profile names in (optional)
+function DBObjectLib:GetProfiles(tbl)
+ if tbl and type(tbl) ~= "table" then
+ error(("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected, got %q."):format(type(tbl)), 2)
+ end
+
+ -- Clear the container table
+ if tbl then
+ for k,v in pairs(tbl) do tbl[k] = nil end
+ else
+ tbl = {}
+ end
+
+ local curProfile = self.keys.profile
+
+ local i = 0
+ for profileKey in pairs(self.profiles) do
+ i = i + 1
+ tbl[i] = profileKey
+ if curProfile and profileKey == curProfile then curProfile = nil end
+ end
+
+ -- Add the current profile, if it hasn't been created yet
+ if curProfile then
+ i = i + 1
+ tbl[i] = curProfile
+ end
+
+ return tbl, i
+end
+
+--- Returns the current profile name used by the database
+function DBObjectLib:GetCurrentProfile()
+ return self.keys.profile
+end
+
+--- Deletes a named profile. This profile must not be the active profile.
+-- @param name The name of the profile to be deleted
+-- @param silent If true, do not raise an error when the profile does not exist
+function DBObjectLib:DeleteProfile(name, silent)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+
+ if self.keys.profile == name then
+ error(("Cannot delete the active profile (%q) in an AceDBObject."):format(name), 2)
+ end
+
+ if not rawget(self.profiles, name) and not silent then
+ error(("Cannot delete profile %q as it does not exist."):format(name), 2)
+ end
+
+ self.profiles[name] = nil
+
+ -- populate to child namespaces
+ if self.children then
+ for _, db in pairs(self.children) do
+ DBObjectLib.DeleteProfile(db, name, true)
+ end
+ end
+
+ -- switch all characters that use this profile back to the default
+ if self.sv.profileKeys then
+ for key, profile in pairs(self.sv.profileKeys) do
+ if profile == name then
+ self.sv.profileKeys[key] = nil
+ end
+ end
+ end
+
+ -- Callback: OnProfileDeleted, database, profileKey
+ self.callbacks:Fire("OnProfileDeleted", self, name)
+end
+
+--- Copies a named profile into the current profile, overwriting any conflicting
+-- settings.
+-- @param name The name of the profile to be copied into the current profile
+-- @param silent If true, do not raise an error when the profile does not exist
+function DBObjectLib:CopyProfile(name, silent)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:CopyProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+
+ if name == self.keys.profile then
+ error(("Cannot have the same source and destination profiles (%q)."):format(name), 2)
+ end
+
+ if not rawget(self.profiles, name) and not silent then
+ error(("Cannot copy profile %q as it does not exist."):format(name), 2)
+ end
+
+ -- Reset the profile before copying
+ DBObjectLib.ResetProfile(self, nil, true)
+
+ local profile = self.profile
+ local source = self.profiles[name]
+
+ copyTable(source, profile)
+
+ -- populate to child namespaces
+ if self.children then
+ for _, db in pairs(self.children) do
+ DBObjectLib.CopyProfile(db, name, true)
+ end
+ end
+
+ -- Callback: OnProfileCopied, database, sourceProfileKey
+ self.callbacks:Fire("OnProfileCopied", self, name)
+end
+
+--- Resets the current profile to the default values (if specified).
+-- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
+-- @param noCallbacks if set to true, won't fire the OnProfileReset callback
+function DBObjectLib:ResetProfile(noChildren, noCallbacks)
+ local profile = self.profile
+
+ for k,v in pairs(profile) do
+ profile[k] = nil
+ end
+
+ local defaults = self.defaults and self.defaults.profile
+ if defaults then
+ copyDefaults(profile, defaults)
+ end
+
+ -- populate to child namespaces
+ if self.children and not noChildren then
+ for _, db in pairs(self.children) do
+ DBObjectLib.ResetProfile(db, nil, noCallbacks)
+ end
+ end
+
+ -- Callback: OnProfileReset, database
+ if not noCallbacks then
+ self.callbacks:Fire("OnProfileReset", self)
+ end
+end
+
+--- Resets the entire database, using the string defaultProfile as the new default
+-- profile.
+-- @param defaultProfile The profile name to use as the default
+function DBObjectLib:ResetDB(defaultProfile)
+ if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
+ error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
+ end
+
+ local sv = self.sv
+ for k,v in pairs(sv) do
+ sv[k] = nil
+ end
+
+ initdb(sv, self.defaults, defaultProfile, self)
+
+ -- fix the child namespaces
+ if self.children then
+ if not sv.namespaces then sv.namespaces = {} end
+ for name, db in pairs(self.children) do
+ if not sv.namespaces[name] then sv.namespaces[name] = {} end
+ initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
+ end
+ end
+
+ -- Callback: OnDatabaseReset, database
+ self.callbacks:Fire("OnDatabaseReset", self)
+ -- Callback: OnProfileChanged, database, profileKey
+ self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
+
+ return self
+end
+
+--- Creates a new database namespace, directly tied to the database. This
+-- is a full scale database in it's own rights other than the fact that
+-- it cannot control its profile individually
+-- @param name The name of the new namespace
+-- @param defaults A table of values to use as defaults
+function DBObjectLib:RegisterNamespace(name, defaults)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+ if defaults and type(defaults) ~= "table" then
+ error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
+ end
+ if self.children and self.children[name] then
+ error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace called %q already exists."):format(name), 2)
+ end
+
+ local sv = self.sv
+ if not sv.namespaces then sv.namespaces = {} end
+ if not sv.namespaces[name] then
+ sv.namespaces[name] = {}
+ end
+
+ local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
+
+ if not self.children then self.children = {} end
+ self.children[name] = newDB
+ return newDB
+end
+
+--- Returns an already existing namespace from the database object.
+-- @param name The name of the new namespace
+-- @param silent if true, the addon is optional, silently return nil if its not found
+-- @usage
+-- local namespace = self.db:GetNamespace('namespace')
+-- @return the namespace object if found
+function DBObjectLib:GetNamespace(name, silent)
+ if type(name) ~= "string" then
+ error(("Usage: AceDBObject:GetNamespace(name): 'name' - string expected, got %q."):format(type(name)), 2)
+ end
+ if not silent and not (self.children and self.children[name]) then
+ error(("Usage: AceDBObject:GetNamespace(name): 'name' - namespace %q does not exist."):format(name), 2)
+ end
+ if not self.children then self.children = {} end
+ return self.children[name]
+end
+
+--[[-------------------------------------------------------------------------
+ AceDB Exposed Methods
+---------------------------------------------------------------------------]]
+
+--- Creates a new database object that can be used to handle database settings and profiles.
+-- By default, an empty DB is created, using a character specific profile.
+--
+-- You can override the default profile used by passing any profile name as the third argument,
+-- or by passing //true// as the third argument to use a globally shared profile called "Default".
+--
+-- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
+-- will use a profile named "char", and not a character-specific profile.
+-- @param tbl The name of variable, or table to use for the database
+-- @param defaults A table of database defaults
+-- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
+-- You can also pass //true// to use a shared global profile called "Default".
+-- @usage
+-- -- Create an empty DB using a character-specific default profile.
+-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
+-- @usage
+-- -- Create a DB using defaults and using a shared default profile
+-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
+function AceDB:New(tbl, defaults, defaultProfile)
+ if type(tbl) == "string" then
+ local name = tbl
+ tbl = _G[name]
+ if not tbl then
+ tbl = {}
+ _G[name] = tbl
+ end
+ end
+
+ if type(tbl) ~= "table" then
+ error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected, got %q."):format(type(tbl)), 2)
+ end
+
+ if defaults and type(defaults) ~= "table" then
+ error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2)
+ end
+
+ if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
+ error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
+ end
+
+ return initdb(tbl, defaults, defaultProfile)
+end
+
+-- upgrade existing databases
+for db in pairs(AceDB.db_registry) do
+ if not db.parent then
+ for name,func in pairs(DBObjectLib) do
+ db[name] = func
+ end
+ else
+ db.RegisterDefaults = DBObjectLib.RegisterDefaults
+ db.ResetProfile = DBObjectLib.ResetProfile
+ end
+end
diff --git a/Libs/AceDB-3.0/AceDB-3.0.xml b/Libs/AceDB-3.0/AceDB-3.0.xml
index 28998e5..108fc70 100644
--- a/Libs/AceDB-3.0/AceDB-3.0.xml
+++ b/Libs/AceDB-3.0/AceDB-3.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/AceEvent-3.0/AceEvent-3.0.lua b/Libs/AceEvent-3.0/AceEvent-3.0.lua
index c6aab1f..7ccd880 100755
--- a/Libs/AceEvent-3.0/AceEvent-3.0.lua
+++ b/Libs/AceEvent-3.0/AceEvent-3.0.lua
@@ -1,126 +1,126 @@
---- AceEvent-3.0 provides event registration and secure dispatching.
--- 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
--- 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
--- make into AceEvent.
--- @class file
--- @name AceEvent-3.0
--- @release $Id: AceEvent-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $
-local CallbackHandler = LibStub("CallbackHandler-1.0")
-
-local MAJOR, MINOR = "AceEvent-3.0", 4
-local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceEvent then return end
-
--- Lua APIs
-local pairs = pairs
-
-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,
- "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
-end
-
-function AceEvent.events:OnUsed(target, eventname)
- AceEvent.frame:RegisterEvent(eventname)
-end
-
-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,
- "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
- )
- AceEvent.SendMessage = AceEvent.messages.Fire
-end
-
---- embedding and embed handling
-local mixins = {
- "RegisterEvent", "UnregisterEvent",
- "RegisterMessage", "UnregisterMessage",
- "SendMessage",
- "UnregisterAllEvents", "UnregisterAllMessages",
-}
-
---- Register for a Blizzard Event.
--- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
--- Any arguments to the event will be passed on after that.
--- @name AceEvent:RegisterEvent
--- @class function
--- @paramsig event[, callback [, arg]]
--- @param event The event to register for
--- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
--- @param arg An optional argument to pass to the callback function
-
---- Unregister an event.
--- @name AceEvent:UnregisterEvent
--- @class function
--- @paramsig event
--- @param event The event to unregister
-
---- Register for a custom AceEvent-internal message.
--- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
--- Any arguments to the event will be passed on after that.
--- @name AceEvent:RegisterMessage
--- @class function
--- @paramsig message[, callback [, arg]]
--- @param message The message to register for
--- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
--- @param arg An optional argument to pass to the callback function
-
---- Unregister a message
--- @name AceEvent:UnregisterMessage
--- @class function
--- @paramsig message
--- @param message The message to unregister
-
---- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
--- @name AceEvent:SendMessage
--- @class function
--- @paramsig message, ...
--- @param message The message to send
--- @param ... Any arguments to the message
-
-
--- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
--- @param target target object to embed AceEvent in
-function AceEvent:Embed(target)
- for k, v in pairs(mixins) do
- target[v] = self[v]
- end
- self.embeds[target] = true
- return target
-end
-
--- AceEvent:OnEmbedDisable( target )
--- target (object) - target object that is being disabled
---
--- Unregister all events messages etc when the target disables.
--- this method should be called by the target manually or by an addon framework
-function AceEvent:OnEmbedDisable(target)
- target:UnregisterAllEvents()
- target:UnregisterAllMessages()
-end
-
--- Script to fire blizzard events into the event listeners
-local events = AceEvent.events
-AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
- events:Fire(event, ...)
-end)
-
---- Finally: upgrade our old embeds
-for target, v in pairs(AceEvent.embeds) do
- AceEvent:Embed(target)
-end
+--- AceEvent-3.0 provides event registration and secure dispatching.
+-- 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
+-- 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
+-- make into AceEvent.
+-- @class file
+-- @name AceEvent-3.0
+-- @release $Id: AceEvent-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $
+local CallbackHandler = LibStub("CallbackHandler-1.0")
+
+local MAJOR, MINOR = "AceEvent-3.0", 4
+local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceEvent then return end
+
+-- Lua APIs
+local pairs = pairs
+
+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,
+ "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
+end
+
+function AceEvent.events:OnUsed(target, eventname)
+ AceEvent.frame:RegisterEvent(eventname)
+end
+
+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,
+ "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
+ )
+ AceEvent.SendMessage = AceEvent.messages.Fire
+end
+
+--- embedding and embed handling
+local mixins = {
+ "RegisterEvent", "UnregisterEvent",
+ "RegisterMessage", "UnregisterMessage",
+ "SendMessage",
+ "UnregisterAllEvents", "UnregisterAllMessages",
+}
+
+--- Register for a Blizzard Event.
+-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
+-- Any arguments to the event will be passed on after that.
+-- @name AceEvent:RegisterEvent
+-- @class function
+-- @paramsig event[, callback [, arg]]
+-- @param event The event to register for
+-- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
+-- @param arg An optional argument to pass to the callback function
+
+--- Unregister an event.
+-- @name AceEvent:UnregisterEvent
+-- @class function
+-- @paramsig event
+-- @param event The event to unregister
+
+--- Register for a custom AceEvent-internal message.
+-- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
+-- Any arguments to the event will be passed on after that.
+-- @name AceEvent:RegisterMessage
+-- @class function
+-- @paramsig message[, callback [, arg]]
+-- @param message The message to register for
+-- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
+-- @param arg An optional argument to pass to the callback function
+
+--- Unregister a message
+-- @name AceEvent:UnregisterMessage
+-- @class function
+-- @paramsig message
+-- @param message The message to unregister
+
+--- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
+-- @name AceEvent:SendMessage
+-- @class function
+-- @paramsig message, ...
+-- @param message The message to send
+-- @param ... Any arguments to the message
+
+
+-- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
+-- @param target target object to embed AceEvent in
+function AceEvent:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+-- AceEvent:OnEmbedDisable( target )
+-- target (object) - target object that is being disabled
+--
+-- Unregister all events messages etc when the target disables.
+-- this method should be called by the target manually or by an addon framework
+function AceEvent:OnEmbedDisable(target)
+ target:UnregisterAllEvents()
+ target:UnregisterAllMessages()
+end
+
+-- Script to fire blizzard events into the event listeners
+local events = AceEvent.events
+AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
+ events:Fire(event, ...)
+end)
+
+--- Finally: upgrade our old embeds
+for target, v in pairs(AceEvent.embeds) do
+ AceEvent:Embed(target)
+end
diff --git a/Libs/AceEvent-3.0/AceEvent-3.0.xml b/Libs/AceEvent-3.0/AceEvent-3.0.xml
index dc3cc5d..41ef791 100755
--- a/Libs/AceEvent-3.0/AceEvent-3.0.xml
+++ b/Libs/AceEvent-3.0/AceEvent-3.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/AceGUI-3.0/AceGUI-3.0.lua b/Libs/AceGUI-3.0/AceGUI-3.0.lua
index 7d9a2cf..f05b1ed 100644
--- a/Libs/AceGUI-3.0/AceGUI-3.0.lua
+++ b/Libs/AceGUI-3.0/AceGUI-3.0.lua
@@ -1,1020 +1,1020 @@
---- **AceGUI-3.0** provides access to numerous widgets which can be used to create GUIs.
--- AceGUI is used by AceConfigDialog to create the option GUIs, but you can use it by itself
--- to create any custom GUI. There are more extensive examples in the test suite in the Ace3
--- stand-alone distribution.
---
--- **Note**: When using AceGUI-3.0 directly, please do not modify the frames of the widgets directly,
--- as any "unknown" change to the widgets will cause addons that get your widget out of the widget pool
--- to misbehave. If you think some part of a widget should be modifiable, please open a ticket, and we"ll
--- implement a proper API to modify it.
--- @usage
--- local AceGUI = LibStub("AceGUI-3.0")
--- -- Create a container frame
--- local f = AceGUI:Create("Frame")
--- f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
--- f:SetTitle("AceGUI-3.0 Example")
--- f:SetStatusText("Status Bar")
--- f:SetLayout("Flow")
--- -- Create a button
--- local btn = AceGUI:Create("Button")
--- btn:SetWidth(170)
--- btn:SetText("Button !")
--- btn:SetCallback("OnClick", function() print("Click!") end)
--- -- Add the button to the container
--- f:AddChild(btn)
--- @class file
--- @name AceGUI-3.0
--- @release $Id: AceGUI-3.0.lua 1288 2022-09-25 14:19:00Z funkehdude $
-local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 41
-local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
-
-if not AceGUI then return end -- No upgrade needed
-
--- Lua APIs
-local tinsert, wipe = table.insert, table.wipe
-local select, pairs, next, type = select, pairs, next, type
-local error, assert = error, assert
-local setmetatable, rawget = setmetatable, rawget
-local math_max, math_min, math_ceil = math.max, math.min, math.ceil
-
--- WoW APIs
-local UIParent = UIParent
-
-AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
-AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
-AceGUI.WidgetBase = AceGUI.WidgetBase or {}
-AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
-AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
-AceGUI.tooltip = AceGUI.tooltip or CreateFrame("GameTooltip", "AceGUITooltip", UIParent, "GameTooltipTemplate")
-
--- local upvalues
-local WidgetRegistry = AceGUI.WidgetRegistry
-local LayoutRegistry = AceGUI.LayoutRegistry
-local WidgetVersions = AceGUI.WidgetVersions
-
---[[
- xpcall safecall implementation
-]]
-local xpcall = xpcall
-
-local function errorhandler(err)
- return geterrorhandler()(err)
-end
-
-local function safecall(func, ...)
- if func then
- return xpcall(func, errorhandler, ...)
- end
-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
- function newWidget(widgetType)
- if not WidgetRegistry[widgetType] then
- error("Attempt to instantiate unknown widget type", 2)
- end
-
- if not objPools[widgetType] then
- objPools[widgetType] = {}
- end
-
- local newObj = next(objPools[widgetType])
- if not newObj then
- newObj = WidgetRegistry[widgetType]()
- newObj.AceGUIWidgetVersion = WidgetVersions[widgetType]
- else
- objPools[widgetType][newObj] = nil
- -- if the widget is older then the latest, don't even try to reuse it
- -- just forget about it, and grab a new one.
- if not newObj.AceGUIWidgetVersion or newObj.AceGUIWidgetVersion < WidgetVersions[widgetType] then
- return newWidget(widgetType)
- end
- end
- return newObj
- end
- -- Releases an instance to the Pool
- function delWidget(obj,widgetType)
- if not objPools[widgetType] then
- objPools[widgetType] = {}
- end
- if objPools[widgetType][obj] then
- error("Attempt to Release Widget that is already released", 2)
- end
- objPools[widgetType][obj] = true
- end
-end
-
-
--------------------
--- API Functions --
--------------------
-
--- Gets a widget Object
-
---- Create a new Widget of the given type.
--- This function will instantiate a new widget (or use one from the widget pool), and call the
--- OnAcquire function on it, before returning.
--- @param type The type of the widget.
--- @return The newly created widget.
-function AceGUI:Create(widgetType)
- if WidgetRegistry[widgetType] then
- local widget = newWidget(widgetType)
-
- 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(("Widget type %s doesn't supply an OnAcquire Function"):format(widgetType))
- end
- -- Set the default Layout ("List")
- safecall(widget.SetLayout, widget, "List")
- safecall(widget.ResumeLayout, widget)
- return widget
- end
-end
-
---- Releases a widget Object.
--- This function calls OnRelease on the widget and places it back in the widget pool.
--- Any data on the widget is being erased, and the widget will be hidden.\\
--- 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)
- if widget.isQueuedForRelease then return end
- widget.isQueuedForRelease = true
- safecall(widget.PauseLayout, widget)
- widget.frame:Hide()
- widget:Fire("OnRelease")
- safecall(widget.ReleaseChildren, widget)
-
- if widget.OnRelease then
- widget:OnRelease()
--- else
--- error(("Widget type %s doesn't supply an OnRelease Function"):format(widget.type))
- end
- for k in pairs(widget.userdata) do
- widget.userdata[k] = nil
- end
- for k in pairs(widget.events) do
- widget.events[k] = nil
- end
- widget.width = nil
- widget.relWidth = nil
- widget.height = nil
- widget.relHeight = nil
- widget.noAutoHeight = nil
- widget.frame:ClearAllPoints()
- widget.frame:Hide()
- widget.frame:SetParent(UIParent)
- widget.frame.width = nil
- widget.frame.height = nil
- if widget.content then
- widget.content.width = nil
- widget.content.height = nil
- end
- widget.isQueuedForRelease = nil
- delWidget(widget, widget.type)
-end
-
---- Check if a widget is currently in the process of being released
--- This function check if this widget, or any of its parents (in which case it'll be released shortly as well)
--- are currently being released. This allows addon to handle any callbacks accordingly.
--- @param widget The widget to check
-function AceGUI:IsReleasing(widget)
- if widget.isQueuedForRelease then
- return true
- end
-
- if widget.parent and widget.parent.AceGUIWidgetVersion then
- return AceGUI:IsReleasing(widget.parent)
- end
-
- return false
-end
-
------------
--- Focus --
------------
-
-
---- Called when a widget has taken focus.
--- e.g. Dropdowns opening, Editboxes gaining kb focus
--- @param widget The widget that should be focused
-function AceGUI:SetFocus(widget)
- if self.FocusedWidget and self.FocusedWidget ~= widget then
- safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
- end
- self.FocusedWidget = widget
-end
-
-
---- Called when something has happened that could cause widgets with focus to drop it
--- e.g. titlebar of a frame being clicked
-function AceGUI:ClearFocus()
- if self.FocusedWidget then
- safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
- self.FocusedWidget = nil
- end
-end
-
--------------
--- Widgets --
--------------
---[[
- Widgets must provide the following functions
- OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
-
- And the following members
- frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
- type - the type of the object, same as the name given to :RegisterWidget()
-
- Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
- It will be cleared automatically when a widget is released
- Placing values directly into a widget object should be avoided
-
- If the Widget can act as a container for other Widgets the following
- content - frame or derivitive that children will be anchored to
-
- The Widget can supply the following Optional Members
- :OnRelease() - Called when the object is Released, should remove any additional anchors and clear any data
- :OnWidthSet(width) - Called when the width of the widget is changed
- :OnHeightSet(height) - Called when the height of the widget is changed
- Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
- AceGUI already sets a handler to the event
- :LayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
- area used for controls. These can be nil if the layout used the existing size to layout the controls.
-
-]]
-
---------------------------
--- Widget Base Template --
---------------------------
-do
- local WidgetBase = AceGUI.WidgetBase
-
- WidgetBase.SetParent = function(self, parent)
- local frame = self.frame
- frame:SetParent(nil)
- frame:SetParent(parent.content)
- self.parent = parent
- end
-
- WidgetBase.SetCallback = function(self, name, func)
- if type(func) == "function" then
- self.events[name] = func
- end
- end
-
- WidgetBase.Fire = function(self, name, ...)
- if self.events[name] then
- local success, ret = safecall(self.events[name], self, name, ...)
- if success then
- return ret
- end
- end
- end
-
- WidgetBase.SetWidth = function(self, width)
- self.frame:SetWidth(width)
- self.frame.width = width
- if self.OnWidthSet then
- self:OnWidthSet(width)
- end
- end
-
- WidgetBase.SetRelativeWidth = function(self, width)
- if width <= 0 or width > 1 then
- error(":SetRelativeWidth(width): Invalid relative width.", 2)
- end
- self.relWidth = width
- self.width = "relative"
- end
-
- WidgetBase.SetHeight = function(self, height)
- self.frame:SetHeight(height)
- self.frame.height = height
- if self.OnHeightSet then
- self:OnHeightSet(height)
- end
- end
-
- --[[ WidgetBase.SetRelativeHeight = function(self, height)
- if height <= 0 or height > 1 then
- error(":SetRelativeHeight(height): Invalid relative height.", 2)
- end
- self.relHeight = height
- self.height = "relative"
- end ]]
-
- WidgetBase.IsVisible = function(self)
- return self.frame:IsVisible()
- end
-
- WidgetBase.IsShown= function(self)
- return self.frame:IsShown()
- end
-
- WidgetBase.Release = function(self)
- AceGUI:Release(self)
- end
-
- WidgetBase.IsReleasing = function(self)
- return AceGUI:IsReleasing(self)
- end
-
- WidgetBase.SetPoint = function(self, ...)
- return self.frame:SetPoint(...)
- end
-
- WidgetBase.ClearAllPoints = function(self)
- return self.frame:ClearAllPoints()
- end
-
- WidgetBase.GetNumPoints = function(self)
- return self.frame:GetNumPoints()
- end
-
- WidgetBase.GetPoint = function(self, ...)
- return self.frame:GetPoint(...)
- end
-
- WidgetBase.GetUserDataTable = function(self)
- return self.userdata
- end
-
- WidgetBase.SetUserData = function(self, key, value)
- self.userdata[key] = value
- end
-
- WidgetBase.GetUserData = function(self, key)
- return self.userdata[key]
- end
-
- WidgetBase.IsFullHeight = function(self)
- return self.height == "fill"
- end
-
- WidgetBase.SetFullHeight = function(self, isFull)
- if isFull then
- self.height = "fill"
- else
- self.height = nil
- end
- end
-
- WidgetBase.IsFullWidth = function(self)
- return self.width == "fill"
- end
-
- WidgetBase.SetFullWidth = function(self, isFull)
- if isFull then
- self.width = "fill"
- else
- self.width = nil
- end
- end
-
--- local function LayoutOnUpdate(this)
--- this:SetScript("OnUpdate",nil)
--- this.obj:PerformLayout()
--- end
-
- local WidgetContainerBase = AceGUI.WidgetContainerBase
-
- WidgetContainerBase.PauseLayout = function(self)
- self.LayoutPaused = true
- end
-
- WidgetContainerBase.ResumeLayout = function(self)
- self.LayoutPaused = nil
- end
-
- WidgetContainerBase.PerformLayout = function(self)
- if self.LayoutPaused then
- return
- end
- 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
- WidgetContainerBase.DoLayout = function(self)
- self:PerformLayout()
--- if not self.parent then
--- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
--- end
- end
-
- WidgetContainerBase.AddChild = function(self, child, beforeWidget)
- if beforeWidget then
- local siblingIndex = 1
- for _, widget in pairs(self.children) do
- if widget == beforeWidget then
- break
- end
- siblingIndex = siblingIndex + 1
- end
- tinsert(self.children, siblingIndex, child)
- else
- tinsert(self.children, child)
- end
- child:SetParent(self)
- child.frame:Show()
- self:DoLayout()
- end
-
- WidgetContainerBase.AddChildren = function(self, ...)
- for i = 1, select("#", ...) do
- local child = select(i, ...)
- tinsert(self.children, child)
- child:SetParent(self)
- child.frame:Show()
- end
- self:DoLayout()
- end
-
- WidgetContainerBase.ReleaseChildren = function(self)
- local children = self.children
- for i = 1,#children do
- AceGUI:Release(children[i])
- children[i] = nil
- end
- end
-
- WidgetContainerBase.SetLayout = function(self, Layout)
- self.LayoutFunc = AceGUI:GetLayout(Layout)
- end
-
- WidgetContainerBase.SetAutoAdjustHeight = function(self, adjust)
- if adjust then
- self.noAutoHeight = nil
- else
- self.noAutoHeight = true
- end
- end
-
- local function FrameResize(this)
- local self = this.obj
- if this:GetWidth() and this:GetHeight() then
- if self.OnWidthSet then
- self:OnWidthSet(this:GetWidth())
- end
- if self.OnHeightSet then
- self:OnHeightSet(this:GetHeight())
- end
- end
- end
-
- local function ContentResize(this)
- if this:GetWidth() and this:GetHeight() then
- this.width = this:GetWidth()
- this.height = this:GetHeight()
- this.obj:DoLayout()
- end
- end
-
- setmetatable(WidgetContainerBase, {__index=WidgetBase})
-
- --One of these function should be called on each Widget Instance as part of its creation process
-
- --- Register a widget-class as a container for newly created widgets.
- -- @param widget The widget class
- function AceGUI:RegisterAsContainer(widget)
- widget.children = {}
- widget.userdata = {}
- widget.events = {}
- widget.base = WidgetContainerBase
- widget.content.obj = widget
- widget.frame.obj = widget
- widget.content:SetScript("OnSizeChanged", ContentResize)
- widget.frame:SetScript("OnSizeChanged", FrameResize)
- setmetatable(widget, {__index = WidgetContainerBase})
- widget:SetLayout("List")
- return widget
- end
-
- --- Register a widget-class as a widget.
- -- @param widget The widget class
- function AceGUI:RegisterAsWidget(widget)
- widget.userdata = {}
- widget.events = {}
- widget.base = WidgetBase
- widget.frame.obj = widget
- widget.frame:SetScript("OnSizeChanged", FrameResize)
- setmetatable(widget, {__index = WidgetBase})
- return widget
- end
-end
-
-
-
-
-------------------
--- Widget API --
-------------------
-
---- Registers a widget Constructor, this function returns a new instance of the Widget
--- @param Name The name of the widget
--- @param Constructor The widget constructor function
--- @param Version The version of the widget
-function AceGUI:RegisterWidgetType(Name, Constructor, Version)
- assert(type(Constructor) == "function")
- assert(type(Version) == "number")
-
- local oldVersion = WidgetVersions[Name]
- if oldVersion and oldVersion >= Version then return end
-
- WidgetVersions[Name] = Version
- WidgetRegistry[Name] = Constructor
-end
-
---- Registers a Layout Function
--- @param Name The name of the layout
--- @param LayoutFunc Reference to the layout function
-function AceGUI:RegisterLayout(Name, LayoutFunc)
- assert(type(LayoutFunc) == "function")
- if type(Name) == "string" then
- Name = Name:upper()
- end
- LayoutRegistry[Name] = LayoutFunc
-end
-
---- Get a Layout Function from the registry
--- @param Name The name of the layout
-function AceGUI:GetLayout(Name)
- if type(Name) == "string" then
- Name = Name:upper()
- end
- return LayoutRegistry[Name]
-end
-
-AceGUI.counts = AceGUI.counts or {}
-
---- A type-based counter to count the number of widgets created.
--- This is used by widgets that require a named frame, e.g. when a Blizzard
--- Template requires it.
--- @param type The widget type
-function AceGUI:GetNextWidgetNum(widgetType)
- if not self.counts[widgetType] then
- self.counts[widgetType] = 0
- end
- self.counts[widgetType] = self.counts[widgetType] + 1
- return self.counts[widgetType]
-end
-
---- Return the number of created widgets for this type.
--- In contrast to GetNextWidgetNum, the number is not incremented.
--- @param widgetType The widget type
-function AceGUI:GetWidgetCount(widgetType)
- return self.counts[widgetType] or 0
-end
-
---- Return the version of the currently registered widget type.
--- @param widgetType The widget type
-function AceGUI:GetWidgetVersion(widgetType)
- return WidgetVersions[widgetType]
-end
-
--------------
--- Layouts --
--------------
-
---[[
- A Layout is a func that takes 2 parameters
- content - the frame that widgets will be placed inside
- children - a table containing the widgets to layout
-]]
-
--- Very simple Layout, Children are stacked on top of each other down the left side
-AceGUI:RegisterLayout("List",
- function(content, children)
- local height = 0
- local width = content.width or content:GetWidth() or 0
- for i = 1, #children do
- local child = children[i]
-
- local frame = child.frame
- frame:ClearAllPoints()
- frame:Show()
- if i == 1 then
- frame:SetPoint("TOPLEFT", content)
- else
- frame:SetPoint("TOPLEFT", children[i-1].frame, "BOTTOMLEFT")
- end
-
- if child.width == "fill" then
- child:SetWidth(width)
- frame:SetPoint("RIGHT", content)
-
- if child.DoLayout then
- child:DoLayout()
- end
- elseif child.width == "relative" then
- child:SetWidth(width * child.relWidth)
-
- if child.DoLayout then
- child:DoLayout()
- end
- end
-
- height = height + (frame.height or frame:GetHeight() or 0)
- end
- safecall(content.obj.LayoutFinished, content.obj, nil, height)
- end)
-
--- A single control fills the whole content area
-AceGUI:RegisterLayout("Fill",
- function(content, children)
- if children[1] then
- children[1]:SetWidth(content:GetWidth() or 0)
- children[1]:SetHeight(content:GetHeight() or 0)
- children[1].frame:ClearAllPoints()
- children[1].frame:SetAllPoints(content)
- children[1].frame:Show()
- safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight())
- end
- end)
-
-local layoutrecursionblock = nil
-local function safelayoutcall(object, func, ...)
- layoutrecursionblock = true
- object[func](object, ...)
- layoutrecursionblock = nil
-end
-
-AceGUI:RegisterLayout("Flow",
- function(content, children)
- if layoutrecursionblock then return end
- --used height so far
- local height = 0
- --width used in the current row
- local usedwidth = 0
- --height of the current row
- local rowheight = 0
- local rowoffset = 0
-
- local width = content.width or content:GetWidth() or 0
-
- --control at the start of the row
- local rowstart
- local rowstartoffset
- local isfullheight
-
- local frameoffset
- local lastframeoffset
- local oversize
- for i = 1, #children do
- local child = children[i]
- oversize = nil
- local frame = child.frame
- local frameheight = frame.height or frame:GetHeight() or 0
- local framewidth = frame.width or frame:GetWidth() or 0
- lastframeoffset = frameoffset
- -- HACK: Why did we set a frameoffset of (frameheight / 2) ?
- -- That was moving all widgets half the widgets size down, is that intended?
- -- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
- -- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
- -- TODO: Investigate moar!
- frameoffset = child.alignoffset or (frameheight / 2)
-
- if child.width == "relative" then
- framewidth = width * child.relWidth
- end
-
- frame:Show()
- frame:ClearAllPoints()
- if i == 1 then
- -- anchor the first control to the top left
- frame:SetPoint("TOPLEFT", content)
- rowheight = frameheight
- rowoffset = frameoffset
- rowstart = frame
- rowstartoffset = frameoffset
- usedwidth = framewidth
- if usedwidth > width then
- oversize = true
- end
- else
- -- if there isn't available width for the control start a new row
- -- if a control is "fill" it will be on a row of its own full width
- if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
- if isfullheight then
- -- a previous row has already filled the entire height, there's nothing we can usefully do anymore
- -- (maybe error/warn about this?)
- break
- end
- --anchor the previous row, we will now know its height and offset
- rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
- height = height + rowheight + 3
- --save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
- rowstart = frame
- rowstartoffset = frameoffset
- rowheight = frameheight
- rowoffset = frameoffset
- usedwidth = framewidth
- if usedwidth > width then
- oversize = true
- end
- -- put the control on the current row, adding it to the width and checking if the height needs to be increased
- else
- --handles cases where the new height is higher than either control because of the offsets
- --math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
-
- --offset is always the larger of the two offsets
- rowoffset = math_max(rowoffset, frameoffset)
- rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
-
- frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", 0, frameoffset - lastframeoffset)
- usedwidth = framewidth + usedwidth
- end
- end
-
- if child.width == "fill" then
- safelayoutcall(child, "SetWidth", width)
- frame:SetPoint("RIGHT", content)
-
- usedwidth = 0
- rowstart = frame
-
- if child.DoLayout then
- child:DoLayout()
- end
- rowheight = frame.height or frame:GetHeight() or 0
- rowoffset = child.alignoffset or (rowheight / 2)
- rowstartoffset = rowoffset
- elseif child.width == "relative" then
- safelayoutcall(child, "SetWidth", width * child.relWidth)
-
- if child.DoLayout then
- child:DoLayout()
- end
- elseif oversize then
- if width > 1 then
- frame:SetPoint("RIGHT", content)
- end
- end
-
- if child.height == "fill" then
- frame:SetPoint("BOTTOM", content)
- isfullheight = true
- end
- end
-
- --anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
- if isfullheight then
- rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
- elseif rowstart then
- rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
- end
-
- height = height + rowheight + 3
- safecall(content.obj.LayoutFinished, content.obj, nil, height)
- end)
-
--- Get alignment method and value. Possible alignment methods are a callback, a number, "start", "middle", "end", "fill" or "TOPLEFT", "BOTTOMRIGHT" etc.
-local GetCellAlign = function (dir, tableObj, colObj, cellObj, cell, child)
- local fn = cellObj and (cellObj["align" .. dir] or cellObj.align)
- or colObj and (colObj["align" .. dir] or colObj.align)
- or tableObj["align" .. dir] or tableObj.align
- or "CENTERLEFT"
- local val
- child, cell = child or 0, cell or 0
-
- if type(fn) == "string" then
- fn = fn:lower()
- fn = dir == "V" and (fn:sub(1, 3) == "top" and "start" or fn:sub(1, 6) == "bottom" and "end" or fn:sub(1, 6) == "center" and "middle")
- or dir == "H" and (fn:sub(-4) == "left" and "start" or fn:sub(-5) == "right" and "end" or fn:sub(-6) == "center" and "middle")
- or fn
- val = (fn == "start" or fn == "fill") and 0 or fn == "end" and cell - child or (cell - child) / 2
- elseif type(fn) == "function" then
- val = fn(child or 0, cell, dir)
- else
- val = fn
- end
-
- return fn, math_max(0, math_min(val, cell))
-end
-
--- Get width or height for multiple cells combined
-local GetCellDimension = function (dir, laneDim, from, to, space)
- local dim = 0
- for cell=from,to do
- dim = dim + (laneDim[cell] or 0)
- end
- return dim + math_max(0, to - from) * (space or 0)
-end
-
---[[ Options
-============
-Container:
- - columns ({col, col, ...}): Column settings. "col" can be a number (<= 0: content width, <1: rel. width, <10: weight, >=10: abs. width) or a table with column setting.
- - space, spaceH, spaceV: Overall, horizontal and vertical spacing between cells.
- - align, alignH, alignV: Overall, horizontal and vertical cell alignment. See GetCellAlign() for possible values.
-Columns:
- - width: Fixed column width (nil or <=0: content width, <1: rel. width, >=1: abs. width).
- - min or 1: Min width for content based width
- - max or 2: Max width for content based width
- - weight: Flexible column width. The leftover width after accounting for fixed-width columns is distributed to weighted columns according to their weights.
- - align, alignH, alignV: Overwrites the container setting for alignment.
-Cell:
- - colspan: Makes a cell span multiple columns.
- - rowspan: Makes a cell span multiple rows.
- - align, alignH, alignV: Overwrites the container and column setting for alignment.
-]]
-AceGUI:RegisterLayout("Table",
- function (content, children)
- local obj = content.obj
- obj:PauseLayout()
-
- local tableObj = obj:GetUserData("table")
- local cols = tableObj.columns
- local spaceH = tableObj.spaceH or tableObj.space or 0
- local spaceV = tableObj.spaceV or tableObj.space or 0
- local totalH = (content:GetWidth() or content.width or 0) - spaceH * (#cols - 1)
-
- -- We need to reuse these because layout events can come in very frequently
- local layoutCache = obj:GetUserData("layoutCache")
- if not layoutCache then
- layoutCache = {{}, {}, {}, {}, {}, {}}
- obj:SetUserData("layoutCache", layoutCache)
- end
- local t, laneH, laneV, rowspans, rowStart, colStart = unpack(layoutCache)
-
- -- Create the grid
- local n, slotFound = 0
- for i,child in ipairs(children) do
- if child:IsShown() then
- repeat
- n = n + 1
- local col = (n - 1) % #cols + 1
- local row = math_ceil(n / #cols)
- local rowspan = rowspans[col]
- local cell = rowspan and rowspan.child or child
- local cellObj = cell:GetUserData("cell")
- slotFound = not rowspan
-
- -- Rowspan
- if not rowspan and cellObj and cellObj.rowspan then
- rowspan = {child = child, from = row, to = row + cellObj.rowspan - 1}
- rowspans[col] = rowspan
- end
- if rowspan and i == #children then
- rowspan.to = row
- end
-
- -- Colspan
- local colspan = math_max(0, math_min((cellObj and cellObj.colspan or 1) - 1, #cols - col))
- n = n + colspan
-
- -- Place the cell
- if not rowspan or rowspan.to == row then
- t[n] = cell
- rowStart[cell] = rowspan and rowspan.from or row
- colStart[cell] = col
-
- if rowspan then
- rowspans[col] = nil
- end
- end
- until slotFound
- end
- end
-
- local rows = math_ceil(n / #cols)
-
- -- Determine fixed size cols and collect weights
- local extantH, totalWeight = totalH, 0
- for col,colObj in ipairs(cols) do
- laneH[col] = 0
-
- if type(colObj) == "number" then
- colObj = {[colObj >= 1 and colObj < 10 and "weight" or "width"] = colObj}
- cols[col] = colObj
- end
-
- if colObj.weight then
- -- Weight
- totalWeight = totalWeight + (colObj.weight or 1)
- else
- if not colObj.width or colObj.width <= 0 then
- -- Content width
- for row=1,rows do
- local child = t[(row - 1) * #cols + col]
- if child then
- local f = child.frame
- f:ClearAllPoints()
- local childH = f:GetWidth() or 0
-
- laneH[col] = math_max(laneH[col], childH - GetCellDimension("H", laneH, colStart[child], col - 1, spaceH))
- end
- end
-
- laneH[col] = math_max(colObj.min or colObj[1] or 0, math_min(laneH[col], colObj.max or colObj[2] or laneH[col]))
- else
- -- Rel./Abs. width
- laneH[col] = colObj.width < 1 and colObj.width * totalH or colObj.width
- end
- extantH = math_max(0, extantH - laneH[col])
- end
- end
-
- -- Determine sizes based on weight
- local scale = totalWeight > 0 and extantH / totalWeight or 0
- for col,colObj in pairs(cols) do
- if colObj.weight then
- laneH[col] = scale * colObj.weight
- end
- end
-
- -- Arrange children
- for row=1,rows do
- local rowV = 0
-
- -- Horizontal placement and sizing
- for col=1,#cols do
- local child = t[(row - 1) * #cols + col]
- if child then
- local colObj = cols[colStart[child]]
- local cellObj = child:GetUserData("cell")
- local offsetH = GetCellDimension("H", laneH, 1, colStart[child] - 1, spaceH) + (colStart[child] == 1 and 0 or spaceH)
- local cellH = GetCellDimension("H", laneH, colStart[child], col, spaceH)
-
- local f = child.frame
- f:ClearAllPoints()
- local childH = f:GetWidth() or 0
-
- local alignFn, align = GetCellAlign("H", tableObj, colObj, cellObj, cellH, childH)
- f:SetPoint("LEFT", content, offsetH + align, 0)
- if child:IsFullWidth() or alignFn == "fill" or childH > cellH then
- f:SetPoint("RIGHT", content, "LEFT", offsetH + align + cellH, 0)
- end
-
- if child.DoLayout then
- child:DoLayout()
- end
-
- rowV = math_max(rowV, (f:GetHeight() or 0) - GetCellDimension("V", laneV, rowStart[child], row - 1, spaceV))
- end
- end
-
- laneV[row] = rowV
-
- -- Vertical placement and sizing
- for col=1,#cols do
- local child = t[(row - 1) * #cols + col]
- if child then
- local colObj = cols[colStart[child]]
- local cellObj = child:GetUserData("cell")
- local offsetV = GetCellDimension("V", laneV, 1, rowStart[child] - 1, spaceV) + (rowStart[child] == 1 and 0 or spaceV)
- local cellV = GetCellDimension("V", laneV, rowStart[child], row, spaceV)
-
- local f = child.frame
- local childV = f:GetHeight() or 0
-
- local alignFn, align = GetCellAlign("V", tableObj, colObj, cellObj, cellV, childV)
- if child:IsFullHeight() or alignFn == "fill" then
- f:SetHeight(cellV)
- end
- f:SetPoint("TOP", content, 0, -(offsetV + align))
- end
- end
- end
-
- -- Calculate total height
- local totalV = GetCellDimension("V", laneV, 1, #laneV, spaceV)
-
- -- Cleanup
- for _,v in pairs(layoutCache) do wipe(v) end
-
- safecall(obj.LayoutFinished, obj, nil, totalV)
- obj:ResumeLayout()
- end)
+--- **AceGUI-3.0** provides access to numerous widgets which can be used to create GUIs.
+-- AceGUI is used by AceConfigDialog to create the option GUIs, but you can use it by itself
+-- to create any custom GUI. There are more extensive examples in the test suite in the Ace3
+-- stand-alone distribution.
+--
+-- **Note**: When using AceGUI-3.0 directly, please do not modify the frames of the widgets directly,
+-- as any "unknown" change to the widgets will cause addons that get your widget out of the widget pool
+-- to misbehave. If you think some part of a widget should be modifiable, please open a ticket, and we"ll
+-- implement a proper API to modify it.
+-- @usage
+-- local AceGUI = LibStub("AceGUI-3.0")
+-- -- Create a container frame
+-- local f = AceGUI:Create("Frame")
+-- f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
+-- f:SetTitle("AceGUI-3.0 Example")
+-- f:SetStatusText("Status Bar")
+-- f:SetLayout("Flow")
+-- -- Create a button
+-- local btn = AceGUI:Create("Button")
+-- btn:SetWidth(170)
+-- btn:SetText("Button !")
+-- btn:SetCallback("OnClick", function() print("Click!") end)
+-- -- Add the button to the container
+-- f:AddChild(btn)
+-- @class file
+-- @name AceGUI-3.0
+-- @release $Id: AceGUI-3.0.lua 1288 2022-09-25 14:19:00Z funkehdude $
+local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 41
+local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
+
+if not AceGUI then return end -- No upgrade needed
+
+-- Lua APIs
+local tinsert, wipe = table.insert, table.wipe
+local select, pairs, next, type = select, pairs, next, type
+local error, assert = error, assert
+local setmetatable, rawget = setmetatable, rawget
+local math_max, math_min, math_ceil = math.max, math.min, math.ceil
+
+-- WoW APIs
+local UIParent = UIParent
+
+AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
+AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
+AceGUI.WidgetBase = AceGUI.WidgetBase or {}
+AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
+AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
+AceGUI.tooltip = AceGUI.tooltip or CreateFrame("GameTooltip", "AceGUITooltip", UIParent, "GameTooltipTemplate")
+
+-- local upvalues
+local WidgetRegistry = AceGUI.WidgetRegistry
+local LayoutRegistry = AceGUI.LayoutRegistry
+local WidgetVersions = AceGUI.WidgetVersions
+
+--[[
+ xpcall safecall implementation
+]]
+local xpcall = xpcall
+
+local function errorhandler(err)
+ return geterrorhandler()(err)
+end
+
+local function safecall(func, ...)
+ if func then
+ return xpcall(func, errorhandler, ...)
+ end
+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
+ function newWidget(widgetType)
+ if not WidgetRegistry[widgetType] then
+ error("Attempt to instantiate unknown widget type", 2)
+ end
+
+ if not objPools[widgetType] then
+ objPools[widgetType] = {}
+ end
+
+ local newObj = next(objPools[widgetType])
+ if not newObj then
+ newObj = WidgetRegistry[widgetType]()
+ newObj.AceGUIWidgetVersion = WidgetVersions[widgetType]
+ else
+ objPools[widgetType][newObj] = nil
+ -- if the widget is older then the latest, don't even try to reuse it
+ -- just forget about it, and grab a new one.
+ if not newObj.AceGUIWidgetVersion or newObj.AceGUIWidgetVersion < WidgetVersions[widgetType] then
+ return newWidget(widgetType)
+ end
+ end
+ return newObj
+ end
+ -- Releases an instance to the Pool
+ function delWidget(obj,widgetType)
+ if not objPools[widgetType] then
+ objPools[widgetType] = {}
+ end
+ if objPools[widgetType][obj] then
+ error("Attempt to Release Widget that is already released", 2)
+ end
+ objPools[widgetType][obj] = true
+ end
+end
+
+
+-------------------
+-- API Functions --
+-------------------
+
+-- Gets a widget Object
+
+--- Create a new Widget of the given type.
+-- This function will instantiate a new widget (or use one from the widget pool), and call the
+-- OnAcquire function on it, before returning.
+-- @param type The type of the widget.
+-- @return The newly created widget.
+function AceGUI:Create(widgetType)
+ if WidgetRegistry[widgetType] then
+ local widget = newWidget(widgetType)
+
+ 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(("Widget type %s doesn't supply an OnAcquire Function"):format(widgetType))
+ end
+ -- Set the default Layout ("List")
+ safecall(widget.SetLayout, widget, "List")
+ safecall(widget.ResumeLayout, widget)
+ return widget
+ end
+end
+
+--- Releases a widget Object.
+-- This function calls OnRelease on the widget and places it back in the widget pool.
+-- Any data on the widget is being erased, and the widget will be hidden.\\
+-- 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)
+ if widget.isQueuedForRelease then return end
+ widget.isQueuedForRelease = true
+ safecall(widget.PauseLayout, widget)
+ widget.frame:Hide()
+ widget:Fire("OnRelease")
+ safecall(widget.ReleaseChildren, widget)
+
+ if widget.OnRelease then
+ widget:OnRelease()
+-- else
+-- error(("Widget type %s doesn't supply an OnRelease Function"):format(widget.type))
+ end
+ for k in pairs(widget.userdata) do
+ widget.userdata[k] = nil
+ end
+ for k in pairs(widget.events) do
+ widget.events[k] = nil
+ end
+ widget.width = nil
+ widget.relWidth = nil
+ widget.height = nil
+ widget.relHeight = nil
+ widget.noAutoHeight = nil
+ widget.frame:ClearAllPoints()
+ widget.frame:Hide()
+ widget.frame:SetParent(UIParent)
+ widget.frame.width = nil
+ widget.frame.height = nil
+ if widget.content then
+ widget.content.width = nil
+ widget.content.height = nil
+ end
+ widget.isQueuedForRelease = nil
+ delWidget(widget, widget.type)
+end
+
+--- Check if a widget is currently in the process of being released
+-- This function check if this widget, or any of its parents (in which case it'll be released shortly as well)
+-- are currently being released. This allows addon to handle any callbacks accordingly.
+-- @param widget The widget to check
+function AceGUI:IsReleasing(widget)
+ if widget.isQueuedForRelease then
+ return true
+ end
+
+ if widget.parent and widget.parent.AceGUIWidgetVersion then
+ return AceGUI:IsReleasing(widget.parent)
+ end
+
+ return false
+end
+
+-----------
+-- Focus --
+-----------
+
+
+--- Called when a widget has taken focus.
+-- e.g. Dropdowns opening, Editboxes gaining kb focus
+-- @param widget The widget that should be focused
+function AceGUI:SetFocus(widget)
+ if self.FocusedWidget and self.FocusedWidget ~= widget then
+ safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
+ end
+ self.FocusedWidget = widget
+end
+
+
+--- Called when something has happened that could cause widgets with focus to drop it
+-- e.g. titlebar of a frame being clicked
+function AceGUI:ClearFocus()
+ if self.FocusedWidget then
+ safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
+ self.FocusedWidget = nil
+ end
+end
+
+-------------
+-- Widgets --
+-------------
+--[[
+ Widgets must provide the following functions
+ OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
+
+ And the following members
+ frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
+ type - the type of the object, same as the name given to :RegisterWidget()
+
+ Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
+ It will be cleared automatically when a widget is released
+ Placing values directly into a widget object should be avoided
+
+ If the Widget can act as a container for other Widgets the following
+ content - frame or derivitive that children will be anchored to
+
+ The Widget can supply the following Optional Members
+ :OnRelease() - Called when the object is Released, should remove any additional anchors and clear any data
+ :OnWidthSet(width) - Called when the width of the widget is changed
+ :OnHeightSet(height) - Called when the height of the widget is changed
+ Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
+ AceGUI already sets a handler to the event
+ :LayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
+ area used for controls. These can be nil if the layout used the existing size to layout the controls.
+
+]]
+
+--------------------------
+-- Widget Base Template --
+--------------------------
+do
+ local WidgetBase = AceGUI.WidgetBase
+
+ WidgetBase.SetParent = function(self, parent)
+ local frame = self.frame
+ frame:SetParent(nil)
+ frame:SetParent(parent.content)
+ self.parent = parent
+ end
+
+ WidgetBase.SetCallback = function(self, name, func)
+ if type(func) == "function" then
+ self.events[name] = func
+ end
+ end
+
+ WidgetBase.Fire = function(self, name, ...)
+ if self.events[name] then
+ local success, ret = safecall(self.events[name], self, name, ...)
+ if success then
+ return ret
+ end
+ end
+ end
+
+ WidgetBase.SetWidth = function(self, width)
+ self.frame:SetWidth(width)
+ self.frame.width = width
+ if self.OnWidthSet then
+ self:OnWidthSet(width)
+ end
+ end
+
+ WidgetBase.SetRelativeWidth = function(self, width)
+ if width <= 0 or width > 1 then
+ error(":SetRelativeWidth(width): Invalid relative width.", 2)
+ end
+ self.relWidth = width
+ self.width = "relative"
+ end
+
+ WidgetBase.SetHeight = function(self, height)
+ self.frame:SetHeight(height)
+ self.frame.height = height
+ if self.OnHeightSet then
+ self:OnHeightSet(height)
+ end
+ end
+
+ --[[ WidgetBase.SetRelativeHeight = function(self, height)
+ if height <= 0 or height > 1 then
+ error(":SetRelativeHeight(height): Invalid relative height.", 2)
+ end
+ self.relHeight = height
+ self.height = "relative"
+ end ]]
+
+ WidgetBase.IsVisible = function(self)
+ return self.frame:IsVisible()
+ end
+
+ WidgetBase.IsShown= function(self)
+ return self.frame:IsShown()
+ end
+
+ WidgetBase.Release = function(self)
+ AceGUI:Release(self)
+ end
+
+ WidgetBase.IsReleasing = function(self)
+ return AceGUI:IsReleasing(self)
+ end
+
+ WidgetBase.SetPoint = function(self, ...)
+ return self.frame:SetPoint(...)
+ end
+
+ WidgetBase.ClearAllPoints = function(self)
+ return self.frame:ClearAllPoints()
+ end
+
+ WidgetBase.GetNumPoints = function(self)
+ return self.frame:GetNumPoints()
+ end
+
+ WidgetBase.GetPoint = function(self, ...)
+ return self.frame:GetPoint(...)
+ end
+
+ WidgetBase.GetUserDataTable = function(self)
+ return self.userdata
+ end
+
+ WidgetBase.SetUserData = function(self, key, value)
+ self.userdata[key] = value
+ end
+
+ WidgetBase.GetUserData = function(self, key)
+ return self.userdata[key]
+ end
+
+ WidgetBase.IsFullHeight = function(self)
+ return self.height == "fill"
+ end
+
+ WidgetBase.SetFullHeight = function(self, isFull)
+ if isFull then
+ self.height = "fill"
+ else
+ self.height = nil
+ end
+ end
+
+ WidgetBase.IsFullWidth = function(self)
+ return self.width == "fill"
+ end
+
+ WidgetBase.SetFullWidth = function(self, isFull)
+ if isFull then
+ self.width = "fill"
+ else
+ self.width = nil
+ end
+ end
+
+-- local function LayoutOnUpdate(this)
+-- this:SetScript("OnUpdate",nil)
+-- this.obj:PerformLayout()
+-- end
+
+ local WidgetContainerBase = AceGUI.WidgetContainerBase
+
+ WidgetContainerBase.PauseLayout = function(self)
+ self.LayoutPaused = true
+ end
+
+ WidgetContainerBase.ResumeLayout = function(self)
+ self.LayoutPaused = nil
+ end
+
+ WidgetContainerBase.PerformLayout = function(self)
+ if self.LayoutPaused then
+ return
+ end
+ 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
+ WidgetContainerBase.DoLayout = function(self)
+ self:PerformLayout()
+-- if not self.parent then
+-- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
+-- end
+ end
+
+ WidgetContainerBase.AddChild = function(self, child, beforeWidget)
+ if beforeWidget then
+ local siblingIndex = 1
+ for _, widget in pairs(self.children) do
+ if widget == beforeWidget then
+ break
+ end
+ siblingIndex = siblingIndex + 1
+ end
+ tinsert(self.children, siblingIndex, child)
+ else
+ tinsert(self.children, child)
+ end
+ child:SetParent(self)
+ child.frame:Show()
+ self:DoLayout()
+ end
+
+ WidgetContainerBase.AddChildren = function(self, ...)
+ for i = 1, select("#", ...) do
+ local child = select(i, ...)
+ tinsert(self.children, child)
+ child:SetParent(self)
+ child.frame:Show()
+ end
+ self:DoLayout()
+ end
+
+ WidgetContainerBase.ReleaseChildren = function(self)
+ local children = self.children
+ for i = 1,#children do
+ AceGUI:Release(children[i])
+ children[i] = nil
+ end
+ end
+
+ WidgetContainerBase.SetLayout = function(self, Layout)
+ self.LayoutFunc = AceGUI:GetLayout(Layout)
+ end
+
+ WidgetContainerBase.SetAutoAdjustHeight = function(self, adjust)
+ if adjust then
+ self.noAutoHeight = nil
+ else
+ self.noAutoHeight = true
+ end
+ end
+
+ local function FrameResize(this)
+ local self = this.obj
+ if this:GetWidth() and this:GetHeight() then
+ if self.OnWidthSet then
+ self:OnWidthSet(this:GetWidth())
+ end
+ if self.OnHeightSet then
+ self:OnHeightSet(this:GetHeight())
+ end
+ end
+ end
+
+ local function ContentResize(this)
+ if this:GetWidth() and this:GetHeight() then
+ this.width = this:GetWidth()
+ this.height = this:GetHeight()
+ this.obj:DoLayout()
+ end
+ end
+
+ setmetatable(WidgetContainerBase, {__index=WidgetBase})
+
+ --One of these function should be called on each Widget Instance as part of its creation process
+
+ --- Register a widget-class as a container for newly created widgets.
+ -- @param widget The widget class
+ function AceGUI:RegisterAsContainer(widget)
+ widget.children = {}
+ widget.userdata = {}
+ widget.events = {}
+ widget.base = WidgetContainerBase
+ widget.content.obj = widget
+ widget.frame.obj = widget
+ widget.content:SetScript("OnSizeChanged", ContentResize)
+ widget.frame:SetScript("OnSizeChanged", FrameResize)
+ setmetatable(widget, {__index = WidgetContainerBase})
+ widget:SetLayout("List")
+ return widget
+ end
+
+ --- Register a widget-class as a widget.
+ -- @param widget The widget class
+ function AceGUI:RegisterAsWidget(widget)
+ widget.userdata = {}
+ widget.events = {}
+ widget.base = WidgetBase
+ widget.frame.obj = widget
+ widget.frame:SetScript("OnSizeChanged", FrameResize)
+ setmetatable(widget, {__index = WidgetBase})
+ return widget
+ end
+end
+
+
+
+
+------------------
+-- Widget API --
+------------------
+
+--- Registers a widget Constructor, this function returns a new instance of the Widget
+-- @param Name The name of the widget
+-- @param Constructor The widget constructor function
+-- @param Version The version of the widget
+function AceGUI:RegisterWidgetType(Name, Constructor, Version)
+ assert(type(Constructor) == "function")
+ assert(type(Version) == "number")
+
+ local oldVersion = WidgetVersions[Name]
+ if oldVersion and oldVersion >= Version then return end
+
+ WidgetVersions[Name] = Version
+ WidgetRegistry[Name] = Constructor
+end
+
+--- Registers a Layout Function
+-- @param Name The name of the layout
+-- @param LayoutFunc Reference to the layout function
+function AceGUI:RegisterLayout(Name, LayoutFunc)
+ assert(type(LayoutFunc) == "function")
+ if type(Name) == "string" then
+ Name = Name:upper()
+ end
+ LayoutRegistry[Name] = LayoutFunc
+end
+
+--- Get a Layout Function from the registry
+-- @param Name The name of the layout
+function AceGUI:GetLayout(Name)
+ if type(Name) == "string" then
+ Name = Name:upper()
+ end
+ return LayoutRegistry[Name]
+end
+
+AceGUI.counts = AceGUI.counts or {}
+
+--- A type-based counter to count the number of widgets created.
+-- This is used by widgets that require a named frame, e.g. when a Blizzard
+-- Template requires it.
+-- @param type The widget type
+function AceGUI:GetNextWidgetNum(widgetType)
+ if not self.counts[widgetType] then
+ self.counts[widgetType] = 0
+ end
+ self.counts[widgetType] = self.counts[widgetType] + 1
+ return self.counts[widgetType]
+end
+
+--- Return the number of created widgets for this type.
+-- In contrast to GetNextWidgetNum, the number is not incremented.
+-- @param widgetType The widget type
+function AceGUI:GetWidgetCount(widgetType)
+ return self.counts[widgetType] or 0
+end
+
+--- Return the version of the currently registered widget type.
+-- @param widgetType The widget type
+function AceGUI:GetWidgetVersion(widgetType)
+ return WidgetVersions[widgetType]
+end
+
+-------------
+-- Layouts --
+-------------
+
+--[[
+ A Layout is a func that takes 2 parameters
+ content - the frame that widgets will be placed inside
+ children - a table containing the widgets to layout
+]]
+
+-- Very simple Layout, Children are stacked on top of each other down the left side
+AceGUI:RegisterLayout("List",
+ function(content, children)
+ local height = 0
+ local width = content.width or content:GetWidth() or 0
+ for i = 1, #children do
+ local child = children[i]
+
+ local frame = child.frame
+ frame:ClearAllPoints()
+ frame:Show()
+ if i == 1 then
+ frame:SetPoint("TOPLEFT", content)
+ else
+ frame:SetPoint("TOPLEFT", children[i-1].frame, "BOTTOMLEFT")
+ end
+
+ if child.width == "fill" then
+ child:SetWidth(width)
+ frame:SetPoint("RIGHT", content)
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ elseif child.width == "relative" then
+ child:SetWidth(width * child.relWidth)
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ end
+
+ height = height + (frame.height or frame:GetHeight() or 0)
+ end
+ safecall(content.obj.LayoutFinished, content.obj, nil, height)
+ end)
+
+-- A single control fills the whole content area
+AceGUI:RegisterLayout("Fill",
+ function(content, children)
+ if children[1] then
+ children[1]:SetWidth(content:GetWidth() or 0)
+ children[1]:SetHeight(content:GetHeight() or 0)
+ children[1].frame:ClearAllPoints()
+ children[1].frame:SetAllPoints(content)
+ children[1].frame:Show()
+ safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight())
+ end
+ end)
+
+local layoutrecursionblock = nil
+local function safelayoutcall(object, func, ...)
+ layoutrecursionblock = true
+ object[func](object, ...)
+ layoutrecursionblock = nil
+end
+
+AceGUI:RegisterLayout("Flow",
+ function(content, children)
+ if layoutrecursionblock then return end
+ --used height so far
+ local height = 0
+ --width used in the current row
+ local usedwidth = 0
+ --height of the current row
+ local rowheight = 0
+ local rowoffset = 0
+
+ local width = content.width or content:GetWidth() or 0
+
+ --control at the start of the row
+ local rowstart
+ local rowstartoffset
+ local isfullheight
+
+ local frameoffset
+ local lastframeoffset
+ local oversize
+ for i = 1, #children do
+ local child = children[i]
+ oversize = nil
+ local frame = child.frame
+ local frameheight = frame.height or frame:GetHeight() or 0
+ local framewidth = frame.width or frame:GetWidth() or 0
+ lastframeoffset = frameoffset
+ -- HACK: Why did we set a frameoffset of (frameheight / 2) ?
+ -- That was moving all widgets half the widgets size down, is that intended?
+ -- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
+ -- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
+ -- TODO: Investigate moar!
+ frameoffset = child.alignoffset or (frameheight / 2)
+
+ if child.width == "relative" then
+ framewidth = width * child.relWidth
+ end
+
+ frame:Show()
+ frame:ClearAllPoints()
+ if i == 1 then
+ -- anchor the first control to the top left
+ frame:SetPoint("TOPLEFT", content)
+ rowheight = frameheight
+ rowoffset = frameoffset
+ rowstart = frame
+ rowstartoffset = frameoffset
+ usedwidth = framewidth
+ if usedwidth > width then
+ oversize = true
+ end
+ else
+ -- if there isn't available width for the control start a new row
+ -- if a control is "fill" it will be on a row of its own full width
+ if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
+ if isfullheight then
+ -- a previous row has already filled the entire height, there's nothing we can usefully do anymore
+ -- (maybe error/warn about this?)
+ break
+ end
+ --anchor the previous row, we will now know its height and offset
+ rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
+ height = height + rowheight + 3
+ --save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
+ rowstart = frame
+ rowstartoffset = frameoffset
+ rowheight = frameheight
+ rowoffset = frameoffset
+ usedwidth = framewidth
+ if usedwidth > width then
+ oversize = true
+ end
+ -- put the control on the current row, adding it to the width and checking if the height needs to be increased
+ else
+ --handles cases where the new height is higher than either control because of the offsets
+ --math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
+
+ --offset is always the larger of the two offsets
+ rowoffset = math_max(rowoffset, frameoffset)
+ rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
+
+ frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", 0, frameoffset - lastframeoffset)
+ usedwidth = framewidth + usedwidth
+ end
+ end
+
+ if child.width == "fill" then
+ safelayoutcall(child, "SetWidth", width)
+ frame:SetPoint("RIGHT", content)
+
+ usedwidth = 0
+ rowstart = frame
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ rowheight = frame.height or frame:GetHeight() or 0
+ rowoffset = child.alignoffset or (rowheight / 2)
+ rowstartoffset = rowoffset
+ elseif child.width == "relative" then
+ safelayoutcall(child, "SetWidth", width * child.relWidth)
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+ elseif oversize then
+ if width > 1 then
+ frame:SetPoint("RIGHT", content)
+ end
+ end
+
+ if child.height == "fill" then
+ frame:SetPoint("BOTTOM", content)
+ isfullheight = true
+ end
+ end
+
+ --anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
+ if isfullheight then
+ rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
+ elseif rowstart then
+ rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
+ end
+
+ height = height + rowheight + 3
+ safecall(content.obj.LayoutFinished, content.obj, nil, height)
+ end)
+
+-- Get alignment method and value. Possible alignment methods are a callback, a number, "start", "middle", "end", "fill" or "TOPLEFT", "BOTTOMRIGHT" etc.
+local GetCellAlign = function (dir, tableObj, colObj, cellObj, cell, child)
+ local fn = cellObj and (cellObj["align" .. dir] or cellObj.align)
+ or colObj and (colObj["align" .. dir] or colObj.align)
+ or tableObj["align" .. dir] or tableObj.align
+ or "CENTERLEFT"
+ local val
+ child, cell = child or 0, cell or 0
+
+ if type(fn) == "string" then
+ fn = fn:lower()
+ fn = dir == "V" and (fn:sub(1, 3) == "top" and "start" or fn:sub(1, 6) == "bottom" and "end" or fn:sub(1, 6) == "center" and "middle")
+ or dir == "H" and (fn:sub(-4) == "left" and "start" or fn:sub(-5) == "right" and "end" or fn:sub(-6) == "center" and "middle")
+ or fn
+ val = (fn == "start" or fn == "fill") and 0 or fn == "end" and cell - child or (cell - child) / 2
+ elseif type(fn) == "function" then
+ val = fn(child or 0, cell, dir)
+ else
+ val = fn
+ end
+
+ return fn, math_max(0, math_min(val, cell))
+end
+
+-- Get width or height for multiple cells combined
+local GetCellDimension = function (dir, laneDim, from, to, space)
+ local dim = 0
+ for cell=from,to do
+ dim = dim + (laneDim[cell] or 0)
+ end
+ return dim + math_max(0, to - from) * (space or 0)
+end
+
+--[[ Options
+============
+Container:
+ - columns ({col, col, ...}): Column settings. "col" can be a number (<= 0: content width, <1: rel. width, <10: weight, >=10: abs. width) or a table with column setting.
+ - space, spaceH, spaceV: Overall, horizontal and vertical spacing between cells.
+ - align, alignH, alignV: Overall, horizontal and vertical cell alignment. See GetCellAlign() for possible values.
+Columns:
+ - width: Fixed column width (nil or <=0: content width, <1: rel. width, >=1: abs. width).
+ - min or 1: Min width for content based width
+ - max or 2: Max width for content based width
+ - weight: Flexible column width. The leftover width after accounting for fixed-width columns is distributed to weighted columns according to their weights.
+ - align, alignH, alignV: Overwrites the container setting for alignment.
+Cell:
+ - colspan: Makes a cell span multiple columns.
+ - rowspan: Makes a cell span multiple rows.
+ - align, alignH, alignV: Overwrites the container and column setting for alignment.
+]]
+AceGUI:RegisterLayout("Table",
+ function (content, children)
+ local obj = content.obj
+ obj:PauseLayout()
+
+ local tableObj = obj:GetUserData("table")
+ local cols = tableObj.columns
+ local spaceH = tableObj.spaceH or tableObj.space or 0
+ local spaceV = tableObj.spaceV or tableObj.space or 0
+ local totalH = (content:GetWidth() or content.width or 0) - spaceH * (#cols - 1)
+
+ -- We need to reuse these because layout events can come in very frequently
+ local layoutCache = obj:GetUserData("layoutCache")
+ if not layoutCache then
+ layoutCache = {{}, {}, {}, {}, {}, {}}
+ obj:SetUserData("layoutCache", layoutCache)
+ end
+ local t, laneH, laneV, rowspans, rowStart, colStart = unpack(layoutCache)
+
+ -- Create the grid
+ local n, slotFound = 0
+ for i,child in ipairs(children) do
+ if child:IsShown() then
+ repeat
+ n = n + 1
+ local col = (n - 1) % #cols + 1
+ local row = math_ceil(n / #cols)
+ local rowspan = rowspans[col]
+ local cell = rowspan and rowspan.child or child
+ local cellObj = cell:GetUserData("cell")
+ slotFound = not rowspan
+
+ -- Rowspan
+ if not rowspan and cellObj and cellObj.rowspan then
+ rowspan = {child = child, from = row, to = row + cellObj.rowspan - 1}
+ rowspans[col] = rowspan
+ end
+ if rowspan and i == #children then
+ rowspan.to = row
+ end
+
+ -- Colspan
+ local colspan = math_max(0, math_min((cellObj and cellObj.colspan or 1) - 1, #cols - col))
+ n = n + colspan
+
+ -- Place the cell
+ if not rowspan or rowspan.to == row then
+ t[n] = cell
+ rowStart[cell] = rowspan and rowspan.from or row
+ colStart[cell] = col
+
+ if rowspan then
+ rowspans[col] = nil
+ end
+ end
+ until slotFound
+ end
+ end
+
+ local rows = math_ceil(n / #cols)
+
+ -- Determine fixed size cols and collect weights
+ local extantH, totalWeight = totalH, 0
+ for col,colObj in ipairs(cols) do
+ laneH[col] = 0
+
+ if type(colObj) == "number" then
+ colObj = {[colObj >= 1 and colObj < 10 and "weight" or "width"] = colObj}
+ cols[col] = colObj
+ end
+
+ if colObj.weight then
+ -- Weight
+ totalWeight = totalWeight + (colObj.weight or 1)
+ else
+ if not colObj.width or colObj.width <= 0 then
+ -- Content width
+ for row=1,rows do
+ local child = t[(row - 1) * #cols + col]
+ if child then
+ local f = child.frame
+ f:ClearAllPoints()
+ local childH = f:GetWidth() or 0
+
+ laneH[col] = math_max(laneH[col], childH - GetCellDimension("H", laneH, colStart[child], col - 1, spaceH))
+ end
+ end
+
+ laneH[col] = math_max(colObj.min or colObj[1] or 0, math_min(laneH[col], colObj.max or colObj[2] or laneH[col]))
+ else
+ -- Rel./Abs. width
+ laneH[col] = colObj.width < 1 and colObj.width * totalH or colObj.width
+ end
+ extantH = math_max(0, extantH - laneH[col])
+ end
+ end
+
+ -- Determine sizes based on weight
+ local scale = totalWeight > 0 and extantH / totalWeight or 0
+ for col,colObj in pairs(cols) do
+ if colObj.weight then
+ laneH[col] = scale * colObj.weight
+ end
+ end
+
+ -- Arrange children
+ for row=1,rows do
+ local rowV = 0
+
+ -- Horizontal placement and sizing
+ for col=1,#cols do
+ local child = t[(row - 1) * #cols + col]
+ if child then
+ local colObj = cols[colStart[child]]
+ local cellObj = child:GetUserData("cell")
+ local offsetH = GetCellDimension("H", laneH, 1, colStart[child] - 1, spaceH) + (colStart[child] == 1 and 0 or spaceH)
+ local cellH = GetCellDimension("H", laneH, colStart[child], col, spaceH)
+
+ local f = child.frame
+ f:ClearAllPoints()
+ local childH = f:GetWidth() or 0
+
+ local alignFn, align = GetCellAlign("H", tableObj, colObj, cellObj, cellH, childH)
+ f:SetPoint("LEFT", content, offsetH + align, 0)
+ if child:IsFullWidth() or alignFn == "fill" or childH > cellH then
+ f:SetPoint("RIGHT", content, "LEFT", offsetH + align + cellH, 0)
+ end
+
+ if child.DoLayout then
+ child:DoLayout()
+ end
+
+ rowV = math_max(rowV, (f:GetHeight() or 0) - GetCellDimension("V", laneV, rowStart[child], row - 1, spaceV))
+ end
+ end
+
+ laneV[row] = rowV
+
+ -- Vertical placement and sizing
+ for col=1,#cols do
+ local child = t[(row - 1) * #cols + col]
+ if child then
+ local colObj = cols[colStart[child]]
+ local cellObj = child:GetUserData("cell")
+ local offsetV = GetCellDimension("V", laneV, 1, rowStart[child] - 1, spaceV) + (rowStart[child] == 1 and 0 or spaceV)
+ local cellV = GetCellDimension("V", laneV, rowStart[child], row, spaceV)
+
+ local f = child.frame
+ local childV = f:GetHeight() or 0
+
+ local alignFn, align = GetCellAlign("V", tableObj, colObj, cellObj, cellV, childV)
+ if child:IsFullHeight() or alignFn == "fill" then
+ f:SetHeight(cellV)
+ end
+ f:SetPoint("TOP", content, 0, -(offsetV + align))
+ end
+ end
+ end
+
+ -- Calculate total height
+ local totalV = GetCellDimension("V", laneV, 1, #laneV, spaceV)
+
+ -- Cleanup
+ for _,v in pairs(layoutCache) do wipe(v) end
+
+ safecall(obj.LayoutFinished, obj, nil, totalV)
+ obj:ResumeLayout()
+ end)
diff --git a/Libs/AceGUI-3.0/AceGUI-3.0.xml b/Libs/AceGUI-3.0/AceGUI-3.0.xml
index ae22c90..b515077 100644
--- a/Libs/AceGUI-3.0/AceGUI-3.0.xml
+++ b/Libs/AceGUI-3.0/AceGUI-3.0.xml
@@ -1,28 +1,28 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua
index bf1eae7..d95db58 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua
@@ -1,143 +1,143 @@
---[[-----------------------------------------------------------------------------
-BlizOptionsGroup Container
-Simple container widget for the integration of AceGUI into the Blizzard Interface Options
--------------------------------------------------------------------------------]]
-local Type, Version = "BlizOptionsGroup", 26
-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
-
--- WoW APIs
-local CreateFrame = CreateFrame
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-
-local function OnShow(frame)
- frame.obj:Fire("OnShow")
-end
-
-local function OnHide(frame)
- frame.obj:Fire("OnHide")
-end
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-
-local function okay(frame)
- frame.obj:Fire("okay")
-end
-
-local function cancel(frame)
- frame.obj:Fire("cancel")
-end
-
-local function default(frame)
- frame.obj:Fire("default")
-end
-
-local function refresh(frame)
- frame.obj:Fire("refresh")
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetName()
- self:SetTitle()
- end,
-
- -- ["OnRelease"] = nil,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- local contentwidth = width - 63
- if contentwidth < 0 then
- contentwidth = 0
- end
- content:SetWidth(contentwidth)
- content.width = contentwidth
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- local contentheight = height - 26
- if contentheight < 0 then
- contentheight = 0
- end
- content:SetHeight(contentheight)
- content.height = contentheight
- end,
-
- ["SetName"] = function(self, name, parent)
- self.frame.name = name
- self.frame.parent = parent
- end,
-
- ["SetTitle"] = function(self, title)
- local content = self.content
- content:ClearAllPoints()
- if not title or title == "" then
- content:SetPoint("TOPLEFT", 10, -10)
- self.label:SetText("")
- else
- content:SetPoint("TOPLEFT", 10, -40)
- self.label:SetText(title)
- end
- content:SetPoint("BOTTOMRIGHT", -10, 10)
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer)
- frame:Hide()
-
- -- support functions for the Blizzard Interface Options
- frame.okay = okay
- frame.cancel = cancel
- frame.default = default
- frame.refresh = refresh
-
- -- 10.0 support function aliases (cancel has been removed)
- frame.OnCommit = okay
- frame.OnDefault = default
- frame.OnRefresh = refresh
-
- frame:SetScript("OnHide", OnHide)
- frame:SetScript("OnShow", OnShow)
-
- local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
- label:SetPoint("TOPLEFT", 10, -15)
- label:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", 10, -45)
- label:SetJustifyH("LEFT")
- label:SetJustifyV("TOP")
-
- --Container Support
- local content = CreateFrame("Frame", nil, frame)
- content:SetPoint("TOPLEFT", 10, -10)
- content:SetPoint("BOTTOMRIGHT", -10, 10)
-
- local widget = {
- label = label,
- frame = frame,
- content = content,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+BlizOptionsGroup Container
+Simple container widget for the integration of AceGUI into the Blizzard Interface Options
+-------------------------------------------------------------------------------]]
+local Type, Version = "BlizOptionsGroup", 26
+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
+
+-- WoW APIs
+local CreateFrame = CreateFrame
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+
+local function OnShow(frame)
+ frame.obj:Fire("OnShow")
+end
+
+local function OnHide(frame)
+ frame.obj:Fire("OnHide")
+end
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+local function okay(frame)
+ frame.obj:Fire("okay")
+end
+
+local function cancel(frame)
+ frame.obj:Fire("cancel")
+end
+
+local function default(frame)
+ frame.obj:Fire("default")
+end
+
+local function refresh(frame)
+ frame.obj:Fire("refresh")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetName()
+ self:SetTitle()
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 63
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 26
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["SetName"] = function(self, name, parent)
+ self.frame.name = name
+ self.frame.parent = parent
+ end,
+
+ ["SetTitle"] = function(self, title)
+ local content = self.content
+ content:ClearAllPoints()
+ if not title or title == "" then
+ content:SetPoint("TOPLEFT", 10, -10)
+ self.label:SetText("")
+ else
+ content:SetPoint("TOPLEFT", 10, -40)
+ self.label:SetText(title)
+ end
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer)
+ frame:Hide()
+
+ -- support functions for the Blizzard Interface Options
+ frame.okay = okay
+ frame.cancel = cancel
+ frame.default = default
+ frame.refresh = refresh
+
+ -- 10.0 support function aliases (cancel has been removed)
+ frame.OnCommit = okay
+ frame.OnDefault = default
+ frame.OnRefresh = refresh
+
+ frame:SetScript("OnHide", OnHide)
+ frame:SetScript("OnShow", OnShow)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
+ label:SetPoint("TOPLEFT", 10, -15)
+ label:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", 10, -45)
+ label:SetJustifyH("LEFT")
+ label:SetJustifyV("TOP")
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, frame)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ label = label,
+ frame = frame,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua
index 2322e3d..cd83755 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua
@@ -1,157 +1,157 @@
---[[-----------------------------------------------------------------------------
-DropdownGroup Container
-Container controlled by a dropdown on the top.
--------------------------------------------------------------------------------]]
-local Type, Version = "DropdownGroup", 22
-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 assert, pairs, type = assert, pairs, type
-
--- WoW APIs
-local CreateFrame = CreateFrame
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function SelectedGroup(self, event, value)
- local group = self.parentgroup
- local status = group.status or group.localstatus
- status.selected = value
- self.parentgroup:Fire("OnGroupSelected", value)
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self.dropdown:SetText("")
- self:SetDropdownWidth(200)
- self:SetTitle("")
- end,
-
- ["OnRelease"] = function(self)
- self.dropdown.list = nil
- self.status = nil
- for k in pairs(self.localstatus) do
- self.localstatus[k] = nil
- end
- end,
-
- ["SetTitle"] = function(self, title)
- self.titletext:SetText(title)
- self.dropdown.frame:ClearAllPoints()
- if title and title ~= "" then
- self.dropdown.frame:SetPoint("TOPRIGHT", -2, 0)
- else
- self.dropdown.frame:SetPoint("TOPLEFT", -1, 0)
- end
- end,
-
- ["SetGroupList"] = function(self,list,order)
- self.dropdown:SetList(list,order)
- end,
-
- ["SetStatusTable"] = function(self, status)
- assert(type(status) == "table")
- self.status = status
- end,
-
- ["SetGroup"] = function(self,group)
- self.dropdown:SetValue(group)
- local status = self.status or self.localstatus
- status.selected = group
- self:Fire("OnGroupSelected", group)
- end,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- local contentwidth = width - 26
- if contentwidth < 0 then
- contentwidth = 0
- end
- content:SetWidth(contentwidth)
- content.width = contentwidth
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- local contentheight = height - 63
- if contentheight < 0 then
- contentheight = 0
- end
- content:SetHeight(contentheight)
- content.height = contentheight
- end,
-
- ["LayoutFinished"] = function(self, width, height)
- self:SetHeight((height or 0) + 63)
- end,
-
- ["SetDropdownWidth"] = function(self, width)
- self.dropdown:SetWidth(width)
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local PaneBackdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 3, right = 3, top = 5, bottom = 3 }
-}
-
-local function Constructor()
- local frame = CreateFrame("Frame")
- frame:SetHeight(100)
- frame:SetWidth(100)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- titletext:SetPoint("TOPLEFT", 4, -5)
- titletext:SetPoint("TOPRIGHT", -4, -5)
- titletext:SetJustifyH("LEFT")
- titletext:SetHeight(18)
-
- local dropdown = AceGUI:Create("Dropdown")
- dropdown.frame:SetParent(frame)
- dropdown.frame:SetFrameLevel(dropdown.frame:GetFrameLevel() + 2)
- dropdown:SetCallback("OnValueChanged", SelectedGroup)
- dropdown.frame:SetPoint("TOPLEFT", -1, 0)
- dropdown.frame:Show()
- dropdown:SetLabel("")
-
- local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
- border:SetPoint("TOPLEFT", 0, -26)
- border:SetPoint("BOTTOMRIGHT", 0, 3)
- border:SetBackdrop(PaneBackdrop)
- border:SetBackdropColor(0.1,0.1,0.1,0.5)
- border:SetBackdropBorderColor(0.4,0.4,0.4)
-
- --Container Support
- local content = CreateFrame("Frame", nil, border)
- content:SetPoint("TOPLEFT", 10, -10)
- content:SetPoint("BOTTOMRIGHT", -10, 10)
-
- local widget = {
- frame = frame,
- localstatus = {},
- titletext = titletext,
- dropdown = dropdown,
- border = border,
- content = content,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- dropdown.parentgroup = widget
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+DropdownGroup Container
+Container controlled by a dropdown on the top.
+-------------------------------------------------------------------------------]]
+local Type, Version = "DropdownGroup", 22
+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 assert, pairs, type = assert, pairs, type
+
+-- WoW APIs
+local CreateFrame = CreateFrame
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function SelectedGroup(self, event, value)
+ local group = self.parentgroup
+ local status = group.status or group.localstatus
+ status.selected = value
+ self.parentgroup:Fire("OnGroupSelected", value)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self.dropdown:SetText("")
+ self:SetDropdownWidth(200)
+ self:SetTitle("")
+ end,
+
+ ["OnRelease"] = function(self)
+ self.dropdown.list = nil
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ end,
+
+ ["SetTitle"] = function(self, title)
+ self.titletext:SetText(title)
+ self.dropdown.frame:ClearAllPoints()
+ if title and title ~= "" then
+ self.dropdown.frame:SetPoint("TOPRIGHT", -2, 0)
+ else
+ self.dropdown.frame:SetPoint("TOPLEFT", -1, 0)
+ end
+ end,
+
+ ["SetGroupList"] = function(self,list,order)
+ self.dropdown:SetList(list,order)
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ end,
+
+ ["SetGroup"] = function(self,group)
+ self.dropdown:SetValue(group)
+ local status = self.status or self.localstatus
+ status.selected = group
+ self:Fire("OnGroupSelected", group)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 26
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 63
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ self:SetHeight((height or 0) + 63)
+ end,
+
+ ["SetDropdownWidth"] = function(self, width)
+ self.dropdown:SetWidth(width)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame")
+ frame:SetHeight(100)
+ frame:SetWidth(100)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ titletext:SetPoint("TOPLEFT", 4, -5)
+ titletext:SetPoint("TOPRIGHT", -4, -5)
+ titletext:SetJustifyH("LEFT")
+ titletext:SetHeight(18)
+
+ local dropdown = AceGUI:Create("Dropdown")
+ dropdown.frame:SetParent(frame)
+ dropdown.frame:SetFrameLevel(dropdown.frame:GetFrameLevel() + 2)
+ dropdown:SetCallback("OnValueChanged", SelectedGroup)
+ dropdown.frame:SetPoint("TOPLEFT", -1, 0)
+ dropdown.frame:Show()
+ dropdown:SetLabel("")
+
+ local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
+ border:SetPoint("TOPLEFT", 0, -26)
+ border:SetPoint("BOTTOMRIGHT", 0, 3)
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1,0.1,0.1,0.5)
+ border:SetBackdropBorderColor(0.4,0.4,0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ frame = frame,
+ localstatus = {},
+ titletext = titletext,
+ dropdown = dropdown,
+ border = border,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ dropdown.parentgroup = widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua
index ca90890..39a1004 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua
@@ -1,318 +1,318 @@
---[[-----------------------------------------------------------------------------
-Frame Container
--------------------------------------------------------------------------------]]
-local Type, Version = "Frame", 30
-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, assert, type = pairs, assert, type
-local wipe = table.wipe
-
--- WoW APIs
-local PlaySound = PlaySound
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Button_OnClick(frame)
- PlaySound(799) -- SOUNDKIT.GS_TITLE_OPTION_EXIT
- frame.obj:Hide()
-end
-
-local function Frame_OnShow(frame)
- frame.obj:Fire("OnShow")
-end
-
-local function Frame_OnClose(frame)
- frame.obj:Fire("OnClose")
-end
-
-local function Frame_OnMouseDown(frame)
- AceGUI:ClearFocus()
-end
-
-local function Title_OnMouseDown(frame)
- frame:GetParent():StartMoving()
- AceGUI:ClearFocus()
-end
-
-local function MoverSizer_OnMouseUp(mover)
- local frame = mover:GetParent()
- frame:StopMovingOrSizing()
- local self = frame.obj
- local status = self.status or self.localstatus
- status.width = frame:GetWidth()
- status.height = frame:GetHeight()
- status.top = frame:GetTop()
- status.left = frame:GetLeft()
-end
-
-local function SizerSE_OnMouseDown(frame)
- frame:GetParent():StartSizing("BOTTOMRIGHT")
- AceGUI:ClearFocus()
-end
-
-local function SizerS_OnMouseDown(frame)
- frame:GetParent():StartSizing("BOTTOM")
- AceGUI:ClearFocus()
-end
-
-local function SizerE_OnMouseDown(frame)
- frame:GetParent():StartSizing("RIGHT")
- AceGUI:ClearFocus()
-end
-
-local function StatusBar_OnEnter(frame)
- frame.obj:Fire("OnEnterStatusBar")
-end
-
-local function StatusBar_OnLeave(frame)
- frame.obj:Fire("OnLeaveStatusBar")
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self.frame:SetParent(UIParent)
- self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
- self.frame:SetFrameLevel(100) -- Lots of room to draw under it
- self:SetTitle()
- self:SetStatusText()
- self:ApplyStatus()
- self:Show()
- self:EnableResize(true)
- end,
-
- ["OnRelease"] = function(self)
- self.status = nil
- wipe(self.localstatus)
- end,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- local contentwidth = width - 34
- if contentwidth < 0 then
- contentwidth = 0
- end
- content:SetWidth(contentwidth)
- content.width = contentwidth
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- local contentheight = height - 57
- if contentheight < 0 then
- contentheight = 0
- end
- content:SetHeight(contentheight)
- content.height = contentheight
- end,
-
- ["SetTitle"] = function(self, title)
- self.titletext:SetText(title)
- self.titlebg:SetWidth((self.titletext:GetWidth() or 0) + 10)
- end,
-
- ["SetStatusText"] = function(self, text)
- self.statustext:SetText(text)
- end,
-
- ["Hide"] = function(self)
- self.frame:Hide()
- end,
-
- ["Show"] = function(self)
- self.frame:Show()
- end,
-
- ["EnableResize"] = function(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,
-
- -- called to set an external table to store status in
- ["SetStatusTable"] = function(self, status)
- assert(type(status) == "table")
- self.status = status
- self:ApplyStatus()
- end,
-
- ["ApplyStatus"] = function(self)
- local status = self.status or self.localstatus
- local frame = self.frame
- self:SetWidth(status.width or 700)
- self:SetHeight(status.height or 500)
- frame:ClearAllPoints()
- if status.top and status.left then
- frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
- frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
- else
- frame:SetPoint("CENTER")
- end
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local FrameBackdrop = {
- bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
- edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
- tile = true, tileSize = 32, edgeSize = 32,
- insets = { left = 8, right = 8, top = 8, bottom = 8 }
-}
-
-local PaneBackdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 3, right = 3, top = 5, bottom = 3 }
-}
-
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
- frame:Hide()
-
- frame:EnableMouse(true)
- frame:SetMovable(true)
- frame:SetResizable(true)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
- frame:SetFrameLevel(100) -- Lots of room to draw under it
- frame:SetBackdrop(FrameBackdrop)
- frame:SetBackdropColor(0, 0, 0, 1)
- if frame.SetResizeBounds then -- WoW 10.0
- frame:SetResizeBounds(400, 200)
- else
- frame:SetMinResize(400, 200)
- end
- frame:SetToplevel(true)
- frame:SetScript("OnShow", Frame_OnShow)
- frame:SetScript("OnHide", Frame_OnClose)
- frame:SetScript("OnMouseDown", Frame_OnMouseDown)
-
- local closebutton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
- closebutton:SetScript("OnClick", Button_OnClick)
- closebutton:SetPoint("BOTTOMRIGHT", -27, 17)
- closebutton:SetHeight(20)
- closebutton:SetWidth(100)
- closebutton:SetText(CLOSE)
-
- local statusbg = CreateFrame("Button", nil, frame, "BackdropTemplate")
- statusbg:SetPoint("BOTTOMLEFT", 15, 15)
- statusbg:SetPoint("BOTTOMRIGHT", -132, 15)
- statusbg:SetHeight(24)
- statusbg:SetBackdrop(PaneBackdrop)
- statusbg:SetBackdropColor(0.1,0.1,0.1)
- statusbg:SetBackdropBorderColor(0.4,0.4,0.4)
- statusbg:SetScript("OnEnter", StatusBar_OnEnter)
- statusbg:SetScript("OnLeave", StatusBar_OnLeave)
-
- local statustext = statusbg:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- statustext:SetPoint("TOPLEFT", 7, -2)
- statustext:SetPoint("BOTTOMRIGHT", -7, 2)
- statustext:SetHeight(20)
- statustext:SetJustifyH("LEFT")
- statustext:SetText("")
-
- local titlebg = frame:CreateTexture(nil, "OVERLAY")
- titlebg:SetTexture(131080) -- Interface\\DialogFrame\\UI-DialogBox-Header
- titlebg:SetTexCoord(0.31, 0.67, 0, 0.63)
- titlebg:SetPoint("TOP", 0, 12)
- titlebg:SetWidth(100)
- titlebg:SetHeight(40)
-
- local title = CreateFrame("Frame", nil, frame)
- title:EnableMouse(true)
- title:SetScript("OnMouseDown", Title_OnMouseDown)
- title:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
- title:SetAllPoints(titlebg)
-
- local titletext = title:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- titletext:SetPoint("TOP", titlebg, "TOP", 0, -14)
-
- local titlebg_l = frame:CreateTexture(nil, "OVERLAY")
- titlebg_l:SetTexture(131080) -- Interface\\DialogFrame\\UI-DialogBox-Header
- titlebg_l:SetTexCoord(0.21, 0.31, 0, 0.63)
- titlebg_l:SetPoint("RIGHT", titlebg, "LEFT")
- titlebg_l:SetWidth(30)
- titlebg_l:SetHeight(40)
-
- local titlebg_r = frame:CreateTexture(nil, "OVERLAY")
- titlebg_r:SetTexture(131080) -- Interface\\DialogFrame\\UI-DialogBox-Header
- titlebg_r:SetTexCoord(0.67, 0.77, 0, 0.63)
- titlebg_r:SetPoint("LEFT", titlebg, "RIGHT")
- titlebg_r:SetWidth(30)
- titlebg_r:SetHeight(40)
-
- local sizer_se = CreateFrame("Frame", nil, frame)
- sizer_se:SetPoint("BOTTOMRIGHT")
- sizer_se:SetWidth(25)
- sizer_se:SetHeight(25)
- sizer_se:EnableMouse()
- sizer_se:SetScript("OnMouseDown",SizerSE_OnMouseDown)
- sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
-
- local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
- line1:SetWidth(14)
- line1:SetHeight(14)
- line1:SetPoint("BOTTOMRIGHT", -8, 8)
- line1:SetTexture(137057) -- 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(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
- 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)
- sizer_s:SetPoint("BOTTOMLEFT")
- sizer_s:SetHeight(25)
- sizer_s:EnableMouse(true)
- sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown)
- sizer_s:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
-
- local sizer_e = CreateFrame("Frame", nil, frame)
- sizer_e:SetPoint("BOTTOMRIGHT", 0, 25)
- sizer_e:SetPoint("TOPRIGHT")
- sizer_e:SetWidth(25)
- sizer_e:EnableMouse(true)
- sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown)
- sizer_e:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
-
- --Container Support
- local content = CreateFrame("Frame", nil, frame)
- content:SetPoint("TOPLEFT", 17, -27)
- content:SetPoint("BOTTOMRIGHT", -17, 40)
-
- local widget = {
- localstatus = {},
- titletext = titletext,
- statustext = statustext,
- titlebg = titlebg,
- sizer_se = sizer_se,
- sizer_s = sizer_s,
- sizer_e = sizer_e,
- content = content,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- closebutton.obj, statusbg.obj = widget, widget
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Frame Container
+-------------------------------------------------------------------------------]]
+local Type, Version = "Frame", 30
+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, assert, type = pairs, assert, type
+local wipe = table.wipe
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Button_OnClick(frame)
+ PlaySound(799) -- SOUNDKIT.GS_TITLE_OPTION_EXIT
+ frame.obj:Hide()
+end
+
+local function Frame_OnShow(frame)
+ frame.obj:Fire("OnShow")
+end
+
+local function Frame_OnClose(frame)
+ frame.obj:Fire("OnClose")
+end
+
+local function Frame_OnMouseDown(frame)
+ AceGUI:ClearFocus()
+end
+
+local function Title_OnMouseDown(frame)
+ frame:GetParent():StartMoving()
+ AceGUI:ClearFocus()
+end
+
+local function MoverSizer_OnMouseUp(mover)
+ local frame = mover:GetParent()
+ frame:StopMovingOrSizing()
+ local self = frame.obj
+ local status = self.status or self.localstatus
+ status.width = frame:GetWidth()
+ status.height = frame:GetHeight()
+ status.top = frame:GetTop()
+ status.left = frame:GetLeft()
+end
+
+local function SizerSE_OnMouseDown(frame)
+ frame:GetParent():StartSizing("BOTTOMRIGHT")
+ AceGUI:ClearFocus()
+end
+
+local function SizerS_OnMouseDown(frame)
+ frame:GetParent():StartSizing("BOTTOM")
+ AceGUI:ClearFocus()
+end
+
+local function SizerE_OnMouseDown(frame)
+ frame:GetParent():StartSizing("RIGHT")
+ AceGUI:ClearFocus()
+end
+
+local function StatusBar_OnEnter(frame)
+ frame.obj:Fire("OnEnterStatusBar")
+end
+
+local function StatusBar_OnLeave(frame)
+ frame.obj:Fire("OnLeaveStatusBar")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self.frame:SetParent(UIParent)
+ self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ self.frame:SetFrameLevel(100) -- Lots of room to draw under it
+ self:SetTitle()
+ self:SetStatusText()
+ self:ApplyStatus()
+ self:Show()
+ self:EnableResize(true)
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ wipe(self.localstatus)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 34
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 57
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["SetTitle"] = function(self, title)
+ self.titletext:SetText(title)
+ self.titlebg:SetWidth((self.titletext:GetWidth() or 0) + 10)
+ end,
+
+ ["SetStatusText"] = function(self, text)
+ self.statustext:SetText(text)
+ end,
+
+ ["Hide"] = function(self)
+ self.frame:Hide()
+ end,
+
+ ["Show"] = function(self)
+ self.frame:Show()
+ end,
+
+ ["EnableResize"] = function(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,
+
+ -- called to set an external table to store status in
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ self:ApplyStatus()
+ end,
+
+ ["ApplyStatus"] = function(self)
+ local status = self.status or self.localstatus
+ local frame = self.frame
+ self:SetWidth(status.width or 700)
+ self:SetHeight(status.height or 500)
+ frame:ClearAllPoints()
+ if status.top and status.left then
+ frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
+ frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
+ else
+ frame:SetPoint("CENTER")
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local FrameBackdrop = {
+ bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
+ edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
+ tile = true, tileSize = 32, edgeSize = 32,
+ insets = { left = 8, right = 8, top = 8, bottom = 8 }
+}
+
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetMovable(true)
+ frame:SetResizable(true)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ frame:SetFrameLevel(100) -- Lots of room to draw under it
+ frame:SetBackdrop(FrameBackdrop)
+ frame:SetBackdropColor(0, 0, 0, 1)
+ if frame.SetResizeBounds then -- WoW 10.0
+ frame:SetResizeBounds(400, 200)
+ else
+ frame:SetMinResize(400, 200)
+ end
+ frame:SetToplevel(true)
+ frame:SetScript("OnShow", Frame_OnShow)
+ frame:SetScript("OnHide", Frame_OnClose)
+ frame:SetScript("OnMouseDown", Frame_OnMouseDown)
+
+ local closebutton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
+ closebutton:SetScript("OnClick", Button_OnClick)
+ closebutton:SetPoint("BOTTOMRIGHT", -27, 17)
+ closebutton:SetHeight(20)
+ closebutton:SetWidth(100)
+ closebutton:SetText(CLOSE)
+
+ local statusbg = CreateFrame("Button", nil, frame, "BackdropTemplate")
+ statusbg:SetPoint("BOTTOMLEFT", 15, 15)
+ statusbg:SetPoint("BOTTOMRIGHT", -132, 15)
+ statusbg:SetHeight(24)
+ statusbg:SetBackdrop(PaneBackdrop)
+ statusbg:SetBackdropColor(0.1,0.1,0.1)
+ statusbg:SetBackdropBorderColor(0.4,0.4,0.4)
+ statusbg:SetScript("OnEnter", StatusBar_OnEnter)
+ statusbg:SetScript("OnLeave", StatusBar_OnLeave)
+
+ local statustext = statusbg:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ statustext:SetPoint("TOPLEFT", 7, -2)
+ statustext:SetPoint("BOTTOMRIGHT", -7, 2)
+ statustext:SetHeight(20)
+ statustext:SetJustifyH("LEFT")
+ statustext:SetText("")
+
+ local titlebg = frame:CreateTexture(nil, "OVERLAY")
+ titlebg:SetTexture(131080) -- Interface\\DialogFrame\\UI-DialogBox-Header
+ titlebg:SetTexCoord(0.31, 0.67, 0, 0.63)
+ titlebg:SetPoint("TOP", 0, 12)
+ titlebg:SetWidth(100)
+ titlebg:SetHeight(40)
+
+ local title = CreateFrame("Frame", nil, frame)
+ title:EnableMouse(true)
+ title:SetScript("OnMouseDown", Title_OnMouseDown)
+ title:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+ title:SetAllPoints(titlebg)
+
+ local titletext = title:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ titletext:SetPoint("TOP", titlebg, "TOP", 0, -14)
+
+ local titlebg_l = frame:CreateTexture(nil, "OVERLAY")
+ titlebg_l:SetTexture(131080) -- Interface\\DialogFrame\\UI-DialogBox-Header
+ titlebg_l:SetTexCoord(0.21, 0.31, 0, 0.63)
+ titlebg_l:SetPoint("RIGHT", titlebg, "LEFT")
+ titlebg_l:SetWidth(30)
+ titlebg_l:SetHeight(40)
+
+ local titlebg_r = frame:CreateTexture(nil, "OVERLAY")
+ titlebg_r:SetTexture(131080) -- Interface\\DialogFrame\\UI-DialogBox-Header
+ titlebg_r:SetTexCoord(0.67, 0.77, 0, 0.63)
+ titlebg_r:SetPoint("LEFT", titlebg, "RIGHT")
+ titlebg_r:SetWidth(30)
+ titlebg_r:SetHeight(40)
+
+ local sizer_se = CreateFrame("Frame", nil, frame)
+ sizer_se:SetPoint("BOTTOMRIGHT")
+ sizer_se:SetWidth(25)
+ sizer_se:SetHeight(25)
+ sizer_se:EnableMouse()
+ sizer_se:SetScript("OnMouseDown",SizerSE_OnMouseDown)
+ sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+
+ local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
+ line1:SetWidth(14)
+ line1:SetHeight(14)
+ line1:SetPoint("BOTTOMRIGHT", -8, 8)
+ line1:SetTexture(137057) -- 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(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
+ 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)
+ sizer_s:SetPoint("BOTTOMLEFT")
+ sizer_s:SetHeight(25)
+ sizer_s:EnableMouse(true)
+ sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown)
+ sizer_s:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+
+ local sizer_e = CreateFrame("Frame", nil, frame)
+ sizer_e:SetPoint("BOTTOMRIGHT", 0, 25)
+ sizer_e:SetPoint("TOPRIGHT")
+ sizer_e:SetWidth(25)
+ sizer_e:EnableMouse(true)
+ sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown)
+ sizer_e:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, frame)
+ content:SetPoint("TOPLEFT", 17, -27)
+ content:SetPoint("BOTTOMRIGHT", -17, 40)
+
+ local widget = {
+ localstatus = {},
+ titletext = titletext,
+ statustext = statustext,
+ titlebg = titlebg,
+ sizer_se = sizer_se,
+ sizer_s = sizer_s,
+ sizer_e = sizer_e,
+ content = content,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ closebutton.obj, statusbg.obj = widget, widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua
index 04b4d5d..1676ae4 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua
@@ -1,103 +1,103 @@
---[[-----------------------------------------------------------------------------
-InlineGroup Container
-Simple container widget that creates a visible "box" with an optional title.
--------------------------------------------------------------------------------]]
-local Type, Version = "InlineGroup", 22
-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
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetWidth(300)
- self:SetHeight(100)
- self:SetTitle("")
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetTitle"] = function(self,title)
- self.titletext:SetText(title)
- end,
-
-
- ["LayoutFinished"] = function(self, width, height)
- if self.noAutoHeight then return end
- self:SetHeight((height or 0) + 40)
- end,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- local contentwidth = width - 20
- if contentwidth < 0 then
- contentwidth = 0
- end
- content:SetWidth(contentwidth)
- content.width = contentwidth
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- local contentheight = height - 20
- if contentheight < 0 then
- contentheight = 0
- end
- content:SetHeight(contentheight)
- content.height = contentheight
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local PaneBackdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 3, right = 3, top = 5, bottom = 3 }
-}
-
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- titletext:SetPoint("TOPLEFT", 14, 0)
- titletext:SetPoint("TOPRIGHT", -14, 0)
- titletext:SetJustifyH("LEFT")
- titletext:SetHeight(18)
-
- local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
- border:SetPoint("TOPLEFT", 0, -17)
- border:SetPoint("BOTTOMRIGHT", -1, 3)
- border:SetBackdrop(PaneBackdrop)
- border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
- border:SetBackdropBorderColor(0.4, 0.4, 0.4)
-
- --Container Support
- local content = CreateFrame("Frame", nil, border)
- content:SetPoint("TOPLEFT", 10, -10)
- content:SetPoint("BOTTOMRIGHT", -10, 10)
-
- local widget = {
- frame = frame,
- content = content,
- titletext = titletext,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+InlineGroup Container
+Simple container widget that creates a visible "box" with an optional title.
+-------------------------------------------------------------------------------]]
+local Type, Version = "InlineGroup", 22
+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
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(300)
+ self:SetHeight(100)
+ self:SetTitle("")
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetTitle"] = function(self,title)
+ self.titletext:SetText(title)
+ end,
+
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight((height or 0) + 40)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 20
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 20
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ titletext:SetPoint("TOPLEFT", 14, 0)
+ titletext:SetPoint("TOPRIGHT", -14, 0)
+ titletext:SetJustifyH("LEFT")
+ titletext:SetHeight(18)
+
+ local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
+ border:SetPoint("TOPLEFT", 0, -17)
+ border:SetPoint("BOTTOMRIGHT", -1, 3)
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ border:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ frame = frame,
+ content = content,
+ titletext = titletext,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua
index be6052f..d110d03 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua
@@ -1,215 +1,215 @@
---[[-----------------------------------------------------------------------------
-ScrollFrame Container
-Plain container that scrolls its content and doesn't grow in height.
--------------------------------------------------------------------------------]]
-local Type, Version = "ScrollFrame", 26
-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, assert, type = pairs, assert, type
-local min, max, floor = math.min, math.max, math.floor
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-local function FixScrollOnUpdate(frame)
- frame:SetScript("OnUpdate", nil)
- frame.obj:FixScroll()
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function ScrollFrame_OnMouseWheel(frame, value)
- frame.obj:MoveScroll(value)
-end
-
-local function ScrollFrame_OnSizeChanged(frame)
- frame:SetScript("OnUpdate", FixScrollOnUpdate)
-end
-
-local function ScrollBar_OnScrollValueChanged(frame, value)
- frame.obj:SetScroll(value)
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetScroll(0)
- self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
- end,
-
- ["OnRelease"] = function(self)
- self.status = nil
- for k in pairs(self.localstatus) do
- self.localstatus[k] = nil
- end
- self.scrollframe:SetPoint("BOTTOMRIGHT")
- self.scrollbar:Hide()
- self.scrollBarShown = nil
- self.content.height, self.content.width, self.content.original_width = nil, nil, nil
- end,
-
- ["SetScroll"] = function(self, value)
- local status = self.status or self.localstatus
- local viewheight = self.scrollframe:GetHeight()
- local height = self.content:GetHeight()
- local offset
-
- if viewheight > height then
- offset = 0
- else
- offset = floor((height - viewheight) / 1000.0 * value)
- end
- self.content:ClearAllPoints()
- self.content:SetPoint("TOPLEFT", 0, offset)
- self.content:SetPoint("TOPRIGHT", 0, offset)
- status.offset = offset
- status.scrollvalue = value
- end,
-
- ["MoveScroll"] = function(self, value)
- local status = self.status or self.localstatus
- local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
-
- if self.scrollBarShown then
- local diff = height - viewheight
- local delta = 1
- if value < 0 then
- delta = -1
- end
- self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
- end
- end,
-
- ["FixScroll"] = function(self)
- if self.updateLock then return end
- self.updateLock = true
- local status = self.status or self.localstatus
- local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
- local offset = status.offset or 0
- -- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
- -- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
- if viewheight < height + 2 then
- if self.scrollBarShown then
- self.scrollBarShown = nil
- self.scrollbar:Hide()
- self.scrollbar:SetValue(0)
- self.scrollframe:SetPoint("BOTTOMRIGHT")
- if self.content.original_width then
- self.content.width = self.content.original_width
- end
- self:DoLayout()
- end
- else
- if not self.scrollBarShown then
- self.scrollBarShown = true
- self.scrollbar:Show()
- self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
- if self.content.original_width then
- self.content.width = self.content.original_width - 20
- end
- self:DoLayout()
- end
- local value = (offset / (viewheight - height) * 1000)
- if value > 1000 then value = 1000 end
- self.scrollbar:SetValue(value)
- self:SetScroll(value)
- if value < 1000 then
- self.content:ClearAllPoints()
- self.content:SetPoint("TOPLEFT", 0, offset)
- self.content:SetPoint("TOPRIGHT", 0, offset)
- status.offset = offset
- end
- end
- self.updateLock = nil
- end,
-
- ["LayoutFinished"] = function(self, width, height)
- self.content:SetHeight(height or 0 + 20)
-
- -- update the scrollframe
- self:FixScroll()
-
- -- schedule another update when everything has "settled"
- self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
- end,
-
- ["SetStatusTable"] = function(self, status)
- assert(type(status) == "table")
- self.status = status
- if not status.scrollvalue then
- status.scrollvalue = 0
- end
- end,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- content.width = width - (self.scrollBarShown and 20 or 0)
- content.original_width = width
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- content.height = height
- end
-}
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
- local num = AceGUI:GetNextWidgetNum(Type)
-
- local scrollframe = CreateFrame("ScrollFrame", nil, frame)
- scrollframe:SetPoint("TOPLEFT")
- scrollframe:SetPoint("BOTTOMRIGHT")
- scrollframe:EnableMouseWheel(true)
- scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
- scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
-
- local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate")
- scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
- scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
- scrollbar:SetMinMaxValues(0, 1000)
- scrollbar:SetValueStep(1)
- scrollbar:SetValue(0)
- scrollbar:SetWidth(16)
- scrollbar:Hide()
- -- set the script as the last step, so it doesn't fire yet
- scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged)
-
- local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
- scrollbg:SetAllPoints(scrollbar)
- scrollbg:SetColorTexture(0, 0, 0, 0.4)
-
- --Container Support
- local content = CreateFrame("Frame", nil, scrollframe)
- content:SetPoint("TOPLEFT")
- content:SetPoint("TOPRIGHT")
- content:SetHeight(400)
- scrollframe:SetScrollChild(content)
-
- local widget = {
- localstatus = { scrollvalue = 0 },
- scrollframe = scrollframe,
- scrollbar = scrollbar,
- content = content,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- scrollframe.obj, scrollbar.obj = widget, widget
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+ScrollFrame Container
+Plain container that scrolls its content and doesn't grow in height.
+-------------------------------------------------------------------------------]]
+local Type, Version = "ScrollFrame", 26
+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, assert, type = pairs, assert, type
+local min, max, floor = math.min, math.max, math.floor
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function FixScrollOnUpdate(frame)
+ frame:SetScript("OnUpdate", nil)
+ frame.obj:FixScroll()
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function ScrollFrame_OnMouseWheel(frame, value)
+ frame.obj:MoveScroll(value)
+end
+
+local function ScrollFrame_OnSizeChanged(frame)
+ frame:SetScript("OnUpdate", FixScrollOnUpdate)
+end
+
+local function ScrollBar_OnScrollValueChanged(frame, value)
+ frame.obj:SetScroll(value)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetScroll(0)
+ self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ self.scrollframe:SetPoint("BOTTOMRIGHT")
+ self.scrollbar:Hide()
+ self.scrollBarShown = nil
+ self.content.height, self.content.width, self.content.original_width = nil, nil, nil
+ end,
+
+ ["SetScroll"] = function(self, value)
+ local status = self.status or self.localstatus
+ local viewheight = self.scrollframe:GetHeight()
+ local height = self.content:GetHeight()
+ local offset
+
+ if viewheight > height then
+ offset = 0
+ else
+ offset = floor((height - viewheight) / 1000.0 * value)
+ end
+ self.content:ClearAllPoints()
+ self.content:SetPoint("TOPLEFT", 0, offset)
+ self.content:SetPoint("TOPRIGHT", 0, offset)
+ status.offset = offset
+ status.scrollvalue = value
+ end,
+
+ ["MoveScroll"] = function(self, value)
+ local status = self.status or self.localstatus
+ local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
+
+ if self.scrollBarShown then
+ local diff = height - viewheight
+ local delta = 1
+ if value < 0 then
+ delta = -1
+ end
+ self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
+ end
+ end,
+
+ ["FixScroll"] = function(self)
+ if self.updateLock then return end
+ self.updateLock = true
+ local status = self.status or self.localstatus
+ local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
+ local offset = status.offset or 0
+ -- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
+ -- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
+ if viewheight < height + 2 then
+ if self.scrollBarShown then
+ self.scrollBarShown = nil
+ self.scrollbar:Hide()
+ self.scrollbar:SetValue(0)
+ self.scrollframe:SetPoint("BOTTOMRIGHT")
+ if self.content.original_width then
+ self.content.width = self.content.original_width
+ end
+ self:DoLayout()
+ end
+ else
+ if not self.scrollBarShown then
+ self.scrollBarShown = true
+ self.scrollbar:Show()
+ self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
+ if self.content.original_width then
+ self.content.width = self.content.original_width - 20
+ end
+ self:DoLayout()
+ end
+ local value = (offset / (viewheight - height) * 1000)
+ if value > 1000 then value = 1000 end
+ self.scrollbar:SetValue(value)
+ self:SetScroll(value)
+ if value < 1000 then
+ self.content:ClearAllPoints()
+ self.content:SetPoint("TOPLEFT", 0, offset)
+ self.content:SetPoint("TOPRIGHT", 0, offset)
+ status.offset = offset
+ end
+ end
+ self.updateLock = nil
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ self.content:SetHeight(height or 0 + 20)
+
+ -- update the scrollframe
+ self:FixScroll()
+
+ -- schedule another update when everything has "settled"
+ self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ if not status.scrollvalue then
+ status.scrollvalue = 0
+ end
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ content.width = width - (self.scrollBarShown and 20 or 0)
+ content.original_width = width
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ content.height = height
+ end
+}
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ local num = AceGUI:GetNextWidgetNum(Type)
+
+ local scrollframe = CreateFrame("ScrollFrame", nil, frame)
+ scrollframe:SetPoint("TOPLEFT")
+ scrollframe:SetPoint("BOTTOMRIGHT")
+ scrollframe:EnableMouseWheel(true)
+ scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
+ scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
+
+ local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate")
+ scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
+ scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
+ scrollbar:SetMinMaxValues(0, 1000)
+ scrollbar:SetValueStep(1)
+ scrollbar:SetValue(0)
+ scrollbar:SetWidth(16)
+ scrollbar:Hide()
+ -- set the script as the last step, so it doesn't fire yet
+ scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged)
+
+ local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
+ scrollbg:SetAllPoints(scrollbar)
+ scrollbg:SetColorTexture(0, 0, 0, 0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, scrollframe)
+ content:SetPoint("TOPLEFT")
+ content:SetPoint("TOPRIGHT")
+ content:SetHeight(400)
+ scrollframe:SetScrollChild(content)
+
+ local widget = {
+ localstatus = { scrollvalue = 0 },
+ scrollframe = scrollframe,
+ scrollbar = scrollbar,
+ content = content,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ scrollframe.obj, scrollbar.obj = widget, widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua
index 6e23abc..57512c3 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua
@@ -1,69 +1,69 @@
---[[-----------------------------------------------------------------------------
-SimpleGroup Container
-Simple container widget that just groups widgets.
--------------------------------------------------------------------------------]]
-local Type, Version = "SimpleGroup", 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 pairs = pairs
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetWidth(300)
- self:SetHeight(100)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["LayoutFinished"] = function(self, width, height)
- if self.noAutoHeight then return end
- self:SetHeight(height or 0)
- end,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- content:SetWidth(width)
- content.width = width
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- content:SetHeight(height)
- content.height = height
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- --Container Support
- local content = CreateFrame("Frame", nil, frame)
- content:SetPoint("TOPLEFT")
- content:SetPoint("BOTTOMRIGHT")
-
- local widget = {
- frame = frame,
- content = content,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+SimpleGroup Container
+Simple container widget that just groups widgets.
+-------------------------------------------------------------------------------]]
+local Type, Version = "SimpleGroup", 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 pairs = pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(300)
+ self:SetHeight(100)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight(height or 0)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ content:SetWidth(width)
+ content.width = width
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ content:SetHeight(height)
+ content.height = height
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, frame)
+ content:SetPoint("TOPLEFT")
+ content:SetPoint("BOTTOMRIGHT")
+
+ local widget = {
+ frame = frame,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua
index 8a5756f..8e46876 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua
@@ -1,535 +1,535 @@
---[[-----------------------------------------------------------------------------
-TabGroup Container
-Container that uses tabs on top to switch between groups.
--------------------------------------------------------------------------------]]
-local Type, Version = "TabGroup", 38
-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, table.wipe
-
--- WoW APIs
-local PlaySound = PlaySound
-local CreateFrame, UIParent = CreateFrame, UIParent
-local _G = _G
-
--- local upvalue storage used by BuildTabs
-local widths = {}
-local rowwidths = {}
-local rowends = {}
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-
-local function PanelTemplates_TabResize(tab, padding, absoluteSize, minWidth, maxWidth, absoluteTextSize)
- local tabName = tab:GetName();
-
- local buttonMiddle = tab.Middle or tab.middleTexture or _G[tabName.."Middle"];
- local buttonMiddleDisabled = tab.MiddleDisabled or (tabName and _G[tabName.."MiddleDisabled"]);
- local left = tab.Left or tab.leftTexture or _G[tabName.."Left"];
- local sideWidths = 2 * left:GetWidth();
- local tabText = tab.Text or _G[tab:GetName().."Text"];
- local highlightTexture = tab.HighlightTexture or (tabName and _G[tabName.."HighlightTexture"]);
-
- local width, tabWidth;
- local textWidth;
- if ( absoluteTextSize ) then
- textWidth = absoluteTextSize;
- else
- tabText:SetWidth(0);
- textWidth = tabText:GetWidth();
- end
- -- If there's an absolute size specified then use it
- if ( absoluteSize ) then
- if ( absoluteSize < sideWidths) then
- width = 1;
- tabWidth = sideWidths
- else
- width = absoluteSize - sideWidths;
- tabWidth = absoluteSize
- end
- tabText:SetWidth(width);
- else
- -- Otherwise try to use padding
- if ( padding ) then
- width = textWidth + padding;
- else
- width = textWidth + 24;
- end
- -- If greater than the maxWidth then cap it
- if ( maxWidth and width > maxWidth ) then
- if ( padding ) then
- width = maxWidth + padding;
- else
- width = maxWidth + 24;
- end
- tabText:SetWidth(width);
- else
- tabText:SetWidth(0);
- end
- if (minWidth and width < minWidth) then
- width = minWidth;
- end
- tabWidth = width + sideWidths;
- end
-
- if ( buttonMiddle ) then
- buttonMiddle:SetWidth(width);
- end
- if ( buttonMiddleDisabled ) then
- buttonMiddleDisabled:SetWidth(width);
- end
-
- tab:SetWidth(tabWidth);
-
- if ( highlightTexture ) then
- highlightTexture:SetWidth(tabWidth);
- end
-end
-
-local function PanelTemplates_DeselectTab(tab)
- local name = tab:GetName();
-
- local left = tab.Left or _G[name.."Left"];
- local middle = tab.Middle or _G[name.."Middle"];
- local right = tab.Right or _G[name.."Right"];
- left:Show();
- middle:Show();
- right:Show();
- --tab:UnlockHighlight();
- tab:Enable();
- local text = tab.Text or _G[name.."Text"];
- text:SetPoint("CENTER", tab, "CENTER", (tab.deselectedTextX or 0), (tab.deselectedTextY or 2));
-
- local leftDisabled = tab.LeftDisabled or _G[name.."LeftDisabled"];
- local middleDisabled = tab.MiddleDisabled or _G[name.."MiddleDisabled"];
- local rightDisabled = tab.RightDisabled or _G[name.."RightDisabled"];
- leftDisabled:Hide();
- middleDisabled:Hide();
- rightDisabled:Hide();
-end
-
-local function PanelTemplates_SelectTab(tab)
- local name = tab:GetName();
-
- local left = tab.Left or _G[name.."Left"];
- local middle = tab.Middle or _G[name.."Middle"];
- local right = tab.Right or _G[name.."Right"];
- left:Hide();
- middle:Hide();
- right:Hide();
- --tab:LockHighlight();
- tab:Disable();
- tab:SetDisabledFontObject(GameFontHighlightSmall);
- local text = tab.Text or _G[name.."Text"];
- text:SetPoint("CENTER", tab, "CENTER", (tab.selectedTextX or 0), (tab.selectedTextY or -3));
-
- local leftDisabled = tab.LeftDisabled or _G[name.."LeftDisabled"];
- local middleDisabled = tab.MiddleDisabled or _G[name.."MiddleDisabled"];
- local rightDisabled = tab.RightDisabled or _G[name.."RightDisabled"];
- leftDisabled:Show();
- middleDisabled:Show();
- rightDisabled:Show();
-
- if GameTooltip:IsOwned(tab) then
- GameTooltip:Hide();
- end
-end
-
-local function PanelTemplates_SetDisabledTabState(tab)
- local name = tab:GetName();
- local left = tab.Left or _G[name.."Left"];
- local middle = tab.Middle or _G[name.."Middle"];
- local right = tab.Right or _G[name.."Right"];
- left:Show();
- middle:Show();
- right:Show();
- --tab:UnlockHighlight();
- tab:Disable();
- tab.text = tab:GetText();
- -- Gray out text
- tab:SetDisabledFontObject(GameFontDisableSmall);
- local leftDisabled = tab.LeftDisabled or _G[name.."LeftDisabled"];
- local middleDisabled = tab.MiddleDisabled or _G[name.."MiddleDisabled"];
- local rightDisabled = tab.RightDisabled or _G[name.."RightDisabled"];
- leftDisabled:Hide();
- middleDisabled:Hide();
- rightDisabled:Hide();
-end
-
-local function UpdateTabLook(frame)
- if frame.disabled then
- PanelTemplates_SetDisabledTabState(frame)
- elseif frame.selected then
- PanelTemplates_SelectTab(frame)
- else
- PanelTemplates_DeselectTab(frame)
- end
-end
-
-local function Tab_SetText(frame, text)
- frame:_SetText(text)
- local width = frame.obj.frame.width or frame.obj.frame:GetWidth() or 0
- PanelTemplates_TabResize(frame, 0, nil, nil, width, frame:GetFontString():GetStringWidth())
-end
-
-local function Tab_SetSelected(frame, selected)
- frame.selected = selected
- UpdateTabLook(frame)
-end
-
-local function Tab_SetDisabled(frame, disabled)
- frame.disabled = disabled
- UpdateTabLook(frame)
-end
-
-local function BuildTabsOnUpdate(frame)
- local self = frame.obj
- self:BuildTabs()
- frame:SetScript("OnUpdate", nil)
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Tab_OnClick(frame)
- if not (frame.selected or frame.disabled) then
- PlaySound(841) -- SOUNDKIT.IG_CHARACTER_INFO_TAB
- frame.obj:SelectTab(frame.value)
- end
-end
-
-local function Tab_OnEnter(frame)
- local self = frame.obj
- self:Fire("OnTabEnter", self.tabs[frame.id].value, frame)
-end
-
-local function Tab_OnLeave(frame)
- local self = frame.obj
- self:Fire("OnTabLeave", self.tabs[frame.id].value, frame)
-end
-
-local function Tab_OnShow(frame)
- _G[frame:GetName().."HighlightTexture"]:SetWidth(frame:GetTextWidth() + 30)
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetTitle()
- end,
-
- ["OnRelease"] = function(self)
- self.status = nil
- for k in pairs(self.localstatus) do
- self.localstatus[k] = nil
- end
- self.tablist = nil
- for _, tab in pairs(self.tabs) do
- tab:Hide()
- end
- end,
-
- ["CreateTab"] = function(self, id)
- local tabname = ("AceGUITabGroup%dTab%d"):format(self.num, id)
- local tab = CreateFrame("Button", tabname, self.border)
- tab:SetSize(115, 24)
- tab.deselectedTextY = -3
- tab.selectedTextY = -2
-
- tab.LeftDisabled = tab:CreateTexture(tabname .. "LeftDisabled", "BORDER")
- tab.LeftDisabled:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
- tab.LeftDisabled:SetSize(20, 24)
- tab.LeftDisabled:SetPoint("BOTTOMLEFT", 0, -3)
- tab.LeftDisabled:SetTexCoord(0, 0.15625, 0, 1.0)
-
- tab.MiddleDisabled = tab:CreateTexture(tabname .. "MiddleDisabled", "BORDER")
- tab.MiddleDisabled:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
- tab.MiddleDisabled:SetSize(88, 24)
- tab.MiddleDisabled:SetPoint("LEFT", tab.LeftDisabled, "RIGHT")
- tab.MiddleDisabled:SetTexCoord(0.15625, 0.84375, 0, 1.0)
-
- tab.RightDisabled = tab:CreateTexture(tabname .. "RightDisabled", "BORDER")
- tab.RightDisabled:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
- tab.RightDisabled:SetSize(20, 24)
- tab.RightDisabled:SetPoint("LEFT", tab.MiddleDisabled, "RIGHT")
- tab.RightDisabled:SetTexCoord(0.84375, 1.0, 0, 1.0)
-
- tab.Left = tab:CreateTexture(tabname .. "Left", "BORDER")
- tab.Left:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
- tab.Left:SetSize(20, 24)
- tab.Left:SetPoint("TOPLEFT")
- tab.Left:SetTexCoord(0, 0.15625, 0, 1.0)
-
- tab.Middle = tab:CreateTexture(tabname .. "Middle", "BORDER")
- tab.Middle:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
- tab.Middle:SetSize(88, 24)
- tab.Middle:SetPoint("LEFT", tab.Left, "RIGHT")
- tab.Middle:SetTexCoord(0.15625, 0.84375, 0, 1.0)
-
- tab.Right = tab:CreateTexture(tabname .. "Right", "BORDER")
- tab.Right:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
- tab.Right:SetSize(20, 24)
- tab.Right:SetPoint("LEFT", tab.Middle, "RIGHT")
- tab.Right:SetTexCoord(0.84375, 1.0, 0, 1.0)
-
- tab.Text = tab:CreateFontString(tabname .. "Text")
- tab:SetFontString(tab.Text)
-
- tab:SetNormalFontObject(GameFontNormalSmall)
- tab:SetHighlightFontObject(GameFontHighlightSmall)
- tab:SetDisabledFontObject(GameFontHighlightSmall)
- tab:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight", "ADD")
- tab.HighlightTexture = tab:GetHighlightTexture()
- tab.HighlightTexture:ClearAllPoints()
- tab.HighlightTexture:SetPoint("LEFT", tab, "LEFT", 10, -4)
- tab.HighlightTexture:SetPoint("RIGHT", tab, "RIGHT", -10, -4)
- _G[tabname .. "HighlightTexture"] = tab.HighlightTexture
-
- tab.obj = self
- tab.id = id
-
- tab.text = tab.Text -- compat
- tab.text:ClearAllPoints()
- tab.text:SetPoint("LEFT", 14, -3)
- tab.text:SetPoint("RIGHT", -12, -3)
-
- tab:SetScript("OnClick", Tab_OnClick)
- tab:SetScript("OnEnter", Tab_OnEnter)
- tab:SetScript("OnLeave", Tab_OnLeave)
- tab:SetScript("OnShow", Tab_OnShow)
-
- tab._SetText = tab.SetText
- tab.SetText = Tab_SetText
- tab.SetSelected = Tab_SetSelected
- tab.SetDisabled = Tab_SetDisabled
-
- return tab
- end,
-
- ["SetTitle"] = function(self, text)
- self.titletext:SetText(text or "")
- if text and text ~= "" then
- self.alignoffset = 25
- else
- self.alignoffset = 18
- end
- self:BuildTabs()
- end,
-
- ["SetStatusTable"] = function(self, status)
- assert(type(status) == "table")
- self.status = status
- end,
-
- ["SelectTab"] = function(self, value)
- local status = self.status or self.localstatus
- local found
- for i, v in ipairs(self.tabs) do
- if v.value == value then
- v:SetSelected(true)
- found = true
- else
- v:SetSelected(false)
- end
- end
- status.selected = value
- if found then
- self:Fire("OnGroupSelected",value)
- end
- end,
-
- ["SetTabs"] = function(self, tabs)
- self.tablist = tabs
- self:BuildTabs()
- end,
-
-
- ["BuildTabs"] = function(self)
- local hastitle = (self.titletext:GetText() and self.titletext:GetText() ~= "")
- local tablist = self.tablist
- local tabs = self.tabs
-
- if not tablist then return end
-
- local width = self.frame.width or self.frame:GetWidth() or 0
-
- wipe(widths)
- wipe(rowwidths)
- wipe(rowends)
-
- --Place Text into tabs and get thier initial width
- for i, v in ipairs(tablist) do
- local tab = tabs[i]
- if not tab then
- tab = self:CreateTab(i)
- tabs[i] = tab
- end
-
- tab:Show()
- tab:SetText(v.text)
- tab:SetDisabled(v.disabled)
- tab.value = v.value
-
- 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
-
- for i = (#tablist)+1, #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 = #tablist
- local numrows = 1
- local usedwidth = 0
-
- for i = 1, #tablist do
- --If this is not the first tab of a row and there isn't room for it
- if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
- rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
- rowends[numrows] = i - 1
- numrows = numrows + 1
- usedwidth = 0
- end
- usedwidth = usedwidth + widths[i]
- end
- rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
- rowends[numrows] = #tablist
-
- --Fix for single tabs being left on the last row, move a tab from the row above if applicable
- if numrows > 1 then
- --if the last row has only one tab
- if rowends[numrows-1] == numtabs-1 then
- --if there are more than 2 tabs in the 2nd last row
- if (numrows == 2 and rowends[numrows-1] > 2) or (rowends[numrows] - rowends[numrows-1] > 2) then
- --move 1 tab from the second last row to the last, if there is enough space
- if (rowwidths[numrows] + widths[numtabs-1]) <= width then
- rowends[numrows-1] = rowends[numrows-1] - 1
- rowwidths[numrows] = rowwidths[numrows] + widths[numtabs-1]
- rowwidths[numrows-1] = rowwidths[numrows-1] - widths[numtabs-1]
- end
- end
- end
- end
-
- --anchor the rows as defined and resize tabs to fill thier row
- local starttab = 1
- for row, endtab in ipairs(rowends) do
- local first = true
- for tabno = starttab, endtab do
- local tab = tabs[tabno]
- tab:ClearAllPoints()
- if first then
- tab:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -(hastitle and 14 or 7)-(row-1)*20 )
- first = false
- else
- tab:SetPoint("LEFT", tabs[tabno-1], "RIGHT", -10, 0)
- end
- end
-
- -- equal padding for each tab to fill the available width,
- -- if the used space is above 75% already
- -- the 18 pixel is the typical width of a scrollbar, so we can have a tab group inside a scrolling frame,
- -- and not have the tabs jump around funny when switching between tabs that need scrolling and those that don't
- local padding = 0
- if not (numrows == 1 and rowwidths[1] < width*0.75 - 18) then
- padding = (width - rowwidths[row]) / (endtab - starttab+1)
- end
-
- for i = starttab, endtab do
- PanelTemplates_TabResize(tabs[i], padding + 4, nil, nil, width, tabs[i]:GetFontString():GetStringWidth())
- end
- starttab = endtab + 1
- end
-
- self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)
- self.border:SetPoint("TOPLEFT", 1, -self.borderoffset)
- end,
-
- ["OnWidthSet"] = function(self, width)
- local content = self.content
- local contentwidth = width - 60
- if contentwidth < 0 then
- contentwidth = 0
- end
- content:SetWidth(contentwidth)
- content.width = contentwidth
- self:BuildTabs(self)
- self.frame:SetScript("OnUpdate", BuildTabsOnUpdate)
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- local contentheight = height - (self.borderoffset + 23)
- if contentheight < 0 then
- contentheight = 0
- end
- content:SetHeight(contentheight)
- content.height = contentheight
- end,
-
- ["LayoutFinished"] = function(self, width, height)
- if self.noAutoHeight then return end
- self:SetHeight((height or 0) + (self.borderoffset + 23))
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local PaneBackdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 3, right = 3, top = 5, bottom = 3 }
-}
-
-local function Constructor()
- local num = AceGUI:GetNextWidgetNum(Type)
- local frame = CreateFrame("Frame",nil,UIParent)
- frame:SetHeight(100)
- frame:SetWidth(100)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
- titletext:SetPoint("TOPLEFT", 14, 0)
- titletext:SetPoint("TOPRIGHT", -14, 0)
- titletext:SetJustifyH("LEFT")
- titletext:SetHeight(18)
- titletext:SetText("")
-
- local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
- border:SetPoint("TOPLEFT", 1, -27)
- border:SetPoint("BOTTOMRIGHT", -1, 3)
- border:SetBackdrop(PaneBackdrop)
- border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
- border:SetBackdropBorderColor(0.4, 0.4, 0.4)
-
- local content = CreateFrame("Frame", nil, border)
- content:SetPoint("TOPLEFT", 10, -7)
- content:SetPoint("BOTTOMRIGHT", -10, 7)
-
- local widget = {
- num = num,
- frame = frame,
- localstatus = {},
- alignoffset = 18,
- titletext = titletext,
- border = border,
- borderoffset = 27,
- tabs = {},
- content = content,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+TabGroup Container
+Container that uses tabs on top to switch between groups.
+-------------------------------------------------------------------------------]]
+local Type, Version = "TabGroup", 38
+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, table.wipe
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+local _G = _G
+
+-- local upvalue storage used by BuildTabs
+local widths = {}
+local rowwidths = {}
+local rowends = {}
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+local function PanelTemplates_TabResize(tab, padding, absoluteSize, minWidth, maxWidth, absoluteTextSize)
+ local tabName = tab:GetName();
+
+ local buttonMiddle = tab.Middle or tab.middleTexture or _G[tabName.."Middle"];
+ local buttonMiddleDisabled = tab.MiddleDisabled or (tabName and _G[tabName.."MiddleDisabled"]);
+ local left = tab.Left or tab.leftTexture or _G[tabName.."Left"];
+ local sideWidths = 2 * left:GetWidth();
+ local tabText = tab.Text or _G[tab:GetName().."Text"];
+ local highlightTexture = tab.HighlightTexture or (tabName and _G[tabName.."HighlightTexture"]);
+
+ local width, tabWidth;
+ local textWidth;
+ if ( absoluteTextSize ) then
+ textWidth = absoluteTextSize;
+ else
+ tabText:SetWidth(0);
+ textWidth = tabText:GetWidth();
+ end
+ -- If there's an absolute size specified then use it
+ if ( absoluteSize ) then
+ if ( absoluteSize < sideWidths) then
+ width = 1;
+ tabWidth = sideWidths
+ else
+ width = absoluteSize - sideWidths;
+ tabWidth = absoluteSize
+ end
+ tabText:SetWidth(width);
+ else
+ -- Otherwise try to use padding
+ if ( padding ) then
+ width = textWidth + padding;
+ else
+ width = textWidth + 24;
+ end
+ -- If greater than the maxWidth then cap it
+ if ( maxWidth and width > maxWidth ) then
+ if ( padding ) then
+ width = maxWidth + padding;
+ else
+ width = maxWidth + 24;
+ end
+ tabText:SetWidth(width);
+ else
+ tabText:SetWidth(0);
+ end
+ if (minWidth and width < minWidth) then
+ width = minWidth;
+ end
+ tabWidth = width + sideWidths;
+ end
+
+ if ( buttonMiddle ) then
+ buttonMiddle:SetWidth(width);
+ end
+ if ( buttonMiddleDisabled ) then
+ buttonMiddleDisabled:SetWidth(width);
+ end
+
+ tab:SetWidth(tabWidth);
+
+ if ( highlightTexture ) then
+ highlightTexture:SetWidth(tabWidth);
+ end
+end
+
+local function PanelTemplates_DeselectTab(tab)
+ local name = tab:GetName();
+
+ local left = tab.Left or _G[name.."Left"];
+ local middle = tab.Middle or _G[name.."Middle"];
+ local right = tab.Right or _G[name.."Right"];
+ left:Show();
+ middle:Show();
+ right:Show();
+ --tab:UnlockHighlight();
+ tab:Enable();
+ local text = tab.Text or _G[name.."Text"];
+ text:SetPoint("CENTER", tab, "CENTER", (tab.deselectedTextX or 0), (tab.deselectedTextY or 2));
+
+ local leftDisabled = tab.LeftDisabled or _G[name.."LeftDisabled"];
+ local middleDisabled = tab.MiddleDisabled or _G[name.."MiddleDisabled"];
+ local rightDisabled = tab.RightDisabled or _G[name.."RightDisabled"];
+ leftDisabled:Hide();
+ middleDisabled:Hide();
+ rightDisabled:Hide();
+end
+
+local function PanelTemplates_SelectTab(tab)
+ local name = tab:GetName();
+
+ local left = tab.Left or _G[name.."Left"];
+ local middle = tab.Middle or _G[name.."Middle"];
+ local right = tab.Right or _G[name.."Right"];
+ left:Hide();
+ middle:Hide();
+ right:Hide();
+ --tab:LockHighlight();
+ tab:Disable();
+ tab:SetDisabledFontObject(GameFontHighlightSmall);
+ local text = tab.Text or _G[name.."Text"];
+ text:SetPoint("CENTER", tab, "CENTER", (tab.selectedTextX or 0), (tab.selectedTextY or -3));
+
+ local leftDisabled = tab.LeftDisabled or _G[name.."LeftDisabled"];
+ local middleDisabled = tab.MiddleDisabled or _G[name.."MiddleDisabled"];
+ local rightDisabled = tab.RightDisabled or _G[name.."RightDisabled"];
+ leftDisabled:Show();
+ middleDisabled:Show();
+ rightDisabled:Show();
+
+ if GameTooltip:IsOwned(tab) then
+ GameTooltip:Hide();
+ end
+end
+
+local function PanelTemplates_SetDisabledTabState(tab)
+ local name = tab:GetName();
+ local left = tab.Left or _G[name.."Left"];
+ local middle = tab.Middle or _G[name.."Middle"];
+ local right = tab.Right or _G[name.."Right"];
+ left:Show();
+ middle:Show();
+ right:Show();
+ --tab:UnlockHighlight();
+ tab:Disable();
+ tab.text = tab:GetText();
+ -- Gray out text
+ tab:SetDisabledFontObject(GameFontDisableSmall);
+ local leftDisabled = tab.LeftDisabled or _G[name.."LeftDisabled"];
+ local middleDisabled = tab.MiddleDisabled or _G[name.."MiddleDisabled"];
+ local rightDisabled = tab.RightDisabled or _G[name.."RightDisabled"];
+ leftDisabled:Hide();
+ middleDisabled:Hide();
+ rightDisabled:Hide();
+end
+
+local function UpdateTabLook(frame)
+ if frame.disabled then
+ PanelTemplates_SetDisabledTabState(frame)
+ elseif frame.selected then
+ PanelTemplates_SelectTab(frame)
+ else
+ PanelTemplates_DeselectTab(frame)
+ end
+end
+
+local function Tab_SetText(frame, text)
+ frame:_SetText(text)
+ local width = frame.obj.frame.width or frame.obj.frame:GetWidth() or 0
+ PanelTemplates_TabResize(frame, 0, nil, nil, width, frame:GetFontString():GetStringWidth())
+end
+
+local function Tab_SetSelected(frame, selected)
+ frame.selected = selected
+ UpdateTabLook(frame)
+end
+
+local function Tab_SetDisabled(frame, disabled)
+ frame.disabled = disabled
+ UpdateTabLook(frame)
+end
+
+local function BuildTabsOnUpdate(frame)
+ local self = frame.obj
+ self:BuildTabs()
+ frame:SetScript("OnUpdate", nil)
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Tab_OnClick(frame)
+ if not (frame.selected or frame.disabled) then
+ PlaySound(841) -- SOUNDKIT.IG_CHARACTER_INFO_TAB
+ frame.obj:SelectTab(frame.value)
+ end
+end
+
+local function Tab_OnEnter(frame)
+ local self = frame.obj
+ self:Fire("OnTabEnter", self.tabs[frame.id].value, frame)
+end
+
+local function Tab_OnLeave(frame)
+ local self = frame.obj
+ self:Fire("OnTabLeave", self.tabs[frame.id].value, frame)
+end
+
+local function Tab_OnShow(frame)
+ _G[frame:GetName().."HighlightTexture"]:SetWidth(frame:GetTextWidth() + 30)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetTitle()
+ end,
+
+ ["OnRelease"] = function(self)
+ self.status = nil
+ for k in pairs(self.localstatus) do
+ self.localstatus[k] = nil
+ end
+ self.tablist = nil
+ for _, tab in pairs(self.tabs) do
+ tab:Hide()
+ end
+ end,
+
+ ["CreateTab"] = function(self, id)
+ local tabname = ("AceGUITabGroup%dTab%d"):format(self.num, id)
+ local tab = CreateFrame("Button", tabname, self.border)
+ tab:SetSize(115, 24)
+ tab.deselectedTextY = -3
+ tab.selectedTextY = -2
+
+ tab.LeftDisabled = tab:CreateTexture(tabname .. "LeftDisabled", "BORDER")
+ tab.LeftDisabled:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
+ tab.LeftDisabled:SetSize(20, 24)
+ tab.LeftDisabled:SetPoint("BOTTOMLEFT", 0, -3)
+ tab.LeftDisabled:SetTexCoord(0, 0.15625, 0, 1.0)
+
+ tab.MiddleDisabled = tab:CreateTexture(tabname .. "MiddleDisabled", "BORDER")
+ tab.MiddleDisabled:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
+ tab.MiddleDisabled:SetSize(88, 24)
+ tab.MiddleDisabled:SetPoint("LEFT", tab.LeftDisabled, "RIGHT")
+ tab.MiddleDisabled:SetTexCoord(0.15625, 0.84375, 0, 1.0)
+
+ tab.RightDisabled = tab:CreateTexture(tabname .. "RightDisabled", "BORDER")
+ tab.RightDisabled:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-ActiveTab")
+ tab.RightDisabled:SetSize(20, 24)
+ tab.RightDisabled:SetPoint("LEFT", tab.MiddleDisabled, "RIGHT")
+ tab.RightDisabled:SetTexCoord(0.84375, 1.0, 0, 1.0)
+
+ tab.Left = tab:CreateTexture(tabname .. "Left", "BORDER")
+ tab.Left:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
+ tab.Left:SetSize(20, 24)
+ tab.Left:SetPoint("TOPLEFT")
+ tab.Left:SetTexCoord(0, 0.15625, 0, 1.0)
+
+ tab.Middle = tab:CreateTexture(tabname .. "Middle", "BORDER")
+ tab.Middle:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
+ tab.Middle:SetSize(88, 24)
+ tab.Middle:SetPoint("LEFT", tab.Left, "RIGHT")
+ tab.Middle:SetTexCoord(0.15625, 0.84375, 0, 1.0)
+
+ tab.Right = tab:CreateTexture(tabname .. "Right", "BORDER")
+ tab.Right:SetTexture("Interface\\OptionsFrame\\UI-OptionsFrame-InActiveTab")
+ tab.Right:SetSize(20, 24)
+ tab.Right:SetPoint("LEFT", tab.Middle, "RIGHT")
+ tab.Right:SetTexCoord(0.84375, 1.0, 0, 1.0)
+
+ tab.Text = tab:CreateFontString(tabname .. "Text")
+ tab:SetFontString(tab.Text)
+
+ tab:SetNormalFontObject(GameFontNormalSmall)
+ tab:SetHighlightFontObject(GameFontHighlightSmall)
+ tab:SetDisabledFontObject(GameFontHighlightSmall)
+ tab:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight", "ADD")
+ tab.HighlightTexture = tab:GetHighlightTexture()
+ tab.HighlightTexture:ClearAllPoints()
+ tab.HighlightTexture:SetPoint("LEFT", tab, "LEFT", 10, -4)
+ tab.HighlightTexture:SetPoint("RIGHT", tab, "RIGHT", -10, -4)
+ _G[tabname .. "HighlightTexture"] = tab.HighlightTexture
+
+ tab.obj = self
+ tab.id = id
+
+ tab.text = tab.Text -- compat
+ tab.text:ClearAllPoints()
+ tab.text:SetPoint("LEFT", 14, -3)
+ tab.text:SetPoint("RIGHT", -12, -3)
+
+ tab:SetScript("OnClick", Tab_OnClick)
+ tab:SetScript("OnEnter", Tab_OnEnter)
+ tab:SetScript("OnLeave", Tab_OnLeave)
+ tab:SetScript("OnShow", Tab_OnShow)
+
+ tab._SetText = tab.SetText
+ tab.SetText = Tab_SetText
+ tab.SetSelected = Tab_SetSelected
+ tab.SetDisabled = Tab_SetDisabled
+
+ return tab
+ end,
+
+ ["SetTitle"] = function(self, text)
+ self.titletext:SetText(text or "")
+ if text and text ~= "" then
+ self.alignoffset = 25
+ else
+ self.alignoffset = 18
+ end
+ self:BuildTabs()
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ end,
+
+ ["SelectTab"] = function(self, value)
+ local status = self.status or self.localstatus
+ local found
+ for i, v in ipairs(self.tabs) do
+ if v.value == value then
+ v:SetSelected(true)
+ found = true
+ else
+ v:SetSelected(false)
+ end
+ end
+ status.selected = value
+ if found then
+ self:Fire("OnGroupSelected",value)
+ end
+ end,
+
+ ["SetTabs"] = function(self, tabs)
+ self.tablist = tabs
+ self:BuildTabs()
+ end,
+
+
+ ["BuildTabs"] = function(self)
+ local hastitle = (self.titletext:GetText() and self.titletext:GetText() ~= "")
+ local tablist = self.tablist
+ local tabs = self.tabs
+
+ if not tablist then return end
+
+ local width = self.frame.width or self.frame:GetWidth() or 0
+
+ wipe(widths)
+ wipe(rowwidths)
+ wipe(rowends)
+
+ --Place Text into tabs and get thier initial width
+ for i, v in ipairs(tablist) do
+ local tab = tabs[i]
+ if not tab then
+ tab = self:CreateTab(i)
+ tabs[i] = tab
+ end
+
+ tab:Show()
+ tab:SetText(v.text)
+ tab:SetDisabled(v.disabled)
+ tab.value = v.value
+
+ 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
+
+ for i = (#tablist)+1, #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 = #tablist
+ local numrows = 1
+ local usedwidth = 0
+
+ for i = 1, #tablist do
+ --If this is not the first tab of a row and there isn't room for it
+ if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
+ rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
+ rowends[numrows] = i - 1
+ numrows = numrows + 1
+ usedwidth = 0
+ end
+ usedwidth = usedwidth + widths[i]
+ end
+ rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
+ rowends[numrows] = #tablist
+
+ --Fix for single tabs being left on the last row, move a tab from the row above if applicable
+ if numrows > 1 then
+ --if the last row has only one tab
+ if rowends[numrows-1] == numtabs-1 then
+ --if there are more than 2 tabs in the 2nd last row
+ if (numrows == 2 and rowends[numrows-1] > 2) or (rowends[numrows] - rowends[numrows-1] > 2) then
+ --move 1 tab from the second last row to the last, if there is enough space
+ if (rowwidths[numrows] + widths[numtabs-1]) <= width then
+ rowends[numrows-1] = rowends[numrows-1] - 1
+ rowwidths[numrows] = rowwidths[numrows] + widths[numtabs-1]
+ rowwidths[numrows-1] = rowwidths[numrows-1] - widths[numtabs-1]
+ end
+ end
+ end
+ end
+
+ --anchor the rows as defined and resize tabs to fill thier row
+ local starttab = 1
+ for row, endtab in ipairs(rowends) do
+ local first = true
+ for tabno = starttab, endtab do
+ local tab = tabs[tabno]
+ tab:ClearAllPoints()
+ if first then
+ tab:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -(hastitle and 14 or 7)-(row-1)*20 )
+ first = false
+ else
+ tab:SetPoint("LEFT", tabs[tabno-1], "RIGHT", -10, 0)
+ end
+ end
+
+ -- equal padding for each tab to fill the available width,
+ -- if the used space is above 75% already
+ -- the 18 pixel is the typical width of a scrollbar, so we can have a tab group inside a scrolling frame,
+ -- and not have the tabs jump around funny when switching between tabs that need scrolling and those that don't
+ local padding = 0
+ if not (numrows == 1 and rowwidths[1] < width*0.75 - 18) then
+ padding = (width - rowwidths[row]) / (endtab - starttab+1)
+ end
+
+ for i = starttab, endtab do
+ PanelTemplates_TabResize(tabs[i], padding + 4, nil, nil, width, tabs[i]:GetFontString():GetStringWidth())
+ end
+ starttab = endtab + 1
+ end
+
+ self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)
+ self.border:SetPoint("TOPLEFT", 1, -self.borderoffset)
+ end,
+
+ ["OnWidthSet"] = function(self, width)
+ local content = self.content
+ local contentwidth = width - 60
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ self:BuildTabs(self)
+ self.frame:SetScript("OnUpdate", BuildTabsOnUpdate)
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - (self.borderoffset + 23)
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight((height or 0) + (self.borderoffset + 23))
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local function Constructor()
+ local num = AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Frame",nil,UIParent)
+ frame:SetHeight(100)
+ frame:SetWidth(100)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
+ titletext:SetPoint("TOPLEFT", 14, 0)
+ titletext:SetPoint("TOPRIGHT", -14, 0)
+ titletext:SetJustifyH("LEFT")
+ titletext:SetHeight(18)
+ titletext:SetText("")
+
+ local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
+ border:SetPoint("TOPLEFT", 1, -27)
+ border:SetPoint("BOTTOMRIGHT", -1, 3)
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ border:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -7)
+ content:SetPoint("BOTTOMRIGHT", -10, 7)
+
+ local widget = {
+ num = num,
+ frame = frame,
+ localstatus = {},
+ alignoffset = 18,
+ titletext = titletext,
+ border = border,
+ borderoffset = 27,
+ tabs = {},
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
index ca9b2df..89f387a 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua
@@ -1,719 +1,719 @@
---[[-----------------------------------------------------------------------------
-TreeGroup Container
-Container that uses a tree control to switch between groups.
--------------------------------------------------------------------------------]]
-local Type, Version = "TreeGroup", 47
-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 next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
-local math_min, math_max, floor = math.min, math.max, math.floor
-local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
--- Recycling functions
-local new, del
-do
- local pool = setmetatable({},{__mode='k'})
- function new()
- local t = next(pool)
- if t then
- pool[t] = nil
- return t
- else
- return {}
- end
- end
- function del(t)
- for k in pairs(t) do
- t[k] = nil
- end
- pool[t] = true
- end
-end
-
-local DEFAULT_TREE_WIDTH = 175
-local DEFAULT_TREE_SIZABLE = true
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-local function GetButtonUniqueValue(line)
- local parent = line.parent
- if parent and parent.value then
- return GetButtonUniqueValue(parent).."\001"..line.value
- else
- return line.value
- end
-end
-
-local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
- local self = button.obj
- local toggle = button.toggle
- local text = treeline.text or ""
- local icon = treeline.icon
- local iconCoords = treeline.iconCoords
- local level = treeline.level
- local value = treeline.value
- local uniquevalue = treeline.uniquevalue
- local disabled = treeline.disabled
-
- button.treeline = treeline
- button.value = value
- button.uniquevalue = uniquevalue
- if selected then
- button:LockHighlight()
- button.selected = true
- else
- button:UnlockHighlight()
- button.selected = false
- end
- button.level = level
- if ( level == 1 ) then
- button:SetNormalFontObject("GameFontNormal")
- button:SetHighlightFontObject("GameFontHighlight")
- button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
- else
- button:SetNormalFontObject("GameFontHighlightSmall")
- button:SetHighlightFontObject("GameFontHighlightSmall")
- button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
- end
-
- if disabled then
- button:EnableMouse(false)
- button.text:SetText("|cff808080"..text..FONT_COLOR_CODE_CLOSE)
- else
- button.text:SetText(text)
- button:EnableMouse(true)
- end
-
- if icon then
- button.icon:SetTexture(icon)
- button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
- else
- button.icon:SetTexture(nil)
- end
-
- if iconCoords then
- button.icon:SetTexCoord(unpack(iconCoords))
- else
- button.icon:SetTexCoord(0, 1, 0, 1)
- end
-
- if canExpand then
- if not isExpanded then
- toggle:SetNormalTexture(130838) -- Interface\\Buttons\\UI-PlusButton-UP
- toggle:SetPushedTexture(130836) -- Interface\\Buttons\\UI-PlusButton-DOWN
- else
- toggle:SetNormalTexture(130821) -- Interface\\Buttons\\UI-MinusButton-UP
- toggle:SetPushedTexture(130820) -- Interface\\Buttons\\UI-MinusButton-DOWN
- end
- toggle:Show()
- else
- toggle:Hide()
- end
-end
-
-local function ShouldDisplayLevel(tree)
- local result = false
- for k, v in ipairs(tree) do
- if v.children == nil and v.visible ~= false then
- result = true
- elseif v.children then
- result = result or ShouldDisplayLevel(v.children)
- end
- if result then return result end
- end
- return false
-end
-
-local function addLine(self, v, tree, level, parent)
- local line = new()
- line.value = v.value
- line.text = v.text
- line.icon = v.icon
- line.iconCoords = v.iconCoords
- line.disabled = v.disabled
- line.tree = tree
- line.level = level
- line.parent = parent
- line.visible = v.visible
- line.uniquevalue = GetButtonUniqueValue(line)
- if v.children then
- line.hasChildren = true
- else
- line.hasChildren = nil
- end
- self.lines[#self.lines+1] = line
- return line
-end
-
---fire an update after one frame to catch the treeframes height
-local function FirstFrameUpdate(frame)
- local self = frame.obj
- frame:SetScript("OnUpdate", nil)
- self:RefreshTree(nil, true)
-end
-
-local function BuildUniqueValue(...)
- local n = select('#', ...)
- if n == 1 then
- return ...
- else
- return (...).."\001"..BuildUniqueValue(select(2,...))
- end
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Expand_OnClick(frame)
- local button = frame.button
- local self = button.obj
- local status = (self.status or self.localstatus).groups
- status[button.uniquevalue] = not status[button.uniquevalue]
- self:RefreshTree()
-end
-
-local function Button_OnClick(frame)
- local self = frame.obj
- self:Fire("OnClick", frame.uniquevalue, frame.selected)
- if not frame.selected then
- self:SetSelected(frame.uniquevalue)
- frame.selected = true
- frame:LockHighlight()
- self:RefreshTree()
- end
- AceGUI:ClearFocus()
-end
-
-local function Button_OnDoubleClick(button)
- local self = button.obj
- local status = (self.status or self.localstatus).groups
- status[button.uniquevalue] = not status[button.uniquevalue]
- self:RefreshTree()
-end
-
-local function Button_OnEnter(frame)
- local self = frame.obj
- self:Fire("OnButtonEnter", frame.uniquevalue, frame)
-
- if self.enabletooltips then
- local tooltip = AceGUI.tooltip
- tooltip:SetOwner(frame, "ANCHOR_NONE")
- tooltip:ClearAllPoints()
- tooltip:SetPoint("LEFT",frame,"RIGHT")
- tooltip:SetText(frame.text:GetText() or "", 1, .82, 0, true)
-
- tooltip:Show()
- end
-end
-
-local function Button_OnLeave(frame)
- local self = frame.obj
- self:Fire("OnButtonLeave", frame.uniquevalue, frame)
-
- if self.enabletooltips then
- AceGUI.tooltip:Hide()
- end
-end
-
-local function OnScrollValueChanged(frame, value)
- if frame.obj.noupdate then return end
- local self = frame.obj
- local status = self.status or self.localstatus
- status.scrollvalue = floor(value + 0.5)
- self:RefreshTree()
- AceGUI:ClearFocus()
-end
-
-local function Tree_OnSizeChanged(frame)
- frame.obj:RefreshTree()
-end
-
-local function Tree_OnMouseWheel(frame, delta)
- local self = frame.obj
- if self.showscroll then
- local scrollbar = self.scrollbar
- local min, max = scrollbar:GetMinMaxValues()
- local value = scrollbar:GetValue()
- local newvalue = math_min(max,math_max(min,value - delta))
- if value ~= newvalue then
- scrollbar:SetValue(newvalue)
- end
- end
-end
-
-local function Dragger_OnLeave(frame)
- frame:SetBackdropColor(1, 1, 1, 0)
-end
-
-local function Dragger_OnEnter(frame)
- frame:SetBackdropColor(1, 1, 1, 0.8)
-end
-
-local function Dragger_OnMouseDown(frame)
- local treeframe = frame:GetParent()
- treeframe:StartSizing("RIGHT")
-end
-
-local function Dragger_OnMouseUp(frame)
- local treeframe = frame:GetParent()
- local self = treeframe.obj
- local treeframeParent = 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:ClearAllPoints()
- treeframe:SetPoint("TOPLEFT", treeframeParent, "TOPLEFT",0,0)
- treeframe:SetPoint("BOTTOMLEFT", treeframeParent, "BOTTOMLEFT",0,0)
-
- local status = self.status or self.localstatus
- status.treewidth = treeframe:GetWidth()
-
- treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
- -- recalculate the content width
- treeframe.obj:OnWidthSet(status.fullwidth)
- -- update the layout of the content
- treeframe.obj:DoLayout()
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-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)
- self.status = nil
- self.tree = nil
- self.frame:SetScript("OnUpdate", nil)
- for k, v in pairs(self.localstatus) do
- if k == "groups" then
- for k2 in pairs(v) do
- v[k2] = nil
- end
- else
- self.localstatus[k] = nil
- end
- end
- self.localstatus.scrollvalue = 0
- self.localstatus.treewidth = DEFAULT_TREE_WIDTH
- self.localstatus.treesizable = DEFAULT_TREE_SIZABLE
- end,
-
- ["EnableButtonTooltips"] = function(self, enable)
- self.enabletooltips = enable
- end,
-
- ["CreateButton"] = function(self)
- local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
- local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), self.treeframe, "OptionsListButtonTemplate")
- button.obj = self
-
- local icon = button:CreateTexture(nil, "OVERLAY")
- icon:SetWidth(14)
- icon:SetHeight(14)
- button.icon = icon
-
- button:SetScript("OnClick",Button_OnClick)
- button:SetScript("OnDoubleClick", Button_OnDoubleClick)
- button:SetScript("OnEnter",Button_OnEnter)
- button:SetScript("OnLeave",Button_OnLeave)
-
- button.toggle.button = button
- button.toggle:SetScript("OnClick",Expand_OnClick)
-
- button.text:SetHeight(14) -- Prevents text wrapping
-
- return button
- end,
-
- ["SetStatusTable"] = function(self, status)
- assert(type(status) == "table")
- self.status = status
- if not status.groups then
- status.groups = {}
- end
- if not status.scrollvalue then
- status.scrollvalue = 0
- end
- if not status.treewidth then
- status.treewidth = DEFAULT_TREE_WIDTH
- end
- if status.treesizable == nil then
- status.treesizable = DEFAULT_TREE_SIZABLE
- end
- self:SetTreeWidth(status.treewidth,status.treesizable)
- self:RefreshTree()
- end,
-
- --sets the tree to be displayed
- ["SetTree"] = function(self, tree, filter)
- self.filter = filter
- if tree then
- assert(type(tree) == "table")
- end
- self.tree = tree
- self:RefreshTree()
- end,
-
- ["BuildLevel"] = function(self, tree, level, parent)
- local groups = (self.status or self.localstatus).groups
-
- for i, v in ipairs(tree) do
- if v.children then
- if not self.filter or ShouldDisplayLevel(v.children) then
- local line = addLine(self, v, tree, level, parent)
- if groups[line.uniquevalue] then
- self:BuildLevel(v.children, level+1, line)
- end
- end
- elseif v.visible ~= false or not self.filter then
- addLine(self, v, tree, level, parent)
- end
- end
- end,
-
- ["RefreshTree"] = function(self,scrollToSelection,fromOnUpdate)
- local buttons = self.buttons
- local lines = self.lines
-
- for i, v in ipairs(buttons) do
- v:Hide()
- end
- while lines[1] do
- local t = tremove(lines)
- for k in pairs(t) do
- t[k] = nil
- end
- del(t)
- end
-
- if not self.tree then return end
- --Build the list of visible entries from the tree and status tables
- local status = self.status or self.localstatus
- local groupstatus = status.groups
- local tree = self.tree
-
- local treeframe = self.treeframe
-
- status.scrollToSelection = status.scrollToSelection or scrollToSelection -- needs to be cached in case the control hasn't been drawn yet (code bails out below)
-
- self:BuildLevel(tree, 1)
-
- local numlines = #lines
-
- local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
- if maxlines <= 0 then return end
-
- if self.frame:GetParent() == UIParent and not fromOnUpdate then
- self.frame:SetScript("OnUpdate", FirstFrameUpdate)
- return
- end
-
- local first, last
-
- scrollToSelection = status.scrollToSelection
- status.scrollToSelection = nil
-
- if numlines <= maxlines then
- --the whole tree fits in the frame
- status.scrollvalue = 0
- self:ShowScroll(false)
- first, last = 1, numlines
- else
- self:ShowScroll(true)
- --scrolling will be needed
- self.noupdate = true
- self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
- --check if we are scrolled down too far
- if numlines - status.scrollvalue < maxlines then
- status.scrollvalue = numlines - maxlines
- end
- self.noupdate = nil
- first, last = status.scrollvalue+1, status.scrollvalue + maxlines
- --show selection?
- if scrollToSelection and status.selected then
- local show
- for i,line in ipairs(lines) do -- find the line number
- if line.uniquevalue==status.selected then
- show=i
- end
- end
- if not show then
- -- selection was deleted or something?
- elseif show>=first and show<=last then
- -- all good
- else
- -- scrolling needed!
- if show 100 and status.treewidth > maxtreewidth then
- self:SetTreeWidth(maxtreewidth, status.treesizable)
- end
- if treeframe.SetResizeBounds then
- treeframe:SetResizeBounds(100, 1, maxtreewidth, 1600)
- else
- treeframe:SetMaxResize(maxtreewidth, 1600)
- end
- end,
-
- ["OnHeightSet"] = function(self, height)
- local content = self.content
- local contentheight = height - 20
- if contentheight < 0 then
- contentheight = 0
- end
- content:SetHeight(contentheight)
- content.height = contentheight
- end,
-
- ["SetTreeWidth"] = function(self, treewidth, resizable)
- if not resizable then
- if type(treewidth) == 'number' then
- resizable = false
- elseif type(treewidth) == 'boolean' then
- resizable = treewidth
- treewidth = DEFAULT_TREE_WIDTH
- else
- resizable = false
- treewidth = DEFAULT_TREE_WIDTH
- end
- end
- self.treeframe:SetWidth(treewidth)
- self.dragger:EnableMouse(resizable)
-
- local status = self.status or self.localstatus
- status.treewidth = treewidth
- status.treesizable = resizable
-
- -- recalculate the content width
- if status.fullwidth then
- self:OnWidthSet(status.fullwidth)
- end
- end,
-
- ["GetTreeWidth"] = function(self)
- local status = self.status or self.localstatus
- return status.treewidth or DEFAULT_TREE_WIDTH
- end,
-
- ["LayoutFinished"] = function(self, width, height)
- if self.noAutoHeight then return end
- self:SetHeight((height or 0) + 20)
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local PaneBackdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 3, right = 3, top = 5, bottom = 3 }
-}
-
-local DraggerBackdrop = {
- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
- edgeFile = nil,
- tile = true, tileSize = 16, edgeSize = 1,
- insets = { left = 3, right = 3, top = 7, bottom = 7 }
-}
-
-local function Constructor()
- local num = AceGUI:GetNextWidgetNum(Type)
- local frame = CreateFrame("Frame", nil, UIParent)
-
- local treeframe = CreateFrame("Frame", nil, frame, "BackdropTemplate")
- treeframe:SetPoint("TOPLEFT")
- treeframe:SetPoint("BOTTOMLEFT")
- treeframe:SetWidth(DEFAULT_TREE_WIDTH)
- treeframe:EnableMouseWheel(true)
- treeframe:SetBackdrop(PaneBackdrop)
- treeframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
- treeframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
- treeframe:SetResizable(true)
- if treeframe.SetResizeBounds then -- WoW 10.0
- treeframe:SetResizeBounds(100, 1, 400, 1600)
- else
- treeframe:SetMinResize(100, 1)
- treeframe:SetMaxResize(400, 1600)
- end
- treeframe:SetScript("OnUpdate", FirstFrameUpdate)
- treeframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
- treeframe:SetScript("OnMouseWheel", Tree_OnMouseWheel)
-
- local dragger = CreateFrame("Frame", nil, treeframe, "BackdropTemplate")
- dragger:SetWidth(8)
- dragger:SetPoint("TOP", treeframe, "TOPRIGHT")
- dragger:SetPoint("BOTTOM", treeframe, "BOTTOMRIGHT")
- dragger:SetBackdrop(DraggerBackdrop)
- dragger:SetBackdropColor(1, 1, 1, 0)
- dragger:SetScript("OnEnter", Dragger_OnEnter)
- dragger:SetScript("OnLeave", Dragger_OnLeave)
- dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
- dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
-
- local scrollbar = CreateFrame("Slider", ("AceConfigDialogTreeGroup%dScrollBar"):format(num), treeframe, "UIPanelScrollBarTemplate")
- scrollbar:SetScript("OnValueChanged", nil)
- scrollbar:SetPoint("TOPRIGHT", -10, -26)
- scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
- scrollbar:SetMinMaxValues(0,0)
- scrollbar:SetValueStep(1)
- scrollbar:SetValue(0)
- scrollbar:SetWidth(16)
- scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
-
- local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
- scrollbg:SetAllPoints(scrollbar)
- scrollbg:SetColorTexture(0,0,0,0.4)
-
- local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
- border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
- border:SetPoint("BOTTOMRIGHT")
- border:SetBackdrop(PaneBackdrop)
- border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
- border:SetBackdropBorderColor(0.4, 0.4, 0.4)
-
- --Container Support
- local content = CreateFrame("Frame", nil, border)
- content:SetPoint("TOPLEFT", 10, -10)
- content:SetPoint("BOTTOMRIGHT", -10, 10)
-
- local widget = {
- frame = frame,
- lines = {},
- levels = {},
- buttons = {},
- hasChildren = {},
- localstatus = { groups = {}, scrollvalue = 0 },
- filter = false,
- treeframe = treeframe,
- dragger = dragger,
- scrollbar = scrollbar,
- border = border,
- content = content,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- treeframe.obj, dragger.obj, scrollbar.obj = widget, widget, widget
-
- return AceGUI:RegisterAsContainer(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+TreeGroup Container
+Container that uses a tree control to switch between groups.
+-------------------------------------------------------------------------------]]
+local Type, Version = "TreeGroup", 47
+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 next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
+local math_min, math_max, floor = math.min, math.max, math.floor
+local select, tremove, unpack, tconcat = select, table.remove, unpack, table.concat
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Recycling functions
+local new, del
+do
+ local pool = setmetatable({},{__mode='k'})
+ function new()
+ local t = next(pool)
+ if t then
+ pool[t] = nil
+ return t
+ else
+ return {}
+ end
+ end
+ function del(t)
+ for k in pairs(t) do
+ t[k] = nil
+ end
+ pool[t] = true
+ end
+end
+
+local DEFAULT_TREE_WIDTH = 175
+local DEFAULT_TREE_SIZABLE = true
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function GetButtonUniqueValue(line)
+ local parent = line.parent
+ if parent and parent.value then
+ return GetButtonUniqueValue(parent).."\001"..line.value
+ else
+ return line.value
+ end
+end
+
+local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
+ local self = button.obj
+ local toggle = button.toggle
+ local text = treeline.text or ""
+ local icon = treeline.icon
+ local iconCoords = treeline.iconCoords
+ local level = treeline.level
+ local value = treeline.value
+ local uniquevalue = treeline.uniquevalue
+ local disabled = treeline.disabled
+
+ button.treeline = treeline
+ button.value = value
+ button.uniquevalue = uniquevalue
+ if selected then
+ button:LockHighlight()
+ button.selected = true
+ else
+ button:UnlockHighlight()
+ button.selected = false
+ end
+ button.level = level
+ if ( level == 1 ) then
+ button:SetNormalFontObject("GameFontNormal")
+ button:SetHighlightFontObject("GameFontHighlight")
+ button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
+ else
+ button:SetNormalFontObject("GameFontHighlightSmall")
+ button:SetHighlightFontObject("GameFontHighlightSmall")
+ button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
+ end
+
+ if disabled then
+ button:EnableMouse(false)
+ button.text:SetText("|cff808080"..text..FONT_COLOR_CODE_CLOSE)
+ else
+ button.text:SetText(text)
+ button:EnableMouse(true)
+ end
+
+ if icon then
+ button.icon:SetTexture(icon)
+ button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
+ else
+ button.icon:SetTexture(nil)
+ end
+
+ if iconCoords then
+ button.icon:SetTexCoord(unpack(iconCoords))
+ else
+ button.icon:SetTexCoord(0, 1, 0, 1)
+ end
+
+ if canExpand then
+ if not isExpanded then
+ toggle:SetNormalTexture(130838) -- Interface\\Buttons\\UI-PlusButton-UP
+ toggle:SetPushedTexture(130836) -- Interface\\Buttons\\UI-PlusButton-DOWN
+ else
+ toggle:SetNormalTexture(130821) -- Interface\\Buttons\\UI-MinusButton-UP
+ toggle:SetPushedTexture(130820) -- Interface\\Buttons\\UI-MinusButton-DOWN
+ end
+ toggle:Show()
+ else
+ toggle:Hide()
+ end
+end
+
+local function ShouldDisplayLevel(tree)
+ local result = false
+ for k, v in ipairs(tree) do
+ if v.children == nil and v.visible ~= false then
+ result = true
+ elseif v.children then
+ result = result or ShouldDisplayLevel(v.children)
+ end
+ if result then return result end
+ end
+ return false
+end
+
+local function addLine(self, v, tree, level, parent)
+ local line = new()
+ line.value = v.value
+ line.text = v.text
+ line.icon = v.icon
+ line.iconCoords = v.iconCoords
+ line.disabled = v.disabled
+ line.tree = tree
+ line.level = level
+ line.parent = parent
+ line.visible = v.visible
+ line.uniquevalue = GetButtonUniqueValue(line)
+ if v.children then
+ line.hasChildren = true
+ else
+ line.hasChildren = nil
+ end
+ self.lines[#self.lines+1] = line
+ return line
+end
+
+--fire an update after one frame to catch the treeframes height
+local function FirstFrameUpdate(frame)
+ local self = frame.obj
+ frame:SetScript("OnUpdate", nil)
+ self:RefreshTree(nil, true)
+end
+
+local function BuildUniqueValue(...)
+ local n = select('#', ...)
+ if n == 1 then
+ return ...
+ else
+ return (...).."\001"..BuildUniqueValue(select(2,...))
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Expand_OnClick(frame)
+ local button = frame.button
+ local self = button.obj
+ local status = (self.status or self.localstatus).groups
+ status[button.uniquevalue] = not status[button.uniquevalue]
+ self:RefreshTree()
+end
+
+local function Button_OnClick(frame)
+ local self = frame.obj
+ self:Fire("OnClick", frame.uniquevalue, frame.selected)
+ if not frame.selected then
+ self:SetSelected(frame.uniquevalue)
+ frame.selected = true
+ frame:LockHighlight()
+ self:RefreshTree()
+ end
+ AceGUI:ClearFocus()
+end
+
+local function Button_OnDoubleClick(button)
+ local self = button.obj
+ local status = (self.status or self.localstatus).groups
+ status[button.uniquevalue] = not status[button.uniquevalue]
+ self:RefreshTree()
+end
+
+local function Button_OnEnter(frame)
+ local self = frame.obj
+ self:Fire("OnButtonEnter", frame.uniquevalue, frame)
+
+ if self.enabletooltips then
+ local tooltip = AceGUI.tooltip
+ tooltip:SetOwner(frame, "ANCHOR_NONE")
+ tooltip:ClearAllPoints()
+ tooltip:SetPoint("LEFT",frame,"RIGHT")
+ tooltip:SetText(frame.text:GetText() or "", 1, .82, 0, true)
+
+ tooltip:Show()
+ end
+end
+
+local function Button_OnLeave(frame)
+ local self = frame.obj
+ self:Fire("OnButtonLeave", frame.uniquevalue, frame)
+
+ if self.enabletooltips then
+ AceGUI.tooltip:Hide()
+ end
+end
+
+local function OnScrollValueChanged(frame, value)
+ if frame.obj.noupdate then return end
+ local self = frame.obj
+ local status = self.status or self.localstatus
+ status.scrollvalue = floor(value + 0.5)
+ self:RefreshTree()
+ AceGUI:ClearFocus()
+end
+
+local function Tree_OnSizeChanged(frame)
+ frame.obj:RefreshTree()
+end
+
+local function Tree_OnMouseWheel(frame, delta)
+ local self = frame.obj
+ if self.showscroll then
+ local scrollbar = self.scrollbar
+ local min, max = scrollbar:GetMinMaxValues()
+ local value = scrollbar:GetValue()
+ local newvalue = math_min(max,math_max(min,value - delta))
+ if value ~= newvalue then
+ scrollbar:SetValue(newvalue)
+ end
+ end
+end
+
+local function Dragger_OnLeave(frame)
+ frame:SetBackdropColor(1, 1, 1, 0)
+end
+
+local function Dragger_OnEnter(frame)
+ frame:SetBackdropColor(1, 1, 1, 0.8)
+end
+
+local function Dragger_OnMouseDown(frame)
+ local treeframe = frame:GetParent()
+ treeframe:StartSizing("RIGHT")
+end
+
+local function Dragger_OnMouseUp(frame)
+ local treeframe = frame:GetParent()
+ local self = treeframe.obj
+ local treeframeParent = 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:ClearAllPoints()
+ treeframe:SetPoint("TOPLEFT", treeframeParent, "TOPLEFT",0,0)
+ treeframe:SetPoint("BOTTOMLEFT", treeframeParent, "BOTTOMLEFT",0,0)
+
+ local status = self.status or self.localstatus
+ status.treewidth = treeframe:GetWidth()
+
+ treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
+ -- recalculate the content width
+ treeframe.obj:OnWidthSet(status.fullwidth)
+ -- update the layout of the content
+ treeframe.obj:DoLayout()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+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)
+ self.status = nil
+ self.tree = nil
+ self.frame:SetScript("OnUpdate", nil)
+ for k, v in pairs(self.localstatus) do
+ if k == "groups" then
+ for k2 in pairs(v) do
+ v[k2] = nil
+ end
+ else
+ self.localstatus[k] = nil
+ end
+ end
+ self.localstatus.scrollvalue = 0
+ self.localstatus.treewidth = DEFAULT_TREE_WIDTH
+ self.localstatus.treesizable = DEFAULT_TREE_SIZABLE
+ end,
+
+ ["EnableButtonTooltips"] = function(self, enable)
+ self.enabletooltips = enable
+ end,
+
+ ["CreateButton"] = function(self)
+ local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
+ local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), self.treeframe, "OptionsListButtonTemplate")
+ button.obj = self
+
+ local icon = button:CreateTexture(nil, "OVERLAY")
+ icon:SetWidth(14)
+ icon:SetHeight(14)
+ button.icon = icon
+
+ button:SetScript("OnClick",Button_OnClick)
+ button:SetScript("OnDoubleClick", Button_OnDoubleClick)
+ button:SetScript("OnEnter",Button_OnEnter)
+ button:SetScript("OnLeave",Button_OnLeave)
+
+ button.toggle.button = button
+ button.toggle:SetScript("OnClick",Expand_OnClick)
+
+ button.text:SetHeight(14) -- Prevents text wrapping
+
+ return button
+ end,
+
+ ["SetStatusTable"] = function(self, status)
+ assert(type(status) == "table")
+ self.status = status
+ if not status.groups then
+ status.groups = {}
+ end
+ if not status.scrollvalue then
+ status.scrollvalue = 0
+ end
+ if not status.treewidth then
+ status.treewidth = DEFAULT_TREE_WIDTH
+ end
+ if status.treesizable == nil then
+ status.treesizable = DEFAULT_TREE_SIZABLE
+ end
+ self:SetTreeWidth(status.treewidth,status.treesizable)
+ self:RefreshTree()
+ end,
+
+ --sets the tree to be displayed
+ ["SetTree"] = function(self, tree, filter)
+ self.filter = filter
+ if tree then
+ assert(type(tree) == "table")
+ end
+ self.tree = tree
+ self:RefreshTree()
+ end,
+
+ ["BuildLevel"] = function(self, tree, level, parent)
+ local groups = (self.status or self.localstatus).groups
+
+ for i, v in ipairs(tree) do
+ if v.children then
+ if not self.filter or ShouldDisplayLevel(v.children) then
+ local line = addLine(self, v, tree, level, parent)
+ if groups[line.uniquevalue] then
+ self:BuildLevel(v.children, level+1, line)
+ end
+ end
+ elseif v.visible ~= false or not self.filter then
+ addLine(self, v, tree, level, parent)
+ end
+ end
+ end,
+
+ ["RefreshTree"] = function(self,scrollToSelection,fromOnUpdate)
+ local buttons = self.buttons
+ local lines = self.lines
+
+ for i, v in ipairs(buttons) do
+ v:Hide()
+ end
+ while lines[1] do
+ local t = tremove(lines)
+ for k in pairs(t) do
+ t[k] = nil
+ end
+ del(t)
+ end
+
+ if not self.tree then return end
+ --Build the list of visible entries from the tree and status tables
+ local status = self.status or self.localstatus
+ local groupstatus = status.groups
+ local tree = self.tree
+
+ local treeframe = self.treeframe
+
+ status.scrollToSelection = status.scrollToSelection or scrollToSelection -- needs to be cached in case the control hasn't been drawn yet (code bails out below)
+
+ self:BuildLevel(tree, 1)
+
+ local numlines = #lines
+
+ local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
+ if maxlines <= 0 then return end
+
+ if self.frame:GetParent() == UIParent and not fromOnUpdate then
+ self.frame:SetScript("OnUpdate", FirstFrameUpdate)
+ return
+ end
+
+ local first, last
+
+ scrollToSelection = status.scrollToSelection
+ status.scrollToSelection = nil
+
+ if numlines <= maxlines then
+ --the whole tree fits in the frame
+ status.scrollvalue = 0
+ self:ShowScroll(false)
+ first, last = 1, numlines
+ else
+ self:ShowScroll(true)
+ --scrolling will be needed
+ self.noupdate = true
+ self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
+ --check if we are scrolled down too far
+ if numlines - status.scrollvalue < maxlines then
+ status.scrollvalue = numlines - maxlines
+ end
+ self.noupdate = nil
+ first, last = status.scrollvalue+1, status.scrollvalue + maxlines
+ --show selection?
+ if scrollToSelection and status.selected then
+ local show
+ for i,line in ipairs(lines) do -- find the line number
+ if line.uniquevalue==status.selected then
+ show=i
+ end
+ end
+ if not show then
+ -- selection was deleted or something?
+ elseif show>=first and show<=last then
+ -- all good
+ else
+ -- scrolling needed!
+ if show 100 and status.treewidth > maxtreewidth then
+ self:SetTreeWidth(maxtreewidth, status.treesizable)
+ end
+ if treeframe.SetResizeBounds then
+ treeframe:SetResizeBounds(100, 1, maxtreewidth, 1600)
+ else
+ treeframe:SetMaxResize(maxtreewidth, 1600)
+ end
+ end,
+
+ ["OnHeightSet"] = function(self, height)
+ local content = self.content
+ local contentheight = height - 20
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ content:SetHeight(contentheight)
+ content.height = contentheight
+ end,
+
+ ["SetTreeWidth"] = function(self, treewidth, resizable)
+ if not resizable then
+ if type(treewidth) == 'number' then
+ resizable = false
+ elseif type(treewidth) == 'boolean' then
+ resizable = treewidth
+ treewidth = DEFAULT_TREE_WIDTH
+ else
+ resizable = false
+ treewidth = DEFAULT_TREE_WIDTH
+ end
+ end
+ self.treeframe:SetWidth(treewidth)
+ self.dragger:EnableMouse(resizable)
+
+ local status = self.status or self.localstatus
+ status.treewidth = treewidth
+ status.treesizable = resizable
+
+ -- recalculate the content width
+ if status.fullwidth then
+ self:OnWidthSet(status.fullwidth)
+ end
+ end,
+
+ ["GetTreeWidth"] = function(self)
+ local status = self.status or self.localstatus
+ return status.treewidth or DEFAULT_TREE_WIDTH
+ end,
+
+ ["LayoutFinished"] = function(self, width, height)
+ if self.noAutoHeight then return end
+ self:SetHeight((height or 0) + 20)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local PaneBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 5, bottom = 3 }
+}
+
+local DraggerBackdrop = {
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = nil,
+ tile = true, tileSize = 16, edgeSize = 1,
+ insets = { left = 3, right = 3, top = 7, bottom = 7 }
+}
+
+local function Constructor()
+ local num = AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Frame", nil, UIParent)
+
+ local treeframe = CreateFrame("Frame", nil, frame, "BackdropTemplate")
+ treeframe:SetPoint("TOPLEFT")
+ treeframe:SetPoint("BOTTOMLEFT")
+ treeframe:SetWidth(DEFAULT_TREE_WIDTH)
+ treeframe:EnableMouseWheel(true)
+ treeframe:SetBackdrop(PaneBackdrop)
+ treeframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ treeframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
+ treeframe:SetResizable(true)
+ if treeframe.SetResizeBounds then -- WoW 10.0
+ treeframe:SetResizeBounds(100, 1, 400, 1600)
+ else
+ treeframe:SetMinResize(100, 1)
+ treeframe:SetMaxResize(400, 1600)
+ end
+ treeframe:SetScript("OnUpdate", FirstFrameUpdate)
+ treeframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
+ treeframe:SetScript("OnMouseWheel", Tree_OnMouseWheel)
+
+ local dragger = CreateFrame("Frame", nil, treeframe, "BackdropTemplate")
+ dragger:SetWidth(8)
+ dragger:SetPoint("TOP", treeframe, "TOPRIGHT")
+ dragger:SetPoint("BOTTOM", treeframe, "BOTTOMRIGHT")
+ dragger:SetBackdrop(DraggerBackdrop)
+ dragger:SetBackdropColor(1, 1, 1, 0)
+ dragger:SetScript("OnEnter", Dragger_OnEnter)
+ dragger:SetScript("OnLeave", Dragger_OnLeave)
+ dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
+ dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
+
+ local scrollbar = CreateFrame("Slider", ("AceConfigDialogTreeGroup%dScrollBar"):format(num), treeframe, "UIPanelScrollBarTemplate")
+ scrollbar:SetScript("OnValueChanged", nil)
+ scrollbar:SetPoint("TOPRIGHT", -10, -26)
+ scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
+ scrollbar:SetMinMaxValues(0,0)
+ scrollbar:SetValueStep(1)
+ scrollbar:SetValue(0)
+ scrollbar:SetWidth(16)
+ scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
+
+ local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
+ scrollbg:SetAllPoints(scrollbar)
+ scrollbg:SetColorTexture(0,0,0,0.4)
+
+ local border = CreateFrame("Frame", nil, frame, "BackdropTemplate")
+ border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
+ border:SetPoint("BOTTOMRIGHT")
+ border:SetBackdrop(PaneBackdrop)
+ border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
+ border:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ --Container Support
+ local content = CreateFrame("Frame", nil, border)
+ content:SetPoint("TOPLEFT", 10, -10)
+ content:SetPoint("BOTTOMRIGHT", -10, 10)
+
+ local widget = {
+ frame = frame,
+ lines = {},
+ levels = {},
+ buttons = {},
+ hasChildren = {},
+ localstatus = { groups = {}, scrollvalue = 0 },
+ filter = false,
+ treeframe = treeframe,
+ dragger = dragger,
+ scrollbar = scrollbar,
+ border = border,
+ content = content,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ treeframe.obj, dragger.obj, scrollbar.obj = widget, widget, widget
+
+ return AceGUI:RegisterAsContainer(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua b/Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua
index 5729bfd..f378d93 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua
@@ -1,336 +1,336 @@
-local AceGUI = LibStub("AceGUI-3.0")
-
--- Lua APIs
-local pairs, assert, type = pairs, assert, type
-
--- WoW APIs
-local PlaySound = PlaySound
-local CreateFrame, UIParent = CreateFrame, UIParent
-
-----------------
--- Main Frame --
-----------------
---[[
- Events :
- OnClose
-
-]]
-do
- local Type = "Window"
- local Version = 8
-
- local function frameOnShow(this)
- this.obj:Fire("OnShow")
- end
-
- local function frameOnClose(this)
- this.obj:Fire("OnClose")
- end
-
- local function closeOnClick(this)
- PlaySound(799) -- SOUNDKIT.GS_TITLE_OPTION_EXIT
- this.obj:Hide()
- end
-
- local function frameOnMouseDown(this)
- AceGUI:ClearFocus()
- end
-
- local function titleOnMouseDown(this)
- this:GetParent():StartMoving()
- AceGUI:ClearFocus()
- end
-
- local function frameOnMouseUp(this)
- local frame = this:GetParent()
- frame:StopMovingOrSizing()
- local self = frame.obj
- local status = self.status or self.localstatus
- status.width = frame:GetWidth()
- status.height = frame:GetHeight()
- status.top = frame:GetTop()
- status.left = frame:GetLeft()
- end
-
- local function sizerseOnMouseDown(this)
- this:GetParent():StartSizing("BOTTOMRIGHT")
- AceGUI:ClearFocus()
- end
-
- local function sizersOnMouseDown(this)
- this:GetParent():StartSizing("BOTTOM")
- AceGUI:ClearFocus()
- end
-
- local function sizereOnMouseDown(this)
- this:GetParent():StartSizing("RIGHT")
- AceGUI:ClearFocus()
- end
-
- local function sizerOnMouseUp(this)
- this:GetParent():StopMovingOrSizing()
- end
-
- 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")
- self:ApplyStatus()
- 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
- self:SetWidth(status.width or 700)
- self:SetHeight(status.height or 500)
- if status.top and status.left then
- frame:SetPoint("TOP",UIParent,"BOTTOM",0,status.top)
- frame:SetPoint("LEFT",UIParent,"LEFT",status.left,0)
- else
- frame:SetPoint("CENTER",UIParent,"CENTER")
- end
- end
-
- local function OnWidthSet(self, width)
- local content = self.content
- local contentwidth = width - 34
- if contentwidth < 0 then
- contentwidth = 0
- end
- content:SetWidth(contentwidth)
- content.width = contentwidth
- end
-
-
- local function OnHeightSet(self, height)
- local content = self.content
- local contentheight = height - 57
- if contentheight < 0 then
- contentheight = 0
- end
- 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
- self.OnRelease = OnRelease
- self.OnAcquire = OnAcquire
- self.SetStatusText = SetStatusText
- self.SetStatusTable = SetStatusTable
- self.ApplyStatus = ApplyStatus
- self.OnWidthSet = OnWidthSet
- self.OnHeightSet = OnHeightSet
- self.EnableResize = EnableResize
-
- self.localstatus = {}
-
- self.frame = frame
- frame.obj = self
- frame:SetWidth(700)
- frame:SetHeight(500)
- frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
- frame:EnableMouse()
- frame:SetMovable(true)
- frame:SetResizable(true)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
- frame:SetScript("OnMouseDown", frameOnMouseDown)
-
- frame:SetScript("OnShow",frameOnShow)
- frame:SetScript("OnHide",frameOnClose)
- if frame.SetResizeBounds then -- WoW 10.0
- frame:SetResizeBounds(240,240)
- else
- frame:SetMinResize(240,240)
- end
- frame:SetToplevel(true)
-
- local titlebg = frame:CreateTexture(nil, "BACKGROUND")
- titlebg:SetTexture(251966) -- 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(137056) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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)
- title:EnableMouse()
- 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)
- sizer_se:SetHeight(25)
- sizer_se:EnableMouse()
- sizer_se:SetScript("OnMouseDown",sizerseOnMouseDown)
- sizer_se:SetScript("OnMouseUp", sizerOnMouseUp)
- self.sizer_se = sizer_se
-
- local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
- self.line1 = line1
- line1:SetWidth(14)
- line1:SetHeight(14)
- line1:SetPoint("BOTTOMRIGHT", -8, 8)
- line1:SetTexture(137057) -- 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")
- self.line2 = line2
- line2:SetWidth(8)
- line2:SetHeight(8)
- line2:SetPoint("BOTTOMRIGHT", -8, 8)
- line2:SetTexture(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
- 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",frame,"BOTTOMRIGHT",-25,0)
- sizer_s:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
- sizer_s:SetHeight(25)
- sizer_s:EnableMouse()
- 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)
- sizer_e:SetWidth(25)
- sizer_e:EnableMouse()
- 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
- end
-
- AceGUI:RegisterWidgetType(Type,Constructor,Version)
-end
+local AceGUI = LibStub("AceGUI-3.0")
+
+-- Lua APIs
+local pairs, assert, type = pairs, assert, type
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+----------------
+-- Main Frame --
+----------------
+--[[
+ Events :
+ OnClose
+
+]]
+do
+ local Type = "Window"
+ local Version = 8
+
+ local function frameOnShow(this)
+ this.obj:Fire("OnShow")
+ end
+
+ local function frameOnClose(this)
+ this.obj:Fire("OnClose")
+ end
+
+ local function closeOnClick(this)
+ PlaySound(799) -- SOUNDKIT.GS_TITLE_OPTION_EXIT
+ this.obj:Hide()
+ end
+
+ local function frameOnMouseDown(this)
+ AceGUI:ClearFocus()
+ end
+
+ local function titleOnMouseDown(this)
+ this:GetParent():StartMoving()
+ AceGUI:ClearFocus()
+ end
+
+ local function frameOnMouseUp(this)
+ local frame = this:GetParent()
+ frame:StopMovingOrSizing()
+ local self = frame.obj
+ local status = self.status or self.localstatus
+ status.width = frame:GetWidth()
+ status.height = frame:GetHeight()
+ status.top = frame:GetTop()
+ status.left = frame:GetLeft()
+ end
+
+ local function sizerseOnMouseDown(this)
+ this:GetParent():StartSizing("BOTTOMRIGHT")
+ AceGUI:ClearFocus()
+ end
+
+ local function sizersOnMouseDown(this)
+ this:GetParent():StartSizing("BOTTOM")
+ AceGUI:ClearFocus()
+ end
+
+ local function sizereOnMouseDown(this)
+ this:GetParent():StartSizing("RIGHT")
+ AceGUI:ClearFocus()
+ end
+
+ local function sizerOnMouseUp(this)
+ this:GetParent():StopMovingOrSizing()
+ end
+
+ 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")
+ self:ApplyStatus()
+ 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
+ self:SetWidth(status.width or 700)
+ self:SetHeight(status.height or 500)
+ if status.top and status.left then
+ frame:SetPoint("TOP",UIParent,"BOTTOM",0,status.top)
+ frame:SetPoint("LEFT",UIParent,"LEFT",status.left,0)
+ else
+ frame:SetPoint("CENTER",UIParent,"CENTER")
+ end
+ end
+
+ local function OnWidthSet(self, width)
+ local content = self.content
+ local contentwidth = width - 34
+ if contentwidth < 0 then
+ contentwidth = 0
+ end
+ content:SetWidth(contentwidth)
+ content.width = contentwidth
+ end
+
+
+ local function OnHeightSet(self, height)
+ local content = self.content
+ local contentheight = height - 57
+ if contentheight < 0 then
+ contentheight = 0
+ end
+ 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
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+ self.SetStatusText = SetStatusText
+ self.SetStatusTable = SetStatusTable
+ self.ApplyStatus = ApplyStatus
+ self.OnWidthSet = OnWidthSet
+ self.OnHeightSet = OnHeightSet
+ self.EnableResize = EnableResize
+
+ self.localstatus = {}
+
+ self.frame = frame
+ frame.obj = self
+ frame:SetWidth(700)
+ frame:SetHeight(500)
+ frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
+ frame:EnableMouse()
+ frame:SetMovable(true)
+ frame:SetResizable(true)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ frame:SetScript("OnMouseDown", frameOnMouseDown)
+
+ frame:SetScript("OnShow",frameOnShow)
+ frame:SetScript("OnHide",frameOnClose)
+ if frame.SetResizeBounds then -- WoW 10.0
+ frame:SetResizeBounds(240,240)
+ else
+ frame:SetMinResize(240,240)
+ end
+ frame:SetToplevel(true)
+
+ local titlebg = frame:CreateTexture(nil, "BACKGROUND")
+ titlebg:SetTexture(251966) -- 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(137056) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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(251963) -- 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)
+ title:EnableMouse()
+ 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)
+ sizer_se:SetHeight(25)
+ sizer_se:EnableMouse()
+ sizer_se:SetScript("OnMouseDown",sizerseOnMouseDown)
+ sizer_se:SetScript("OnMouseUp", sizerOnMouseUp)
+ self.sizer_se = sizer_se
+
+ local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
+ self.line1 = line1
+ line1:SetWidth(14)
+ line1:SetHeight(14)
+ line1:SetPoint("BOTTOMRIGHT", -8, 8)
+ line1:SetTexture(137057) -- 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")
+ self.line2 = line2
+ line2:SetWidth(8)
+ line2:SetHeight(8)
+ line2:SetPoint("BOTTOMRIGHT", -8, 8)
+ line2:SetTexture(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
+ 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",frame,"BOTTOMRIGHT",-25,0)
+ sizer_s:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
+ sizer_s:SetHeight(25)
+ sizer_s:EnableMouse()
+ 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)
+ sizer_e:SetWidth(25)
+ sizer_e:EnableMouse()
+ 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
+ end
+
+ AceGUI:RegisterWidgetType(Type,Constructor,Version)
+end
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua
index 8e650ce..0e286ca 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua
@@ -1,103 +1,103 @@
---[[-----------------------------------------------------------------------------
-Button Widget
-Graphical Button.
--------------------------------------------------------------------------------]]
-local Type, Version = "Button", 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 pairs = pairs
-
--- WoW APIs
-local _G = _G
-local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Button_OnClick(frame, ...)
- AceGUI:ClearFocus()
- PlaySound(852) -- SOUNDKIT.IG_MAINMENU_OPTION
- frame.obj:Fire("OnClick", ...)
-end
-
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- -- restore default values
- self:SetHeight(24)
- self:SetWidth(200)
- self:SetDisabled(false)
- self:SetAutoWidth(false)
- self:SetText()
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetText"] = function(self, text)
- self.text:SetText(text)
- if self.autoWidth then
- self:SetWidth(self.text:GetStringWidth() + 30)
- end
- end,
-
- ["SetAutoWidth"] = function(self, autoWidth)
- self.autoWidth = autoWidth
- if self.autoWidth then
- self:SetWidth(self.text:GetStringWidth() + 30)
- end
- end,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if disabled then
- self.frame:Disable()
- else
- self.frame:Enable()
- end
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
- local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate")
- frame:Hide()
-
- frame:EnableMouse(true)
- frame:SetScript("OnClick", Button_OnClick)
- frame:SetScript("OnEnter", Control_OnEnter)
- frame:SetScript("OnLeave", Control_OnLeave)
-
- local text = frame:GetFontString()
- text:ClearAllPoints()
- text:SetPoint("TOPLEFT", 15, -1)
- text:SetPoint("BOTTOMRIGHT", -15, 1)
- text:SetJustifyV("MIDDLE")
-
- local widget = {
- text = text,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Button Widget
+Graphical Button.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Button", 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 pairs = pairs
+
+-- WoW APIs
+local _G = _G
+local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Button_OnClick(frame, ...)
+ AceGUI:ClearFocus()
+ PlaySound(852) -- SOUNDKIT.IG_MAINMENU_OPTION
+ frame.obj:Fire("OnClick", ...)
+end
+
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- restore default values
+ self:SetHeight(24)
+ self:SetWidth(200)
+ self:SetDisabled(false)
+ self:SetAutoWidth(false)
+ self:SetText()
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetText"] = function(self, text)
+ self.text:SetText(text)
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetAutoWidth"] = function(self, autoWidth)
+ self.autoWidth = autoWidth
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ else
+ self.frame:Enable()
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate")
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnClick", Button_OnClick)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+
+ local text = frame:GetFontString()
+ text:ClearAllPoints()
+ text:SetPoint("TOPLEFT", 15, -1)
+ text:SetPoint("BOTTOMRIGHT", -15, 1)
+ text:SetJustifyV("MIDDLE")
+
+ local widget = {
+ text = text,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua
index 6e64292..fe17e03 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua
@@ -1,292 +1,292 @@
---[[-----------------------------------------------------------------------------
-Checkbox Widget
--------------------------------------------------------------------------------]]
-local Type, Version = "CheckBox", 26
-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 select, pairs = select, pairs
-
--- WoW APIs
-local PlaySound = PlaySound
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-local function AlignImage(self)
- local img = self.image:GetTexture()
- self.text:ClearAllPoints()
- if not img then
- self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
- self.text:SetPoint("RIGHT")
- else
- self.text:SetPoint("LEFT", self.image, "RIGHT", 1, 0)
- self.text:SetPoint("RIGHT")
- end
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function CheckBox_OnMouseDown(frame)
- local self = frame.obj
- if not self.disabled then
- if self.image:GetTexture() then
- self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1)
- else
- self.text:SetPoint("LEFT", self.checkbg, "RIGHT", 1, -1)
- end
- end
- AceGUI:ClearFocus()
-end
-
-local function CheckBox_OnMouseUp(frame)
- local self = frame.obj
- if not self.disabled then
- self:ToggleChecked()
-
- if self.checked then
- PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
- else -- for both nil and false (tristate)
- PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF
- end
-
- self:Fire("OnValueChanged", self.checked)
- AlignImage(self)
- end
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetType()
- self:SetValue(false)
- self:SetTriState(nil)
- -- height is calculated from the width and required space for the description
- self:SetWidth(200)
- self:SetImage()
- self:SetDisabled(nil)
- self:SetDescription(nil)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["OnWidthSet"] = function(self, width)
- if self.desc then
- self.desc:SetWidth(width - 30)
- if self.desc:GetText() and self.desc:GetText() ~= "" then
- self:SetHeight(28 + self.desc:GetStringHeight())
- end
- end
- end,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if disabled then
- self.frame:Disable()
- self.text:SetTextColor(0.5, 0.5, 0.5)
- SetDesaturation(self.check, true)
- if self.desc then
- self.desc:SetTextColor(0.5, 0.5, 0.5)
- end
- else
- self.frame:Enable()
- self.text:SetTextColor(1, 1, 1)
- if self.tristate and self.checked == nil then
- SetDesaturation(self.check, true)
- else
- SetDesaturation(self.check, false)
- end
- if self.desc then
- self.desc:SetTextColor(1, 1, 1)
- end
- end
- end,
-
- ["SetValue"] = function(self, value)
- local check = self.check
- self.checked = value
- if value then
- SetDesaturation(check, false)
- check:Show()
- else
- --Nil is the unknown tristate value
- if self.tristate and value == nil then
- SetDesaturation(check, true)
- check:Show()
- else
- SetDesaturation(check, false)
- check:Hide()
- end
- end
- self:SetDisabled(self.disabled)
- end,
-
- ["GetValue"] = function(self)
- return self.checked
- end,
-
- ["SetTriState"] = function(self, enabled)
- self.tristate = enabled
- self:SetValue(self:GetValue())
- end,
-
- ["SetType"] = function(self, type)
- local checkbg = self.checkbg
- local check = self.check
- local highlight = self.highlight
-
- local size
- if type == "radio" then
- size = 16
- checkbg:SetTexture(130843) -- Interface\\Buttons\\UI-RadioButton
- checkbg:SetTexCoord(0, 0.25, 0, 1)
- check:SetTexture(130843) -- Interface\\Buttons\\UI-RadioButton
- check:SetTexCoord(0.25, 0.5, 0, 1)
- check:SetBlendMode("ADD")
- highlight:SetTexture(130843) -- Interface\\Buttons\\UI-RadioButton
- highlight:SetTexCoord(0.5, 0.75, 0, 1)
- else
- size = 24
- checkbg:SetTexture(130755) -- Interface\\Buttons\\UI-CheckBox-Up
- checkbg:SetTexCoord(0, 1, 0, 1)
- check:SetTexture(130751) -- Interface\\Buttons\\UI-CheckBox-Check
- check:SetTexCoord(0, 1, 0, 1)
- check:SetBlendMode("BLEND")
- highlight:SetTexture(130753) -- Interface\\Buttons\\UI-CheckBox-Highlight
- highlight:SetTexCoord(0, 1, 0, 1)
- end
- checkbg:SetHeight(size)
- checkbg:SetWidth(size)
- end,
-
- ["ToggleChecked"] = function(self)
- local value = self:GetValue()
- if self.tristate then
- --cycle in true, nil, false order
- if value then
- self:SetValue(nil)
- elseif value == nil then
- self:SetValue(false)
- else
- self:SetValue(true)
- end
- else
- self:SetValue(not self:GetValue())
- end
- end,
-
- ["SetLabel"] = function(self, label)
- self.text:SetText(label)
- end,
-
- ["SetDescription"] = function(self, desc)
- if desc then
- if not self.desc then
- local f = self.frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
- f:ClearAllPoints()
- f:SetPoint("TOPLEFT", self.checkbg, "TOPRIGHT", 5, -21)
- f:SetWidth(self.frame.width - 30)
- f:SetPoint("RIGHT", self.frame, "RIGHT", -30, 0)
- f:SetJustifyH("LEFT")
- f:SetJustifyV("TOP")
- self.desc = f
- end
- self.desc:Show()
- --self.text:SetFontObject(GameFontNormal)
- self.desc:SetText(desc)
- self:SetHeight(28 + self.desc:GetStringHeight())
- else
- if self.desc then
- self.desc:SetText("")
- self.desc:Hide()
- end
- --self.text:SetFontObject(GameFontHighlight)
- self:SetHeight(24)
- end
- end,
-
- ["SetImage"] = function(self, path, ...)
- local image = self.image
- image:SetTexture(path)
-
- if image:GetTexture() then
- local n = select("#", ...)
- if n == 4 or n == 8 then
- image:SetTexCoord(...)
- else
- image:SetTexCoord(0, 1, 0, 1)
- end
- end
- AlignImage(self)
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Button", nil, UIParent)
- frame:Hide()
-
- frame:EnableMouse(true)
- frame:SetScript("OnEnter", Control_OnEnter)
- frame:SetScript("OnLeave", Control_OnLeave)
- frame:SetScript("OnMouseDown", CheckBox_OnMouseDown)
- frame:SetScript("OnMouseUp", CheckBox_OnMouseUp)
-
- local checkbg = frame:CreateTexture(nil, "ARTWORK")
- checkbg:SetWidth(24)
- checkbg:SetHeight(24)
- checkbg:SetPoint("TOPLEFT")
- checkbg:SetTexture(130755) -- Interface\\Buttons\\UI-CheckBox-Up
-
- local check = frame:CreateTexture(nil, "OVERLAY")
- check:SetAllPoints(checkbg)
- check:SetTexture(130751) -- Interface\\Buttons\\UI-CheckBox-Check
-
- local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
- text:SetJustifyH("LEFT")
- text:SetHeight(18)
- text:SetPoint("LEFT", checkbg, "RIGHT")
- text:SetPoint("RIGHT")
-
- local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
- highlight:SetTexture(130753) -- Interface\\Buttons\\UI-CheckBox-Highlight
- highlight:SetBlendMode("ADD")
- highlight:SetAllPoints(checkbg)
-
- local image = frame:CreateTexture(nil, "OVERLAY")
- image:SetHeight(16)
- image:SetWidth(16)
- image:SetPoint("LEFT", checkbg, "RIGHT", 1, 0)
-
- local widget = {
- checkbg = checkbg,
- check = check,
- text = text,
- highlight = highlight,
- image = image,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Checkbox Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "CheckBox", 26
+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 select, pairs = select, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function AlignImage(self)
+ local img = self.image:GetTexture()
+ self.text:ClearAllPoints()
+ if not img then
+ self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
+ self.text:SetPoint("RIGHT")
+ else
+ self.text:SetPoint("LEFT", self.image, "RIGHT", 1, 0)
+ self.text:SetPoint("RIGHT")
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function CheckBox_OnMouseDown(frame)
+ local self = frame.obj
+ if not self.disabled then
+ if self.image:GetTexture() then
+ self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1)
+ else
+ self.text:SetPoint("LEFT", self.checkbg, "RIGHT", 1, -1)
+ end
+ end
+ AceGUI:ClearFocus()
+end
+
+local function CheckBox_OnMouseUp(frame)
+ local self = frame.obj
+ if not self.disabled then
+ self:ToggleChecked()
+
+ if self.checked then
+ PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
+ else -- for both nil and false (tristate)
+ PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF
+ end
+
+ self:Fire("OnValueChanged", self.checked)
+ AlignImage(self)
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetType()
+ self:SetValue(false)
+ self:SetTriState(nil)
+ -- height is calculated from the width and required space for the description
+ self:SetWidth(200)
+ self:SetImage()
+ self:SetDisabled(nil)
+ self:SetDescription(nil)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["OnWidthSet"] = function(self, width)
+ if self.desc then
+ self.desc:SetWidth(width - 30)
+ if self.desc:GetText() and self.desc:GetText() ~= "" then
+ self:SetHeight(28 + self.desc:GetStringHeight())
+ end
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.text:SetTextColor(0.5, 0.5, 0.5)
+ SetDesaturation(self.check, true)
+ if self.desc then
+ self.desc:SetTextColor(0.5, 0.5, 0.5)
+ end
+ else
+ self.frame:Enable()
+ self.text:SetTextColor(1, 1, 1)
+ if self.tristate and self.checked == nil then
+ SetDesaturation(self.check, true)
+ else
+ SetDesaturation(self.check, false)
+ end
+ if self.desc then
+ self.desc:SetTextColor(1, 1, 1)
+ end
+ end
+ end,
+
+ ["SetValue"] = function(self, value)
+ local check = self.check
+ self.checked = value
+ if value then
+ SetDesaturation(check, false)
+ check:Show()
+ else
+ --Nil is the unknown tristate value
+ if self.tristate and value == nil then
+ SetDesaturation(check, true)
+ check:Show()
+ else
+ SetDesaturation(check, false)
+ check:Hide()
+ end
+ end
+ self:SetDisabled(self.disabled)
+ end,
+
+ ["GetValue"] = function(self)
+ return self.checked
+ end,
+
+ ["SetTriState"] = function(self, enabled)
+ self.tristate = enabled
+ self:SetValue(self:GetValue())
+ end,
+
+ ["SetType"] = function(self, type)
+ local checkbg = self.checkbg
+ local check = self.check
+ local highlight = self.highlight
+
+ local size
+ if type == "radio" then
+ size = 16
+ checkbg:SetTexture(130843) -- Interface\\Buttons\\UI-RadioButton
+ checkbg:SetTexCoord(0, 0.25, 0, 1)
+ check:SetTexture(130843) -- Interface\\Buttons\\UI-RadioButton
+ check:SetTexCoord(0.25, 0.5, 0, 1)
+ check:SetBlendMode("ADD")
+ highlight:SetTexture(130843) -- Interface\\Buttons\\UI-RadioButton
+ highlight:SetTexCoord(0.5, 0.75, 0, 1)
+ else
+ size = 24
+ checkbg:SetTexture(130755) -- Interface\\Buttons\\UI-CheckBox-Up
+ checkbg:SetTexCoord(0, 1, 0, 1)
+ check:SetTexture(130751) -- Interface\\Buttons\\UI-CheckBox-Check
+ check:SetTexCoord(0, 1, 0, 1)
+ check:SetBlendMode("BLEND")
+ highlight:SetTexture(130753) -- Interface\\Buttons\\UI-CheckBox-Highlight
+ highlight:SetTexCoord(0, 1, 0, 1)
+ end
+ checkbg:SetHeight(size)
+ checkbg:SetWidth(size)
+ end,
+
+ ["ToggleChecked"] = function(self)
+ local value = self:GetValue()
+ if self.tristate then
+ --cycle in true, nil, false order
+ if value then
+ self:SetValue(nil)
+ elseif value == nil then
+ self:SetValue(false)
+ else
+ self:SetValue(true)
+ end
+ else
+ self:SetValue(not self:GetValue())
+ end
+ end,
+
+ ["SetLabel"] = function(self, label)
+ self.text:SetText(label)
+ end,
+
+ ["SetDescription"] = function(self, desc)
+ if desc then
+ if not self.desc then
+ local f = self.frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
+ f:ClearAllPoints()
+ f:SetPoint("TOPLEFT", self.checkbg, "TOPRIGHT", 5, -21)
+ f:SetWidth(self.frame.width - 30)
+ f:SetPoint("RIGHT", self.frame, "RIGHT", -30, 0)
+ f:SetJustifyH("LEFT")
+ f:SetJustifyV("TOP")
+ self.desc = f
+ end
+ self.desc:Show()
+ --self.text:SetFontObject(GameFontNormal)
+ self.desc:SetText(desc)
+ self:SetHeight(28 + self.desc:GetStringHeight())
+ else
+ if self.desc then
+ self.desc:SetText("")
+ self.desc:Hide()
+ end
+ --self.text:SetFontObject(GameFontHighlight)
+ self:SetHeight(24)
+ end
+ end,
+
+ ["SetImage"] = function(self, path, ...)
+ local image = self.image
+ image:SetTexture(path)
+
+ if image:GetTexture() then
+ local n = select("#", ...)
+ if n == 4 or n == 8 then
+ image:SetTexCoord(...)
+ else
+ image:SetTexCoord(0, 1, 0, 1)
+ end
+ end
+ AlignImage(self)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Button", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnMouseDown", CheckBox_OnMouseDown)
+ frame:SetScript("OnMouseUp", CheckBox_OnMouseUp)
+
+ local checkbg = frame:CreateTexture(nil, "ARTWORK")
+ checkbg:SetWidth(24)
+ checkbg:SetHeight(24)
+ checkbg:SetPoint("TOPLEFT")
+ checkbg:SetTexture(130755) -- Interface\\Buttons\\UI-CheckBox-Up
+
+ local check = frame:CreateTexture(nil, "OVERLAY")
+ check:SetAllPoints(checkbg)
+ check:SetTexture(130751) -- Interface\\Buttons\\UI-CheckBox-Check
+
+ local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+ text:SetJustifyH("LEFT")
+ text:SetHeight(18)
+ text:SetPoint("LEFT", checkbg, "RIGHT")
+ text:SetPoint("RIGHT")
+
+ local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlight:SetTexture(130753) -- Interface\\Buttons\\UI-CheckBox-Highlight
+ highlight:SetBlendMode("ADD")
+ highlight:SetAllPoints(checkbg)
+
+ local image = frame:CreateTexture(nil, "OVERLAY")
+ image:SetHeight(16)
+ image:SetWidth(16)
+ image:SetPoint("LEFT", checkbg, "RIGHT", 1, 0)
+
+ local widget = {
+ checkbg = checkbg,
+ check = check,
+ text = text,
+ highlight = highlight,
+ image = image,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
index 699d583..ec811d0 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
@@ -1,186 +1,230 @@
---[[-----------------------------------------------------------------------------
-ColorPicker Widget
--------------------------------------------------------------------------------]]
-local Type, Version = "ColorPicker", 25
-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
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-local function ColorCallback(self, r, g, b, a, isAlpha)
- if not self.HasAlpha then
- a = 1
- end
- self:SetColor(r, g, b, a)
- if ColorPickerFrame:IsVisible() then
- --colorpicker is still open
- 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", r, g, b, a)
- end
- end
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function ColorSwatch_OnClick(frame)
- ColorPickerFrame:Hide()
- local self = frame.obj
- if not self.disabled then
- ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
- ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
- ColorPickerFrame:SetClampedToScreen(true)
-
- ColorPickerFrame.func = function()
- local r, g, b = ColorPickerFrame:GetColorRGB()
- local a = 1 - OpacitySliderFrame:GetValue()
- ColorCallback(self, r, g, b, a)
- end
-
- ColorPickerFrame.hasOpacity = self.HasAlpha
- ColorPickerFrame.opacityFunc = function()
- local r, g, b = ColorPickerFrame:GetColorRGB()
- local a = 1 - OpacitySliderFrame:GetValue()
- ColorCallback(self, r, g, b, a, true)
- end
-
- local r, g, b, a = self.r, self.g, self.b, self.a
- if self.HasAlpha then
- ColorPickerFrame.opacity = 1 - (a or 0)
- end
- ColorPickerFrame:SetColorRGB(r, g, b)
-
- ColorPickerFrame.cancelFunc = function()
- ColorCallback(self, r, g, b, a, true)
- end
-
- ColorPickerFrame:Show()
- end
- AceGUI:ClearFocus()
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetHeight(24)
- self:SetWidth(200)
- self:SetHasAlpha(false)
- self:SetColor(0, 0, 0, 1)
- self:SetDisabled(nil)
- self:SetLabel(nil)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetLabel"] = function(self, text)
- self.text:SetText(text)
- end,
-
- ["SetColor"] = function(self, r, g, b, a)
- self.r = r
- self.g = g
- self.b = b
- self.a = a or 1
- self.colorSwatch:SetVertexColor(r, g, b, a)
- end,
-
- ["SetHasAlpha"] = function(self, HasAlpha)
- self.HasAlpha = HasAlpha
- end,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if self.disabled then
- self.frame:Disable()
- self.text:SetTextColor(0.5, 0.5, 0.5)
- else
- self.frame:Enable()
- self.text:SetTextColor(1, 1, 1)
- end
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Button", nil, UIParent)
- frame:Hide()
-
- frame:EnableMouse(true)
- frame:SetScript("OnEnter", Control_OnEnter)
- frame:SetScript("OnLeave", Control_OnLeave)
- frame:SetScript("OnClick", ColorSwatch_OnClick)
-
- local colorSwatch = frame:CreateTexture(nil, "OVERLAY")
- colorSwatch:SetWidth(19)
- colorSwatch:SetHeight(19)
- colorSwatch:SetTexture(130939) -- Interface\\ChatFrame\\ChatFrameColorSwatch
- colorSwatch:SetPoint("LEFT")
-
- local texture = frame:CreateTexture(nil, "BACKGROUND")
- colorSwatch.background = texture
- texture:SetWidth(16)
- texture:SetHeight(16)
- texture:SetColorTexture(1, 1, 1)
- texture:SetPoint("CENTER", colorSwatch)
- texture:Show()
-
- local checkers = frame:CreateTexture(nil, "BACKGROUND")
- colorSwatch.checkers = checkers
- checkers:SetWidth(14)
- checkers:SetHeight(14)
- checkers:SetTexture(188523) -- Tileset\\Generic\\Checkers
- checkers:SetTexCoord(.25, 0, 0.5, .25)
- checkers:SetDesaturated(true)
- checkers:SetVertexColor(1, 1, 1, 0.75)
- checkers:SetPoint("CENTER", colorSwatch)
- checkers:Show()
-
- local text = frame:CreateFontString(nil,"OVERLAY","GameFontHighlight")
- text:SetHeight(24)
- text:SetJustifyH("LEFT")
- text:SetTextColor(1, 1, 1)
- text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
- text:SetPoint("RIGHT")
-
- --local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
- --highlight:SetTexture(136810) -- Interface\\QuestFrame\\UI-QuestTitleHighlight
- --highlight:SetBlendMode("ADD")
- --highlight:SetAllPoints(frame)
-
- local widget = {
- colorSwatch = colorSwatch,
- text = text,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+ColorPicker Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "ColorPicker", 28
+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
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Unfortunately we have no way to realistically detect if a client uses inverted alpha
+-- as no API will tell you. Wrath uses the old colorpicker, era uses the new one, both are inverted
+local INVERTED_ALPHA = (WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE)
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function ColorCallback(self, r, g, b, a, isAlpha)
+ if INVERTED_ALPHA and a then
+ a = 1 - a
+ end
+ if not self.HasAlpha then
+ a = 1
+ end
+ -- no change, skip update
+ if r == self.r and g == self.g and b == self.b and a == self.a then
+ return
+ end
+ self:SetColor(r, g, b, a)
+ if ColorPickerFrame:IsVisible() then
+ --colorpicker is still open
+ 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", r, g, b, a)
+ end
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function ColorSwatch_OnClick(frame)
+ ColorPickerFrame:Hide()
+ local self = frame.obj
+ if not self.disabled then
+ ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+ ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
+ ColorPickerFrame:SetClampedToScreen(true)
+
+ if ColorPickerFrame.SetupColorPickerAndShow then -- 10.2.5 color picker overhaul
+ local r2, g2, b2, a2 = self.r, self.g, self.b, (self.a or 1)
+ if INVERTED_ALPHA then
+ a2 = 1 - a2
+ end
+
+ local info = {
+ swatchFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = ColorPickerFrame:GetColorAlpha()
+ ColorCallback(self, r, g, b, a)
+ end,
+
+ hasOpacity = self.HasAlpha,
+ opacityFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = ColorPickerFrame:GetColorAlpha()
+ ColorCallback(self, r, g, b, a, true)
+ end,
+ opacity = a2,
+
+ cancelFunc = function()
+ ColorCallback(self, r2, g2, b2, a2, true)
+ end,
+
+ r = r2,
+ g = g2,
+ b = b2,
+ }
+
+ ColorPickerFrame:SetupColorPickerAndShow(info)
+ else
+ ColorPickerFrame.func = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = OpacitySliderFrame:GetValue()
+ ColorCallback(self, r, g, b, a)
+ end
+
+ ColorPickerFrame.hasOpacity = self.HasAlpha
+ ColorPickerFrame.opacityFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = OpacitySliderFrame:GetValue()
+ ColorCallback(self, r, g, b, a, true)
+ end
+
+ local r, g, b, a = self.r, self.g, self.b, 1 - (self.a or 1)
+ if self.HasAlpha then
+ ColorPickerFrame.opacity = a
+ end
+ ColorPickerFrame:SetColorRGB(r, g, b)
+
+ ColorPickerFrame.cancelFunc = function()
+ ColorCallback(self, r, g, b, a, true)
+ end
+
+ ColorPickerFrame:Show()
+ end
+ end
+ AceGUI:ClearFocus()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetHeight(24)
+ self:SetWidth(200)
+ self:SetHasAlpha(false)
+ self:SetColor(0, 0, 0, 1)
+ self:SetDisabled(nil)
+ self:SetLabel(nil)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetLabel"] = function(self, text)
+ self.text:SetText(text)
+ end,
+
+ ["SetColor"] = function(self, r, g, b, a)
+ self.r = r
+ self.g = g
+ self.b = b
+ self.a = a or 1
+ self.colorSwatch:SetVertexColor(r, g, b, a)
+ end,
+
+ ["SetHasAlpha"] = function(self, HasAlpha)
+ self.HasAlpha = HasAlpha
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if self.disabled then
+ self.frame:Disable()
+ self.text:SetTextColor(0.5, 0.5, 0.5)
+ else
+ self.frame:Enable()
+ self.text:SetTextColor(1, 1, 1)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Button", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnClick", ColorSwatch_OnClick)
+
+ local colorSwatch = frame:CreateTexture(nil, "OVERLAY")
+ colorSwatch:SetWidth(19)
+ colorSwatch:SetHeight(19)
+ colorSwatch:SetTexture(130939) -- Interface\\ChatFrame\\ChatFrameColorSwatch
+ colorSwatch:SetPoint("LEFT")
+
+ local texture = frame:CreateTexture(nil, "BACKGROUND")
+ colorSwatch.background = texture
+ texture:SetWidth(16)
+ texture:SetHeight(16)
+ texture:SetColorTexture(1, 1, 1)
+ texture:SetPoint("CENTER", colorSwatch)
+ texture:Show()
+
+ local checkers = frame:CreateTexture(nil, "BACKGROUND")
+ colorSwatch.checkers = checkers
+ checkers:SetWidth(14)
+ checkers:SetHeight(14)
+ checkers:SetTexture(188523) -- Tileset\\Generic\\Checkers
+ checkers:SetTexCoord(.25, 0, 0.5, .25)
+ checkers:SetDesaturated(true)
+ checkers:SetVertexColor(1, 1, 1, 0.75)
+ checkers:SetPoint("CENTER", colorSwatch)
+ checkers:Show()
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontHighlight")
+ text:SetHeight(24)
+ text:SetJustifyH("LEFT")
+ text:SetTextColor(1, 1, 1)
+ text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
+ text:SetPoint("RIGHT")
+
+ --local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ --highlight:SetTexture(136810) -- Interface\\QuestFrame\\UI-QuestTitleHighlight
+ --highlight:SetBlendMode("ADD")
+ --highlight:SetAllPoints(frame)
+
+ local widget = {
+ colorSwatch = colorSwatch,
+ text = text,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
index 0ad94f8..947184c 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
@@ -1,471 +1,471 @@
---[[ $Id: AceGUIWidget-DropDown-Items.lua 1272 2022-08-29 15:56:35Z nevcairiel $ ]]--
-
-local AceGUI = LibStub("AceGUI-3.0")
-
--- Lua APIs
-local select, assert = select, assert
-
--- WoW APIs
-local PlaySound = PlaySound
-local CreateFrame = CreateFrame
-
-local function fixlevels(parent,...)
- local i = 1
- local child = select(i, ...)
- while child do
- child:SetFrameLevel(parent:GetFrameLevel()+1)
- fixlevels(child, child:GetChildren())
- i = i + 1
- child = select(i, ...)
- end
-end
-
-local function fixstrata(strata, parent, ...)
- local i = 1
- local child = select(i, ...)
- parent:SetFrameStrata(strata)
- while child do
- fixstrata(strata, child, child:GetChildren())
- i = i + 1
- child = select(i, ...)
- end
-end
-
--- ItemBase is the base "class" for all dropdown items.
--- Each item has to use ItemBase.Create(widgetType) to
--- create an initial 'self' value.
--- ItemBase will add common functions and ui event handlers.
--- Be sure to keep basic usage when you override functions.
-
-local ItemBase = {
- -- NOTE: The ItemBase version is added to each item's version number
- -- to ensure proper updates on ItemBase changes.
- -- Use at least 1000er steps.
- version = 2000,
- counter = 0,
-}
-
-function ItemBase.Frame_OnEnter(this)
- local self = this.obj
-
- if self.useHighlight then
- self.highlight:Show()
- end
- self:Fire("OnEnter")
-
- if self.specialOnEnter then
- self.specialOnEnter(self)
- end
-end
-
-function ItemBase.Frame_OnLeave(this)
- local self = this.obj
-
- self.highlight:Hide()
- self:Fire("OnLeave")
-
- if self.specialOnLeave then
- self.specialOnLeave(self)
- end
-end
-
--- exported, AceGUI callback
-function ItemBase.OnAcquire(self)
- self.frame:SetToplevel(true)
- self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
-end
-
--- exported, AceGUI callback
-function ItemBase.OnRelease(self)
- self:SetDisabled(false)
- self.pullout = nil
- self.frame:SetParent(nil)
- self.frame:ClearAllPoints()
- self.frame:Hide()
-end
-
--- exported
--- NOTE: this is called by a Dropdown-Pullout.
--- Do not call this method directly
-function ItemBase.SetPullout(self, pullout)
- self.pullout = pullout
-
- self.frame:SetParent(nil)
- self.frame:SetParent(pullout.itemFrame)
- self.parent = pullout.itemFrame
- fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren())
-end
-
--- exported
-function ItemBase.SetText(self, text)
- self.text:SetText(text or "")
-end
-
--- exported
-function ItemBase.GetText(self)
- return self.text:GetText()
-end
-
--- exported
-function ItemBase.SetPoint(self, ...)
- self.frame:SetPoint(...)
-end
-
--- exported
-function ItemBase.Show(self)
- self.frame:Show()
-end
-
--- exported
-function ItemBase.Hide(self)
- self.frame:Hide()
-end
-
--- exported
-function ItemBase.SetDisabled(self, disabled)
- self.disabled = disabled
- if disabled then
- self.useHighlight = false
- self.text:SetTextColor(.5, .5, .5)
- else
- self.useHighlight = true
- self.text:SetTextColor(1, 1, 1)
- end
-end
-
--- exported
--- NOTE: this is called by a Dropdown-Pullout.
--- Do not call this method directly
-function ItemBase.SetOnLeave(self, func)
- self.specialOnLeave = func
-end
-
--- exported
--- NOTE: this is called by a Dropdown-Pullout.
--- Do not call this method directly
-function ItemBase.SetOnEnter(self, func)
- self.specialOnEnter = func
-end
-
-function ItemBase.Create(type)
- -- NOTE: Most of the following code is copied from AceGUI-3.0/Dropdown widget
- local count = AceGUI:GetNextWidgetNum(type)
- local frame = CreateFrame("Button", "AceGUI30DropDownItem"..count)
- local self = {}
- self.frame = frame
- frame.obj = self
- self.type = type
-
- self.useHighlight = true
-
- frame:SetHeight(17)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
- text:SetTextColor(1,1,1)
- text:SetJustifyH("LEFT")
- text:SetPoint("TOPLEFT",frame,"TOPLEFT",18,0)
- text:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-8,0)
- self.text = text
-
- local highlight = frame:CreateTexture(nil, "OVERLAY")
- highlight:SetTexture(136810) -- Interface\\QuestFrame\\UI-QuestTitleHighlight
- highlight:SetBlendMode("ADD")
- highlight:SetHeight(14)
- highlight:ClearAllPoints()
- highlight:SetPoint("RIGHT",frame,"RIGHT",-3,0)
- highlight:SetPoint("LEFT",frame,"LEFT",5,0)
- highlight:Hide()
- self.highlight = highlight
-
- local check = frame:CreateTexture(nil, "OVERLAY")
- check:SetWidth(16)
- check:SetHeight(16)
- check:SetPoint("LEFT",frame,"LEFT",3,-1)
- check:SetTexture(130751) -- Interface\\Buttons\\UI-CheckBox-Check
- check:Hide()
- self.check = check
-
- local sub = frame:CreateTexture(nil, "OVERLAY")
- sub:SetWidth(16)
- sub:SetHeight(16)
- sub:SetPoint("RIGHT",frame,"RIGHT",-3,-1)
- sub:SetTexture(130940) -- Interface\\ChatFrame\\ChatFrameExpandArrow
- sub:Hide()
- self.sub = sub
-
- frame:SetScript("OnEnter", ItemBase.Frame_OnEnter)
- frame:SetScript("OnLeave", ItemBase.Frame_OnLeave)
-
- self.OnAcquire = ItemBase.OnAcquire
- self.OnRelease = ItemBase.OnRelease
-
- self.SetPullout = ItemBase.SetPullout
- self.GetText = ItemBase.GetText
- self.SetText = ItemBase.SetText
- self.SetDisabled = ItemBase.SetDisabled
-
- self.SetPoint = ItemBase.SetPoint
- self.Show = ItemBase.Show
- self.Hide = ItemBase.Hide
-
- self.SetOnLeave = ItemBase.SetOnLeave
- self.SetOnEnter = ItemBase.SetOnEnter
-
- return self
-end
-
--- Register a dummy LibStub library to retrieve the ItemBase, so other addons can use it.
-local IBLib = LibStub:NewLibrary("AceGUI-3.0-DropDown-ItemBase", ItemBase.version)
-if IBLib then
- IBLib.GetItemBase = function() return ItemBase end
-end
-
---[[
- Template for items:
-
--- Item:
---
-do
- local widgetType = "Dropdown-Item-"
- local widgetVersion = 1
-
- local function Constructor()
- local self = ItemBase.Create(widgetType)
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
-end
---]]
-
--- Item: Header
--- A single text entry.
--- Special: Different text color and no highlight
-do
- local widgetType = "Dropdown-Item-Header"
- local widgetVersion = 1
-
- local function OnEnter(this)
- local self = this.obj
- self:Fire("OnEnter")
-
- if self.specialOnEnter then
- self.specialOnEnter(self)
- end
- end
-
- local function OnLeave(this)
- local self = this.obj
- self:Fire("OnLeave")
-
- if self.specialOnLeave then
- self.specialOnLeave(self)
- end
- end
-
- -- exported, override
- local function SetDisabled(self, disabled)
- ItemBase.SetDisabled(self, disabled)
- if not disabled then
- self.text:SetTextColor(1, 1, 0)
- end
- end
-
- local function Constructor()
- local self = ItemBase.Create(widgetType)
-
- self.SetDisabled = SetDisabled
-
- self.frame:SetScript("OnEnter", OnEnter)
- self.frame:SetScript("OnLeave", OnLeave)
-
- self.text:SetTextColor(1, 1, 0)
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
-end
-
--- Item: Execute
--- A simple button
-do
- local widgetType = "Dropdown-Item-Execute"
- local widgetVersion = 1
-
- local function Frame_OnClick(this, button)
- local self = this.obj
- if self.disabled then return end
- self:Fire("OnClick")
- if self.pullout then
- self.pullout:Close()
- end
- end
-
- local function Constructor()
- local self = ItemBase.Create(widgetType)
-
- self.frame:SetScript("OnClick", Frame_OnClick)
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
-end
-
--- Item: Toggle
--- Some sort of checkbox for dropdown menus.
--- Does not close the pullout on click.
-do
- local widgetType = "Dropdown-Item-Toggle"
- local widgetVersion = 4
-
- local function UpdateToggle(self)
- if self.value then
- self.check:Show()
- else
- self.check:Hide()
- end
- end
-
- local function OnRelease(self)
- ItemBase.OnRelease(self)
- self:SetValue(nil)
- end
-
- local function Frame_OnClick(this, button)
- local self = this.obj
- if self.disabled then return end
- self.value = not self.value
- if self.value then
- PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
- else
- PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF
- end
- UpdateToggle(self)
- self:Fire("OnValueChanged", self.value)
- end
-
- -- exported
- local function SetValue(self, value)
- self.value = value
- UpdateToggle(self)
- end
-
- -- exported
- local function GetValue(self)
- return self.value
- end
-
- local function Constructor()
- local self = ItemBase.Create(widgetType)
-
- self.frame:SetScript("OnClick", Frame_OnClick)
-
- self.SetValue = SetValue
- self.GetValue = GetValue
- self.OnRelease = OnRelease
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
-end
-
--- Item: Menu
--- Shows a submenu on mouse over
--- Does not close the pullout on click
-do
- local widgetType = "Dropdown-Item-Menu"
- local widgetVersion = 2
-
- local function OnEnter(this)
- local self = this.obj
- self:Fire("OnEnter")
-
- if self.specialOnEnter then
- self.specialOnEnter(self)
- end
-
- self.highlight:Show()
-
- if not self.disabled and self.submenu then
- self.submenu:Open("TOPLEFT", self.frame, "TOPRIGHT", self.pullout:GetRightBorderWidth(), 0, self.frame:GetFrameLevel() + 100)
- end
- end
-
- local function OnHide(this)
- local self = this.obj
- if self.submenu then
- self.submenu:Close()
- end
- end
-
- -- exported
- local function SetMenu(self, menu)
- assert(menu.type == "Dropdown-Pullout")
- self.submenu = menu
- end
-
- -- exported
- local function CloseMenu(self)
- self.submenu:Close()
- end
-
- local function Constructor()
- local self = ItemBase.Create(widgetType)
-
- self.sub:Show()
-
- self.frame:SetScript("OnEnter", OnEnter)
- self.frame:SetScript("OnHide", OnHide)
-
- self.SetMenu = SetMenu
- self.CloseMenu = CloseMenu
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
-end
-
--- Item: Separator
--- A single line to separate items
-do
- local widgetType = "Dropdown-Item-Separator"
- local widgetVersion = 2
-
- -- exported, override
- local function SetDisabled(self, disabled)
- ItemBase.SetDisabled(self, disabled)
- self.useHighlight = false
- end
-
- local function Constructor()
- local self = ItemBase.Create(widgetType)
-
- self.SetDisabled = SetDisabled
-
- local line = self.frame:CreateTexture(nil, "OVERLAY")
- line:SetHeight(1)
- line:SetColorTexture(.5, .5, .5)
- line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
- line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
-
- self.text:Hide()
-
- self.useHighlight = false
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
-end
+--[[ $Id: AceGUIWidget-DropDown-Items.lua 1272 2022-08-29 15:56:35Z nevcairiel $ ]]--
+
+local AceGUI = LibStub("AceGUI-3.0")
+
+-- Lua APIs
+local select, assert = select, assert
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame = CreateFrame
+
+local function fixlevels(parent,...)
+ local i = 1
+ local child = select(i, ...)
+ while child do
+ child:SetFrameLevel(parent:GetFrameLevel()+1)
+ fixlevels(child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+local function fixstrata(strata, parent, ...)
+ local i = 1
+ local child = select(i, ...)
+ parent:SetFrameStrata(strata)
+ while child do
+ fixstrata(strata, child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+-- ItemBase is the base "class" for all dropdown items.
+-- Each item has to use ItemBase.Create(widgetType) to
+-- create an initial 'self' value.
+-- ItemBase will add common functions and ui event handlers.
+-- Be sure to keep basic usage when you override functions.
+
+local ItemBase = {
+ -- NOTE: The ItemBase version is added to each item's version number
+ -- to ensure proper updates on ItemBase changes.
+ -- Use at least 1000er steps.
+ version = 2000,
+ counter = 0,
+}
+
+function ItemBase.Frame_OnEnter(this)
+ local self = this.obj
+
+ if self.useHighlight then
+ self.highlight:Show()
+ end
+ self:Fire("OnEnter")
+
+ if self.specialOnEnter then
+ self.specialOnEnter(self)
+ end
+end
+
+function ItemBase.Frame_OnLeave(this)
+ local self = this.obj
+
+ self.highlight:Hide()
+ self:Fire("OnLeave")
+
+ if self.specialOnLeave then
+ self.specialOnLeave(self)
+ end
+end
+
+-- exported, AceGUI callback
+function ItemBase.OnAcquire(self)
+ self.frame:SetToplevel(true)
+ self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+end
+
+-- exported, AceGUI callback
+function ItemBase.OnRelease(self)
+ self:SetDisabled(false)
+ self.pullout = nil
+ self.frame:SetParent(nil)
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+end
+
+-- exported
+-- NOTE: this is called by a Dropdown-Pullout.
+-- Do not call this method directly
+function ItemBase.SetPullout(self, pullout)
+ self.pullout = pullout
+
+ self.frame:SetParent(nil)
+ self.frame:SetParent(pullout.itemFrame)
+ self.parent = pullout.itemFrame
+ fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren())
+end
+
+-- exported
+function ItemBase.SetText(self, text)
+ self.text:SetText(text or "")
+end
+
+-- exported
+function ItemBase.GetText(self)
+ return self.text:GetText()
+end
+
+-- exported
+function ItemBase.SetPoint(self, ...)
+ self.frame:SetPoint(...)
+end
+
+-- exported
+function ItemBase.Show(self)
+ self.frame:Show()
+end
+
+-- exported
+function ItemBase.Hide(self)
+ self.frame:Hide()
+end
+
+-- exported
+function ItemBase.SetDisabled(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.useHighlight = false
+ self.text:SetTextColor(.5, .5, .5)
+ else
+ self.useHighlight = true
+ self.text:SetTextColor(1, 1, 1)
+ end
+end
+
+-- exported
+-- NOTE: this is called by a Dropdown-Pullout.
+-- Do not call this method directly
+function ItemBase.SetOnLeave(self, func)
+ self.specialOnLeave = func
+end
+
+-- exported
+-- NOTE: this is called by a Dropdown-Pullout.
+-- Do not call this method directly
+function ItemBase.SetOnEnter(self, func)
+ self.specialOnEnter = func
+end
+
+function ItemBase.Create(type)
+ -- NOTE: Most of the following code is copied from AceGUI-3.0/Dropdown widget
+ local count = AceGUI:GetNextWidgetNum(type)
+ local frame = CreateFrame("Button", "AceGUI30DropDownItem"..count)
+ local self = {}
+ self.frame = frame
+ frame.obj = self
+ self.type = type
+
+ self.useHighlight = true
+
+ frame:SetHeight(17)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
+ text:SetTextColor(1,1,1)
+ text:SetJustifyH("LEFT")
+ text:SetPoint("TOPLEFT",frame,"TOPLEFT",18,0)
+ text:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-8,0)
+ self.text = text
+
+ local highlight = frame:CreateTexture(nil, "OVERLAY")
+ highlight:SetTexture(136810) -- Interface\\QuestFrame\\UI-QuestTitleHighlight
+ highlight:SetBlendMode("ADD")
+ highlight:SetHeight(14)
+ highlight:ClearAllPoints()
+ highlight:SetPoint("RIGHT",frame,"RIGHT",-3,0)
+ highlight:SetPoint("LEFT",frame,"LEFT",5,0)
+ highlight:Hide()
+ self.highlight = highlight
+
+ local check = frame:CreateTexture(nil, "OVERLAY")
+ check:SetWidth(16)
+ check:SetHeight(16)
+ check:SetPoint("LEFT",frame,"LEFT",3,-1)
+ check:SetTexture(130751) -- Interface\\Buttons\\UI-CheckBox-Check
+ check:Hide()
+ self.check = check
+
+ local sub = frame:CreateTexture(nil, "OVERLAY")
+ sub:SetWidth(16)
+ sub:SetHeight(16)
+ sub:SetPoint("RIGHT",frame,"RIGHT",-3,-1)
+ sub:SetTexture(130940) -- Interface\\ChatFrame\\ChatFrameExpandArrow
+ sub:Hide()
+ self.sub = sub
+
+ frame:SetScript("OnEnter", ItemBase.Frame_OnEnter)
+ frame:SetScript("OnLeave", ItemBase.Frame_OnLeave)
+
+ self.OnAcquire = ItemBase.OnAcquire
+ self.OnRelease = ItemBase.OnRelease
+
+ self.SetPullout = ItemBase.SetPullout
+ self.GetText = ItemBase.GetText
+ self.SetText = ItemBase.SetText
+ self.SetDisabled = ItemBase.SetDisabled
+
+ self.SetPoint = ItemBase.SetPoint
+ self.Show = ItemBase.Show
+ self.Hide = ItemBase.Hide
+
+ self.SetOnLeave = ItemBase.SetOnLeave
+ self.SetOnEnter = ItemBase.SetOnEnter
+
+ return self
+end
+
+-- Register a dummy LibStub library to retrieve the ItemBase, so other addons can use it.
+local IBLib = LibStub:NewLibrary("AceGUI-3.0-DropDown-ItemBase", ItemBase.version)
+if IBLib then
+ IBLib.GetItemBase = function() return ItemBase end
+end
+
+--[[
+ Template for items:
+
+-- Item:
+--
+do
+ local widgetType = "Dropdown-Item-"
+ local widgetVersion = 1
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+--]]
+
+-- Item: Header
+-- A single text entry.
+-- Special: Different text color and no highlight
+do
+ local widgetType = "Dropdown-Item-Header"
+ local widgetVersion = 1
+
+ local function OnEnter(this)
+ local self = this.obj
+ self:Fire("OnEnter")
+
+ if self.specialOnEnter then
+ self.specialOnEnter(self)
+ end
+ end
+
+ local function OnLeave(this)
+ local self = this.obj
+ self:Fire("OnLeave")
+
+ if self.specialOnLeave then
+ self.specialOnLeave(self)
+ end
+ end
+
+ -- exported, override
+ local function SetDisabled(self, disabled)
+ ItemBase.SetDisabled(self, disabled)
+ if not disabled then
+ self.text:SetTextColor(1, 1, 0)
+ end
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.SetDisabled = SetDisabled
+
+ self.frame:SetScript("OnEnter", OnEnter)
+ self.frame:SetScript("OnLeave", OnLeave)
+
+ self.text:SetTextColor(1, 1, 0)
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Execute
+-- A simple button
+do
+ local widgetType = "Dropdown-Item-Execute"
+ local widgetVersion = 1
+
+ local function Frame_OnClick(this, button)
+ local self = this.obj
+ if self.disabled then return end
+ self:Fire("OnClick")
+ if self.pullout then
+ self.pullout:Close()
+ end
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.frame:SetScript("OnClick", Frame_OnClick)
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Toggle
+-- Some sort of checkbox for dropdown menus.
+-- Does not close the pullout on click.
+do
+ local widgetType = "Dropdown-Item-Toggle"
+ local widgetVersion = 4
+
+ local function UpdateToggle(self)
+ if self.value then
+ self.check:Show()
+ else
+ self.check:Hide()
+ end
+ end
+
+ local function OnRelease(self)
+ ItemBase.OnRelease(self)
+ self:SetValue(nil)
+ end
+
+ local function Frame_OnClick(this, button)
+ local self = this.obj
+ if self.disabled then return end
+ self.value = not self.value
+ if self.value then
+ PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
+ else
+ PlaySound(857) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF
+ end
+ UpdateToggle(self)
+ self:Fire("OnValueChanged", self.value)
+ end
+
+ -- exported
+ local function SetValue(self, value)
+ self.value = value
+ UpdateToggle(self)
+ end
+
+ -- exported
+ local function GetValue(self)
+ return self.value
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.frame:SetScript("OnClick", Frame_OnClick)
+
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.OnRelease = OnRelease
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Menu
+-- Shows a submenu on mouse over
+-- Does not close the pullout on click
+do
+ local widgetType = "Dropdown-Item-Menu"
+ local widgetVersion = 2
+
+ local function OnEnter(this)
+ local self = this.obj
+ self:Fire("OnEnter")
+
+ if self.specialOnEnter then
+ self.specialOnEnter(self)
+ end
+
+ self.highlight:Show()
+
+ if not self.disabled and self.submenu then
+ self.submenu:Open("TOPLEFT", self.frame, "TOPRIGHT", self.pullout:GetRightBorderWidth(), 0, self.frame:GetFrameLevel() + 100)
+ end
+ end
+
+ local function OnHide(this)
+ local self = this.obj
+ if self.submenu then
+ self.submenu:Close()
+ end
+ end
+
+ -- exported
+ local function SetMenu(self, menu)
+ assert(menu.type == "Dropdown-Pullout")
+ self.submenu = menu
+ end
+
+ -- exported
+ local function CloseMenu(self)
+ self.submenu:Close()
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.sub:Show()
+
+ self.frame:SetScript("OnEnter", OnEnter)
+ self.frame:SetScript("OnHide", OnHide)
+
+ self.SetMenu = SetMenu
+ self.CloseMenu = CloseMenu
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
+
+-- Item: Separator
+-- A single line to separate items
+do
+ local widgetType = "Dropdown-Item-Separator"
+ local widgetVersion = 2
+
+ -- exported, override
+ local function SetDisabled(self, disabled)
+ ItemBase.SetDisabled(self, disabled)
+ self.useHighlight = false
+ end
+
+ local function Constructor()
+ local self = ItemBase.Create(widgetType)
+
+ self.SetDisabled = SetDisabled
+
+ local line = self.frame:CreateTexture(nil, "OVERLAY")
+ line:SetHeight(1)
+ line:SetColorTexture(.5, .5, .5)
+ line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
+ line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
+
+ self.text:Hide()
+
+ self.useHighlight = false
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
+end
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
index 3d8dd11..59c7f53 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
@@ -1,732 +1,732 @@
---[[ $Id: AceGUIWidget-DropDown.lua 1284 2022-09-25 09:15:30Z nevcairiel $ ]]--
-local AceGUI = LibStub("AceGUI-3.0")
-
--- Lua APIs
-local min, max, floor = math.min, math.max, math.floor
-local select, pairs, ipairs, type, tostring = select, pairs, ipairs, type, tostring
-local tsort = table.sort
-
--- WoW APIs
-local PlaySound = PlaySound
-local UIParent, CreateFrame = UIParent, CreateFrame
-local _G = _G
-
-local function fixlevels(parent,...)
- local i = 1
- local child = select(i, ...)
- while child do
- child:SetFrameLevel(parent:GetFrameLevel()+1)
- fixlevels(child, child:GetChildren())
- i = i + 1
- child = select(i, ...)
- end
-end
-
-local function fixstrata(strata, parent, ...)
- local i = 1
- local child = select(i, ...)
- parent:SetFrameStrata(strata)
- while child do
- fixstrata(strata, child, child:GetChildren())
- i = i + 1
- child = select(i, ...)
- end
-end
-
-do
- local widgetType = "Dropdown-Pullout"
- local widgetVersion = 5
-
- --[[ Static data ]]--
-
- local backdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
- edgeSize = 32,
- tileSize = 32,
- tile = true,
- insets = { left = 11, right = 12, top = 12, bottom = 11 },
- }
- local sliderBackdrop = {
- bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
- edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
- tile = true, tileSize = 8, edgeSize = 8,
- insets = { left = 3, right = 3, top = 3, bottom = 3 }
- }
-
- local defaultWidth = 200
- local defaultMaxHeight = 600
-
- --[[ UI Event Handlers ]]--
-
- -- HACK: This should be no part of the pullout, but there
- -- is no other 'clean' way to response to any item-OnEnter
- -- Used to close Submenus when an other item is entered
- local function OnEnter(item)
- local self = item.pullout
- for k, v in ipairs(self.items) do
- if v.CloseMenu and v ~= item then
- v:CloseMenu()
- end
- end
- end
-
- -- See the note in Constructor() for each scroll related function
- local function OnMouseWheel(this, value)
- this.obj:MoveScroll(value)
- end
-
- local function OnScrollValueChanged(this, value)
- this.obj:SetScroll(value)
- end
-
- local function OnSizeChanged(this)
- this.obj:FixScroll()
- end
-
- --[[ Exported methods ]]--
-
- -- exported
- local function SetScroll(self, value)
- local status = self.scrollStatus
- local frame, child = self.scrollFrame, self.itemFrame
- local height, viewheight = frame:GetHeight(), child:GetHeight()
-
- local offset
- if height > viewheight then
- offset = 0
- else
- offset = floor((viewheight - height) / 1000 * value)
- 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
-
- -- exported
- local function MoveScroll(self, value)
- local status = self.scrollStatus
- local frame, child = self.scrollFrame, self.itemFrame
- local height, viewheight = frame:GetHeight(), child:GetHeight()
-
- if height > viewheight then
- self.slider:Hide()
- else
- self.slider:Show()
- local diff = height - viewheight
- local delta = 1
- if value < 0 then
- delta = -1
- end
- self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
- end
- end
-
- -- exported
- local function FixScroll(self)
- local status = self.scrollStatus
- local frame, child = self.scrollFrame, self.itemFrame
- local height, viewheight = frame:GetHeight(), child:GetHeight()
- local offset = status.offset or 0
-
- if viewheight < height then
- self.slider:Hide()
- child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
- self.slider:SetValue(0)
- else
- self.slider:Show()
- local value = (offset / (viewheight - height) * 1000)
- if value > 1000 then value = 1000 end
- self.slider:SetValue(value)
- self:SetScroll(value)
- 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
- end
-
- -- exported, AceGUI callback
- local function OnAcquire(self)
- self.frame:SetParent(UIParent)
- --self.itemFrame:SetToplevel(true)
- end
-
- -- exported, AceGUI callback
- local function OnRelease(self)
- self:Clear()
- self.frame:ClearAllPoints()
- self.frame:Hide()
- end
-
- -- exported
- local function AddItem(self, item)
- self.items[#self.items + 1] = item
-
- local h = #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
-
- item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
- item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
-
- item:SetPullout(self)
- item:SetOnEnter(OnEnter)
- end
-
- -- exported
- local function Open(self, point, relFrame, relPoint, x, y)
- local items = self.items
- local frame = self.frame
- local itemFrame = self.itemFrame
-
- frame:SetPoint(point, relFrame, relPoint, x, y)
-
-
- local height = 8
- for i, item in pairs(items) do
- item:SetPoint("TOP", itemFrame, "TOP", 0, -2 + (i - 1) * -16)
- item:Show()
-
- height = height + 16
- end
- itemFrame:SetHeight(height)
- fixstrata("TOOLTIP", frame, frame:GetChildren())
- frame:Show()
- self:Fire("OnOpen")
- end
-
- -- exported
- local function Close(self)
- self.frame:Hide()
- self:Fire("OnClose")
- end
-
- -- exported
- local function Clear(self)
- local items = self.items
- for i, item in pairs(items) do
- AceGUI:Release(item)
- items[i] = nil
- end
- end
-
- -- exported
- local function IterateItems(self)
- return ipairs(self.items)
- end
-
- -- exported
- local function SetHideOnLeave(self, val)
- self.hideOnLeave = val
- end
-
- -- exported
- local function SetMaxHeight(self, height)
- self.maxHeight = height or defaultMaxHeight
- if self.frame:GetHeight() > height then
- self.frame:SetHeight(height)
- elseif (self.itemFrame:GetHeight() + 34) < height then
- self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
- end
- end
-
- -- exported
- local function GetRightBorderWidth(self)
- return 6 + (self.slider:IsShown() and 12 or 0)
- end
-
- -- exported
- local function GetLeftBorderWidth(self)
- return 6
- end
-
- --[[ Constructor ]]--
-
- local function Constructor()
- local count = AceGUI:GetNextWidgetNum(widgetType)
- local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent, "BackdropTemplate")
- local self = {}
- self.count = count
- self.type = widgetType
- self.frame = frame
- frame.obj = self
-
- self.OnAcquire = OnAcquire
- self.OnRelease = OnRelease
-
- self.AddItem = AddItem
- self.Open = Open
- self.Close = Close
- self.Clear = Clear
- self.IterateItems = IterateItems
- self.SetHideOnLeave = SetHideOnLeave
-
- self.SetScroll = SetScroll
- self.MoveScroll = MoveScroll
- self.FixScroll = FixScroll
-
- self.SetMaxHeight = SetMaxHeight
- self.GetRightBorderWidth = GetRightBorderWidth
- self.GetLeftBorderWidth = GetLeftBorderWidth
-
- self.items = {}
-
- self.scrollStatus = {
- scrollvalue = 0,
- }
-
- self.maxHeight = defaultMaxHeight
-
- frame:SetBackdrop(backdrop)
- frame:SetBackdropColor(0, 0, 0)
- frame:SetFrameStrata("FULLSCREEN_DIALOG")
- frame:SetClampedToScreen(true)
- frame:SetWidth(defaultWidth)
- frame:SetHeight(self.maxHeight)
- --frame:SetToplevel(true)
-
- -- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
- local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
- local itemFrame = CreateFrame("Frame", nil, scrollFrame)
-
- self.scrollFrame = scrollFrame
- self.itemFrame = itemFrame
-
- scrollFrame.obj = self
- itemFrame.obj = self
-
- local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame, "BackdropTemplate")
- slider:SetOrientation("VERTICAL")
- slider:SetHitRectInsets(0, 0, -10, 0)
- slider:SetBackdrop(sliderBackdrop)
- slider:SetWidth(8)
- slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
- slider:SetFrameStrata("FULLSCREEN_DIALOG")
- self.slider = slider
- slider.obj = self
-
- scrollFrame:SetScrollChild(itemFrame)
- 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)
- scrollFrame:SetToplevel(true)
- scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
- itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
- itemFrame:SetHeight(400)
- itemFrame:SetToplevel(true)
- itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
-
- slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
- slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
- slider:SetScript("OnValueChanged", OnScrollValueChanged)
- slider:SetMinMaxValues(0, 1000)
- slider:SetValueStep(1)
- slider:SetValue(0)
-
- scrollFrame:Show()
- itemFrame:Show()
- slider:Hide()
-
- self:FixScroll()
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
-end
-
-do
- local widgetType = "Dropdown"
- local widgetVersion = 36
-
- --[[ Static data ]]--
-
- --[[ UI event handler ]]--
-
- local function Control_OnEnter(this)
- this.obj.button:LockHighlight()
- this.obj:Fire("OnEnter")
- end
-
- local function Control_OnLeave(this)
- this.obj.button:UnlockHighlight()
- this.obj:Fire("OnLeave")
- end
-
- local function Dropdown_OnHide(this)
- local self = this.obj
- if self.open then
- self.pullout:Close()
- end
- end
-
- local function Dropdown_TogglePullout(this)
- local self = this.obj
- if self.open then
- self.open = nil
- self.pullout:Close()
- AceGUI:ClearFocus()
- else
- self.open = true
- self.pullout:SetWidth(self.pulloutWidth or self.frame:GetWidth())
- self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
- AceGUI:SetFocus(self)
- end
- end
-
- local function OnPulloutOpen(this)
- local self = this.userdata.obj
- local value = self.value
-
- if not self.multiselect then
- for i, item in this:IterateItems() do
- item:SetValue(item.userdata.value == value)
- end
- end
-
- self.open = true
- self:Fire("OnOpened")
- end
-
- local function OnPulloutClose(this)
- local self = this.userdata.obj
- self.open = nil
- self:Fire("OnClosed")
- end
-
- local function ShowMultiText(self)
- local text
- for i, widget in self.pullout:IterateItems() do
- if widget.type == "Dropdown-Item-Toggle" then
- if widget:GetValue() then
- if text then
- text = text..", "..widget:GetText()
- else
- text = widget:GetText()
- end
- end
- end
- end
- self:SetText(text)
- end
-
- local function OnItemValueChanged(this, event, checked)
- local self = this.userdata.obj
-
- if self.multiselect then
- self:Fire("OnValueChanged", this.userdata.value, checked)
- ShowMultiText(self)
- else
- if checked then
- self:SetValue(this.userdata.value)
- self:Fire("OnValueChanged", this.userdata.value)
- else
- this:SetValue(true)
- end
- if self.open then
- self.pullout:Close()
- end
- end
- end
-
- --[[ Exported methods ]]--
-
- -- exported, AceGUI callback
- local function OnAcquire(self)
- local pullout = AceGUI:Create("Dropdown-Pullout")
- self.pullout = pullout
- pullout.userdata.obj = self
- pullout:SetCallback("OnClose", OnPulloutClose)
- pullout:SetCallback("OnOpen", OnPulloutOpen)
- self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
- fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
-
- self:SetHeight(44)
- self:SetWidth(200)
- self:SetLabel()
- self:SetPulloutWidth(nil)
- self.list = {}
- end
-
- -- exported, AceGUI callback
- local function OnRelease(self)
- if self.open then
- self.pullout:Close()
- end
- AceGUI:Release(self.pullout)
- self.pullout = nil
-
- self:SetText("")
- self:SetDisabled(false)
- self:SetMultiselect(false)
-
- self.value = nil
- self.list = nil
- self.open = nil
- self.hasClose = nil
-
- self.frame:ClearAllPoints()
- self.frame:Hide()
- end
-
- -- exported
- local function SetDisabled(self, disabled)
- self.disabled = disabled
- if disabled then
- self.text:SetTextColor(0.5,0.5,0.5)
- self.button:Disable()
- self.button_cover:Disable()
- self.label:SetTextColor(0.5,0.5,0.5)
- else
- self.button:Enable()
- self.button_cover:Enable()
- self.label:SetTextColor(1,.82,0)
- self.text:SetTextColor(1,1,1)
- end
- end
-
- -- exported
- local function ClearFocus(self)
- if self.open then
- self.pullout:Close()
- end
- end
-
- -- exported
- local function SetText(self, text)
- self.text:SetText(text or "")
- end
-
- -- exported
- local function SetLabel(self, text)
- if text and text ~= "" then
- self.label:SetText(text)
- self.label:Show()
- self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-14)
- self:SetHeight(40)
- self.alignoffset = 26
- else
- self.label:SetText("")
- self.label:Hide()
- self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
- self:SetHeight(26)
- self.alignoffset = 12
- end
- end
-
- -- exported
- local function SetValue(self, value)
- self:SetText(self.list[value] or "")
- self.value = value
- end
-
- -- exported
- local function GetValue(self)
- return self.value
- end
-
- -- exported
- local function SetItemValue(self, item, value)
- if not self.multiselect then return end
- for i, widget in self.pullout:IterateItems() do
- if widget.userdata.value == item then
- if widget.SetValue then
- widget:SetValue(value)
- end
- end
- end
- ShowMultiText(self)
- end
-
- -- exported
- local function SetItemDisabled(self, item, disabled)
- for i, widget in self.pullout:IterateItems() do
- if widget.userdata.value == item then
- widget:SetDisabled(disabled)
- end
- end
- end
-
- local function AddListItem(self, value, text, itemType)
- if not itemType then itemType = "Dropdown-Item-Toggle" end
- local exists = AceGUI:GetWidgetVersion(itemType)
- if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end
-
- local item = AceGUI:Create(itemType)
- item:SetText(text)
- item.userdata.obj = self
- item.userdata.value = value
- item:SetCallback("OnValueChanged", OnItemValueChanged)
- self.pullout:AddItem(item)
- end
-
- local function AddCloseButton(self)
- if not self.hasClose then
- local close = AceGUI:Create("Dropdown-Item-Execute")
- close:SetText(CLOSE)
- self.pullout:AddItem(close)
- self.hasClose = true
- end
- end
-
- -- exported
- local sortlist = {}
- local function sortTbl(x,y)
- local num1, num2 = tonumber(x), tonumber(y)
- if num1 and num2 then -- numeric comparison, either two numbers or numeric strings
- return num1 < num2
- else -- compare everything else tostring'ed
- return tostring(x) < tostring(y)
- end
- end
- local function SetList(self, list, order, itemType)
- self.list = list or {}
- self.pullout:Clear()
- self.hasClose = nil
- if not list then return end
-
- if type(order) ~= "table" then
- for v in pairs(list) do
- sortlist[#sortlist + 1] = v
- end
- tsort(sortlist, sortTbl)
-
- for i, key in ipairs(sortlist) do
- AddListItem(self, key, list[key], itemType)
- sortlist[i] = nil
- end
- else
- for i, key in ipairs(order) do
- AddListItem(self, key, list[key], itemType)
- end
- end
- if self.multiselect then
- ShowMultiText(self)
- AddCloseButton(self)
- end
- end
-
- -- exported
- local function AddItem(self, value, text, itemType)
- self.list[value] = text
- AddListItem(self, value, text, itemType)
- end
-
- -- exported
- local function SetMultiselect(self, multi)
- self.multiselect = multi
- if multi then
- ShowMultiText(self)
- AddCloseButton(self)
- end
- end
-
- -- exported
- local function GetMultiselect(self)
- return self.multiselect
- end
-
- local function SetPulloutWidth(self, width)
- self.pulloutWidth = width
- end
-
- --[[ Constructor ]]--
-
- local function Constructor()
- local count = AceGUI:GetNextWidgetNum(widgetType)
- local frame = CreateFrame("Frame", nil, UIParent)
- local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
-
- local self = {}
- self.type = widgetType
- self.frame = frame
- self.dropdown = dropdown
- self.count = count
- frame.obj = self
- dropdown.obj = self
-
- self.OnRelease = OnRelease
- self.OnAcquire = OnAcquire
-
- self.ClearFocus = ClearFocus
-
- self.SetText = SetText
- self.SetValue = SetValue
- self.GetValue = GetValue
- self.SetList = SetList
- self.SetLabel = SetLabel
- self.SetDisabled = SetDisabled
- self.AddItem = AddItem
- self.SetMultiselect = SetMultiselect
- self.GetMultiselect = GetMultiselect
- self.SetItemValue = SetItemValue
- self.SetItemDisabled = SetItemDisabled
- self.SetPulloutWidth = SetPulloutWidth
-
- self.alignoffset = 26
-
- frame:SetScript("OnHide",Dropdown_OnHide)
-
- dropdown:ClearAllPoints()
- dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
- dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
- dropdown:SetScript("OnHide", nil)
-
- local left = _G[dropdown:GetName() .. "Left"]
- local middle = _G[dropdown:GetName() .. "Middle"]
- local right = _G[dropdown:GetName() .. "Right"]
-
- middle:ClearAllPoints()
- right:ClearAllPoints()
-
- middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
- middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
- right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
-
- local button = _G[dropdown:GetName() .. "Button"]
- self.button = button
- button.obj = self
- button:SetScript("OnEnter",Control_OnEnter)
- button:SetScript("OnLeave",Control_OnLeave)
- button:SetScript("OnClick",Dropdown_TogglePullout)
-
- local button_cover = CreateFrame("BUTTON",nil,self.frame)
- self.button_cover = button_cover
- button_cover.obj = self
- button_cover:SetPoint("TOPLEFT",self.frame,"BOTTOMLEFT",0,25)
- button_cover:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT")
- button_cover:SetScript("OnEnter",Control_OnEnter)
- button_cover:SetScript("OnLeave",Control_OnLeave)
- button_cover:SetScript("OnClick",Dropdown_TogglePullout)
-
- local text = _G[dropdown:GetName() .. "Text"]
- self.text = text
- text.obj = self
- text:ClearAllPoints()
- text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
- text:SetPoint("LEFT", left, "LEFT", 25, 2)
-
- local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
- label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
- label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
- label:SetJustifyH("LEFT")
- label:SetHeight(18)
- label:Hide()
- self.label = label
-
- AceGUI:RegisterAsWidget(self)
- return self
- end
-
- AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
-end
+--[[ $Id: AceGUIWidget-DropDown.lua 1284 2022-09-25 09:15:30Z nevcairiel $ ]]--
+local AceGUI = LibStub("AceGUI-3.0")
+
+-- Lua APIs
+local min, max, floor = math.min, math.max, math.floor
+local select, pairs, ipairs, type, tostring = select, pairs, ipairs, type, tostring
+local tsort = table.sort
+
+-- WoW APIs
+local PlaySound = PlaySound
+local UIParent, CreateFrame = UIParent, CreateFrame
+local _G = _G
+
+local function fixlevels(parent,...)
+ local i = 1
+ local child = select(i, ...)
+ while child do
+ child:SetFrameLevel(parent:GetFrameLevel()+1)
+ fixlevels(child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+local function fixstrata(strata, parent, ...)
+ local i = 1
+ local child = select(i, ...)
+ parent:SetFrameStrata(strata)
+ while child do
+ fixstrata(strata, child, child:GetChildren())
+ i = i + 1
+ child = select(i, ...)
+ end
+end
+
+do
+ local widgetType = "Dropdown-Pullout"
+ local widgetVersion = 5
+
+ --[[ Static data ]]--
+
+ local backdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
+ edgeSize = 32,
+ tileSize = 32,
+ tile = true,
+ insets = { left = 11, right = 12, top = 12, bottom = 11 },
+ }
+ local sliderBackdrop = {
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+ }
+
+ local defaultWidth = 200
+ local defaultMaxHeight = 600
+
+ --[[ UI Event Handlers ]]--
+
+ -- HACK: This should be no part of the pullout, but there
+ -- is no other 'clean' way to response to any item-OnEnter
+ -- Used to close Submenus when an other item is entered
+ local function OnEnter(item)
+ local self = item.pullout
+ for k, v in ipairs(self.items) do
+ if v.CloseMenu and v ~= item then
+ v:CloseMenu()
+ end
+ end
+ end
+
+ -- See the note in Constructor() for each scroll related function
+ local function OnMouseWheel(this, value)
+ this.obj:MoveScroll(value)
+ end
+
+ local function OnScrollValueChanged(this, value)
+ this.obj:SetScroll(value)
+ end
+
+ local function OnSizeChanged(this)
+ this.obj:FixScroll()
+ end
+
+ --[[ Exported methods ]]--
+
+ -- exported
+ local function SetScroll(self, value)
+ local status = self.scrollStatus
+ local frame, child = self.scrollFrame, self.itemFrame
+ local height, viewheight = frame:GetHeight(), child:GetHeight()
+
+ local offset
+ if height > viewheight then
+ offset = 0
+ else
+ offset = floor((viewheight - height) / 1000 * value)
+ 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
+
+ -- exported
+ local function MoveScroll(self, value)
+ local status = self.scrollStatus
+ local frame, child = self.scrollFrame, self.itemFrame
+ local height, viewheight = frame:GetHeight(), child:GetHeight()
+
+ if height > viewheight then
+ self.slider:Hide()
+ else
+ self.slider:Show()
+ local diff = height - viewheight
+ local delta = 1
+ if value < 0 then
+ delta = -1
+ end
+ self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
+ end
+ end
+
+ -- exported
+ local function FixScroll(self)
+ local status = self.scrollStatus
+ local frame, child = self.scrollFrame, self.itemFrame
+ local height, viewheight = frame:GetHeight(), child:GetHeight()
+ local offset = status.offset or 0
+
+ if viewheight < height then
+ self.slider:Hide()
+ child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
+ self.slider:SetValue(0)
+ else
+ self.slider:Show()
+ local value = (offset / (viewheight - height) * 1000)
+ if value > 1000 then value = 1000 end
+ self.slider:SetValue(value)
+ self:SetScroll(value)
+ 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
+ end
+
+ -- exported, AceGUI callback
+ local function OnAcquire(self)
+ self.frame:SetParent(UIParent)
+ --self.itemFrame:SetToplevel(true)
+ end
+
+ -- exported, AceGUI callback
+ local function OnRelease(self)
+ self:Clear()
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ -- exported
+ local function AddItem(self, item)
+ self.items[#self.items + 1] = item
+
+ local h = #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
+
+ item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
+ item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
+
+ item:SetPullout(self)
+ item:SetOnEnter(OnEnter)
+ end
+
+ -- exported
+ local function Open(self, point, relFrame, relPoint, x, y)
+ local items = self.items
+ local frame = self.frame
+ local itemFrame = self.itemFrame
+
+ frame:SetPoint(point, relFrame, relPoint, x, y)
+
+
+ local height = 8
+ for i, item in pairs(items) do
+ item:SetPoint("TOP", itemFrame, "TOP", 0, -2 + (i - 1) * -16)
+ item:Show()
+
+ height = height + 16
+ end
+ itemFrame:SetHeight(height)
+ fixstrata("TOOLTIP", frame, frame:GetChildren())
+ frame:Show()
+ self:Fire("OnOpen")
+ end
+
+ -- exported
+ local function Close(self)
+ self.frame:Hide()
+ self:Fire("OnClose")
+ end
+
+ -- exported
+ local function Clear(self)
+ local items = self.items
+ for i, item in pairs(items) do
+ AceGUI:Release(item)
+ items[i] = nil
+ end
+ end
+
+ -- exported
+ local function IterateItems(self)
+ return ipairs(self.items)
+ end
+
+ -- exported
+ local function SetHideOnLeave(self, val)
+ self.hideOnLeave = val
+ end
+
+ -- exported
+ local function SetMaxHeight(self, height)
+ self.maxHeight = height or defaultMaxHeight
+ if self.frame:GetHeight() > height then
+ self.frame:SetHeight(height)
+ elseif (self.itemFrame:GetHeight() + 34) < height then
+ self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
+ end
+ end
+
+ -- exported
+ local function GetRightBorderWidth(self)
+ return 6 + (self.slider:IsShown() and 12 or 0)
+ end
+
+ -- exported
+ local function GetLeftBorderWidth(self)
+ return 6
+ end
+
+ --[[ Constructor ]]--
+
+ local function Constructor()
+ local count = AceGUI:GetNextWidgetNum(widgetType)
+ local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent, "BackdropTemplate")
+ local self = {}
+ self.count = count
+ self.type = widgetType
+ self.frame = frame
+ frame.obj = self
+
+ self.OnAcquire = OnAcquire
+ self.OnRelease = OnRelease
+
+ self.AddItem = AddItem
+ self.Open = Open
+ self.Close = Close
+ self.Clear = Clear
+ self.IterateItems = IterateItems
+ self.SetHideOnLeave = SetHideOnLeave
+
+ self.SetScroll = SetScroll
+ self.MoveScroll = MoveScroll
+ self.FixScroll = FixScroll
+
+ self.SetMaxHeight = SetMaxHeight
+ self.GetRightBorderWidth = GetRightBorderWidth
+ self.GetLeftBorderWidth = GetLeftBorderWidth
+
+ self.items = {}
+
+ self.scrollStatus = {
+ scrollvalue = 0,
+ }
+
+ self.maxHeight = defaultMaxHeight
+
+ frame:SetBackdrop(backdrop)
+ frame:SetBackdropColor(0, 0, 0)
+ frame:SetFrameStrata("FULLSCREEN_DIALOG")
+ frame:SetClampedToScreen(true)
+ frame:SetWidth(defaultWidth)
+ frame:SetHeight(self.maxHeight)
+ --frame:SetToplevel(true)
+
+ -- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
+ local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
+ local itemFrame = CreateFrame("Frame", nil, scrollFrame)
+
+ self.scrollFrame = scrollFrame
+ self.itemFrame = itemFrame
+
+ scrollFrame.obj = self
+ itemFrame.obj = self
+
+ local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame, "BackdropTemplate")
+ slider:SetOrientation("VERTICAL")
+ slider:SetHitRectInsets(0, 0, -10, 0)
+ slider:SetBackdrop(sliderBackdrop)
+ slider:SetWidth(8)
+ slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
+ slider:SetFrameStrata("FULLSCREEN_DIALOG")
+ self.slider = slider
+ slider.obj = self
+
+ scrollFrame:SetScrollChild(itemFrame)
+ 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)
+ scrollFrame:SetToplevel(true)
+ scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
+ itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
+ itemFrame:SetHeight(400)
+ itemFrame:SetToplevel(true)
+ itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
+
+ slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
+ slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
+ slider:SetScript("OnValueChanged", OnScrollValueChanged)
+ slider:SetMinMaxValues(0, 1000)
+ slider:SetValueStep(1)
+ slider:SetValue(0)
+
+ scrollFrame:Show()
+ itemFrame:Show()
+ slider:Hide()
+
+ self:FixScroll()
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+end
+
+do
+ local widgetType = "Dropdown"
+ local widgetVersion = 36
+
+ --[[ Static data ]]--
+
+ --[[ UI event handler ]]--
+
+ local function Control_OnEnter(this)
+ this.obj.button:LockHighlight()
+ this.obj:Fire("OnEnter")
+ end
+
+ local function Control_OnLeave(this)
+ this.obj.button:UnlockHighlight()
+ this.obj:Fire("OnLeave")
+ end
+
+ local function Dropdown_OnHide(this)
+ local self = this.obj
+ if self.open then
+ self.pullout:Close()
+ end
+ end
+
+ local function Dropdown_TogglePullout(this)
+ local self = this.obj
+ if self.open then
+ self.open = nil
+ self.pullout:Close()
+ AceGUI:ClearFocus()
+ else
+ self.open = true
+ self.pullout:SetWidth(self.pulloutWidth or self.frame:GetWidth())
+ self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
+ AceGUI:SetFocus(self)
+ end
+ end
+
+ local function OnPulloutOpen(this)
+ local self = this.userdata.obj
+ local value = self.value
+
+ if not self.multiselect then
+ for i, item in this:IterateItems() do
+ item:SetValue(item.userdata.value == value)
+ end
+ end
+
+ self.open = true
+ self:Fire("OnOpened")
+ end
+
+ local function OnPulloutClose(this)
+ local self = this.userdata.obj
+ self.open = nil
+ self:Fire("OnClosed")
+ end
+
+ local function ShowMultiText(self)
+ local text
+ for i, widget in self.pullout:IterateItems() do
+ if widget.type == "Dropdown-Item-Toggle" then
+ if widget:GetValue() then
+ if text then
+ text = text..", "..widget:GetText()
+ else
+ text = widget:GetText()
+ end
+ end
+ end
+ end
+ self:SetText(text)
+ end
+
+ local function OnItemValueChanged(this, event, checked)
+ local self = this.userdata.obj
+
+ if self.multiselect then
+ self:Fire("OnValueChanged", this.userdata.value, checked)
+ ShowMultiText(self)
+ else
+ if checked then
+ self:SetValue(this.userdata.value)
+ self:Fire("OnValueChanged", this.userdata.value)
+ else
+ this:SetValue(true)
+ end
+ if self.open then
+ self.pullout:Close()
+ end
+ end
+ end
+
+ --[[ Exported methods ]]--
+
+ -- exported, AceGUI callback
+ local function OnAcquire(self)
+ local pullout = AceGUI:Create("Dropdown-Pullout")
+ self.pullout = pullout
+ pullout.userdata.obj = self
+ pullout:SetCallback("OnClose", OnPulloutClose)
+ pullout:SetCallback("OnOpen", OnPulloutOpen)
+ self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
+ fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
+
+ self:SetHeight(44)
+ self:SetWidth(200)
+ self:SetLabel()
+ self:SetPulloutWidth(nil)
+ self.list = {}
+ end
+
+ -- exported, AceGUI callback
+ local function OnRelease(self)
+ if self.open then
+ self.pullout:Close()
+ end
+ AceGUI:Release(self.pullout)
+ self.pullout = nil
+
+ self:SetText("")
+ self:SetDisabled(false)
+ self:SetMultiselect(false)
+
+ self.value = nil
+ self.list = nil
+ self.open = nil
+ self.hasClose = nil
+
+ self.frame:ClearAllPoints()
+ self.frame:Hide()
+ end
+
+ -- exported
+ local function SetDisabled(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.text:SetTextColor(0.5,0.5,0.5)
+ self.button:Disable()
+ self.button_cover:Disable()
+ self.label:SetTextColor(0.5,0.5,0.5)
+ else
+ self.button:Enable()
+ self.button_cover:Enable()
+ self.label:SetTextColor(1,.82,0)
+ self.text:SetTextColor(1,1,1)
+ end
+ end
+
+ -- exported
+ local function ClearFocus(self)
+ if self.open then
+ self.pullout:Close()
+ end
+ end
+
+ -- exported
+ local function SetText(self, text)
+ self.text:SetText(text or "")
+ end
+
+ -- exported
+ local function SetLabel(self, text)
+ if text and text ~= "" then
+ self.label:SetText(text)
+ self.label:Show()
+ self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-14)
+ self:SetHeight(40)
+ self.alignoffset = 26
+ else
+ self.label:SetText("")
+ self.label:Hide()
+ self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
+ self:SetHeight(26)
+ self.alignoffset = 12
+ end
+ end
+
+ -- exported
+ local function SetValue(self, value)
+ self:SetText(self.list[value] or "")
+ self.value = value
+ end
+
+ -- exported
+ local function GetValue(self)
+ return self.value
+ end
+
+ -- exported
+ local function SetItemValue(self, item, value)
+ if not self.multiselect then return end
+ for i, widget in self.pullout:IterateItems() do
+ if widget.userdata.value == item then
+ if widget.SetValue then
+ widget:SetValue(value)
+ end
+ end
+ end
+ ShowMultiText(self)
+ end
+
+ -- exported
+ local function SetItemDisabled(self, item, disabled)
+ for i, widget in self.pullout:IterateItems() do
+ if widget.userdata.value == item then
+ widget:SetDisabled(disabled)
+ end
+ end
+ end
+
+ local function AddListItem(self, value, text, itemType)
+ if not itemType then itemType = "Dropdown-Item-Toggle" end
+ local exists = AceGUI:GetWidgetVersion(itemType)
+ if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end
+
+ local item = AceGUI:Create(itemType)
+ item:SetText(text)
+ item.userdata.obj = self
+ item.userdata.value = value
+ item:SetCallback("OnValueChanged", OnItemValueChanged)
+ self.pullout:AddItem(item)
+ end
+
+ local function AddCloseButton(self)
+ if not self.hasClose then
+ local close = AceGUI:Create("Dropdown-Item-Execute")
+ close:SetText(CLOSE)
+ self.pullout:AddItem(close)
+ self.hasClose = true
+ end
+ end
+
+ -- exported
+ local sortlist = {}
+ local function sortTbl(x,y)
+ local num1, num2 = tonumber(x), tonumber(y)
+ if num1 and num2 then -- numeric comparison, either two numbers or numeric strings
+ return num1 < num2
+ else -- compare everything else tostring'ed
+ return tostring(x) < tostring(y)
+ end
+ end
+ local function SetList(self, list, order, itemType)
+ self.list = list or {}
+ self.pullout:Clear()
+ self.hasClose = nil
+ if not list then return end
+
+ if type(order) ~= "table" then
+ for v in pairs(list) do
+ sortlist[#sortlist + 1] = v
+ end
+ tsort(sortlist, sortTbl)
+
+ for i, key in ipairs(sortlist) do
+ AddListItem(self, key, list[key], itemType)
+ sortlist[i] = nil
+ end
+ else
+ for i, key in ipairs(order) do
+ AddListItem(self, key, list[key], itemType)
+ end
+ end
+ if self.multiselect then
+ ShowMultiText(self)
+ AddCloseButton(self)
+ end
+ end
+
+ -- exported
+ local function AddItem(self, value, text, itemType)
+ self.list[value] = text
+ AddListItem(self, value, text, itemType)
+ end
+
+ -- exported
+ local function SetMultiselect(self, multi)
+ self.multiselect = multi
+ if multi then
+ ShowMultiText(self)
+ AddCloseButton(self)
+ end
+ end
+
+ -- exported
+ local function GetMultiselect(self)
+ return self.multiselect
+ end
+
+ local function SetPulloutWidth(self, width)
+ self.pulloutWidth = width
+ end
+
+ --[[ Constructor ]]--
+
+ local function Constructor()
+ local count = AceGUI:GetNextWidgetNum(widgetType)
+ local frame = CreateFrame("Frame", nil, UIParent)
+ local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
+
+ local self = {}
+ self.type = widgetType
+ self.frame = frame
+ self.dropdown = dropdown
+ self.count = count
+ frame.obj = self
+ dropdown.obj = self
+
+ self.OnRelease = OnRelease
+ self.OnAcquire = OnAcquire
+
+ self.ClearFocus = ClearFocus
+
+ self.SetText = SetText
+ self.SetValue = SetValue
+ self.GetValue = GetValue
+ self.SetList = SetList
+ self.SetLabel = SetLabel
+ self.SetDisabled = SetDisabled
+ self.AddItem = AddItem
+ self.SetMultiselect = SetMultiselect
+ self.GetMultiselect = GetMultiselect
+ self.SetItemValue = SetItemValue
+ self.SetItemDisabled = SetItemDisabled
+ self.SetPulloutWidth = SetPulloutWidth
+
+ self.alignoffset = 26
+
+ frame:SetScript("OnHide",Dropdown_OnHide)
+
+ dropdown:ClearAllPoints()
+ dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
+ dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
+ dropdown:SetScript("OnHide", nil)
+
+ local left = _G[dropdown:GetName() .. "Left"]
+ local middle = _G[dropdown:GetName() .. "Middle"]
+ local right = _G[dropdown:GetName() .. "Right"]
+
+ middle:ClearAllPoints()
+ right:ClearAllPoints()
+
+ middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
+ middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
+ right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
+
+ local button = _G[dropdown:GetName() .. "Button"]
+ self.button = button
+ button.obj = self
+ button:SetScript("OnEnter",Control_OnEnter)
+ button:SetScript("OnLeave",Control_OnLeave)
+ button:SetScript("OnClick",Dropdown_TogglePullout)
+
+ local button_cover = CreateFrame("BUTTON",nil,self.frame)
+ self.button_cover = button_cover
+ button_cover.obj = self
+ button_cover:SetPoint("TOPLEFT",self.frame,"BOTTOMLEFT",0,25)
+ button_cover:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT")
+ button_cover:SetScript("OnEnter",Control_OnEnter)
+ button_cover:SetScript("OnLeave",Control_OnLeave)
+ button_cover:SetScript("OnClick",Dropdown_TogglePullout)
+
+ local text = _G[dropdown:GetName() .. "Text"]
+ self.text = text
+ text.obj = self
+ text:ClearAllPoints()
+ text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
+ text:SetPoint("LEFT", left, "LEFT", 25, 2)
+
+ local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
+ label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
+ label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
+ label:SetJustifyH("LEFT")
+ label:SetHeight(18)
+ label:Hide()
+ self.label = label
+
+ AceGUI:RegisterAsWidget(self)
+ return self
+ end
+
+ AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
+end
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
index 85a32a0..f2a238b 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
@@ -1,259 +1,263 @@
---[[-----------------------------------------------------------------------------
-EditBox Widget
--------------------------------------------------------------------------------]]
-local Type, Version = "EditBox", 28
-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 tostring, pairs = tostring, pairs
-
--- WoW APIs
-local PlaySound = PlaySound
-local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
-local CreateFrame, UIParent = CreateFrame, UIParent
-local _G = _G
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-if not AceGUIEditBoxInsertLink then
- -- upgradeable hook
- hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
-end
-
-function _G.AceGUIEditBoxInsertLink(text)
- for i = 1, AceGUI:GetWidgetCount(Type) do
- local editbox = _G["AceGUI-3.0EditBox"..i]
- if editbox and editbox:IsVisible() and editbox:HasFocus() then
- editbox:Insert(text)
- return true
- end
- end
-end
-
-local function ShowButton(self)
- if not self.disablebutton then
- self.button:Show()
- self.editbox:SetTextInsets(0, 20, 3, 3)
- end
-end
-
-local function HideButton(self)
- self.button:Hide()
- self.editbox:SetTextInsets(0, 0, 3, 3)
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function Frame_OnShowFocus(frame)
- frame.obj.editbox:SetFocus()
- frame:SetScript("OnShow", nil)
-end
-
-local function EditBox_OnEscapePressed(frame)
- AceGUI:ClearFocus()
-end
-
-local function EditBox_OnEnterPressed(frame)
- local self = frame.obj
- local value = frame:GetText()
- local cancel = self:Fire("OnEnterPressed", value)
- if not cancel then
- PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
- HideButton(self)
- end
-end
-
-local function EditBox_OnReceiveDrag(frame)
- local self = frame.obj
- local type, id, info = GetCursorInfo()
- local name
- if type == "item" then
- name = info
- elseif type == "spell" then
- name = GetSpellInfo(id, info)
- elseif type == "macro" then
- name = GetMacroInfo(id)
- end
- if name then
- self:SetText(name)
- self:Fire("OnEnterPressed", name)
- ClearCursor()
- HideButton(self)
- AceGUI:ClearFocus()
- end
-end
-
-local function EditBox_OnTextChanged(frame)
- local self = frame.obj
- local value = frame:GetText()
- if tostring(value) ~= tostring(self.lasttext) then
- self:Fire("OnTextChanged", value)
- self.lasttext = value
- ShowButton(self)
- end
-end
-
-local function EditBox_OnFocusGained(frame)
- AceGUI:SetFocus(frame.obj)
-end
-
-local function Button_OnClick(frame)
- local editbox = frame.obj.editbox
- editbox:ClearFocus()
- EditBox_OnEnterPressed(editbox)
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- -- height is controlled by SetLabel
- self:SetWidth(200)
- self:SetDisabled(false)
- self:SetLabel()
- self:SetText()
- self:DisableButton(false)
- self:SetMaxLetters(0)
- end,
-
- ["OnRelease"] = function(self)
- self:ClearFocus()
- end,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if disabled then
- self.editbox:EnableMouse(false)
- self.editbox:ClearFocus()
- self.editbox:SetTextColor(0.5,0.5,0.5)
- self.label:SetTextColor(0.5,0.5,0.5)
- else
- self.editbox:EnableMouse(true)
- self.editbox:SetTextColor(1,1,1)
- self.label:SetTextColor(1,.82,0)
- end
- end,
-
- ["SetText"] = function(self, text)
- self.lasttext = text or ""
- self.editbox:SetText(text or "")
- self.editbox:SetCursorPosition(0)
- HideButton(self)
- end,
-
- ["GetText"] = function(self, text)
- return self.editbox:GetText()
- end,
-
- ["SetLabel"] = function(self, text)
- if text and text ~= "" then
- self.label:SetText(text)
- self.label:Show()
- self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,-18)
- self:SetHeight(44)
- self.alignoffset = 30
- else
- self.label:SetText("")
- self.label:Hide()
- self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,0)
- self:SetHeight(26)
- self.alignoffset = 12
- end
- end,
-
- ["DisableButton"] = function(self, disabled)
- self.disablebutton = disabled
- if disabled then
- HideButton(self)
- end
- end,
-
- ["SetMaxLetters"] = function (self, num)
- self.editbox:SetMaxLetters(num or 0)
- end,
-
- ["ClearFocus"] = function(self)
- self.editbox:ClearFocus()
- self.frame:SetScript("OnShow", nil)
- end,
-
- ["SetFocus"] = function(self)
- self.editbox:SetFocus()
- if not self.frame:IsShown() then
- self.frame:SetScript("OnShow", Frame_OnShowFocus)
- end
- end,
-
- ["HighlightText"] = function(self, from, to)
- self.editbox:HighlightText(from, to)
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local num = AceGUI:GetNextWidgetNum(Type)
- local frame = CreateFrame("Frame", nil, UIParent)
- frame:Hide()
-
- local editbox = CreateFrame("EditBox", "AceGUI-3.0EditBox"..num, frame, "InputBoxTemplate")
- editbox:SetAutoFocus(false)
- editbox:SetFontObject(ChatFontNormal)
- editbox:SetScript("OnEnter", Control_OnEnter)
- editbox:SetScript("OnLeave", Control_OnLeave)
- editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
- editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
- editbox:SetScript("OnTextChanged", EditBox_OnTextChanged)
- editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
- editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
- editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained)
- editbox:SetTextInsets(0, 0, 3, 3)
- editbox:SetMaxLetters(256)
- editbox:SetPoint("BOTTOMLEFT", 6, 0)
- editbox:SetPoint("BOTTOMRIGHT")
- editbox:SetHeight(19)
-
- local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- label:SetPoint("TOPLEFT", 0, -2)
- label:SetPoint("TOPRIGHT", 0, -2)
- label:SetJustifyH("LEFT")
- label:SetHeight(18)
-
- local button = CreateFrame("Button", nil, editbox, "UIPanelButtonTemplate")
- button:SetWidth(40)
- button:SetHeight(20)
- button:SetPoint("RIGHT", -2, 0)
- button:SetText(OKAY)
- button:SetScript("OnClick", Button_OnClick)
- button:Hide()
-
- local widget = {
- alignoffset = 30,
- editbox = editbox,
- label = label,
- button = button,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- editbox.obj, button.obj = widget, widget
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+EditBox Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "EditBox", 29
+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 tostring, pairs = tostring, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local GetCursorInfo, ClearCursor = GetCursorInfo, ClearCursor
+local CreateFrame, UIParent = CreateFrame, UIParent
+local _G = _G
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+if not AceGUIEditBoxInsertLink then
+ -- upgradeable hook
+ hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
+end
+
+function _G.AceGUIEditBoxInsertLink(text)
+ for i = 1, AceGUI:GetWidgetCount(Type) do
+ local editbox = _G["AceGUI-3.0EditBox"..i]
+ if editbox and editbox:IsVisible() and editbox:HasFocus() then
+ editbox:Insert(text)
+ return true
+ end
+ end
+end
+
+local function ShowButton(self)
+ if not self.disablebutton then
+ self.button:Show()
+ self.editbox:SetTextInsets(0, 20, 3, 3)
+ end
+end
+
+local function HideButton(self)
+ self.button:Hide()
+ self.editbox:SetTextInsets(0, 0, 3, 3)
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Frame_OnShowFocus(frame)
+ frame.obj.editbox:SetFocus()
+ frame:SetScript("OnShow", nil)
+end
+
+local function EditBox_OnEscapePressed(frame)
+ AceGUI:ClearFocus()
+end
+
+local function EditBox_OnEnterPressed(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ local cancel = self:Fire("OnEnterPressed", value)
+ if not cancel then
+ PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
+ HideButton(self)
+ end
+end
+
+local function EditBox_OnReceiveDrag(frame)
+ local self = frame.obj
+ local type, id, info, extra = GetCursorInfo()
+ local name
+ if type == "item" then
+ name = info
+ elseif type == "spell" then
+ if C_Spell and C_Spell.GetSpellName then
+ name = C_Spell.GetSpellName(extra)
+ else
+ name = GetSpellInfo(id, info)
+ end
+ elseif type == "macro" then
+ name = GetMacroInfo(id)
+ end
+ if name then
+ self:SetText(name)
+ self:Fire("OnEnterPressed", name)
+ ClearCursor()
+ HideButton(self)
+ AceGUI:ClearFocus()
+ end
+end
+
+local function EditBox_OnTextChanged(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ if tostring(value) ~= tostring(self.lasttext) then
+ self:Fire("OnTextChanged", value)
+ self.lasttext = value
+ ShowButton(self)
+ end
+end
+
+local function EditBox_OnFocusGained(frame)
+ AceGUI:SetFocus(frame.obj)
+end
+
+local function Button_OnClick(frame)
+ local editbox = frame.obj.editbox
+ editbox:ClearFocus()
+ EditBox_OnEnterPressed(editbox)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- height is controlled by SetLabel
+ self:SetWidth(200)
+ self:SetDisabled(false)
+ self:SetLabel()
+ self:SetText()
+ self:DisableButton(false)
+ self:SetMaxLetters(0)
+ end,
+
+ ["OnRelease"] = function(self)
+ self:ClearFocus()
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.editbox:EnableMouse(false)
+ self.editbox:ClearFocus()
+ self.editbox:SetTextColor(0.5,0.5,0.5)
+ self.label:SetTextColor(0.5,0.5,0.5)
+ else
+ self.editbox:EnableMouse(true)
+ self.editbox:SetTextColor(1,1,1)
+ self.label:SetTextColor(1,.82,0)
+ end
+ end,
+
+ ["SetText"] = function(self, text)
+ self.lasttext = text or ""
+ self.editbox:SetText(text or "")
+ self.editbox:SetCursorPosition(0)
+ HideButton(self)
+ end,
+
+ ["GetText"] = function(self, text)
+ return self.editbox:GetText()
+ end,
+
+ ["SetLabel"] = function(self, text)
+ if text and text ~= "" then
+ self.label:SetText(text)
+ self.label:Show()
+ self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,-18)
+ self:SetHeight(44)
+ self.alignoffset = 30
+ else
+ self.label:SetText("")
+ self.label:Hide()
+ self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,0)
+ self:SetHeight(26)
+ self.alignoffset = 12
+ end
+ end,
+
+ ["DisableButton"] = function(self, disabled)
+ self.disablebutton = disabled
+ if disabled then
+ HideButton(self)
+ end
+ end,
+
+ ["SetMaxLetters"] = function (self, num)
+ self.editbox:SetMaxLetters(num or 0)
+ end,
+
+ ["ClearFocus"] = function(self)
+ self.editbox:ClearFocus()
+ self.frame:SetScript("OnShow", nil)
+ end,
+
+ ["SetFocus"] = function(self)
+ self.editbox:SetFocus()
+ if not self.frame:IsShown() then
+ self.frame:SetScript("OnShow", Frame_OnShowFocus)
+ end
+ end,
+
+ ["HighlightText"] = function(self, from, to)
+ self.editbox:HighlightText(from, to)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local num = AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local editbox = CreateFrame("EditBox", "AceGUI-3.0EditBox"..num, frame, "InputBoxTemplate")
+ editbox:SetAutoFocus(false)
+ editbox:SetFontObject(ChatFontNormal)
+ editbox:SetScript("OnEnter", Control_OnEnter)
+ editbox:SetScript("OnLeave", Control_OnLeave)
+ editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
+ editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
+ editbox:SetScript("OnTextChanged", EditBox_OnTextChanged)
+ editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
+ editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
+ editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained)
+ editbox:SetTextInsets(0, 0, 3, 3)
+ editbox:SetMaxLetters(256)
+ editbox:SetPoint("BOTTOMLEFT", 6, 0)
+ editbox:SetPoint("BOTTOMRIGHT")
+ editbox:SetHeight(19)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
+ label:SetPoint("TOPLEFT", 0, -2)
+ label:SetPoint("TOPRIGHT", 0, -2)
+ label:SetJustifyH("LEFT")
+ label:SetHeight(18)
+
+ local button = CreateFrame("Button", nil, editbox, "UIPanelButtonTemplate")
+ button:SetWidth(40)
+ button:SetHeight(20)
+ button:SetPoint("RIGHT", -2, 0)
+ button:SetText(OKAY)
+ button:SetScript("OnClick", Button_OnClick)
+ button:Hide()
+
+ local widget = {
+ alignoffset = 30,
+ editbox = editbox,
+ label = label,
+ button = button,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ editbox.obj, button.obj = widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua
index 670cd4e..862ae88 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua
@@ -1,78 +1,78 @@
---[[-----------------------------------------------------------------------------
-Heading Widget
--------------------------------------------------------------------------------]]
-local Type, Version = "Heading", 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 pairs = pairs
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetText()
- self:SetFullWidth()
- self:SetHeight(18)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetText"] = function(self, text)
- self.label:SetText(text or "")
- if text and text ~= "" then
- self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0)
- self.right:Show()
- else
- self.left:SetPoint("RIGHT", -3, 0)
- self.right:Hide()
- end
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
- frame:Hide()
-
- local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
- label:SetPoint("TOP")
- label:SetPoint("BOTTOM")
- label:SetJustifyH("CENTER")
-
- local left = frame:CreateTexture(nil, "BACKGROUND")
- left:SetHeight(8)
- left:SetPoint("LEFT", 3, 0)
- left:SetPoint("RIGHT", label, "LEFT", -5, 0)
- left:SetTexture(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
- left:SetTexCoord(0.81, 0.94, 0.5, 1)
-
- local right = frame:CreateTexture(nil, "BACKGROUND")
- right:SetHeight(8)
- right:SetPoint("RIGHT", -3, 0)
- right:SetPoint("LEFT", label, "RIGHT", 5, 0)
- right:SetTexture(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
- right:SetTexCoord(0.81, 0.94, 0.5, 1)
-
- local widget = {
- label = label,
- left = left,
- right = right,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Heading Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "Heading", 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 pairs = pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetText()
+ self:SetFullWidth()
+ self:SetHeight(18)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetText"] = function(self, text)
+ self.label:SetText(text or "")
+ if text and text ~= "" then
+ self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0)
+ self.right:Show()
+ else
+ self.left:SetPoint("RIGHT", -3, 0)
+ self.right:Hide()
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
+ label:SetPoint("TOP")
+ label:SetPoint("BOTTOM")
+ label:SetJustifyH("CENTER")
+
+ local left = frame:CreateTexture(nil, "BACKGROUND")
+ left:SetHeight(8)
+ left:SetPoint("LEFT", 3, 0)
+ left:SetPoint("RIGHT", label, "LEFT", -5, 0)
+ left:SetTexture(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
+ left:SetTexCoord(0.81, 0.94, 0.5, 1)
+
+ local right = frame:CreateTexture(nil, "BACKGROUND")
+ right:SetHeight(8)
+ right:SetPoint("RIGHT", -3, 0)
+ right:SetPoint("LEFT", label, "RIGHT", 5, 0)
+ right:SetTexture(137057) -- Interface\\Tooltips\\UI-Tooltip-Border
+ right:SetTexCoord(0.81, 0.94, 0.5, 1)
+
+ local widget = {
+ label = label,
+ left = left,
+ right = right,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua
index 092697e..378e813 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua
@@ -1,140 +1,140 @@
---[[-----------------------------------------------------------------------------
-Icon Widget
--------------------------------------------------------------------------------]]
-local Type, Version = "Icon", 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 select, pairs, print = select, pairs, print
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function Button_OnClick(frame, button)
- frame.obj:Fire("OnClick", button)
- AceGUI:ClearFocus()
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetHeight(110)
- self:SetWidth(110)
- self:SetLabel()
- self:SetImage(nil)
- self:SetImageSize(64, 64)
- self:SetDisabled(false)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetLabel"] = function(self, text)
- if text and text ~= "" then
- self.label:Show()
- self.label:SetText(text)
- self:SetHeight(self.image:GetHeight() + 25)
- else
- self.label:Hide()
- self:SetHeight(self.image:GetHeight() + 10)
- end
- end,
-
- ["SetImage"] = function(self, path, ...)
- local image = self.image
- image:SetTexture(path)
-
- if image:GetTexture() then
- local n = select("#", ...)
- if n == 4 or n == 8 then
- image:SetTexCoord(...)
- else
- image:SetTexCoord(0, 1, 0, 1)
- end
- end
- end,
-
- ["SetImageSize"] = function(self, width, height)
- self.image:SetWidth(width)
- self.image:SetHeight(height)
- --self.frame:SetWidth(width + 30)
- if self.label:IsShown() then
- self:SetHeight(height + 25)
- else
- self:SetHeight(height + 10)
- end
- end,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if disabled then
- self.frame:Disable()
- self.label:SetTextColor(0.5, 0.5, 0.5)
- self.image:SetVertexColor(0.5, 0.5, 0.5, 0.5)
- else
- self.frame:Enable()
- self.label:SetTextColor(1, 1, 1)
- self.image:SetVertexColor(1, 1, 1, 1)
- end
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Button", nil, UIParent)
- frame:Hide()
-
- frame:EnableMouse(true)
- frame:SetScript("OnEnter", Control_OnEnter)
- frame:SetScript("OnLeave", Control_OnLeave)
- frame:SetScript("OnClick", Button_OnClick)
-
- local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
- label:SetPoint("BOTTOMLEFT")
- label:SetPoint("BOTTOMRIGHT")
- label:SetJustifyH("CENTER")
- label:SetJustifyV("TOP")
- label:SetHeight(18)
-
- local image = frame:CreateTexture(nil, "BACKGROUND")
- image:SetWidth(64)
- image:SetHeight(64)
- image:SetPoint("TOP", 0, -5)
-
- local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
- highlight:SetAllPoints(image)
- highlight:SetTexture(136580) -- Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight
- highlight:SetTexCoord(0, 1, 0.23, 0.77)
- highlight:SetBlendMode("ADD")
-
- local widget = {
- label = label,
- image = image,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- widget.SetText = function(self, ...) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(...) end
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Icon Widget
+-------------------------------------------------------------------------------]]
+local Type, Version = "Icon", 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 select, pairs, print = select, pairs, print
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Button_OnClick(frame, button)
+ frame.obj:Fire("OnClick", button)
+ AceGUI:ClearFocus()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetHeight(110)
+ self:SetWidth(110)
+ self:SetLabel()
+ self:SetImage(nil)
+ self:SetImageSize(64, 64)
+ self:SetDisabled(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetLabel"] = function(self, text)
+ if text and text ~= "" then
+ self.label:Show()
+ self.label:SetText(text)
+ self:SetHeight(self.image:GetHeight() + 25)
+ else
+ self.label:Hide()
+ self:SetHeight(self.image:GetHeight() + 10)
+ end
+ end,
+
+ ["SetImage"] = function(self, path, ...)
+ local image = self.image
+ image:SetTexture(path)
+
+ if image:GetTexture() then
+ local n = select("#", ...)
+ if n == 4 or n == 8 then
+ image:SetTexCoord(...)
+ else
+ image:SetTexCoord(0, 1, 0, 1)
+ end
+ end
+ end,
+
+ ["SetImageSize"] = function(self, width, height)
+ self.image:SetWidth(width)
+ self.image:SetHeight(height)
+ --self.frame:SetWidth(width + 30)
+ if self.label:IsShown() then
+ self:SetHeight(height + 25)
+ else
+ self:SetHeight(height + 10)
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.label:SetTextColor(0.5, 0.5, 0.5)
+ self.image:SetVertexColor(0.5, 0.5, 0.5, 0.5)
+ else
+ self.frame:Enable()
+ self.label:SetTextColor(1, 1, 1)
+ self.image:SetVertexColor(1, 1, 1, 1)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Button", nil, UIParent)
+ frame:Hide()
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnClick", Button_OnClick)
+
+ local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
+ label:SetPoint("BOTTOMLEFT")
+ label:SetPoint("BOTTOMRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetJustifyV("TOP")
+ label:SetHeight(18)
+
+ local image = frame:CreateTexture(nil, "BACKGROUND")
+ image:SetWidth(64)
+ image:SetHeight(64)
+ image:SetPoint("TOP", 0, -5)
+
+ local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlight:SetAllPoints(image)
+ highlight:SetTexture(136580) -- Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight
+ highlight:SetTexCoord(0, 1, 0.23, 0.77)
+ highlight:SetBlendMode("ADD")
+
+ local widget = {
+ label = label,
+ image = image,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ widget.SetText = function(self, ...) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(...) end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua
index 76a2cf9..255dd97 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua
@@ -1,94 +1,94 @@
---[[-----------------------------------------------------------------------------
-InteractiveLabel Widget
--------------------------------------------------------------------------------]]
-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 select, pairs = select, pairs
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function Label_OnClick(frame, button)
- frame.obj:Fire("OnClick", button)
- AceGUI:ClearFocus()
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:LabelOnAcquire()
- self:SetHighlight()
- self:SetHighlightTexCoord()
- self:SetDisabled(false)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetHighlight"] = function(self, ...)
- self.highlight:SetTexture(...)
- end,
-
- ["SetHighlightTexCoord"] = function(self, ...)
- local c = select("#", ...)
- if c == 4 or c == 8 then
- self.highlight:SetTexCoord(...)
- else
- self.highlight:SetTexCoord(0, 1, 0, 1)
- end
- end,
-
- ["SetDisabled"] = function(self,disabled)
- self.disabled = disabled
- if disabled then
- self.frame:EnableMouse(false)
- self.label:SetTextColor(0.5, 0.5, 0.5)
- else
- self.frame:EnableMouse(true)
- self.label:SetTextColor(1, 1, 1)
- end
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- -- create a Label type that we will hijack
- local label = AceGUI:Create("Label")
-
- local frame = label.frame
- frame:EnableMouse(true)
- frame:SetScript("OnEnter", Control_OnEnter)
- frame:SetScript("OnLeave", Control_OnLeave)
- frame:SetScript("OnMouseDown", Label_OnClick)
-
- local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
- highlight:SetTexture(nil)
- highlight:SetAllPoints()
- highlight:SetBlendMode("ADD")
-
- label.highlight = highlight
- label.type = Type
- label.LabelOnAcquire = label.OnAcquire
- for method, func in pairs(methods) do
- label[method] = func
- end
-
- return label
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
-
+--[[-----------------------------------------------------------------------------
+InteractiveLabel Widget
+-------------------------------------------------------------------------------]]
+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 select, pairs = select, pairs
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Label_OnClick(frame, button)
+ frame.obj:Fire("OnClick", button)
+ AceGUI:ClearFocus()
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:LabelOnAcquire()
+ self:SetHighlight()
+ self:SetHighlightTexCoord()
+ self:SetDisabled(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetHighlight"] = function(self, ...)
+ self.highlight:SetTexture(...)
+ end,
+
+ ["SetHighlightTexCoord"] = function(self, ...)
+ local c = select("#", ...)
+ if c == 4 or c == 8 then
+ self.highlight:SetTexCoord(...)
+ else
+ self.highlight:SetTexCoord(0, 1, 0, 1)
+ end
+ end,
+
+ ["SetDisabled"] = function(self,disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:EnableMouse(false)
+ self.label:SetTextColor(0.5, 0.5, 0.5)
+ else
+ self.frame:EnableMouse(true)
+ self.label:SetTextColor(1, 1, 1)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ -- create a Label type that we will hijack
+ local label = AceGUI:Create("Label")
+
+ local frame = label.frame
+ frame:EnableMouse(true)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+ frame:SetScript("OnMouseDown", Label_OnClick)
+
+ local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
+ highlight:SetTexture(nil)
+ highlight:SetAllPoints()
+ highlight:SetBlendMode("ADD")
+
+ label.highlight = highlight
+ label.type = Type
+ label.LabelOnAcquire = label.OnAcquire
+ for method, func in pairs(methods) do
+ label[method] = func
+ end
+
+ return label
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
+
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
index 96f7e5b..0c779dc 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua
@@ -1,245 +1,245 @@
---[[-----------------------------------------------------------------------------
-Keybinding Widget
-Set Keybindings in the Config UI.
--------------------------------------------------------------------------------]]
-local Type, Version = "Keybinding", 26
-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
-
--- WoW APIs
-local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function Keybinding_OnClick(frame, button)
- if button == "LeftButton" or button == "RightButton" then
- local self = frame.obj
- if self.waitingForKey then
- frame:EnableKeyboard(false)
- frame:EnableMouseWheel(false)
- self.msgframe:Hide()
- frame:UnlockHighlight()
- self.waitingForKey = nil
- else
- frame:EnableKeyboard(true)
- frame:EnableMouseWheel(true)
- self.msgframe:Show()
- frame:LockHighlight()
- self.waitingForKey = true
- end
- end
- AceGUI:ClearFocus()
-end
-
-local ignoreKeys = {
- ["BUTTON1"] = true, ["BUTTON2"] = true,
- ["UNKNOWN"] = true,
- ["LSHIFT"] = true, ["LCTRL"] = true, ["LALT"] = true,
- ["RSHIFT"] = true, ["RCTRL"] = true, ["RALT"] = true,
-}
-local function Keybinding_OnKeyDown(frame, key)
- local self = frame.obj
- if self.waitingForKey then
- local keyPressed = key
- if keyPressed == "ESCAPE" then
- keyPressed = ""
- else
- if ignoreKeys[keyPressed] then return end
- if IsShiftKeyDown() then
- keyPressed = "SHIFT-"..keyPressed
- end
- if IsControlKeyDown() then
- keyPressed = "CTRL-"..keyPressed
- end
- if IsAltKeyDown() then
- keyPressed = "ALT-"..keyPressed
- end
- end
-
- frame:EnableKeyboard(false)
- frame:EnableMouseWheel(false)
- self.msgframe:Hide()
- frame:UnlockHighlight()
- self.waitingForKey = nil
-
- if not self.disabled then
- self:SetKey(keyPressed)
- self:Fire("OnKeyChanged", keyPressed)
- end
- end
-end
-
-local function Keybinding_OnMouseDown(frame, button)
- if button == "LeftButton" or button == "RightButton" then
- return
- elseif button == "MiddleButton" then
- button = "BUTTON3"
- elseif button == "Button4" then
- button = "BUTTON4"
- elseif button == "Button5" then
- button = "BUTTON5"
- end
- Keybinding_OnKeyDown(frame, button)
-end
-
-local function Keybinding_OnMouseWheel(frame, direction)
- local button
- if direction >= 0 then
- button = "MOUSEWHEELUP"
- else
- button = "MOUSEWHEELDOWN"
- end
- Keybinding_OnKeyDown(frame, button)
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetWidth(200)
- self:SetLabel("")
- self:SetKey("")
- self.waitingForKey = nil
- self.msgframe:Hide()
- self:SetDisabled(false)
- self.button:EnableKeyboard(false)
- self.button:EnableMouseWheel(false)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if disabled then
- self.button:Disable()
- self.label:SetTextColor(0.5,0.5,0.5)
- else
- self.button:Enable()
- self.label:SetTextColor(1,1,1)
- end
- end,
-
- ["SetKey"] = function(self, key)
- if (key or "") == "" then
- self.button:SetText(NOT_BOUND)
- self.button:SetNormalFontObject("GameFontNormal")
- else
- self.button:SetText(key)
- self.button:SetNormalFontObject("GameFontHighlight")
- end
- end,
-
- ["GetKey"] = function(self)
- local key = self.button:GetText()
- if key == NOT_BOUND then
- key = nil
- end
- return key
- end,
-
- ["SetLabel"] = function(self, label)
- self.label:SetText(label or "")
- if (label or "") == "" then
- self.alignoffset = nil
- self:SetHeight(24)
- else
- self.alignoffset = 30
- self:SetHeight(44)
- end
- end,
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-
-local ControlBackdrop = {
- bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
- edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
- tile = true, tileSize = 16, edgeSize = 16,
- insets = { left = 3, right = 3, top = 3, bottom = 3 }
-}
-
-local function keybindingMsgFixWidth(frame)
- frame:SetWidth(frame.msg:GetWidth() + 10)
- frame:SetScript("OnUpdate", nil)
-end
-
-local function Constructor()
- local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type)
-
- local frame = CreateFrame("Frame", nil, UIParent)
- local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate")
-
- button:EnableMouse(true)
- button:EnableMouseWheel(false)
- button:RegisterForClicks("AnyDown")
- button:SetScript("OnEnter", Control_OnEnter)
- button:SetScript("OnLeave", Control_OnLeave)
- button:SetScript("OnClick", Keybinding_OnClick)
- button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
- button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
- button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
- button:SetPoint("BOTTOMLEFT")
- button:SetPoint("BOTTOMRIGHT")
- button:SetHeight(24)
- button:EnableKeyboard(false)
-
- local text = button:GetFontString()
- text:SetPoint("LEFT", 7, 0)
- text:SetPoint("RIGHT", -7, 0)
-
- local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
- label:SetPoint("TOPLEFT")
- label:SetPoint("TOPRIGHT")
- label:SetJustifyH("CENTER")
- label:SetHeight(18)
-
- local msgframe = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
- msgframe:SetHeight(30)
- msgframe:SetBackdrop(ControlBackdrop)
- msgframe:SetBackdropColor(0,0,0)
- msgframe:SetFrameStrata("FULLSCREEN_DIALOG")
- msgframe:SetFrameLevel(1000)
- msgframe:SetToplevel(true)
-
- local msg = msgframe:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- msg:SetText("Press a key to bind, ESC to clear the binding or click the button again to cancel.")
- msgframe.msg = msg
- msg:SetPoint("TOPLEFT", 5, -5)
- msgframe:SetScript("OnUpdate", keybindingMsgFixWidth)
- msgframe:SetPoint("BOTTOM", button, "TOP")
- msgframe:Hide()
-
- local widget = {
- button = button,
- label = label,
- msgframe = msgframe,
- frame = frame,
- alignoffset = 30,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- button.obj = widget
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Keybinding Widget
+Set Keybindings in the Config UI.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Keybinding", 26
+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
+
+-- WoW APIs
+local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Keybinding_OnClick(frame, button)
+ if button == "LeftButton" or button == "RightButton" then
+ local self = frame.obj
+ if self.waitingForKey then
+ frame:EnableKeyboard(false)
+ frame:EnableMouseWheel(false)
+ self.msgframe:Hide()
+ frame:UnlockHighlight()
+ self.waitingForKey = nil
+ else
+ frame:EnableKeyboard(true)
+ frame:EnableMouseWheel(true)
+ self.msgframe:Show()
+ frame:LockHighlight()
+ self.waitingForKey = true
+ end
+ end
+ AceGUI:ClearFocus()
+end
+
+local ignoreKeys = {
+ ["BUTTON1"] = true, ["BUTTON2"] = true,
+ ["UNKNOWN"] = true,
+ ["LSHIFT"] = true, ["LCTRL"] = true, ["LALT"] = true,
+ ["RSHIFT"] = true, ["RCTRL"] = true, ["RALT"] = true,
+}
+local function Keybinding_OnKeyDown(frame, key)
+ local self = frame.obj
+ if self.waitingForKey then
+ local keyPressed = key
+ if keyPressed == "ESCAPE" then
+ keyPressed = ""
+ else
+ if ignoreKeys[keyPressed] then return end
+ if IsShiftKeyDown() then
+ keyPressed = "SHIFT-"..keyPressed
+ end
+ if IsControlKeyDown() then
+ keyPressed = "CTRL-"..keyPressed
+ end
+ if IsAltKeyDown() then
+ keyPressed = "ALT-"..keyPressed
+ end
+ end
+
+ frame:EnableKeyboard(false)
+ frame:EnableMouseWheel(false)
+ self.msgframe:Hide()
+ frame:UnlockHighlight()
+ self.waitingForKey = nil
+
+ if not self.disabled then
+ self:SetKey(keyPressed)
+ self:Fire("OnKeyChanged", keyPressed)
+ end
+ end
+end
+
+local function Keybinding_OnMouseDown(frame, button)
+ if button == "LeftButton" or button == "RightButton" then
+ return
+ elseif button == "MiddleButton" then
+ button = "BUTTON3"
+ elseif button == "Button4" then
+ button = "BUTTON4"
+ elseif button == "Button5" then
+ button = "BUTTON5"
+ end
+ Keybinding_OnKeyDown(frame, button)
+end
+
+local function Keybinding_OnMouseWheel(frame, direction)
+ local button
+ if direction >= 0 then
+ button = "MOUSEWHEELUP"
+ else
+ button = "MOUSEWHEELDOWN"
+ end
+ Keybinding_OnKeyDown(frame, button)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(200)
+ self:SetLabel("")
+ self:SetKey("")
+ self.waitingForKey = nil
+ self.msgframe:Hide()
+ self:SetDisabled(false)
+ self.button:EnableKeyboard(false)
+ self.button:EnableMouseWheel(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.button:Disable()
+ self.label:SetTextColor(0.5,0.5,0.5)
+ else
+ self.button:Enable()
+ self.label:SetTextColor(1,1,1)
+ end
+ end,
+
+ ["SetKey"] = function(self, key)
+ if (key or "") == "" then
+ self.button:SetText(NOT_BOUND)
+ self.button:SetNormalFontObject("GameFontNormal")
+ else
+ self.button:SetText(key)
+ self.button:SetNormalFontObject("GameFontHighlight")
+ end
+ end,
+
+ ["GetKey"] = function(self)
+ local key = self.button:GetText()
+ if key == NOT_BOUND then
+ key = nil
+ end
+ return key
+ end,
+
+ ["SetLabel"] = function(self, label)
+ self.label:SetText(label or "")
+ if (label or "") == "" then
+ self.alignoffset = nil
+ self:SetHeight(24)
+ else
+ self.alignoffset = 30
+ self:SetHeight(44)
+ end
+ end,
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+
+local ControlBackdrop = {
+ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+ edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+ tile = true, tileSize = 16, edgeSize = 16,
+ insets = { left = 3, right = 3, top = 3, bottom = 3 }
+}
+
+local function keybindingMsgFixWidth(frame)
+ frame:SetWidth(frame.msg:GetWidth() + 10)
+ frame:SetScript("OnUpdate", nil)
+end
+
+local function Constructor()
+ local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type)
+
+ local frame = CreateFrame("Frame", nil, UIParent)
+ local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate")
+
+ button:EnableMouse(true)
+ button:EnableMouseWheel(false)
+ button:RegisterForClicks("AnyDown")
+ button:SetScript("OnEnter", Control_OnEnter)
+ button:SetScript("OnLeave", Control_OnLeave)
+ button:SetScript("OnClick", Keybinding_OnClick)
+ button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
+ button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
+ button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
+ button:SetPoint("BOTTOMLEFT")
+ button:SetPoint("BOTTOMRIGHT")
+ button:SetHeight(24)
+ button:EnableKeyboard(false)
+
+ local text = button:GetFontString()
+ text:SetPoint("LEFT", 7, 0)
+ text:SetPoint("RIGHT", -7, 0)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
+ label:SetPoint("TOPLEFT")
+ label:SetPoint("TOPRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetHeight(18)
+
+ local msgframe = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
+ msgframe:SetHeight(30)
+ msgframe:SetBackdrop(ControlBackdrop)
+ msgframe:SetBackdropColor(0,0,0)
+ msgframe:SetFrameStrata("FULLSCREEN_DIALOG")
+ msgframe:SetFrameLevel(1000)
+ msgframe:SetToplevel(true)
+
+ local msg = msgframe:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ msg:SetText("Press a key to bind, ESC to clear the binding or click the button again to cancel.")
+ msgframe.msg = msg
+ msg:SetPoint("TOPLEFT", 5, -5)
+ msgframe:SetScript("OnUpdate", keybindingMsgFixWidth)
+ msgframe:SetPoint("BOTTOM", button, "TOP")
+ msgframe:Hide()
+
+ local widget = {
+ button = button,
+ label = label,
+ msgframe = msgframe,
+ frame = frame,
+ alignoffset = 30,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ button.obj = widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua
index 6bbcf3b..d0841ef 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua
@@ -1,179 +1,179 @@
---[[-----------------------------------------------------------------------------
-Label Widget
-Displays text and optionally an icon.
--------------------------------------------------------------------------------]]
-local Type, Version = "Label", 28
-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, select, pairs = math.max, select, pairs
-
--- WoW APIs
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-
-local function UpdateImageAnchor(self)
- if self.resizing then return end
- local frame = self.frame
- local width = frame.width or frame:GetWidth() or 0
- local image = self.image
- local label = self.label
- local height
-
- label:ClearAllPoints()
- image:ClearAllPoints()
-
- if self.imageshown then
- 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")
- label:SetPoint("TOP", image, "BOTTOM")
- label:SetPoint("LEFT")
- label:SetWidth(width)
- height = image:GetHeight() + label:GetStringHeight()
- else
- -- image on the left
- image:SetPoint("TOPLEFT")
- if image:GetHeight() > label:GetStringHeight() then
- label:SetPoint("LEFT", image, "RIGHT", 4, 0)
- else
- label:SetPoint("TOPLEFT", image, "TOPRIGHT", 4, 0)
- end
- label:SetWidth(width - imagewidth - 4)
- height = max(image:GetHeight(), label:GetStringHeight())
- end
- else
- -- no image shown
- label:SetPoint("TOPLEFT")
- label:SetWidth(width)
- height = label:GetStringHeight()
- end
-
- -- avoid zero-height labels, since they can used as spacers
- if not height or height == 0 then
- height = 1
- end
-
- self.resizing = true
- frame:SetHeight(height)
- frame.height = height
- self.resizing = nil
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- -- set the flag to stop constant size updates
- self.resizing = true
- -- height is set dynamically by the text and image size
- self:SetWidth(200)
- self:SetText()
- self:SetImage(nil)
- self:SetImageSize(16, 16)
- self:SetColor()
- self:SetFontObject()
- self:SetJustifyH("LEFT")
- self:SetJustifyV("TOP")
-
- -- reset the flag
- self.resizing = nil
- -- run the update explicitly
- UpdateImageAnchor(self)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["OnWidthSet"] = function(self, width)
- UpdateImageAnchor(self)
- end,
-
- ["SetText"] = function(self, text)
- self.label:SetText(text)
- UpdateImageAnchor(self)
- end,
-
- ["SetColor"] = function(self, r, g, b)
- if not (r and g and b) then
- r, g, b = 1, 1, 1
- end
- self.label:SetVertexColor(r, g, b)
- end,
-
- ["SetImage"] = function(self, path, ...)
- local image = self.image
- image:SetTexture(path)
-
- if image:GetTexture() then
- self.imageshown = true
- local n = select("#", ...)
- if n == 4 or n == 8 then
- image:SetTexCoord(...)
- else
- image:SetTexCoord(0, 1, 0, 1)
- end
- else
- self.imageshown = nil
- end
- UpdateImageAnchor(self)
- end,
-
- ["SetFont"] = function(self, font, height, flags)
- if not self.fontObject then
- self.fontObject = CreateFont("AceGUI30LabelFont" .. AceGUI:GetNextWidgetNum(Type))
- end
- self.fontObject:SetFont(font, height, flags)
- self:SetFontObject(self.fontObject)
- end,
-
- ["SetFontObject"] = function(self, font)
- self.label:SetFontObject(font or GameFontHighlightSmall)
- UpdateImageAnchor(self)
- end,
-
- ["SetImageSize"] = function(self, width, height)
- self.image:SetWidth(width)
- 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,
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
- frame:Hide()
-
- local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
- local image = frame:CreateTexture(nil, "BACKGROUND")
-
- -- create widget
- local widget = {
- label = label,
- image = image,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+--[[-----------------------------------------------------------------------------
+Label Widget
+Displays text and optionally an icon.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Label", 28
+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, select, pairs = math.max, select, pairs
+
+-- WoW APIs
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+local function UpdateImageAnchor(self)
+ if self.resizing then return end
+ local frame = self.frame
+ local width = frame.width or frame:GetWidth() or 0
+ local image = self.image
+ local label = self.label
+ local height
+
+ label:ClearAllPoints()
+ image:ClearAllPoints()
+
+ if self.imageshown then
+ 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")
+ label:SetPoint("TOP", image, "BOTTOM")
+ label:SetPoint("LEFT")
+ label:SetWidth(width)
+ height = image:GetHeight() + label:GetStringHeight()
+ else
+ -- image on the left
+ image:SetPoint("TOPLEFT")
+ if image:GetHeight() > label:GetStringHeight() then
+ label:SetPoint("LEFT", image, "RIGHT", 4, 0)
+ else
+ label:SetPoint("TOPLEFT", image, "TOPRIGHT", 4, 0)
+ end
+ label:SetWidth(width - imagewidth - 4)
+ height = max(image:GetHeight(), label:GetStringHeight())
+ end
+ else
+ -- no image shown
+ label:SetPoint("TOPLEFT")
+ label:SetWidth(width)
+ height = label:GetStringHeight()
+ end
+
+ -- avoid zero-height labels, since they can used as spacers
+ if not height or height == 0 then
+ height = 1
+ end
+
+ self.resizing = true
+ frame:SetHeight(height)
+ frame.height = height
+ self.resizing = nil
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- set the flag to stop constant size updates
+ self.resizing = true
+ -- height is set dynamically by the text and image size
+ self:SetWidth(200)
+ self:SetText()
+ self:SetImage(nil)
+ self:SetImageSize(16, 16)
+ self:SetColor()
+ self:SetFontObject()
+ self:SetJustifyH("LEFT")
+ self:SetJustifyV("TOP")
+
+ -- reset the flag
+ self.resizing = nil
+ -- run the update explicitly
+ UpdateImageAnchor(self)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["OnWidthSet"] = function(self, width)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetText"] = function(self, text)
+ self.label:SetText(text)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetColor"] = function(self, r, g, b)
+ if not (r and g and b) then
+ r, g, b = 1, 1, 1
+ end
+ self.label:SetVertexColor(r, g, b)
+ end,
+
+ ["SetImage"] = function(self, path, ...)
+ local image = self.image
+ image:SetTexture(path)
+
+ if image:GetTexture() then
+ self.imageshown = true
+ local n = select("#", ...)
+ if n == 4 or n == 8 then
+ image:SetTexCoord(...)
+ else
+ image:SetTexCoord(0, 1, 0, 1)
+ end
+ else
+ self.imageshown = nil
+ end
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetFont"] = function(self, font, height, flags)
+ if not self.fontObject then
+ self.fontObject = CreateFont("AceGUI30LabelFont" .. AceGUI:GetNextWidgetNum(Type))
+ end
+ self.fontObject:SetFont(font, height, flags)
+ self:SetFontObject(self.fontObject)
+ end,
+
+ ["SetFontObject"] = function(self, font)
+ self.label:SetFontObject(font or GameFontHighlightSmall)
+ UpdateImageAnchor(self)
+ end,
+
+ ["SetImageSize"] = function(self, width, height)
+ self.image:SetWidth(width)
+ 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,
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
+ local image = frame:CreateTexture(nil, "BACKGROUND")
+
+ -- create widget
+ local widget = {
+ label = label,
+ image = image,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
index c33a986..f0095b5 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
@@ -1,369 +1,373 @@
-local Type, Version = "MultiLineEditBox", 32
-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
-
--- WoW APIs
-local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
-local CreateFrame, UIParent = CreateFrame, UIParent
-local _G = _G
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-
-if not AceGUIMultiLineEditBoxInsertLink then
- -- upgradeable hook
- hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
-end
-
-function _G.AceGUIMultiLineEditBoxInsertLink(text)
- for i = 1, AceGUI:GetWidgetCount(Type) do
- local editbox = _G[("MultiLineEditBox%uEdit"):format(i)]
- if editbox and editbox:IsVisible() and editbox:HasFocus() then
- editbox:Insert(text)
- return true
- end
- end
-end
-
-
-local function Layout(self)
- self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
-
- if self.labelHeight == 0 then
- self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
- else
- self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
- end
-
- if self.disablebutton then
- self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
- self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
- else
- self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
- self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
- end
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function OnClick(self) -- Button
- self = self.obj
- self.editBox:ClearFocus()
- if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
- self.button:Disable()
- end
-end
-
-local function OnCursorChanged(self, _, y, _, cursorHeight) -- EditBox
- self, y = self.obj.scrollFrame, -y
- local offset = self:GetVerticalScroll()
- if y < offset then
- self:SetVerticalScroll(y)
- else
- y = y + cursorHeight - self:GetHeight()
- if y > offset then
- self:SetVerticalScroll(y)
- end
- end
-end
-
-local function OnEditFocusLost(self) -- EditBox
- self:HighlightText(0, 0)
- self.obj:Fire("OnEditFocusLost")
-end
-
-local function OnEnter(self) -- EditBox / ScrollFrame
- self = self.obj
- if not self.entered then
- self.entered = true
- self:Fire("OnEnter")
- end
-end
-
-local function OnLeave(self) -- EditBox / ScrollFrame
- self = self.obj
- if self.entered then
- self.entered = nil
- self:Fire("OnLeave")
- end
-end
-
-local function OnMouseUp(self) -- ScrollFrame
- self = self.obj.editBox
- self:SetFocus()
- self:SetCursorPosition(self:GetNumLetters())
-end
-
-local function OnReceiveDrag(self) -- EditBox / ScrollFrame
- local type, id, info = GetCursorInfo()
- if type == "spell" then
- info = GetSpellInfo(id, info)
- elseif type ~= "item" then
- return
- end
- ClearCursor()
- self = self.obj
- local editBox = self.editBox
- if not editBox:HasFocus() then
- editBox:SetFocus()
- editBox:SetCursorPosition(editBox:GetNumLetters())
- end
- editBox:Insert(info)
- self.button:Enable()
-end
-
-local function OnSizeChanged(self, width, height) -- ScrollFrame
- self.obj.editBox:SetWidth(width)
-end
-
-local function OnTextChanged(self, userInput) -- EditBox
- if userInput then
- self = self.obj
- self:Fire("OnTextChanged", self.editBox:GetText())
- self.button:Enable()
- end
-end
-
-local function OnTextSet(self) -- EditBox
- self:HighlightText(0, 0)
- self:SetCursorPosition(self:GetNumLetters())
- self:SetCursorPosition(0)
- self.obj.button:Disable()
-end
-
-local function OnVerticalScroll(self, offset) -- ScrollFrame
- local editBox = self.obj.editBox
- editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
-end
-
-local function OnScrollRangeChanged(self, xrange, yrange)
- if yrange == 0 then
- self.obj.editBox:SetHitRectInsets(0, 0, 0, 0)
- else
- OnVerticalScroll(self, self:GetVerticalScroll())
- end
-end
-
-local function OnShowFocus(frame)
- frame.obj.editBox:SetFocus()
- frame:SetScript("OnShow", nil)
-end
-
-local function OnEditFocusGained(frame)
- AceGUI:SetFocus(frame.obj)
- frame.obj:Fire("OnEditFocusGained")
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self.editBox:SetText("")
- self:SetDisabled(false)
- self:SetWidth(200)
- self:DisableButton(false)
- self:SetNumLines()
- self.entered = nil
- self:SetMaxLetters(0)
- end,
-
- ["OnRelease"] = function(self)
- self:ClearFocus()
- end,
-
- ["SetDisabled"] = function(self, disabled)
- local editBox = self.editBox
- if disabled then
- editBox:ClearFocus()
- editBox:EnableMouse(false)
- editBox:SetTextColor(0.5, 0.5, 0.5)
- self.label:SetTextColor(0.5, 0.5, 0.5)
- self.scrollFrame:EnableMouse(false)
- self.button:Disable()
- else
- editBox:EnableMouse(true)
- editBox:SetTextColor(1, 1, 1)
- self.label:SetTextColor(1, 0.82, 0)
- self.scrollFrame:EnableMouse(true)
- end
- end,
-
- ["SetLabel"] = function(self, text)
- if text and text ~= "" then
- self.label:SetText(text)
- if self.labelHeight ~= 10 then
- self.labelHeight = 10
- self.label:Show()
- end
- elseif self.labelHeight ~= 0 then
- self.labelHeight = 0
- self.label:Hide()
- end
- Layout(self)
- end,
-
- ["SetNumLines"] = function(self, value)
- if not value or value < 4 then
- value = 4
- end
- self.numlines = value
- Layout(self)
- end,
-
- ["SetText"] = function(self, text)
- self.editBox:SetText(text)
- end,
-
- ["GetText"] = function(self)
- return self.editBox:GetText()
- end,
-
- ["SetMaxLetters"] = function (self, num)
- self.editBox:SetMaxLetters(num or 0)
- end,
-
- ["DisableButton"] = function(self, disabled)
- self.disablebutton = disabled
- if disabled then
- self.button:Hide()
- else
- self.button:Show()
- end
- Layout(self)
- end,
-
- ["ClearFocus"] = function(self)
- self.editBox:ClearFocus()
- self.frame:SetScript("OnShow", nil)
- end,
-
- ["SetFocus"] = function(self)
- self.editBox:SetFocus()
- if not self.frame:IsShown() then
- self.frame:SetScript("OnShow", OnShowFocus)
- end
- end,
-
- ["HighlightText"] = function(self, from, to)
- self.editBox:HighlightText(from, to)
- end,
-
- ["GetCursorPosition"] = function(self)
- return self.editBox:GetCursorPosition()
- end,
-
- ["SetCursorPosition"] = function(self, ...)
- return self.editBox:SetCursorPosition(...)
- end,
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local backdrop = {
- bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
- edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
- insets = { left = 4, right = 3, top = 4, bottom = 3 }
-}
-
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
- frame:Hide()
-
- local widgetNum = AceGUI:GetNextWidgetNum(Type)
-
- local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
- label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
- label:SetJustifyH("LEFT")
- label:SetText(ACCEPT)
- label:SetHeight(10)
-
- local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, "UIPanelButtonTemplate")
- button:SetPoint("BOTTOMLEFT", 0, 4)
- button:SetHeight(22)
- button:SetWidth(label:GetStringWidth() + 24)
- button:SetText(ACCEPT)
- button:SetScript("OnClick", OnClick)
- button:Disable()
-
- local text = button:GetFontString()
- text:ClearAllPoints()
- text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
- text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
- text:SetJustifyV("MIDDLE")
-
- local scrollBG = CreateFrame("Frame", nil, frame, "BackdropTemplate")
- scrollBG:SetBackdrop(backdrop)
- scrollBG:SetBackdropColor(0, 0, 0)
- scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
-
- local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
-
- local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
- scrollBar:ClearAllPoints()
- scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
- scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
- scrollBar:SetPoint("RIGHT", frame, "RIGHT")
-
- scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
- scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
-
- scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
- scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
- scrollFrame:SetScript("OnEnter", OnEnter)
- scrollFrame:SetScript("OnLeave", OnLeave)
- scrollFrame:SetScript("OnMouseUp", OnMouseUp)
- scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
- scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
- scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
- scrollFrame:HookScript("OnScrollRangeChanged", OnScrollRangeChanged)
-
- local editBox = CreateFrame("EditBox", ("%s%dEdit"):format(Type, widgetNum), scrollFrame)
- editBox:SetAllPoints()
- editBox:SetFontObject(ChatFontNormal)
- editBox:SetMultiLine(true)
- editBox:EnableMouse(true)
- editBox:SetAutoFocus(false)
- editBox:SetCountInvisibleLetters(false)
- editBox:SetScript("OnCursorChanged", OnCursorChanged)
- editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
- editBox:SetScript("OnEnter", OnEnter)
- editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
- editBox:SetScript("OnLeave", OnLeave)
- editBox:SetScript("OnMouseDown", OnReceiveDrag)
- editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
- editBox:SetScript("OnTextChanged", OnTextChanged)
- editBox:SetScript("OnTextSet", OnTextSet)
- editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
-
-
- scrollFrame:SetScrollChild(editBox)
-
- local widget = {
- button = button,
- editBox = editBox,
- frame = frame,
- label = label,
- labelHeight = 10,
- numlines = 4,
- scrollBar = scrollBar,
- scrollBG = scrollBG,
- scrollFrame = scrollFrame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type, Constructor, Version)
+local Type, Version = "MultiLineEditBox", 33
+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
+
+-- WoW APIs
+local GetCursorInfo, ClearCursor = GetCursorInfo, ClearCursor
+local CreateFrame, UIParent = CreateFrame, UIParent
+local _G = _G
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+
+if not AceGUIMultiLineEditBoxInsertLink then
+ -- upgradeable hook
+ hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
+end
+
+function _G.AceGUIMultiLineEditBoxInsertLink(text)
+ for i = 1, AceGUI:GetWidgetCount(Type) do
+ local editbox = _G[("MultiLineEditBox%uEdit"):format(i)]
+ if editbox and editbox:IsVisible() and editbox:HasFocus() then
+ editbox:Insert(text)
+ return true
+ end
+ end
+end
+
+
+local function Layout(self)
+ self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
+
+ if self.labelHeight == 0 then
+ self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
+ else
+ self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
+ end
+
+ if self.disablebutton then
+ self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
+ self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
+ else
+ self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
+ self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function OnClick(self) -- Button
+ self = self.obj
+ self.editBox:ClearFocus()
+ if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
+ self.button:Disable()
+ end
+end
+
+local function OnCursorChanged(self, _, y, _, cursorHeight) -- EditBox
+ self, y = self.obj.scrollFrame, -y
+ local offset = self:GetVerticalScroll()
+ if y < offset then
+ self:SetVerticalScroll(y)
+ else
+ y = y + cursorHeight - self:GetHeight()
+ if y > offset then
+ self:SetVerticalScroll(y)
+ end
+ end
+end
+
+local function OnEditFocusLost(self) -- EditBox
+ self:HighlightText(0, 0)
+ self.obj:Fire("OnEditFocusLost")
+end
+
+local function OnEnter(self) -- EditBox / ScrollFrame
+ self = self.obj
+ if not self.entered then
+ self.entered = true
+ self:Fire("OnEnter")
+ end
+end
+
+local function OnLeave(self) -- EditBox / ScrollFrame
+ self = self.obj
+ if self.entered then
+ self.entered = nil
+ self:Fire("OnLeave")
+ end
+end
+
+local function OnMouseUp(self) -- ScrollFrame
+ self = self.obj.editBox
+ self:SetFocus()
+ self:SetCursorPosition(self:GetNumLetters())
+end
+
+local function OnReceiveDrag(self) -- EditBox / ScrollFrame
+ local type, id, info, extra = GetCursorInfo()
+ if type == "spell" then
+ if C_Spell and C_Spell.GetSpellName then
+ info = C_Spell.GetSpellName(extra)
+ else
+ info = GetSpellInfo(id, info)
+ end
+ elseif type ~= "item" then
+ return
+ end
+ ClearCursor()
+ self = self.obj
+ local editBox = self.editBox
+ if not editBox:HasFocus() then
+ editBox:SetFocus()
+ editBox:SetCursorPosition(editBox:GetNumLetters())
+ end
+ editBox:Insert(info)
+ self.button:Enable()
+end
+
+local function OnSizeChanged(self, width, height) -- ScrollFrame
+ self.obj.editBox:SetWidth(width)
+end
+
+local function OnTextChanged(self, userInput) -- EditBox
+ if userInput then
+ self = self.obj
+ self:Fire("OnTextChanged", self.editBox:GetText())
+ self.button:Enable()
+ end
+end
+
+local function OnTextSet(self) -- EditBox
+ self:HighlightText(0, 0)
+ self:SetCursorPosition(self:GetNumLetters())
+ self:SetCursorPosition(0)
+ self.obj.button:Disable()
+end
+
+local function OnVerticalScroll(self, offset) -- ScrollFrame
+ local editBox = self.obj.editBox
+ editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
+end
+
+local function OnScrollRangeChanged(self, xrange, yrange)
+ if yrange == 0 then
+ self.obj.editBox:SetHitRectInsets(0, 0, 0, 0)
+ else
+ OnVerticalScroll(self, self:GetVerticalScroll())
+ end
+end
+
+local function OnShowFocus(frame)
+ frame.obj.editBox:SetFocus()
+ frame:SetScript("OnShow", nil)
+end
+
+local function OnEditFocusGained(frame)
+ AceGUI:SetFocus(frame.obj)
+ frame.obj:Fire("OnEditFocusGained")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self.editBox:SetText("")
+ self:SetDisabled(false)
+ self:SetWidth(200)
+ self:DisableButton(false)
+ self:SetNumLines()
+ self.entered = nil
+ self:SetMaxLetters(0)
+ end,
+
+ ["OnRelease"] = function(self)
+ self:ClearFocus()
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ local editBox = self.editBox
+ if disabled then
+ editBox:ClearFocus()
+ editBox:EnableMouse(false)
+ editBox:SetTextColor(0.5, 0.5, 0.5)
+ self.label:SetTextColor(0.5, 0.5, 0.5)
+ self.scrollFrame:EnableMouse(false)
+ self.button:Disable()
+ else
+ editBox:EnableMouse(true)
+ editBox:SetTextColor(1, 1, 1)
+ self.label:SetTextColor(1, 0.82, 0)
+ self.scrollFrame:EnableMouse(true)
+ end
+ end,
+
+ ["SetLabel"] = function(self, text)
+ if text and text ~= "" then
+ self.label:SetText(text)
+ if self.labelHeight ~= 10 then
+ self.labelHeight = 10
+ self.label:Show()
+ end
+ elseif self.labelHeight ~= 0 then
+ self.labelHeight = 0
+ self.label:Hide()
+ end
+ Layout(self)
+ end,
+
+ ["SetNumLines"] = function(self, value)
+ if not value or value < 4 then
+ value = 4
+ end
+ self.numlines = value
+ Layout(self)
+ end,
+
+ ["SetText"] = function(self, text)
+ self.editBox:SetText(text)
+ end,
+
+ ["GetText"] = function(self)
+ return self.editBox:GetText()
+ end,
+
+ ["SetMaxLetters"] = function (self, num)
+ self.editBox:SetMaxLetters(num or 0)
+ end,
+
+ ["DisableButton"] = function(self, disabled)
+ self.disablebutton = disabled
+ if disabled then
+ self.button:Hide()
+ else
+ self.button:Show()
+ end
+ Layout(self)
+ end,
+
+ ["ClearFocus"] = function(self)
+ self.editBox:ClearFocus()
+ self.frame:SetScript("OnShow", nil)
+ end,
+
+ ["SetFocus"] = function(self)
+ self.editBox:SetFocus()
+ if not self.frame:IsShown() then
+ self.frame:SetScript("OnShow", OnShowFocus)
+ end
+ end,
+
+ ["HighlightText"] = function(self, from, to)
+ self.editBox:HighlightText(from, to)
+ end,
+
+ ["GetCursorPosition"] = function(self)
+ return self.editBox:GetCursorPosition()
+ end,
+
+ ["SetCursorPosition"] = function(self, ...)
+ return self.editBox:SetCursorPosition(...)
+ end,
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local backdrop = {
+ bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
+ edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
+ insets = { left = 4, right = 3, top = 4, bottom = 3 }
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+ frame:Hide()
+
+ local widgetNum = AceGUI:GetNextWidgetNum(Type)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
+ label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
+ label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
+ label:SetJustifyH("LEFT")
+ label:SetText(ACCEPT)
+ label:SetHeight(10)
+
+ local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, "UIPanelButtonTemplate")
+ button:SetPoint("BOTTOMLEFT", 0, 4)
+ button:SetHeight(22)
+ button:SetWidth(label:GetStringWidth() + 24)
+ button:SetText(ACCEPT)
+ button:SetScript("OnClick", OnClick)
+ button:Disable()
+
+ local text = button:GetFontString()
+ text:ClearAllPoints()
+ text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
+ text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
+ text:SetJustifyV("MIDDLE")
+
+ local scrollBG = CreateFrame("Frame", nil, frame, "BackdropTemplate")
+ scrollBG:SetBackdrop(backdrop)
+ scrollBG:SetBackdropColor(0, 0, 0)
+ scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
+
+ local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
+
+ local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
+ scrollBar:ClearAllPoints()
+ scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
+ scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
+ scrollBar:SetPoint("RIGHT", frame, "RIGHT")
+
+ scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
+ scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
+
+ scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
+ scrollFrame:SetScript("OnEnter", OnEnter)
+ scrollFrame:SetScript("OnLeave", OnLeave)
+ scrollFrame:SetScript("OnMouseUp", OnMouseUp)
+ scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
+ scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
+ scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
+ scrollFrame:HookScript("OnScrollRangeChanged", OnScrollRangeChanged)
+
+ local editBox = CreateFrame("EditBox", ("%s%dEdit"):format(Type, widgetNum), scrollFrame)
+ editBox:SetAllPoints()
+ editBox:SetFontObject(ChatFontNormal)
+ editBox:SetMultiLine(true)
+ editBox:EnableMouse(true)
+ editBox:SetAutoFocus(false)
+ editBox:SetCountInvisibleLetters(false)
+ editBox:SetScript("OnCursorChanged", OnCursorChanged)
+ editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
+ editBox:SetScript("OnEnter", OnEnter)
+ editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
+ editBox:SetScript("OnLeave", OnLeave)
+ editBox:SetScript("OnMouseDown", OnReceiveDrag)
+ editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
+ editBox:SetScript("OnTextChanged", OnTextChanged)
+ editBox:SetScript("OnTextSet", OnTextSet)
+ editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
+
+
+ scrollFrame:SetScrollChild(editBox)
+
+ local widget = {
+ button = button,
+ editBox = editBox,
+ frame = frame,
+ label = label,
+ labelHeight = 10,
+ numlines = 4,
+ scrollBar = scrollBar,
+ scrollBG = scrollBG,
+ scrollFrame = scrollFrame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua
index 8989608..483d400 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua
@@ -1,280 +1,280 @@
---[[-----------------------------------------------------------------------------
-Slider Widget
-Graphical Slider, like, for Range values.
--------------------------------------------------------------------------------]]
-local Type, Version = "Slider", 23
-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 tonumber, pairs = tonumber, pairs
-
--- WoW APIs
-local PlaySound = PlaySound
-local CreateFrame, UIParent = CreateFrame, UIParent
-
---[[-----------------------------------------------------------------------------
-Support functions
--------------------------------------------------------------------------------]]
-local function UpdateText(self)
- local value = self.value or 0
- if self.ispercent then
- self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
- else
- self.editbox:SetText(floor(value * 100 + 0.5) / 100)
- end
-end
-
-local function UpdateLabels(self)
- local min_value, max_value = (self.min or 0), (self.max or 100)
- if self.ispercent then
- self.lowtext:SetFormattedText("%s%%", (min_value * 100))
- self.hightext:SetFormattedText("%s%%", (max_value * 100))
- else
- self.lowtext:SetText(min_value)
- self.hightext:SetText(max_value)
- end
-end
-
---[[-----------------------------------------------------------------------------
-Scripts
--------------------------------------------------------------------------------]]
-local function Control_OnEnter(frame)
- frame.obj:Fire("OnEnter")
-end
-
-local function Control_OnLeave(frame)
- frame.obj:Fire("OnLeave")
-end
-
-local function Frame_OnMouseDown(frame)
- frame.obj.slider:EnableMouseWheel(true)
- AceGUI:ClearFocus()
-end
-
-local function Slider_OnValueChanged(frame, newvalue)
- local self = frame.obj
- if not frame.setup then
- 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", newvalue)
- end
- if self.value then
- UpdateText(self)
- end
- end
-end
-
-local function Slider_OnMouseUp(frame)
- local self = frame.obj
- self:Fire("OnMouseUp", self.value)
-end
-
-local function Slider_OnMouseWheel(frame, v)
- local self = frame.obj
- if not self.disabled then
- local value = self.value
- if v > 0 then
- value = min(value + (self.step or 1), self.max)
- else
- value = max(value - (self.step or 1), self.min)
- end
- self.slider:SetValue(value)
- end
-end
-
-local function EditBox_OnEscapePressed(frame)
- frame:ClearFocus()
-end
-
-local function EditBox_OnEnterPressed(frame)
- local self = frame.obj
- local value = frame:GetText()
- if self.ispercent then
- value = value:gsub('%%', '')
- value = tonumber(value) / 100
- else
- value = tonumber(value)
- end
-
- if value then
- PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
- self.slider:SetValue(value)
- self:Fire("OnMouseUp", value)
- end
-end
-
-local function EditBox_OnEnter(frame)
- frame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
-end
-
-local function EditBox_OnLeave(frame)
- frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
-end
-
---[[-----------------------------------------------------------------------------
-Methods
--------------------------------------------------------------------------------]]
-local methods = {
- ["OnAcquire"] = function(self)
- self:SetWidth(200)
- self:SetHeight(44)
- self:SetDisabled(false)
- self:SetIsPercent(nil)
- self:SetSliderValues(0,100,1)
- self:SetValue(0)
- self.slider:EnableMouseWheel(false)
- end,
-
- -- ["OnRelease"] = nil,
-
- ["SetDisabled"] = function(self, disabled)
- self.disabled = disabled
- if disabled then
- self.slider:EnableMouse(false)
- self.label:SetTextColor(.5, .5, .5)
- self.hightext:SetTextColor(.5, .5, .5)
- self.lowtext:SetTextColor(.5, .5, .5)
- --self.valuetext:SetTextColor(.5, .5, .5)
- self.editbox:SetTextColor(.5, .5, .5)
- self.editbox:EnableMouse(false)
- self.editbox:ClearFocus()
- else
- self.slider:EnableMouse(true)
- self.label:SetTextColor(1, .82, 0)
- self.hightext:SetTextColor(1, 1, 1)
- self.lowtext:SetTextColor(1, 1, 1)
- --self.valuetext:SetTextColor(1, 1, 1)
- self.editbox:SetTextColor(1, 1, 1)
- self.editbox:EnableMouse(true)
- end
- end,
-
- ["SetValue"] = function(self, value)
- self.slider.setup = true
- self.slider:SetValue(value)
- self.value = value
- UpdateText(self)
- self.slider.setup = nil
- end,
-
- ["GetValue"] = function(self)
- return self.value
- end,
-
- ["SetLabel"] = function(self, text)
- self.label:SetText(text)
- end,
-
- ["SetSliderValues"] = function(self, min_value, max_value, step)
- local frame = self.slider
- frame.setup = true
- self.min = min_value
- self.max = max_value
- self.step = step
- frame:SetMinMaxValues(min_value or 0,max_value or 100)
- UpdateLabels(self)
- frame:SetValueStep(step or 1)
- if self.value then
- frame:SetValue(self.value)
- end
- frame.setup = nil
- end,
-
- ["SetIsPercent"] = function(self, value)
- self.ispercent = value
- UpdateLabels(self)
- UpdateText(self)
- end
-}
-
---[[-----------------------------------------------------------------------------
-Constructor
--------------------------------------------------------------------------------]]
-local SliderBackdrop = {
- bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
- edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
- tile = true, tileSize = 8, edgeSize = 8,
- insets = { left = 3, right = 3, top = 6, bottom = 6 }
-}
-
-local ManualBackdrop = {
- bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
- edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
- tile = true, edgeSize = 1, tileSize = 5,
-}
-
-local function Constructor()
- local frame = CreateFrame("Frame", nil, UIParent)
-
- frame:EnableMouse(true)
- frame:SetScript("OnMouseDown", Frame_OnMouseDown)
-
- local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
- label:SetPoint("TOPLEFT")
- label:SetPoint("TOPRIGHT")
- label:SetJustifyH("CENTER")
- label:SetHeight(15)
-
- local slider = CreateFrame("Slider", nil, frame, "BackdropTemplate")
- slider:SetOrientation("HORIZONTAL")
- slider:SetHeight(15)
- slider:SetHitRectInsets(0, 0, -10, 0)
- slider:SetBackdrop(SliderBackdrop)
- slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
- slider:SetPoint("TOP", label, "BOTTOM")
- slider:SetPoint("LEFT", 3, 0)
- slider:SetPoint("RIGHT", -3, 0)
- slider:SetValue(0)
- slider:SetScript("OnValueChanged",Slider_OnValueChanged)
- slider:SetScript("OnEnter", Control_OnEnter)
- slider:SetScript("OnLeave", Control_OnLeave)
- slider:SetScript("OnMouseUp", Slider_OnMouseUp)
- slider:SetScript("OnMouseWheel", Slider_OnMouseWheel)
-
- local lowtext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
- lowtext:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 2, 3)
-
- local hightext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
- hightext:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", -2, 3)
-
- local editbox = CreateFrame("EditBox", nil, frame, "BackdropTemplate")
- editbox:SetAutoFocus(false)
- editbox:SetFontObject(GameFontHighlightSmall)
- editbox:SetPoint("TOP", slider, "BOTTOM")
- editbox:SetHeight(14)
- editbox:SetWidth(70)
- editbox:SetJustifyH("CENTER")
- editbox:EnableMouse(true)
- editbox:SetBackdrop(ManualBackdrop)
- editbox:SetBackdropColor(0, 0, 0, 0.5)
- editbox:SetBackdropBorderColor(0.3, 0.3, 0.30, 0.80)
- editbox:SetScript("OnEnter", EditBox_OnEnter)
- editbox:SetScript("OnLeave", EditBox_OnLeave)
- editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
- editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
-
- local widget = {
- label = label,
- slider = slider,
- lowtext = lowtext,
- hightext = hightext,
- editbox = editbox,
- alignoffset = 25,
- frame = frame,
- type = Type
- }
- for method, func in pairs(methods) do
- widget[method] = func
- end
- slider.obj, editbox.obj = widget, widget
-
- return AceGUI:RegisterAsWidget(widget)
-end
-
-AceGUI:RegisterWidgetType(Type,Constructor,Version)
+--[[-----------------------------------------------------------------------------
+Slider Widget
+Graphical Slider, like, for Range values.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Slider", 23
+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 tonumber, pairs = tonumber, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function UpdateText(self)
+ local value = self.value or 0
+ if self.ispercent then
+ self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
+ else
+ self.editbox:SetText(floor(value * 100 + 0.5) / 100)
+ end
+end
+
+local function UpdateLabels(self)
+ local min_value, max_value = (self.min or 0), (self.max or 100)
+ if self.ispercent then
+ self.lowtext:SetFormattedText("%s%%", (min_value * 100))
+ self.hightext:SetFormattedText("%s%%", (max_value * 100))
+ else
+ self.lowtext:SetText(min_value)
+ self.hightext:SetText(max_value)
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Frame_OnMouseDown(frame)
+ frame.obj.slider:EnableMouseWheel(true)
+ AceGUI:ClearFocus()
+end
+
+local function Slider_OnValueChanged(frame, newvalue)
+ local self = frame.obj
+ if not frame.setup then
+ 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", newvalue)
+ end
+ if self.value then
+ UpdateText(self)
+ end
+ end
+end
+
+local function Slider_OnMouseUp(frame)
+ local self = frame.obj
+ self:Fire("OnMouseUp", self.value)
+end
+
+local function Slider_OnMouseWheel(frame, v)
+ local self = frame.obj
+ if not self.disabled then
+ local value = self.value
+ if v > 0 then
+ value = min(value + (self.step or 1), self.max)
+ else
+ value = max(value - (self.step or 1), self.min)
+ end
+ self.slider:SetValue(value)
+ end
+end
+
+local function EditBox_OnEscapePressed(frame)
+ frame:ClearFocus()
+end
+
+local function EditBox_OnEnterPressed(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ if self.ispercent then
+ value = value:gsub('%%', '')
+ value = tonumber(value) / 100
+ else
+ value = tonumber(value)
+ end
+
+ if value then
+ PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
+ self.slider:SetValue(value)
+ self:Fire("OnMouseUp", value)
+ end
+end
+
+local function EditBox_OnEnter(frame)
+ frame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
+end
+
+local function EditBox_OnLeave(frame)
+ frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(200)
+ self:SetHeight(44)
+ self:SetDisabled(false)
+ self:SetIsPercent(nil)
+ self:SetSliderValues(0,100,1)
+ self:SetValue(0)
+ self.slider:EnableMouseWheel(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.slider:EnableMouse(false)
+ self.label:SetTextColor(.5, .5, .5)
+ self.hightext:SetTextColor(.5, .5, .5)
+ self.lowtext:SetTextColor(.5, .5, .5)
+ --self.valuetext:SetTextColor(.5, .5, .5)
+ self.editbox:SetTextColor(.5, .5, .5)
+ self.editbox:EnableMouse(false)
+ self.editbox:ClearFocus()
+ else
+ self.slider:EnableMouse(true)
+ self.label:SetTextColor(1, .82, 0)
+ self.hightext:SetTextColor(1, 1, 1)
+ self.lowtext:SetTextColor(1, 1, 1)
+ --self.valuetext:SetTextColor(1, 1, 1)
+ self.editbox:SetTextColor(1, 1, 1)
+ self.editbox:EnableMouse(true)
+ end
+ end,
+
+ ["SetValue"] = function(self, value)
+ self.slider.setup = true
+ self.slider:SetValue(value)
+ self.value = value
+ UpdateText(self)
+ self.slider.setup = nil
+ end,
+
+ ["GetValue"] = function(self)
+ return self.value
+ end,
+
+ ["SetLabel"] = function(self, text)
+ self.label:SetText(text)
+ end,
+
+ ["SetSliderValues"] = function(self, min_value, max_value, step)
+ local frame = self.slider
+ frame.setup = true
+ self.min = min_value
+ self.max = max_value
+ self.step = step
+ frame:SetMinMaxValues(min_value or 0,max_value or 100)
+ UpdateLabels(self)
+ frame:SetValueStep(step or 1)
+ if self.value then
+ frame:SetValue(self.value)
+ end
+ frame.setup = nil
+ end,
+
+ ["SetIsPercent"] = function(self, value)
+ self.ispercent = value
+ UpdateLabels(self)
+ UpdateText(self)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local SliderBackdrop = {
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 6, bottom = 6 }
+}
+
+local ManualBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ tile = true, edgeSize = 1, tileSize = 5,
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnMouseDown", Frame_OnMouseDown)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ label:SetPoint("TOPLEFT")
+ label:SetPoint("TOPRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetHeight(15)
+
+ local slider = CreateFrame("Slider", nil, frame, "BackdropTemplate")
+ slider:SetOrientation("HORIZONTAL")
+ slider:SetHeight(15)
+ slider:SetHitRectInsets(0, 0, -10, 0)
+ slider:SetBackdrop(SliderBackdrop)
+ slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
+ slider:SetPoint("TOP", label, "BOTTOM")
+ slider:SetPoint("LEFT", 3, 0)
+ slider:SetPoint("RIGHT", -3, 0)
+ slider:SetValue(0)
+ slider:SetScript("OnValueChanged",Slider_OnValueChanged)
+ slider:SetScript("OnEnter", Control_OnEnter)
+ slider:SetScript("OnLeave", Control_OnLeave)
+ slider:SetScript("OnMouseUp", Slider_OnMouseUp)
+ slider:SetScript("OnMouseWheel", Slider_OnMouseWheel)
+
+ local lowtext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ lowtext:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 2, 3)
+
+ local hightext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ hightext:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", -2, 3)
+
+ local editbox = CreateFrame("EditBox", nil, frame, "BackdropTemplate")
+ editbox:SetAutoFocus(false)
+ editbox:SetFontObject(GameFontHighlightSmall)
+ editbox:SetPoint("TOP", slider, "BOTTOM")
+ editbox:SetHeight(14)
+ editbox:SetWidth(70)
+ editbox:SetJustifyH("CENTER")
+ editbox:EnableMouse(true)
+ editbox:SetBackdrop(ManualBackdrop)
+ editbox:SetBackdropColor(0, 0, 0, 0.5)
+ editbox:SetBackdropBorderColor(0.3, 0.3, 0.30, 0.80)
+ editbox:SetScript("OnEnter", EditBox_OnEnter)
+ editbox:SetScript("OnLeave", EditBox_OnLeave)
+ editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
+ editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
+
+ local widget = {
+ label = label,
+ slider = slider,
+ lowtext = lowtext,
+ hightext = hightext,
+ editbox = editbox,
+ alignoffset = 25,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ slider.obj, editbox.obj = widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type,Constructor,Version)
diff --git a/Libs/AceSerializer-3.0/AceSerializer-3.0.lua b/Libs/AceSerializer-3.0/AceSerializer-3.0.lua
index 74dbe6b..25b3fb1 100644
--- a/Libs/AceSerializer-3.0/AceSerializer-3.0.lua
+++ b/Libs/AceSerializer-3.0/AceSerializer-3.0.lua
@@ -1,287 +1,287 @@
---- **AceSerializer-3.0** can serialize any variable (except functions or userdata) into a string format,
--- that can be send over the addon comm channel. AceSerializer was designed to keep all data intact, especially
--- very large numbers or floating point numbers, and table structures. The only caveat currently is, that multiple
--- references to the same table will be send individually.
---
--- **AceSerializer-3.0** can be embeded into your addon, either explicitly by calling AceSerializer: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 AceSerializer itself.\\
--- It is recommended to embed AceSerializer, otherwise you'll have to specify a custom `self` on all calls you
--- make into AceSerializer.
--- @class file
--- @name AceSerializer-3.0
--- @release $Id: AceSerializer-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-local MAJOR,MINOR = "AceSerializer-3.0", 5
-local AceSerializer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceSerializer then return end
-
--- Lua APIs
-local strbyte, strchar, gsub, gmatch, format = string.byte, string.char, string.gsub, string.gmatch, string.format
-local assert, error, pcall = assert, error, pcall
-local type, tostring, tonumber = type, tostring, tonumber
-local pairs, select, frexp = pairs, select, math.frexp
-local tconcat = table.concat
-
--- quick copies of string representations of wonky numbers
-local inf = math.huge
-
-local serNaN -- can't do this in 4.3, see ace3 ticket 268
-local serInf, serInfMac = "1.#INF", "inf"
-local serNegInf, serNegInfMac = "-1.#INF", "-inf"
-
-
--- Serialization functions
-
-local function SerializeStringHelper(ch) -- Used by SerializeValue for strings
- -- We use \126 ("~") as an escape character for all nonprints plus a few more
- local n = strbyte(ch)
- if n==30 then -- v3 / ticket 115: catch a nonprint that ends up being "~^" when encoded... DOH
- return "\126\122"
- elseif n<=32 then -- nonprint + space
- return "\126"..strchar(n+64)
- elseif n==94 then -- value separator
- return "\126\125"
- elseif n==126 then -- our own escape character
- return "\126\124"
- elseif n==127 then -- nonprint (DEL)
- return "\126\123"
- else
- assert(false) -- can't be reached if caller uses a sane regex
- end
-end
-
-local function SerializeValue(v, res, nres)
- -- We use "^" as a value separator, followed by one byte for type indicator
- local t=type(v)
-
- if t=="string" then -- ^S = string (escaped to remove nonprints, "^"s, etc)
- res[nres+1] = "^S"
- res[nres+2] = gsub(v,"[%c \94\126\127]", SerializeStringHelper)
- nres=nres+2
-
- elseif t=="number" then -- ^N = number (just tostring()ed) or ^F (float components)
- local str = tostring(v)
- if tonumber(str)==v --[[not in 4.3 or str==serNaN]] then
- -- translates just fine, transmit as-is
- res[nres+1] = "^N"
- res[nres+2] = str
- nres=nres+2
- elseif v == inf or v == -inf then
- res[nres+1] = "^N"
- res[nres+2] = v == inf and serInf or serNegInf
- nres=nres+2
- else
- local m,e = frexp(v)
- res[nres+1] = "^F"
- res[nres+2] = format("%.0f",m*2^53) -- force mantissa to become integer (it's originally 0.5--0.9999)
- res[nres+3] = "^f"
- res[nres+4] = tostring(e-53) -- adjust exponent to counteract mantissa manipulation
- nres=nres+4
- end
-
- elseif t=="table" then -- ^T...^t = table (list of key,value pairs)
- nres=nres+1
- res[nres] = "^T"
- for key,value in pairs(v) do
- nres = SerializeValue(key, res, nres)
- nres = SerializeValue(value, res, nres)
- end
- nres=nres+1
- res[nres] = "^t"
-
- elseif t=="boolean" then -- ^B = true, ^b = false
- nres=nres+1
- if v then
- res[nres] = "^B" -- true
- else
- res[nres] = "^b" -- false
- end
-
- elseif t=="nil" then -- ^Z = nil (zero, "N" was taken :P)
- nres=nres+1
- res[nres] = "^Z"
-
- else
- error(MAJOR..": Cannot serialize a value of type '"..t.."'") -- can't produce error on right level, this is wildly recursive
- end
-
- return nres
-end
-
-
-
-local serializeTbl = { "^1" } -- "^1" = Hi, I'm data serialized by AceSerializer protocol rev 1
-
---- Serialize the data passed into the function.
--- Takes a list of values (strings, numbers, booleans, nils, tables)
--- and returns it in serialized form (a string).\\
--- May throw errors on invalid data types.
--- @param ... List of values to serialize
--- @return The data in its serialized form (string)
-function AceSerializer:Serialize(...)
- local nres = 1
-
- for i=1,select("#", ...) do
- local v = select(i, ...)
- nres = SerializeValue(v, serializeTbl, nres)
- end
-
- serializeTbl[nres+1] = "^^" -- "^^" = End of serialized data
-
- return tconcat(serializeTbl, "", 1, nres+1)
-end
-
--- Deserialization functions
-local function DeserializeStringHelper(escape)
- if escape<"~\122" then
- return strchar(strbyte(escape,2,2)-64)
- elseif escape=="~\122" then -- v3 / ticket 115: special case encode since 30+64=94 ("^") - OOPS.
- return "\030"
- elseif escape=="~\123" then
- return "\127"
- elseif escape=="~\124" then
- return "\126"
- elseif escape=="~\125" then
- return "\94"
- end
- error("DeserializeStringHelper got called for '"..escape.."'?!?") -- can't be reached unless regex is screwed up
-end
-
-local function DeserializeNumberHelper(number)
- --[[ not in 4.3 if number == serNaN then
- return 0/0
- else]]if number == serNegInf or number == serNegInfMac then
- return -inf
- elseif number == serInf or number == serInfMac then
- return inf
- else
- return tonumber(number)
- end
-end
-
--- DeserializeValue: worker function for :Deserialize()
--- It works in two modes:
--- Main (top-level) mode: Deserialize a list of values and return them all
--- Recursive (table) mode: Deserialize only a single value (_may_ of course be another table with lots of subvalues in it)
---
--- The function _always_ works recursively due to having to build a list of values to return
---
--- Callers are expected to pcall(DeserializeValue) to trap errors
-
-local function DeserializeValue(iter,single,ctl,data)
-
- if not single then
- ctl,data = iter()
- end
-
- if not ctl then
- error("Supplied data misses AceSerializer terminator ('^^')")
- end
-
- if ctl=="^^" then
- -- ignore extraneous data
- return
- end
-
- local res
-
- if ctl=="^S" then
- res = gsub(data, "~.", DeserializeStringHelper)
- elseif ctl=="^N" then
- res = DeserializeNumberHelper(data)
- if not res then
- error("Invalid serialized number: '"..tostring(data).."'")
- end
- elseif ctl=="^F" then -- ^F^f
- local ctl2,e = iter()
- if ctl2~="^f" then
- error("Invalid serialized floating-point number, expected '^f', not '"..tostring(ctl2).."'")
- end
- local m=tonumber(data)
- e=tonumber(e)
- if not (m and e) then
- error("Invalid serialized floating-point number, expected mantissa and exponent, got '"..tostring(m).."' and '"..tostring(e).."'")
- end
- res = m*(2^e)
- elseif ctl=="^B" then -- yeah yeah ignore data portion
- res = true
- elseif ctl=="^b" then -- yeah yeah ignore data portion
- res = false
- elseif ctl=="^Z" then -- yeah yeah ignore data portion
- res = nil
- elseif ctl=="^T" then
- -- ignore ^T's data, future extensibility?
- res = {}
- local k,v
- while true do
- ctl,data = iter()
- if ctl=="^t" then break end -- ignore ^t's data
- k = DeserializeValue(iter,true,ctl,data)
- if k==nil then
- error("Invalid AceSerializer table format (no table end marker)")
- end
- ctl,data = iter()
- v = DeserializeValue(iter,true,ctl,data)
- if v==nil then
- error("Invalid AceSerializer table format (no table end marker)")
- end
- res[k]=v
- end
- else
- error("Invalid AceSerializer control code '"..ctl.."'")
- end
-
- if not single then
- return res,DeserializeValue(iter)
- else
- return res
- end
-end
-
---- Deserializes the data into its original values.
--- Accepts serialized data, ignoring all control characters and whitespace.
--- @param str The serialized data (from :Serialize)
--- @return true followed by a list of values, OR false followed by an error message
-function AceSerializer:Deserialize(str)
- str = gsub(str, "[%c ]", "") -- ignore all control characters; nice for embedding in email and stuff
-
- local iter = gmatch(str, "(^.)([^^]*)") -- Any ^x followed by string of non-^
- local ctl,data = iter()
- if not ctl or ctl~="^1" then
- -- we purposefully ignore the data portion of the start code, it can be used as an extension mechanism
- return false, "Supplied data is not AceSerializer data (rev 1)"
- end
-
- return pcall(DeserializeValue, iter)
-end
-
-
-----------------------------------------
--- Base library stuff
-----------------------------------------
-
-AceSerializer.internals = { -- for test scripts
- SerializeValue = SerializeValue,
- SerializeStringHelper = SerializeStringHelper,
-}
-
-local mixins = {
- "Serialize",
- "Deserialize",
-}
-
-AceSerializer.embeds = AceSerializer.embeds or {}
-
-function AceSerializer:Embed(target)
- for k, v in pairs(mixins) do
- target[v] = self[v]
- end
- self.embeds[target] = true
- return target
-end
-
--- Update embeds
-for target, v in pairs(AceSerializer.embeds) do
- AceSerializer:Embed(target)
-end
+--- **AceSerializer-3.0** can serialize any variable (except functions or userdata) into a string format,
+-- that can be send over the addon comm channel. AceSerializer was designed to keep all data intact, especially
+-- very large numbers or floating point numbers, and table structures. The only caveat currently is, that multiple
+-- references to the same table will be send individually.
+--
+-- **AceSerializer-3.0** can be embeded into your addon, either explicitly by calling AceSerializer: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 AceSerializer itself.\\
+-- It is recommended to embed AceSerializer, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceSerializer.
+-- @class file
+-- @name AceSerializer-3.0
+-- @release $Id: AceSerializer-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+local MAJOR,MINOR = "AceSerializer-3.0", 5
+local AceSerializer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceSerializer then return end
+
+-- Lua APIs
+local strbyte, strchar, gsub, gmatch, format = string.byte, string.char, string.gsub, string.gmatch, string.format
+local assert, error, pcall = assert, error, pcall
+local type, tostring, tonumber = type, tostring, tonumber
+local pairs, select, frexp = pairs, select, math.frexp
+local tconcat = table.concat
+
+-- quick copies of string representations of wonky numbers
+local inf = math.huge
+
+local serNaN -- can't do this in 4.3, see ace3 ticket 268
+local serInf, serInfMac = "1.#INF", "inf"
+local serNegInf, serNegInfMac = "-1.#INF", "-inf"
+
+
+-- Serialization functions
+
+local function SerializeStringHelper(ch) -- Used by SerializeValue for strings
+ -- We use \126 ("~") as an escape character for all nonprints plus a few more
+ local n = strbyte(ch)
+ if n==30 then -- v3 / ticket 115: catch a nonprint that ends up being "~^" when encoded... DOH
+ return "\126\122"
+ elseif n<=32 then -- nonprint + space
+ return "\126"..strchar(n+64)
+ elseif n==94 then -- value separator
+ return "\126\125"
+ elseif n==126 then -- our own escape character
+ return "\126\124"
+ elseif n==127 then -- nonprint (DEL)
+ return "\126\123"
+ else
+ assert(false) -- can't be reached if caller uses a sane regex
+ end
+end
+
+local function SerializeValue(v, res, nres)
+ -- We use "^" as a value separator, followed by one byte for type indicator
+ local t=type(v)
+
+ if t=="string" then -- ^S = string (escaped to remove nonprints, "^"s, etc)
+ res[nres+1] = "^S"
+ res[nres+2] = gsub(v,"[%c \94\126\127]", SerializeStringHelper)
+ nres=nres+2
+
+ elseif t=="number" then -- ^N = number (just tostring()ed) or ^F (float components)
+ local str = tostring(v)
+ if tonumber(str)==v --[[not in 4.3 or str==serNaN]] then
+ -- translates just fine, transmit as-is
+ res[nres+1] = "^N"
+ res[nres+2] = str
+ nres=nres+2
+ elseif v == inf or v == -inf then
+ res[nres+1] = "^N"
+ res[nres+2] = v == inf and serInf or serNegInf
+ nres=nres+2
+ else
+ local m,e = frexp(v)
+ res[nres+1] = "^F"
+ res[nres+2] = format("%.0f",m*2^53) -- force mantissa to become integer (it's originally 0.5--0.9999)
+ res[nres+3] = "^f"
+ res[nres+4] = tostring(e-53) -- adjust exponent to counteract mantissa manipulation
+ nres=nres+4
+ end
+
+ elseif t=="table" then -- ^T...^t = table (list of key,value pairs)
+ nres=nres+1
+ res[nres] = "^T"
+ for key,value in pairs(v) do
+ nres = SerializeValue(key, res, nres)
+ nres = SerializeValue(value, res, nres)
+ end
+ nres=nres+1
+ res[nres] = "^t"
+
+ elseif t=="boolean" then -- ^B = true, ^b = false
+ nres=nres+1
+ if v then
+ res[nres] = "^B" -- true
+ else
+ res[nres] = "^b" -- false
+ end
+
+ elseif t=="nil" then -- ^Z = nil (zero, "N" was taken :P)
+ nres=nres+1
+ res[nres] = "^Z"
+
+ else
+ error(MAJOR..": Cannot serialize a value of type '"..t.."'") -- can't produce error on right level, this is wildly recursive
+ end
+
+ return nres
+end
+
+
+
+local serializeTbl = { "^1" } -- "^1" = Hi, I'm data serialized by AceSerializer protocol rev 1
+
+--- Serialize the data passed into the function.
+-- Takes a list of values (strings, numbers, booleans, nils, tables)
+-- and returns it in serialized form (a string).\\
+-- May throw errors on invalid data types.
+-- @param ... List of values to serialize
+-- @return The data in its serialized form (string)
+function AceSerializer:Serialize(...)
+ local nres = 1
+
+ for i=1,select("#", ...) do
+ local v = select(i, ...)
+ nres = SerializeValue(v, serializeTbl, nres)
+ end
+
+ serializeTbl[nres+1] = "^^" -- "^^" = End of serialized data
+
+ return tconcat(serializeTbl, "", 1, nres+1)
+end
+
+-- Deserialization functions
+local function DeserializeStringHelper(escape)
+ if escape<"~\122" then
+ return strchar(strbyte(escape,2,2)-64)
+ elseif escape=="~\122" then -- v3 / ticket 115: special case encode since 30+64=94 ("^") - OOPS.
+ return "\030"
+ elseif escape=="~\123" then
+ return "\127"
+ elseif escape=="~\124" then
+ return "\126"
+ elseif escape=="~\125" then
+ return "\94"
+ end
+ error("DeserializeStringHelper got called for '"..escape.."'?!?") -- can't be reached unless regex is screwed up
+end
+
+local function DeserializeNumberHelper(number)
+ --[[ not in 4.3 if number == serNaN then
+ return 0/0
+ else]]if number == serNegInf or number == serNegInfMac then
+ return -inf
+ elseif number == serInf or number == serInfMac then
+ return inf
+ else
+ return tonumber(number)
+ end
+end
+
+-- DeserializeValue: worker function for :Deserialize()
+-- It works in two modes:
+-- Main (top-level) mode: Deserialize a list of values and return them all
+-- Recursive (table) mode: Deserialize only a single value (_may_ of course be another table with lots of subvalues in it)
+--
+-- The function _always_ works recursively due to having to build a list of values to return
+--
+-- Callers are expected to pcall(DeserializeValue) to trap errors
+
+local function DeserializeValue(iter,single,ctl,data)
+
+ if not single then
+ ctl,data = iter()
+ end
+
+ if not ctl then
+ error("Supplied data misses AceSerializer terminator ('^^')")
+ end
+
+ if ctl=="^^" then
+ -- ignore extraneous data
+ return
+ end
+
+ local res
+
+ if ctl=="^S" then
+ res = gsub(data, "~.", DeserializeStringHelper)
+ elseif ctl=="^N" then
+ res = DeserializeNumberHelper(data)
+ if not res then
+ error("Invalid serialized number: '"..tostring(data).."'")
+ end
+ elseif ctl=="^F" then -- ^F^f
+ local ctl2,e = iter()
+ if ctl2~="^f" then
+ error("Invalid serialized floating-point number, expected '^f', not '"..tostring(ctl2).."'")
+ end
+ local m=tonumber(data)
+ e=tonumber(e)
+ if not (m and e) then
+ error("Invalid serialized floating-point number, expected mantissa and exponent, got '"..tostring(m).."' and '"..tostring(e).."'")
+ end
+ res = m*(2^e)
+ elseif ctl=="^B" then -- yeah yeah ignore data portion
+ res = true
+ elseif ctl=="^b" then -- yeah yeah ignore data portion
+ res = false
+ elseif ctl=="^Z" then -- yeah yeah ignore data portion
+ res = nil
+ elseif ctl=="^T" then
+ -- ignore ^T's data, future extensibility?
+ res = {}
+ local k,v
+ while true do
+ ctl,data = iter()
+ if ctl=="^t" then break end -- ignore ^t's data
+ k = DeserializeValue(iter,true,ctl,data)
+ if k==nil then
+ error("Invalid AceSerializer table format (no table end marker)")
+ end
+ ctl,data = iter()
+ v = DeserializeValue(iter,true,ctl,data)
+ if v==nil then
+ error("Invalid AceSerializer table format (no table end marker)")
+ end
+ res[k]=v
+ end
+ else
+ error("Invalid AceSerializer control code '"..ctl.."'")
+ end
+
+ if not single then
+ return res,DeserializeValue(iter)
+ else
+ return res
+ end
+end
+
+--- Deserializes the data into its original values.
+-- Accepts serialized data, ignoring all control characters and whitespace.
+-- @param str The serialized data (from :Serialize)
+-- @return true followed by a list of values, OR false followed by an error message
+function AceSerializer:Deserialize(str)
+ str = gsub(str, "[%c ]", "") -- ignore all control characters; nice for embedding in email and stuff
+
+ local iter = gmatch(str, "(^.)([^^]*)") -- Any ^x followed by string of non-^
+ local ctl,data = iter()
+ if not ctl or ctl~="^1" then
+ -- we purposefully ignore the data portion of the start code, it can be used as an extension mechanism
+ return false, "Supplied data is not AceSerializer data (rev 1)"
+ end
+
+ return pcall(DeserializeValue, iter)
+end
+
+
+----------------------------------------
+-- Base library stuff
+----------------------------------------
+
+AceSerializer.internals = { -- for test scripts
+ SerializeValue = SerializeValue,
+ SerializeStringHelper = SerializeStringHelper,
+}
+
+local mixins = {
+ "Serialize",
+ "Deserialize",
+}
+
+AceSerializer.embeds = AceSerializer.embeds or {}
+
+function AceSerializer:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+-- Update embeds
+for target, v in pairs(AceSerializer.embeds) do
+ AceSerializer:Embed(target)
+end
diff --git a/Libs/AceSerializer-3.0/AceSerializer-3.0.xml b/Libs/AceSerializer-3.0/AceSerializer-3.0.xml
index f44106d..677d08e 100644
--- a/Libs/AceSerializer-3.0/AceSerializer-3.0.xml
+++ b/Libs/AceSerializer-3.0/AceSerializer-3.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/AceTimer-3.0/AceTimer-3.0.lua b/Libs/AceTimer-3.0/AceTimer-3.0.lua
index c337398..78fb4ed 100755
--- a/Libs/AceTimer-3.0/AceTimer-3.0.lua
+++ b/Libs/AceTimer-3.0/AceTimer-3.0.lua
@@ -1,278 +1,278 @@
---- **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
--- 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.
---
--- 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.
---
--- **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
--- and can be accessed directly, without having to explicitly call AceTimer itself.\\
--- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
--- make into AceTimer.
--- @class file
--- @name AceTimer-3.0
--- @release $Id: AceTimer-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-
-local MAJOR, MINOR = "AceTimer-3.0", 17 -- Bump minor on changes
-local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceTimer then return end -- No upgrade needed
-AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
-local activeTimers = AceTimer.activeTimers -- Upvalue our private data
-
--- Lua APIs
-local type, unpack, next, error, select = type, unpack, next, error, select
--- WoW APIs
-local GetTime, C_TimerAfter = GetTime, C_Timer.After
-
-local function new(self, loop, func, delay, ...)
- if delay < 0.01 then
- delay = 0.01 -- Restrict to the lowest time that the C_Timer API allows us
- end
-
- local timer = {
- object = self,
- func = func,
- looping = loop,
- argsCount = select("#", ...),
- delay = delay,
- ends = GetTime() + delay,
- ...
- }
-
- activeTimers[timer] = timer
-
- -- Create new timer closure to wrap the "timer" object
- timer.callback = function()
- if not timer.cancelled then
- if type(timer.func) == "string" then
- -- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
- -- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue.
- timer.object[timer.func](timer.object, unpack(timer, 1, timer.argsCount))
- else
- timer.func(unpack(timer, 1, timer.argsCount))
- end
-
- if timer.looping and not timer.cancelled then
- -- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly
- -- due to fps differences
- local time = GetTime()
- local ndelay = timer.delay - (time - timer.ends)
- -- Ensure the delay doesn't go below the threshold
- if ndelay < 0.01 then ndelay = 0.01 end
- C_TimerAfter(ndelay, timer.callback)
- timer.ends = time + ndelay
- else
- activeTimers[timer.handle or timer] = nil
- end
- end
- end
-
- C_TimerAfter(delay, timer.callback)
- return timer
-end
-
---- 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 ... An optional, unlimited amount of arguments to pass to the callback function.
--- @usage
--- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
---
--- function MyAddOn:OnEnable()
--- self:ScheduleTimer("TimerFeedback", 5)
--- end
---
--- function MyAddOn:TimerFeedback()
--- print("5 seconds passed")
--- end
-function AceTimer:ScheduleTimer(func, delay, ...)
- if not func or not delay then
- error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
- end
- if type(func) == "string" then
- if type(self) ~= "table" then
- error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2)
- elseif not self[func] then
- error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
- end
- end
- return new(self, nil, func, delay, ...)
-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 ... An optional, unlimited amount of arguments to pass to the callback function.
--- @usage
--- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
---
--- function MyAddOn:OnEnable()
--- self.timerCount = 0
--- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
--- end
---
--- function MyAddOn:TimerFeedback()
--- self.timerCount = self.timerCount + 1
--- print(("%d seconds passed"):format(5 * self.timerCount))
--- -- run 30 seconds in total
--- if self.timerCount == 6 then
--- self:CancelTimer(self.testTimer)
--- end
--- end
-function AceTimer:ScheduleRepeatingTimer(func, delay, ...)
- if not func or not delay then
- error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
- end
- if type(func) == "string" then
- if type(self) ~= "table" then
- error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2)
- elseif not self[func] then
- error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
- end
- end
- return new(self, true, func, delay, ...)
-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
--- 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
- else
- timer.cancelled = true
- activeTimers[id] = nil
- return true
- end
-end
-
---- Cancels all timers registered to the current addon object ('self')
-function AceTimer:CancelAllTimers()
- for k,v in next, activeTimers do
- if v.object == self then
- AceTimer.CancelTimer(self, k)
- 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()
- end
-end
-
-
--- ---------------------------------------------------------------------
--- Upgrading
-
--- Upgrade from old hash-bucket based timers to C_Timer.After timers.
-if oldminor and oldminor < 10 then
- -- disable old timer logic
- AceTimer.frame:SetScript("OnUpdate", nil)
- AceTimer.frame:SetScript("OnEvent", nil)
- AceTimer.frame:UnregisterAllEvents()
- -- convert timers
- for object,timers in next, AceTimer.selfs do
- for handle,timer in next, timers do
- if type(timer) == "table" and timer.callback then
- local newTimer
- if timer.delay then
- newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg)
- else
- newTimer = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg)
- end
- -- Use the old handle for old timers
- activeTimers[newTimer] = nil
- activeTimers[handle] = newTimer
- newTimer.handle = handle
- end
- end
- end
- AceTimer.selfs = nil
- AceTimer.hash = nil
- AceTimer.debug = nil
-elseif oldminor and oldminor < 17 then
- -- Upgrade from old animation based timers to C_Timer.After timers.
- AceTimer.inactiveTimers = nil
- AceTimer.frame = nil
- local oldTimers = AceTimer.activeTimers
- -- Clear old timer table and update upvalue
- AceTimer.activeTimers = {}
- activeTimers = AceTimer.activeTimers
- for handle, timer in next, oldTimers do
- local newTimer
- -- Stop the old timer animation
- local duration, elapsed = timer:GetDuration(), timer:GetElapsed()
- timer:GetParent():Stop()
- if timer.looping then
- newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.func, duration, unpack(timer.args, 1, timer.argsCount))
- else
- newTimer = AceTimer.ScheduleTimer(timer.object, timer.func, duration - elapsed, unpack(timer.args, 1, timer.argsCount))
- end
- -- Use the old handle for old timers
- activeTimers[newTimer] = nil
- activeTimers[handle] = newTimer
- newTimer.handle = handle
- end
-
- -- Migrate transitional handles
- if oldminor < 13 and AceTimer.hashCompatTable then
- for handle, id in next, AceTimer.hashCompatTable do
- local t = activeTimers[id]
- if t then
- activeTimers[id] = nil
- activeTimers[handle] = t
- t.handle = handle
- end
- end
- AceTimer.hashCompatTable = nil
- end
-end
-
--- ---------------------------------------------------------------------
--- Embed handling
-
-AceTimer.embeds = AceTimer.embeds or {}
-
-local mixins = {
- "ScheduleTimer", "ScheduleRepeatingTimer",
- "CancelTimer", "CancelAllTimers",
- "TimeLeft"
-}
-
-function AceTimer:Embed(target)
- AceTimer.embeds[target] = true
- for _,v in next, mixins do
- target[v] = AceTimer[v]
- end
- return target
-end
-
--- AceTimer:OnEmbedDisable(target)
--- target (object) - target object that AceTimer is embedded in.
---
--- cancel all timers registered for the object
-function AceTimer:OnEmbedDisable(target)
- target:CancelAllTimers()
-end
-
-for addon in next, AceTimer.embeds do
- AceTimer:Embed(addon)
-end
+--- **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
+-- 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.
+--
+-- 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.
+--
+-- **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
+-- and can be accessed directly, without having to explicitly call AceTimer itself.\\
+-- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceTimer.
+-- @class file
+-- @name AceTimer-3.0
+-- @release $Id: AceTimer-3.0.lua 1342 2024-05-26 11:49:35Z nevcairiel $
+
+local MAJOR, MINOR = "AceTimer-3.0", 17 -- Bump minor on changes
+local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceTimer then return end -- No upgrade needed
+AceTimer.activeTimers = AceTimer.activeTimers or {} -- Active timer list
+local activeTimers = AceTimer.activeTimers -- Upvalue our private data
+
+-- Lua APIs
+local type, unpack, next, error, select = type, unpack, next, error, select
+-- WoW APIs
+local GetTime, C_TimerAfter = GetTime, C_Timer.After
+
+local function new(self, loop, func, delay, ...)
+ if delay < 0.01 then
+ delay = 0.01 -- Restrict to the lowest time that the C_Timer API allows us
+ end
+
+ local timer = {
+ object = self,
+ func = func,
+ looping = loop,
+ argsCount = select("#", ...),
+ delay = delay,
+ ends = GetTime() + delay,
+ ...
+ }
+
+ activeTimers[timer] = timer
+
+ -- Create new timer closure to wrap the "timer" object
+ timer.callback = function()
+ if not timer.cancelled then
+ if type(timer.func) == "string" then
+ -- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
+ -- e.g. local t = {1, 2, nil, 3, nil} print(#t) will result in 2, instead of 5. This fixes said issue.
+ timer.object[timer.func](timer.object, unpack(timer, 1, timer.argsCount))
+ else
+ timer.func(unpack(timer, 1, timer.argsCount))
+ end
+
+ if timer.looping and not timer.cancelled then
+ -- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly
+ -- due to fps differences
+ local time = GetTime()
+ local ndelay = timer.delay - (time - timer.ends)
+ -- Ensure the delay doesn't go below the threshold
+ if ndelay < 0.01 then ndelay = 0.01 end
+ C_TimerAfter(ndelay, timer.callback)
+ timer.ends = time + ndelay
+ else
+ activeTimers[timer.handle or timer] = nil
+ end
+ end
+ end
+
+ C_TimerAfter(delay, timer.callback)
+ return timer
+end
+
+--- Schedule a new one-shot timer.
+-- The timer will fire once in `delay` seconds, unless canceled before.
+-- @param func Callback function for the timer pulse (funcref or method name).
+-- @param delay Delay for the timer, in seconds.
+-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
+-- @usage
+-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
+--
+-- function MyAddOn:OnEnable()
+-- self:ScheduleTimer("TimerFeedback", 5)
+-- end
+--
+-- function MyAddOn:TimerFeedback()
+-- print("5 seconds passed")
+-- end
+function AceTimer:ScheduleTimer(func, delay, ...)
+ if not func or not delay then
+ error(MAJOR..": ScheduleTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
+ end
+ if type(func) == "string" then
+ if type(self) ~= "table" then
+ error(MAJOR..": ScheduleTimer(callback, delay, args...): 'self' - must be a table.", 2)
+ elseif not self[func] then
+ error(MAJOR..": ScheduleTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
+ end
+ end
+ return new(self, nil, func, delay, ...)
+end
+
+--- Schedule a repeating timer.
+-- The timer will fire every `delay` seconds, until canceled.
+-- @param func Callback function for the timer pulse (funcref or method name).
+-- @param delay Delay for the timer, in seconds.
+-- @param ... An optional, unlimited amount of arguments to pass to the callback function.
+-- @usage
+-- MyAddOn = LibStub("AceAddon-3.0"):NewAddon("MyAddOn", "AceTimer-3.0")
+--
+-- function MyAddOn:OnEnable()
+-- self.timerCount = 0
+-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
+-- end
+--
+-- function MyAddOn:TimerFeedback()
+-- self.timerCount = self.timerCount + 1
+-- print(("%d seconds passed"):format(5 * self.timerCount))
+-- -- run 30 seconds in total
+-- if self.timerCount == 6 then
+-- self:CancelTimer(self.testTimer)
+-- end
+-- end
+function AceTimer:ScheduleRepeatingTimer(func, delay, ...)
+ if not func or not delay then
+ error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'callback' and 'delay' must have set values.", 2)
+ end
+ if type(func) == "string" then
+ if type(self) ~= "table" then
+ error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): 'self' - must be a table.", 2)
+ elseif not self[func] then
+ error(MAJOR..": ScheduleRepeatingTimer(callback, delay, args...): Tried to register '"..func.."' as the callback, but it doesn't exist in the module.", 2)
+ end
+ end
+ return new(self, true, func, delay, ...)
+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
+-- 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
+ else
+ timer.cancelled = true
+ activeTimers[id] = nil
+ return true
+ end
+end
+
+--- Cancels all timers registered to the current addon object ('self')
+function AceTimer:CancelAllTimers()
+ for k,v in next, activeTimers do
+ if v.object == self then
+ AceTimer.CancelTimer(self, k)
+ 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()
+ end
+end
+
+
+-- ---------------------------------------------------------------------
+-- Upgrading
+
+-- Upgrade from old hash-bucket based timers to C_Timer.After timers.
+if oldminor and oldminor < 10 then
+ -- disable old timer logic
+ AceTimer.frame:SetScript("OnUpdate", nil)
+ AceTimer.frame:SetScript("OnEvent", nil)
+ AceTimer.frame:UnregisterAllEvents()
+ -- convert timers
+ for object,timers in next, AceTimer.selfs do
+ for handle,timer in next, timers do
+ if type(timer) == "table" and timer.callback then
+ local newTimer
+ if timer.delay then
+ newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.callback, timer.delay, timer.arg)
+ else
+ newTimer = AceTimer.ScheduleTimer(timer.object, timer.callback, timer.when - GetTime(), timer.arg)
+ end
+ -- Use the old handle for old timers
+ activeTimers[newTimer] = nil
+ activeTimers[handle] = newTimer
+ newTimer.handle = handle
+ end
+ end
+ end
+ AceTimer.selfs = nil
+ AceTimer.hash = nil
+ AceTimer.debug = nil
+elseif oldminor and oldminor < 17 then
+ -- Upgrade from old animation based timers to C_Timer.After timers.
+ AceTimer.inactiveTimers = nil
+ AceTimer.frame = nil
+ local oldTimers = AceTimer.activeTimers
+ -- Clear old timer table and update upvalue
+ AceTimer.activeTimers = {}
+ activeTimers = AceTimer.activeTimers
+ for handle, timer in next, oldTimers do
+ local newTimer
+ -- Stop the old timer animation
+ local duration, elapsed = timer:GetDuration(), timer:GetElapsed()
+ timer:GetParent():Stop()
+ if timer.looping then
+ newTimer = AceTimer.ScheduleRepeatingTimer(timer.object, timer.func, duration, unpack(timer.args, 1, timer.argsCount))
+ else
+ newTimer = AceTimer.ScheduleTimer(timer.object, timer.func, duration - elapsed, unpack(timer.args, 1, timer.argsCount))
+ end
+ -- Use the old handle for old timers
+ activeTimers[newTimer] = nil
+ activeTimers[handle] = newTimer
+ newTimer.handle = handle
+ end
+
+ -- Migrate transitional handles
+ if oldminor < 13 and AceTimer.hashCompatTable then
+ for handle, id in next, AceTimer.hashCompatTable do
+ local t = activeTimers[id]
+ if t then
+ activeTimers[id] = nil
+ activeTimers[handle] = t
+ t.handle = handle
+ end
+ end
+ AceTimer.hashCompatTable = nil
+ end
+end
+
+-- ---------------------------------------------------------------------
+-- Embed handling
+
+AceTimer.embeds = AceTimer.embeds or {}
+
+local mixins = {
+ "ScheduleTimer", "ScheduleRepeatingTimer",
+ "CancelTimer", "CancelAllTimers",
+ "TimeLeft"
+}
+
+function AceTimer:Embed(target)
+ AceTimer.embeds[target] = true
+ for _,v in next, mixins do
+ target[v] = AceTimer[v]
+ end
+ return target
+end
+
+-- AceTimer:OnEmbedDisable(target)
+-- target (object) - target object that AceTimer is embedded in.
+--
+-- cancel all timers registered for the object
+function AceTimer:OnEmbedDisable(target)
+ target:CancelAllTimers()
+end
+
+for addon in next, AceTimer.embeds do
+ AceTimer:Embed(addon)
+end
diff --git a/Libs/AceTimer-3.0/AceTimer-3.0.xml b/Libs/AceTimer-3.0/AceTimer-3.0.xml
index 1987d78..d5aee81 100755
--- a/Libs/AceTimer-3.0/AceTimer-3.0.xml
+++ b/Libs/AceTimer-3.0/AceTimer-3.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
index bd04241..6b32193 100755
--- a/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
+++ b/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
@@ -1,207 +1,202 @@
---[[ $Id: CallbackHandler-1.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $ ]]
-local MAJOR, MINOR = "CallbackHandler-1.0", 7
-local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not CallbackHandler then return end -- No upgrade needed
-
-local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-
--- Lua APIs
-local error = error
-local setmetatable, rawget = setmetatable, rawget
-local next, select, pairs, type, tostring = next, select, pairs, type, tostring
-
-local xpcall = xpcall
-
-local function errorhandler(err)
- return geterrorhandler()(err)
-end
-
-local function Dispatch(handlers, ...)
- local index, method = next(handlers)
- if not method then return end
- repeat
- xpcall(method, errorhandler, ...)
- index, method = next(handlers, index)
- until not method
-end
-
---------------------------------------------------------------------------
--- CallbackHandler:New
---
--- target - target object to embed public APIs in
--- RegisterName - name of the callback registration API, default "RegisterCallback"
--- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
--- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
-
-function CallbackHandler.New(_self, target, RegisterName, UnregisterName, UnregisterAllName)
-
- RegisterName = RegisterName or "RegisterCallback"
- UnregisterName = UnregisterName or "UnregisterCallback"
- if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
- UnregisterAllName = "UnregisterAllCallbacks"
- end
-
- -- we declare all objects and exported APIs inside this closure to quickly gain access
- -- to e.g. function names, the "target" parameter, etc
-
-
- -- Create the registry object
- local events = setmetatable({}, meta)
- local registry = { recurse=0, events=events }
-
- -- registry:Fire() - fires the given event/message into the registry
- function registry:Fire(eventname, ...)
- if not rawget(events, eventname) or not next(events[eventname]) then return end
- local oldrecurse = registry.recurse
- registry.recurse = oldrecurse + 1
-
- Dispatch(events[eventname], eventname, ...)
-
- registry.recurse = oldrecurse
-
- if registry.insertQueue and oldrecurse==0 then
- -- Something in one of our callbacks wanted to register more callbacks; they got queued
- for event,callbacks in pairs(registry.insertQueue) do
- local first = not rawget(events, event) or not next(events[event]) -- test for empty before. not test for one member after. that one member may have been overwritten.
- for object,func in pairs(callbacks) do
- events[event][object] = func
- -- fire OnUsed callback?
- if first and registry.OnUsed then
- registry.OnUsed(registry, target, event)
- first = nil
- end
- end
- end
- registry.insertQueue = nil
- end
- end
-
- -- Registration of a callback, handles:
- -- self["method"], leads to self["method"](self, ...)
- -- self with function ref, leads to functionref(...)
- -- "addonId" (instead of self) with function ref, leads to functionref(...)
- -- all with an optional arg, which, if present, gets passed as first argument (after self if present)
- target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
- if type(eventname) ~= "string" then
- error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
- end
-
- method = method or eventname
-
- local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
-
- if type(method) ~= "string" and type(method) ~= "function" then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
- end
-
- local regfunc
-
- if type(method) == "string" then
- -- self["method"] calling style
- if type(self) ~= "table" then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
- elseif self==target then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
- elseif type(self[method]) ~= "function" then
- error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
- end
-
- if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
- local arg=select(1,...)
- regfunc = function(...) self[method](self,arg,...) end
- else
- regfunc = function(...) self[method](self,...) end
- end
- else
- -- function ref with self=object or self="addonId" or self=thread
- if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
- error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
- end
-
- if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
- local arg=select(1,...)
- regfunc = function(...) method(arg,...) end
- else
- regfunc = method
- end
- end
-
-
- if events[eventname][self] or registry.recurse<1 then
- -- if registry.recurse<1 then
- -- we're overwriting an existing entry, or not currently recursing. just set it.
- events[eventname][self] = regfunc
- -- fire OnUsed callback?
- if registry.OnUsed and first then
- registry.OnUsed(registry, target, eventname)
- end
- else
- -- we're currently processing a callback in this registry, so delay the registration of this new entry!
- -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
- registry.insertQueue = registry.insertQueue or setmetatable({},meta)
- registry.insertQueue[eventname][self] = regfunc
- end
- end
-
- -- Unregister a callback
- target[UnregisterName] = function(self, eventname)
- if not self or self==target then
- error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
- end
- if type(eventname) ~= "string" then
- error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
- end
- if rawget(events, eventname) and events[eventname][self] then
- events[eventname][self] = nil
- -- Fire OnUnused callback?
- if registry.OnUnused and not next(events[eventname]) then
- registry.OnUnused(registry, target, eventname)
- end
- end
- if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
- registry.insertQueue[eventname][self] = nil
- end
- end
-
- -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
- if UnregisterAllName then
- target[UnregisterAllName] = function(...)
- if select("#",...)<1 then
- error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
- end
- if select("#",...)==1 and ...==target then
- error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
- end
-
-
- for i=1,select("#",...) do
- local self = select(i,...)
- if registry.insertQueue then
- for eventname, callbacks in pairs(registry.insertQueue) do
- if callbacks[self] then
- callbacks[self] = nil
- end
- end
- end
- for eventname, callbacks in pairs(events) do
- if callbacks[self] then
- callbacks[self] = nil
- -- Fire OnUnused callback?
- if registry.OnUnused and not next(callbacks) then
- registry.OnUnused(registry, target, eventname)
- end
- end
- end
- end
- end
- end
-
- return registry
-end
-
-
--- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
--- try to upgrade old implicit embeds since the system is selfcontained and
--- relies on closures to work.
-
+--[[ $Id: CallbackHandler-1.0.lua 1298 2022-12-12 15:10:10Z nevcairiel $ ]]
+local MAJOR, MINOR = "CallbackHandler-1.0", 8
+local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not CallbackHandler then return end -- No upgrade needed
+
+local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
+
+-- Lua APIs
+local securecallfunction, error = securecallfunction, error
+local setmetatable, rawget = setmetatable, rawget
+local next, select, pairs, type, tostring = next, select, pairs, type, tostring
+
+
+local function Dispatch(handlers, ...)
+ local index, method = next(handlers)
+ if not method then return end
+ repeat
+ securecallfunction(method, ...)
+ index, method = next(handlers, index)
+ until not method
+end
+
+--------------------------------------------------------------------------
+-- CallbackHandler:New
+--
+-- target - target object to embed public APIs in
+-- RegisterName - name of the callback registration API, default "RegisterCallback"
+-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
+-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
+
+function CallbackHandler.New(_self, target, RegisterName, UnregisterName, UnregisterAllName)
+
+ RegisterName = RegisterName or "RegisterCallback"
+ UnregisterName = UnregisterName or "UnregisterCallback"
+ if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
+ UnregisterAllName = "UnregisterAllCallbacks"
+ end
+
+ -- we declare all objects and exported APIs inside this closure to quickly gain access
+ -- to e.g. function names, the "target" parameter, etc
+
+
+ -- Create the registry object
+ local events = setmetatable({}, meta)
+ local registry = { recurse=0, events=events }
+
+ -- registry:Fire() - fires the given event/message into the registry
+ function registry:Fire(eventname, ...)
+ if not rawget(events, eventname) or not next(events[eventname]) then return end
+ local oldrecurse = registry.recurse
+ registry.recurse = oldrecurse + 1
+
+ Dispatch(events[eventname], eventname, ...)
+
+ registry.recurse = oldrecurse
+
+ if registry.insertQueue and oldrecurse==0 then
+ -- Something in one of our callbacks wanted to register more callbacks; they got queued
+ for event,callbacks in pairs(registry.insertQueue) do
+ local first = not rawget(events, event) or not next(events[event]) -- test for empty before. not test for one member after. that one member may have been overwritten.
+ for object,func in pairs(callbacks) do
+ events[event][object] = func
+ -- fire OnUsed callback?
+ if first and registry.OnUsed then
+ registry.OnUsed(registry, target, event)
+ first = nil
+ end
+ end
+ end
+ registry.insertQueue = nil
+ end
+ end
+
+ -- Registration of a callback, handles:
+ -- self["method"], leads to self["method"](self, ...)
+ -- self with function ref, leads to functionref(...)
+ -- "addonId" (instead of self) with function ref, leads to functionref(...)
+ -- all with an optional arg, which, if present, gets passed as first argument (after self if present)
+ target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
+ if type(eventname) ~= "string" then
+ error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
+ end
+
+ method = method or eventname
+
+ local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
+
+ if type(method) ~= "string" and type(method) ~= "function" then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
+ end
+
+ local regfunc
+
+ if type(method) == "string" then
+ -- self["method"] calling style
+ if type(self) ~= "table" then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
+ elseif self==target then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
+ elseif type(self[method]) ~= "function" then
+ error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
+ end
+
+ if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
+ local arg=select(1,...)
+ regfunc = function(...) self[method](self,arg,...) end
+ else
+ regfunc = function(...) self[method](self,...) end
+ end
+ else
+ -- function ref with self=object or self="addonId" or self=thread
+ if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
+ error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
+ end
+
+ if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
+ local arg=select(1,...)
+ regfunc = function(...) method(arg,...) end
+ else
+ regfunc = method
+ end
+ end
+
+
+ if events[eventname][self] or registry.recurse<1 then
+ -- if registry.recurse<1 then
+ -- we're overwriting an existing entry, or not currently recursing. just set it.
+ events[eventname][self] = regfunc
+ -- fire OnUsed callback?
+ if registry.OnUsed and first then
+ registry.OnUsed(registry, target, eventname)
+ end
+ else
+ -- we're currently processing a callback in this registry, so delay the registration of this new entry!
+ -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
+ registry.insertQueue = registry.insertQueue or setmetatable({},meta)
+ registry.insertQueue[eventname][self] = regfunc
+ end
+ end
+
+ -- Unregister a callback
+ target[UnregisterName] = function(self, eventname)
+ if not self or self==target then
+ error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
+ end
+ if type(eventname) ~= "string" then
+ error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
+ end
+ if rawget(events, eventname) and events[eventname][self] then
+ events[eventname][self] = nil
+ -- Fire OnUnused callback?
+ if registry.OnUnused and not next(events[eventname]) then
+ registry.OnUnused(registry, target, eventname)
+ end
+ end
+ if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
+ registry.insertQueue[eventname][self] = nil
+ end
+ end
+
+ -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
+ if UnregisterAllName then
+ target[UnregisterAllName] = function(...)
+ if select("#",...)<1 then
+ error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
+ end
+ if select("#",...)==1 and ...==target then
+ error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
+ end
+
+
+ for i=1,select("#",...) do
+ local self = select(i,...)
+ if registry.insertQueue then
+ for eventname, callbacks in pairs(registry.insertQueue) do
+ if callbacks[self] then
+ callbacks[self] = nil
+ end
+ end
+ end
+ for eventname, callbacks in pairs(events) do
+ if callbacks[self] then
+ callbacks[self] = nil
+ -- Fire OnUnused callback?
+ if registry.OnUnused and not next(callbacks) then
+ registry.OnUnused(registry, target, eventname)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ return registry
+end
+
+
+-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
+-- try to upgrade old implicit embeds since the system is selfcontained and
+-- relies on closures to work.
+
diff --git a/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
index a5b22a7..c107f88 100755
--- a/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
+++ b/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
@@ -1,4 +1,4 @@
-
-
-
+
+
+
diff --git a/Libs/LibStub/LibStub.lua b/Libs/LibStub/LibStub.lua
index 7a442e2..d50c267 100755
--- a/Libs/LibStub/LibStub.lua
+++ b/Libs/LibStub/LibStub.lua
@@ -1,30 +1,30 @@
--- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
--- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
-local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
-local LibStub = _G[LIBSTUB_MAJOR]
-
-if not LibStub or LibStub.minor < LIBSTUB_MINOR then
- LibStub = LibStub or {libs = {}, minors = {} }
- _G[LIBSTUB_MAJOR] = LibStub
- LibStub.minor = LIBSTUB_MINOR
-
- function LibStub:NewLibrary(major, minor)
- assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
- minor = assert(tonumber(string.match(minor, "%d+")), "Minor version must either be a number or contain a number.")
-
- local oldminor = self.minors[major]
- if oldminor and oldminor >= minor then return nil end
- self.minors[major], self.libs[major] = minor, self.libs[major] or {}
- return self.libs[major], oldminor
- end
-
- function LibStub:GetLibrary(major, silent)
- if not self.libs[major] and not silent then
- error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
- end
- return self.libs[major], self.minors[major]
- end
-
- function LibStub:IterateLibraries() return pairs(self.libs) end
- setmetatable(LibStub, { __call = LibStub.GetLibrary })
-end
+-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
+-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+ LibStub = LibStub or {libs = {}, minors = {} }
+ _G[LIBSTUB_MAJOR] = LibStub
+ LibStub.minor = LIBSTUB_MINOR
+
+ function LibStub:NewLibrary(major, minor)
+ assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+ minor = assert(tonumber(string.match(minor, "%d+")), "Minor version must either be a number or contain a number.")
+
+ local oldminor = self.minors[major]
+ if oldminor and oldminor >= minor then return nil end
+ self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+ return self.libs[major], oldminor
+ end
+
+ function LibStub:GetLibrary(major, silent)
+ if not self.libs[major] and not silent then
+ error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+ end
+ return self.libs[major], self.minors[major]
+ end
+
+ function LibStub:IterateLibraries() return pairs(self.libs) end
+ setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end