Mercurial > wow > reaction
changeset 28:21bcaf8215ff
- converted to Ace3
- rearranged file layout
- configGUI menus not working right now
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bar.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,146 @@ +local ReAction = ReAction +local L = ReAction.L +local _G = _G +local CreateFrame = CreateFrame + +-- update ReAction revision if this file is newer +local revision = tonumber(("$Revision: 1 $"):match("%d+")) +if revision > ReAction.revision then + Reaction.revision = revision +end + +------ BAR CLASS ------ +local Bar = { _classID = {} } + +local function Constructor( self, name, config ) + self.name, self.config = name, config + + if type(config) ~= "table" then + error("ReAction.Bar: config table required") + end + + local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate") + f:SetFrameStrata("MEDIUM") + config.width = config.width or 400 + config.height = config.height or 80 + f:SetWidth(config.width) + f:SetWidth(config.height) + + self.frame = f + self:RefreshLayout() + self:ApplyAnchor() + f:Show() +end + +function Bar:Destroy() + local f = self.frame + f:UnregisterAllEvents() + f:Hide() + f:SetParent(UIParent) + f:ClearAllPoints() + self.labelString = nil + self.controlFrame = nil + self.frame = nil + self.config = nil +end + +function Bar:RefreshLayout() + ReAction:CallMethodOnAllModules("RefreshBar", self) +end + +function Bar:ApplyAnchor() + local f, config = self.frame, self.config + f:SetWidth(config.width) + f:SetHeight(config.height) + local anchor = config.anchor + if anchor then + local anchorTo + if config.anchorTo then + anchorTo = ReAction:GetBar(config.anchorTo) or _G[config.anchorTo] + end + f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0) + else + f:SetPoint("CENTER") + end +end + +function Bar:GetFrame() + return self.frame +end + +function Bar:GetSize() + return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200 +end + +function Bar:SetSize(w,h) + self.config.width = w + self.config.height = h +end + +function Bar:GetButtonSize() + local w = self.config.btnWidth or 32 + local h = self.config.btnHeight or 32 + -- TODO: get from modules? + return w,h +end + +function Bar:SetButtonSize(w,h) + if w > 0 and h > 0 then + self.config.btnWidth = w + self.config.btnHeight = h + end +end + +function Bar:GetButtonGrid() + local cfg = self.config + local r = cfg.btnRows or 1 + local c = cfg.btnColumns or 1 + local s = cfg.spacing or 4 + return r,c,s +end + +function Bar:SetButtonGrid(r,c,s) + if r > 0 and c > 0 and s > 0 then + local cfg = self.config + cfg.btnRows = r + cfg.btnColumns = c + cfg.spacing = s + end +end + +function Bar:GetName() + return self.name +end + +function Bar:PlaceButton(f, idx, baseW, baseH) + local r, c, s = self:GetButtonGrid() + local bh, bw = self:GetButtonSize() + local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based + local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s + local scale = bw/baseW + + f:ClearAllPoints() + f:SetPoint("TOPLEFT",x/scale,-y/scale) + f:SetScale(scale) +-- f:Show() +end + + + +------ Export as a class-factory ------ +ReAction.Bar = { + prototype = Bar, + + IsInstance = function(self, x) + return type(x) == "table" and x._classID == Bar._classID + end, + + new = function(self, ...) + local x = { } + for k,v in pairs(Bar) do + x[k] = v + end + Constructor(x, ...) + return x + end +}
--- a/ReAction.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/ReAction.lua Mon Mar 17 18:24:53 2008 +0000 @@ -1,95 +1,19 @@ ---[[ - ReAction Add-On main file. - Performs add-on and library initialization and setup. ---]] +-- ReAction.lua +-- See modules/ReAction_ModuleTemplate for Module API listing +-- See Bar.lua for Bar object listing ------- LOCALIZATION ---------- -local L = AceLibrary("AceLocale-2.2"):new("ReAction") - - ------- GLOBAL VARIABLES ------ --- 'ReAction' is exported as a global. -ReAction = AceLibrary("AceAddon-2.0"):new( - "AceModuleCore-2.0", - "AceEvent-2.0", - "AceDB-2.0" -) --- global variable strings for integration with WoW keybindings dialog (see bindings.xml) -BINDING_HEADER_REACTION = L["ReAction"] -BINDING_NAME_REACTION_TOGGLELOCK = L["Toggle ReAction Bar Lock"] -BINDING_NAME_REACTION_TOGGLEKEYBIND = L["ReAction Keybinding Mode"] - +------ LIBRARIES ------ +local L = LibStub("AceLocale-3.0"):GetLocale("ReAction") ------ CORE ------ -local ReAction = ReAction +local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction" ) ReAction.revision = tonumber(("$Revision: 1 $"):match("%d+")) ReAction.L = L +------ GLOBALS ------ +_G["ReAction"] = ReAction - --- from AceAddon-2.0 -function ReAction:OnInitialize() - self:RegisterDB("ReActionDB") -end - --- from AceAddon-2.0 -function ReAction:OnEnable() - -end - --- from AceAddon-2.0 -function ReAction:OnDisable() - -end - --- from AceDB-2.0 -function ReAction:OnProfileEnable() - -end - --- from AceDB-2.0 -function ReAction:OnProfileDisable() - -end - --- from AceModuleCore-2.0 -function ReAction:OnModuleEnable(module) - -- this handles initialization ordering issues with ReAction_Bar - local barMod = self:GetModule("Bar") - if barMod and module.ApplyToBar then - for _, b in pairs(barMod.bars) do - if b then - module:ApplyToBar(b) - end - end - end -end - --- from AceModuleCore-2.0 -function ReAction:OnModuleDisable(module) - local barMod = self:GetModule("Bar") - if barMod and module.RemoveFromBar then - for _, b in pairs(barMod.bars) do - if b then - module:RemoveFromBar(b) - end - end - end -end - ---[[ - Module API (see bar.lua for usage) - - module:ApplyToBar(bar) - module:RemoveFromBar(bar) - module:RefreshBar(bar) - module:ApplyConfigMode(mode,listOfBars) - module:GetBarNameModifier(bar) - module:EraseBarConfig(barName) -]]-- - - --- debugging +------ DEBUGGING ------ ReAction.debug = true if ReAction.debug then ReAction.print = function(msg) @@ -100,3 +24,204 @@ ReAction.print = function() end end +------ PRIVATE ------ +local SelectBar, DestroyBar, InitializeBars, TearDownBars, DeepCopy, SafeCall, CheckMethod +do + local pcall = pcall + local geterrorhandler = geterrorhandler + + SelectBar = function(x) + local bar, name + if type(x) == "string" then + name = x + bar = ReAction:GetBar(name) + elseif ReAction.Bar:IsInstance(x) then + bar = x + for k,v in pairs(ReAction.bars) do + if v == bar then + name = k + end + end + else + error("bad argument to SelectBar") + end + return bar, name + end + + DestroyBar = function(x) + local bar, name = SelectBar(x) + if name and bar then + ReAction.bars[name] = nil + ReAction:CallMethodOnAllModules("RemoveFromBar", bar) + bar:Destroy() + end + end + + InitializeBars = function () + if not(ReAction.inited) then + for name, config in pairs(ReAction.db.profile.bars) do + if config then + ReAction:CreateBar(name, config) + end + end + ReAction:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering + ReAction.inited = true + end + end + + TearDownBars = function() + for name, bar in pairs(ReAction.bars) do + if bar then + ReAction.bars[name] = DestroyBar(bar) + end + end + ReAction.inited = false + end + + DeepCopy = function(x) + if type(x) ~= "table" then + return x + end + local r = {} + for k,v in pairs(x) do + r[k] = DeepCopy(v) + end + return r + end + + SafeCall = function(f, ...) + if f then + local success, err = pcall(f,...) + if not success then + geterrorhandler()(err) + end + end + end + + CheckMethod = function(m) + if type(m) == "function" then + return m + end + if type(m) ~= "string" then + error("Invalid method") + end + end +end + + +------ HANDLERS ------ +function ReAction:OnInitialize() + self.db = LibStub("AceDB-3.0"):New("ReAction_DB", + { + profile = { + bars = { }, + defaultBar = { } + } + } + -- default profile is character-specific + ) + self.db.RegisterCallback(self,"OnProfileChanged") + + self.bars = {} +end + +function ReAction:OnEnable() + InitializeBars() +end + +function ReAction:OnDisable() + TearDownBars() +end + +function ReAction:OnProfileChanged() + self.TearDownBars() + self.InitializeBars() +end + +function ReAction:OnModuleEnable(module) + if module.ApplyToBar then + for _, b in pairs(bars) do + if b then + module:ApplyToBar(b) + end + end + end +end + +function ReAction:OnModuleDisable(module) + if module.RemoveFromBar then + for _, b in pairs(bars) do + if b then + module:RemoveFromBar(b) + end + end + end +end + + +------ API ------ +function ReAction:CallMethodOnAllModules(method, ...) + local m = CheckMethod(method) + for _, x in self:IterateModules() do + if x then + SafeCall(m or x[method], x, ...) + end + end +end + +function ReAction:CallMethodOnAllBars(method,...) + local m = CheckMethod(method) + for _, x in pairs(self.bars) do + if x then + SafeCall(m or x[method], x, ...) + end + end +end + +function ReAction:CreateBar(name, defaultConfig, prefix) + local profile = self.db.profile + defaultConfig = defaultConfig or profile.defaultBar + prefix = prefix or L["Bar "] + if not name then + i = 1 + repeat + name = prefix..i + i = i + 1 + until self.bars[name] == nil + end + profile.bars[name] = profile.bars[name] or DeepCopy(defaultConfig) + local bar = self.Bar:new( name, profile.bars[name] ) -- ReAction.Bar defined in Bar.lua + self:CallMethodOnAllModules("ApplyToBar", bar) + self.bars[name] = bar + return bar +end + +function ReAction:EraseBar(x) + local bar, name = SelectBar(x) + if name and bar then + DestroyBar(bar) + self.db.profile.bars[name] = nil + self:CallMethodOnAllModules("EraseBarConfig", name) + end +end + +function ReAction:GetBar(name) + return self.bars[name] +end + +function ReAction:RenameBar(x, newname) + local bar, name = SelectBar(x) + if bar and name and newname then + if self.bars[newname] then + error(L["ReAction: name already in use"]) + end + self.bars[newname] = self.bars[name] + self.bars[name] = nil + bar.name = newname or "" + local cfg = self.db.profile.bars + cfg[newname], cfg[name] = cfg[name], nil + self:CallMethodOnAllModules("RenameBarConfig", name, newname) + end +end + +
--- a/ReAction.toc Tue Mar 11 21:39:34 2008 +0000 +++ b/ReAction.toc Mon Mar 17 18:24:53 2008 +0000 @@ -5,8 +5,7 @@ ## LoadOnDemand: 0 ## Author: Flick ## Version: 1.0 -## SavedVariables: ReActionDB +## SavedVariables: ReAction_DB ## X-Category: Action Bars -## X-Embeds: AceAddon-2.0, AceConsole-2.0, AceDB-2.0, AceEvent-2.0, AceHook-2.1, AceLibrary, AceLocale-2.2, AceModuleCore-2.0, AceOO-2.0, Dewdrop-2.0, Waterfall-1.0 ReAction.xml
--- a/ReAction.xml Tue Mar 11 21:39:34 2008 +0000 +++ b/ReAction.xml Mon Mar 17 18:24:53 2008 +0000 @@ -6,8 +6,9 @@ <Include file="locale\locale.xml"/> <Script file="ReAction.lua"/> -<Script file="ReAction_Bar.lua"/> +<Script file="Bar.lua"/> <Include file="modules\modules.xml"/> +<Include file="bindings.lua"/> </Ui>
--- a/ReAction_Bar.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ ---[[ - ReAction bar module. - - This is the heart of ReAction, the bar management module. Many of its - functions turn around and iterate all modules registered to the ReAction - parent core. - - Also defined in this file is the Bar class implementation, which can be - used by other modules to manipulate the action bars. Many of the module - iterated calls pass a bar or list of bars as an argument. - - Module methods called by the Bar module: - module:ApplyToBar(bar) - module:RemoveFromBar(bar) - module:RefreshBar(bar) - module:ApplyConfigMode(mode,listOfBars) - module:GetBarNameModifier(bar) - module:EraseBarConfig(barName) - - - useful Bar object API (partial list): - f = bar:GetFrame() -- f is derived from SecureStateDriver - bar:RefreshLayout() - w,h = bar:GetSize() - r,c,s = bar:GetButtonGrid() -- #rows, #columns, inter-button spacing - name = bar:GetName() - bar:PlaceButton(frame, idx, baseSizeX, baseSizeY) -- idx is 1-based - ---]] - --- local imports -local ReAction = ReAction -local L = ReAction.L -local _G = _G -local AceOO = AceLibrary("AceOO-2.0") -local CreateFrame = CreateFrame -local geterrorhandler = geterrorhandler -local pcall = pcall -local print = ReAction.print - --- update ReAction revision if this file is newer -local revision = tonumber(("$Revision: 1 $"):match("%d+")) -if revision > ReAction.revision then - Reaction.revision = revision -end - -local moduleID = "Bar" - --- --- Bar module declaration --- -local module = ReAction:NewModule( moduleID ) - --- --- Bar class declaration --- -local BarClass = AceOO.Class() -local Bar = BarClass.prototype -module.BarClass = BarClass - --- --- local utility --- -local function deepCopy(x) - if type(x) ~= "table" then - return x - end - local r = {} - for k,v in pairs(x) do - r[k] = deepCopy(v) - end - return r -end - --- --- Bar module implementation --- -function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", - { - bars = { }, - defaultBar = { } - } - ) - self.bars = {} -end - -function module:OnEnable() - self:InitializeBars() -end - -function module:OnDisable() - self:TearDownBars() -end - -function module:OnProfileEnable() - self:InitializeBars() -end - -function module:OnProfileDisable() - self:TearDownBars() -end - -function module:InitializeBars() - if not(self.inited) then - for name, config in pairs(self.db.profile.bars) do - if config then - self:CreateBar(name, config) - end - end - self:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering - self.inited = true - end -end - -function module:TearDownBars() - for name, bar in pairs(self.bars) do - if bar then - self.bars[name] = self:DeleteBar(bar) - end - end - self.inited = false -end - --- Gets config from existing DB name or default if not supplied --- Saves to DB if name not known -function module:CreateBar(name, config) - local profile = self.db.profile - if not name then - i = 1 - repeat - name = L["Bar "]..i - i = i + 1 - until self.bars[name] == nil - end - config = config or profile.bars[name] or deepCopy(profile.defaultBar) - if not profile.bars[name] then - profile.bars[name] = config - end - local bar = self.BarClass:new( name, config ) - ReAction:CallMethodOnAllModules("ApplyToBar", bar) - self.bars[name] = bar - return bar -end - - -local SelectBar -do - SelectBar = function(x) - local bar, name - if type(x) == "string" then - name = x - bar = module:GetBar(name) - elseif AceOO.inherits(x,BarClass) then - bar = x - for k,v in pairs(module.bars) do - if v == bar then - name = k - end - end - else - error("bad argument to SelectBar") - end - return bar, name - end -end - --- Takes either a bar name string or a bar object. --- Does NOT destroy the DB entry, this function is only used for --- enable/disable and profile switching. To remove a bar permanently, --- use EraseBar() instead. -function module:DeleteBar(x) - local bar, name = SelectBar(x) - if name and bar then - self.bars[name] = nil - ReAction:CallMethodOnAllModules("RemoveFromBar", bar) - bar:Destroy() - end -end - -function module:EraseBar(x) - local bar, name = SelectBar(x) - if name and bar then - self:DeleteBar(bar) - self.db.profile.bars[name] = nil - ReAction:CallMethodOnAllModules("EraseBarConfig", name) - end -end - -function module:GetBar(name) - return self.bars[name] -end - -function module:RenameBar(x, newname) - local bar, name = SelectBar(x) - if bar and name and newname then - if self.bars[newname] then - error(L["ReAction: name already in use"]) - end - self.bars[newname] = self.bars[name] - self.bars[name] = nil - bar:SetName(newname) - local cfg = self.db.profile.bars - cfg[newname], cfg[name] = cfg[name], nil - end -end - -function module:CallMethodOnAllBars(method,...) - local m - if type(method) == "function" then - m = method - elseif type(method) ~= "string" then - error("Invalid method passed to ReAction_Bar:CallMethodOnAllBars()") - end - for _, bar in pairs(self.bars) do - if bar then - local m = m or bar[method] - if m then - local success,err = pcall(m,bar,...) - if not success then - geterrorhandler()(err) - end - end - end - end -end - - - -function module:GetBarMenuOptions(bar) - if not(bar.modMenuOpts[moduleID]) then - bar.modMenuOpts[moduleID] = { - delete = { - type = "execute", - name = L["Delete Bar"], - desc = L["Remove the bar from the current profile"], - func = function() self:EraseBar(bar) end, - order = 1 - }, - } - end - return bar.modMenuOpts[moduleID] -end - -function module:GetBarConfigOptions(bar, cfgModule) - if not(bar.modConfigOpts[moduleID]) then - bar.modConfigOpts[moduleID] = { - delete = { - type = "execute", - name = L["Delete Bar"], - desc = L["Remove the bar from the current profile"], - func = function() self:EraseBar(bar); cfgModule:RefreshConfig() end - }, - rename = { - type = "text", - name = L["Rename Bar"], - desc = L["Set a name for the bar"], - get = "GetName", - set = function(name) self:RenameBar(bar,name); cfgModule:RefreshConfig() end - } - } - end - return bar.modConfigOpts[moduleID] -end - - - --- --- Bar class implementation --- -function Bar:init( name, config ) - BarClass.super.prototype.init(self) - self.name, self.config = name, config - - if type(config) ~= "table" then - error("ReAction:Bar: config table required") - end - - local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate") - f:SetFrameStrata("MEDIUM") - config.width = config.width or 400 - config.height = config.height or 80 - f:SetWidth(config.width) - f:SetWidth(config.height) - - self.frame = f - self:RefreshLayout() - self:ApplyAnchor() - f:Show() -end - -function Bar:Destroy() - local f = self.frame - f:UnregisterAllEvents() - f:Hide() - f:SetParent(UIParent) - f:ClearAllPoints() - self.labelString = nil - self.controlFrame = nil - self.frame = nil - self.config = nil -end - -function Bar:RefreshLayout() - ReAction:CallMethodOnAllModules("RefreshBar", self) -end - -function Bar:ApplyAnchor() - local f, config = self.frame, self.config - f:SetWidth(config.width) - f:SetHeight(config.height) - local anchor = config.anchor - if anchor then - local anchorTo - if config.anchorTo then - anchorTo = module:GetBar(config.anchorTo) or _G[config.anchorTo] - end - f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0) - else - f:SetPoint("CENTER") - end -end - -function Bar:GetFrame() - return self.frame -end - -function Bar:GetSize() - return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200 -end - -function Bar:SetSize(w,h) - self.config.width = w - self.config.height = h -end - -function Bar:GetButtonSize() - local w = self.config.btnWidth or 32 - local h = self.config.btnHeight or 32 - -- TODO: get from modules? - return w,h -end - -function Bar:SetButtonSize(w,h) - if w > 0 and h > 0 then - self.config.btnWidth = w - self.config.btnHeight = h - end -end - -function Bar:GetButtonGrid() - local cfg = self.config - local r = cfg.btnRows or 1 - local c = cfg.btnColumns or 1 - local s = cfg.spacing or 4 - return r,c,s -end - -function Bar:SetButtonGrid(r,c,s) - if r > 0 and c > 0 and s > 0 then - local cfg = self.config - cfg.btnRows = r - cfg.btnColumns = c - cfg.spacing = s - end -end - --- This should only be called from module:RenameBar(), otherwise --- the bar's internal name and the module's list of bars by name --- can get out of sync. -function Bar:SetName( name ) - name = name or "" - self.name = name -end - -function Bar:GetName() - return self.name -end - -function Bar:PlaceButton(f, idx, baseW, baseH) - local r, c, s = self:GetButtonGrid() - local bh, bw = self:GetButtonSize() - local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based - local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s - local scale = bw/baseW - - f:ClearAllPoints() - f:SetPoint("TOPLEFT",x/scale,-y/scale) - f:SetScale(scale) --- f:Show() -end -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bindings.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,7 @@ +local L = LibStub("AceLocale-3.0"):GetLocale("ReAction") +local _G = _G + +_G["BINDING_HEADER_REACTION"] = L["ReAction"] + +_G["BINDING_NAME_REACTION_TOGGLELOCK"] = L["Toggle ReAction Bar Lock"] +_G["BINDING_NAME_REACTION_TOGGLEKEYBIND"] = L["ReAction Keybinding Mode"]
--- a/lib/AceAddon-2.0/AceAddon-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1394 +0,0 @@ ---[[ -Name: AceAddon-2.0 -Revision: $Rev: 46764 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/wiki/AceAddon-2.0 -SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceAddon-2.0 -Description: Base for all Ace addons to inherit from. -Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0 -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceAddon-2.0" -local MINOR_VERSION = "$Revision: 46764 $" - --- This ensures the code is only executed if the libary doesn't already exist, or is a newer version -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end - -local function safecall(func,...) - local success, err = pcall(func,...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end -end --- Localization -local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, CREDITS, WEBSITE, CATEGORIES, ABOUT, LICENSE, PRINT_ADDON_INFO, DONATE, DONATE_DESC, HOWTO_DONATE_WINDOWS, HOWTO_DONATE_MAC -if GetLocale() == "deDE" then - STANDBY = "|cffff5050(Standby)|r" -- capitalized - - TITLE = "Titel" - NOTES = "Anmerkung" - VERSION = "Version" - AUTHOR = "Autor" - DATE = "Datum" - CATEGORY = "Kategorie" - EMAIL = "E-Mail" - WEBSITE = "Webseite" - CREDITS = "Credits" -- fix - LICENSE = "License" -- fix - - ABOUT = "Über" - PRINT_ADDON_INFO = "Gibt Addondaten aus" - DONATE = "Donate" -- fix - DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix - HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - - CATEGORIES = { - ["Action Bars"] = "Aktionsleisten", - ["Auction"] = "Auktion", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Schlachtfeld/PvP", - ["Buffs"] = "Stärkungszauber", - ["Chat/Communication"] = "Chat/Kommunikation", - ["Druid"] = "Druide", - ["Hunter"] = "Jäger", - ["Mage"] = "Magier", - ["Paladin"] = "Paladin", - ["Priest"] = "Priester", - ["Rogue"] = "Schurke", - ["Shaman"] = "Schamane", - ["Warlock"] = "Hexenmeister", - ["Warrior"] = "Krieger", - ["Healer"] = "Heiler", - ["Tank"] = "Tank", - ["Caster"] = "Zauberer", - ["Combat"] = "Kampf", - ["Compilations"] = "Zusammenstellungen", - ["Data Export"] = "Datenexport", - ["Development Tools"] = "Entwicklungs Tools", - ["Guild"] = "Gilde", - ["Frame Modification"] = "Frame Veränderungen", - ["Interface Enhancements"] = "Interface Verbesserungen", - ["Inventory"] = "Inventar", - ["Library"] = "Bibliotheken", - ["Map"] = "Karte", - ["Mail"] = "Post", - ["Miscellaneous"] = "Diverses", - ["Quest"] = "Quest", - ["Raid"] = "Schlachtzug", - ["Tradeskill"] = "Beruf", - ["UnitFrame"] = "Einheiten-Fenster", - } -elseif GetLocale() == "frFR" then - STANDBY = "|cffff5050(attente)|r" - - TITLE = "Titre" - NOTES = "Notes" - VERSION = "Version" - AUTHOR = "Auteur" - DATE = "Date" - CATEGORY = "Catégorie" - EMAIL = "E-mail" - WEBSITE = "Site web" - CREDITS = "Credits" -- fix - LICENSE = "License" -- fix - - ABOUT = "A propos" - PRINT_ADDON_INFO = "Afficher les informations sur l'addon" - DONATE = "Donate" -- fix - DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix - HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - - CATEGORIES = { - ["Action Bars"] = "Barres d'action", - ["Auction"] = "Hôtel des ventes", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Champs de bataille/JcJ", - ["Buffs"] = "Buffs", - ["Chat/Communication"] = "Chat/Communication", - ["Druid"] = "Druide", - ["Hunter"] = "Chasseur", - ["Mage"] = "Mage", - ["Paladin"] = "Paladin", - ["Priest"] = "Prêtre", - ["Rogue"] = "Voleur", - ["Shaman"] = "Chaman", - ["Warlock"] = "Démoniste", - ["Warrior"] = "Guerrier", - ["Healer"] = "Soigneur", - ["Tank"] = "Tank", - ["Caster"] = "Casteur", - ["Combat"] = "Combat", - ["Compilations"] = "Compilations", - ["Data Export"] = "Exportation de données", - ["Development Tools"] = "Outils de développement", - ["Guild"] = "Guilde", - ["Frame Modification"] = "Modification des fenêtres", - ["Interface Enhancements"] = "Améliorations de l'interface", - ["Inventory"] = "Inventaire", - ["Library"] = "Bibliothèques", - ["Map"] = "Carte", - ["Mail"] = "Courrier", - ["Miscellaneous"] = "Divers", - ["Quest"] = "Quêtes", - ["Raid"] = "Raid", - ["Tradeskill"] = "Métiers", - ["UnitFrame"] = "Fenêtres d'unité", - } -elseif GetLocale() == "koKR" then - STANDBY = "|cffff5050(사용가능)|r" - - TITLE = "제목" - NOTES = "노트" - VERSION = "버전" - AUTHOR = "저작자" - DATE = "날짜" - CATEGORY = "분류" - EMAIL = "전자 우편" - WEBSITE = "웹 사이트" - CREDITS = "공로자" - LICENSE = "라이센스" - - ABOUT = "정보" - PRINT_ADDON_INFO = "애드온에 대한 정보를 출력합니다." - DONATE = "기부" - DONATE_DESC = "이 애드온의 저작자에게 기부를 합니다." - HOWTO_DONATE_WINDOWS = "Ctrl-A를 눌려 링크를 선택후, Ctrl-C로 복사합니다. Alt-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." - HOWTO_DONATE_MAC = "Cmd-A를 눌려 링크를 선택후, Cmd-C로 복사합니다. Cmd-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." - - CATEGORIES = { - ["Action Bars"] = "액션바", - ["Auction"] = "경매", - ["Audio"] = "음향", - ["Battlegrounds/PvP"] = "전장/PvP", - ["Buffs"] = "버프", - ["Chat/Communication"] = "대화/의사소통", - ["Druid"] = "드루이드", - ["Hunter"] = "사냥꾼", - ["Mage"] = "마법사", - ["Paladin"] = "성기사", - ["Priest"] = "사제", - ["Rogue"] = "도적", - ["Shaman"] = "주술사", - ["Warlock"] = "흑마법사", - ["Warrior"] = "전사", - ["Healer"] = "힐러", - ["Tank"] = "탱커", - ["Caster"] = "캐스터", - ["Combat"] = "전투", - ["Compilations"] = "복합", - ["Data Export"] = "자료 출력", - ["Development Tools"] = "개발 도구", - ["Guild"] = "길드", - ["Frame Modification"] = "구조 변경", - ["Interface Enhancements"] = "인터페이스 강화", - ["Inventory"] = "인벤토리", - ["Library"] = "라이브러리", - ["Map"] = "지도", - ["Mail"] = "우편", - ["Miscellaneous"] = "기타", - ["Quest"] = "퀘스트", - ["Raid"] = "공격대", - ["Tradeskill"] = "전문기술", - ["UnitFrame"] = "유닛 프레임", - } -elseif GetLocale() == "zhTW" then - STANDBY = "|cffff5050(待命)|r" - - TITLE = "標題" - NOTES = "註記" - VERSION = "版本" - AUTHOR = "作者" - DATE = "日期" - CATEGORY = "類別" - EMAIL = "電子郵件" - WEBSITE = "網站" - CREDITS = "特別感謝" - LICENSE = "版權" - - ABOUT = "關於" - PRINT_ADDON_INFO = "顯示插件資訊。" - DONATE = "捐贈" - DONATE_DESC = "捐贈金錢給插件作者。" - HOWTO_DONATE_WINDOWS = "請按Ctrl-A選擇網站連結,Ctrl-C複製網址,Alt-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" - HOWTO_DONATE_MAC = "請按Cmd-A選擇網站連結,Cmd-C複製網址,Cmd-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" - - CATEGORIES = { - ["Action Bars"] = "動作條", - ["Auction"] = "拍賣", - ["Audio"] = "音效", - ["Battlegrounds/PvP"] = "戰場/PvP", - ["Buffs"] = "增益", - ["Chat/Communication"] = "聊天/通訊", - ["Druid"] = "德魯伊", - ["Hunter"] = "獵人", - ["Mage"] = "法師", - ["Paladin"] = "聖騎士", - ["Priest"] = "牧師", - ["Rogue"] = "盜賊", - ["Shaman"] = "薩滿", - ["Warlock"] = "術士", - ["Warrior"] = "戰士", - ["Healer"] = "治療者", - ["Tank"] = "坦克", - ["Caster"] = "施法者", - ["Combat"] = "戰鬥", - ["Compilations"] = "整合", - ["Data Export"] = "資料匯出", - ["Development Tools"] = "開發工具", - ["Guild"] = "公會", - ["Frame Modification"] = "框架修改", - ["Interface Enhancements"] = "介面增強", - ["Inventory"] = "庫存", - ["Library"] = "程式庫", - ["Map"] = "地圖", - ["Mail"] = "郵件", - ["Miscellaneous"] = "雜項", - ["Quest"] = "任務", - ["Raid"] = "團隊", - ["Tradeskill"] = "交易技能", - ["UnitFrame"] = "單位框架", - } -elseif GetLocale() == "zhCN" then - STANDBY = "|cffff5050(暂挂)|r" - - TITLE = "标题" - NOTES = "附注" - VERSION = "版本" - AUTHOR = "作者" - DATE = "日期" - CATEGORY = "分类" - EMAIL = "电子邮件" - WEBSITE = "网站" - CREDITS = "Credits" -- fix - LICENSE = "License" -- fix - - ABOUT = "关于" - PRINT_ADDON_INFO = "印列出插件信息" - DONATE = "Donate" -- fix - DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix - HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - - CATEGORIES = { - ["Action Bars"] = "动作条", - ["Auction"] = "拍卖", - ["Audio"] = "音频", - ["Battlegrounds/PvP"] = "战场/PvP", - ["Buffs"] = "增益魔法", - ["Chat/Communication"] = "聊天/交流", - ["Druid"] = "德鲁伊", - ["Hunter"] = "猎人", - ["Mage"] = "法师", - ["Paladin"] = "圣骑士", - ["Priest"] = "牧师", - ["Rogue"] = "盗贼", - ["Shaman"] = "萨满祭司", - ["Warlock"] = "术士", - ["Warrior"] = "战士", --- ["Healer"] = "治疗保障", --- ["Tank"] = "近战控制", --- ["Caster"] = "远程输出", - ["Combat"] = "战斗", - ["Compilations"] = "编译", - ["Data Export"] = "数据导出", - ["Development Tools"] = "开发工具", - ["Guild"] = "公会", - ["Frame Modification"] = "框架修改", - ["Interface Enhancements"] = "界面增强", - ["Inventory"] = "背包", - ["Library"] = "库", - ["Map"] = "地图", - ["Mail"] = "邮件", - ["Miscellaneous"] = "杂项", - ["Quest"] = "任务", - ["Raid"] = "团队", - ["Tradeskill"] = "商业技能", - ["UnitFrame"] = "头像框架", - } -elseif GetLocale() == "esES" then - STANDBY = "|cffff5050(espera)|r" - - TITLE = "Título" - NOTES = "Notas" - VERSION = "Versión" - AUTHOR = "Autor" - DATE = "Fecha" - CATEGORY = "Categoría" - EMAIL = "E-mail" - WEBSITE = "Web" - CREDITS = "Créditos" - LICENSE = "License" -- fix - - ABOUT = "Acerca de" - PRINT_ADDON_INFO = "Muestra información acerca del accesorio." - DONATE = "Donate" -- fix - DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix - HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix - - CATEGORIES = { - ["Action Bars"] = "Barras de Acción", - ["Auction"] = "Subasta", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Campos de Batalla/JcJ", - ["Buffs"] = "Buffs", - ["Chat/Communication"] = "Chat/Comunicación", - ["Druid"] = "Druida", - ["Hunter"] = "Cazador", - ["Mage"] = "Mago", - ["Paladin"] = "Paladín", - ["Priest"] = "Sacerdote", - ["Rogue"] = "Pícaro", - ["Shaman"] = "Chamán", - ["Warlock"] = "Brujo", - ["Warrior"] = "Guerrero", - ["Healer"] = "Sanador", - ["Tank"] = "Tanque", - ["Caster"] = "Conjurador", - ["Combat"] = "Combate", - ["Compilations"] = "Compilaciones", - ["Data Export"] = "Exportar Datos", - ["Development Tools"] = "Herramientas de Desarrollo", - ["Guild"] = "Hermandad", - ["Frame Modification"] = "Modificación de Marcos", - ["Interface Enhancements"] = "Mejoras de la Interfaz", - ["Inventory"] = "Inventario", - ["Library"] = "Biblioteca", - ["Map"] = "Mapa", - ["Mail"] = "Correo", - ["Miscellaneous"] = "Misceláneo", - ["Quest"] = "Misión", - ["Raid"] = "Banda", - ["Tradeskill"] = "Habilidad de Comercio", - ["UnitFrame"] = "Marco de Unidades", - } -else -- enUS - STANDBY = "|cffff5050(standby)|r" - - TITLE = "Title" - NOTES = "Notes" - VERSION = "Version" - AUTHOR = "Author" - DATE = "Date" - CATEGORY = "Category" - EMAIL = "E-mail" - WEBSITE = "Website" - CREDITS = "Credits" - LICENSE = "License" - - ABOUT = "About" - PRINT_ADDON_INFO = "Show information about the addon." - DONATE = "Donate" - DONATE_DESC = "Give a much-needed donation to the author of this addon." - HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." - HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." - - CATEGORIES = { - ["Action Bars"] = "Action Bars", - ["Auction"] = "Auction", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Battlegrounds/PvP", - ["Buffs"] = "Buffs", - ["Chat/Communication"] = "Chat/Communication", - ["Druid"] = "Druid", - ["Hunter"] = "Hunter", - ["Mage"] = "Mage", - ["Paladin"] = "Paladin", - ["Priest"] = "Priest", - ["Rogue"] = "Rogue", - ["Shaman"] = "Shaman", - ["Warlock"] = "Warlock", - ["Warrior"] = "Warrior", - ["Healer"] = "Healer", - ["Tank"] = "Tank", - ["Caster"] = "Caster", - ["Combat"] = "Combat", - ["Compilations"] = "Compilations", - ["Data Export"] = "Data Export", - ["Development Tools"] = "Development Tools", - ["Guild"] = "Guild", - ["Frame Modification"] = "Frame Modification", - ["Interface Enhancements"] = "Interface Enhancements", - ["Inventory"] = "Inventory", - ["Library"] = "Library", - ["Map"] = "Map", - ["Mail"] = "Mail", - ["Miscellaneous"] = "Miscellaneous", - ["Quest"] = "Quest", - ["Raid"] = "Raid", - ["Tradeskill"] = "Tradeskill", - ["UnitFrame"] = "UnitFrame", - } -end - -setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive - local lowerKey = key:lower() - for k,v in pairs(CATEGORIES) do - if k:lower() == lowerKey then - return v - end - end -end }) - --- Create the library object - -local AceOO = AceLibrary("AceOO-2.0") -local AceAddon = AceOO.Class() -local AceEvent -local AceConsole -local AceModuleCore - -function AceAddon:GetLocalizedCategory(name) - self:argCheck(name, 2, "string") - return CATEGORIES[name] or UNKNOWN -end - -function AceAddon:ToString() - return "AceAddon" -end - -local function print(text) - DEFAULT_CHAT_FRAME:AddMessage(text) -end - -function AceAddon:ADDON_LOADED(name) - local unregister = true - local initAddon = {} - while #self.nextAddon > 0 do - local addon = table.remove(self.nextAddon, 1) - if addon.possibleNames[name] then - table.insert(initAddon, addon) - else - unregister = nil - table.insert(self.skipAddon, addon) - end - end - self.nextAddon, self.skipAddon = self.skipAddon, self.nextAddon - if unregister then - AceAddon:UnregisterEvent("ADDON_LOADED") - end - while #initAddon > 0 do - local addon = table.remove(initAddon, 1) - table.insert(self.addons, addon) - if not self.addons[name] then - self.addons[name] = addon - end - addon.possibleNames = nil - self:InitializeAddon(addon, name) - end -end - -local function RegisterOnEnable(self) - if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK - AceAddon.playerLoginFired = true - end - if AceAddon.playerLoginFired then - AceAddon.addonsStarted[self] = true - if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then - AceAddon:ManualEnable(self) - end - else - if not AceAddon.addonsToOnEnable then - AceAddon.addonsToOnEnable = {} - end - table.insert(AceAddon.addonsToOnEnable, self) - end -end - -function AceAddon:InitializeAddon(addon, name) - if addon.name == nil then - addon.name = name - end - if GetAddOnMetadata then - -- TOC checks - if addon.title == nil then - addon.title = GetAddOnMetadata(name, "Title") - end - if type(addon.title) == "string" then - local num = addon.title:find(" |cff7fff7f %-Ace2%-|r$") - if num then - addon.title = addon.title:sub(1, num - 1) - end - addon.title = addon.title:trim() - end - if addon.notes == nil then - addon.notes = GetAddOnMetadata(name, "Notes") - end - if type(addon.notes) == "string" then - addon.notes = addon.notes:trim() - end - if addon.version == nil then - addon.version = GetAddOnMetadata(name, "Version") - end - if type(addon.version) == "string" then - if addon.version:find("%$Revision: (%d+) %$") then - addon.version = addon.version:gsub("%$Revision: (%d+) %$", "%1") - elseif addon.version:find("%$Rev: (%d+) %$") then - addon.version = addon.version:gsub("%$Rev: (%d+) %$", "%1") - elseif addon.version:find("%$LastChangedRevision: (%d+) %$") then - addon.version = addon.version:gsub("%$LastChangedRevision: (%d+) %$", "%1") - end - addon.version = addon.version:trim() - end - if addon.author == nil then - addon.author = GetAddOnMetadata(name, "Author") - end - if type(addon.author) == "string" then - addon.author = addon.author:trim() - end - if addon.credits == nil then - addon.credits = GetAddOnMetadata(name, "X-Credits") - end - if type(addon.credits) == "string" then - addon.credits = addon.credits:trim() - end - if addon.donate == nil then - addon.donate = GetAddOnMetadata(name, "X-Donate") - end - if type(addon.donate) == "string" then - addon.donate = addon.donate:trim() - end - if addon.date == nil then - addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate") - end - if type(addon.date) == "string" then - if addon.date:find("%$Date: (.-) %$") then - addon.date = addon.date:gsub("%$Date: (.-) %$", "%1") - elseif addon.date:find("%$LastChangedDate: (.-) %$") then - addon.date = addon.date:gsub("%$LastChangedDate: (.-) %$", "%1") - end - addon.date = addon.date:trim() - end - - if addon.category == nil then - addon.category = GetAddOnMetadata(name, "X-Category") - end - if type(addon.category) == "string" then - addon.category = addon.category:trim() - end - if addon.email == nil then - addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email") - end - if type(addon.email) == "string" then - addon.email = addon.email:trim() - end - if addon.license == nil then - addon.license = GetAddOnMetadata(name, "X-License") - end - if type(addon.license) == "string" then - addon.license = addon.license:trim() - end - if addon.website == nil then - addon.website = GetAddOnMetadata(name, "X-Website") - end - if type(addon.website) == "string" then - addon.website = addon.website:trim() - end - end - local current = addon.class - while true do - if current == AceOO.Class or not current then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedInitialize) == "function" then - mixin:OnEmbedInitialize(addon, name) - end - end - end - current = current.super - end - local n = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0 - - if type(addon.OnInitialize) == "function" then - safecall(addon.OnInitialize, addon, name) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonInitialized", addon) - end - RegisterOnEnable(addon) - local n2 = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0 - if n2 - n > 1 then - local mine = table.remove(AceAddon.addonsToOnEnable) - table.insert(AceAddon.addonsToOnEnable, n+1, mine) - end -end - -local aboutFrame -local function createAboutFrame() - aboutFrame = CreateFrame("Frame", "AceAddon20AboutFrame", UIParent, "DialogBoxFrame") - aboutFrame:SetWidth(500) - aboutFrame:SetHeight(400) - aboutFrame:SetPoint("CENTER") - aboutFrame:SetBackdrop({ - bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], - edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], - tile = true, tileSize = 16, edgeSize = 16, - insets = { left = 5, right = 5, top = 5, bottom = 5 } - }) - aboutFrame:SetBackdropColor(0,0,0,1) - - local donateButton = CreateFrame("Button", "AceAddon20AboutFrameDonateButton", aboutFrame, "UIPanelButtonTemplate2") - aboutFrame.donateButton = donateButton - donateButton:SetPoint("BOTTOMRIGHT", -20, 20) - _G.AceAddon20AboutFrameDonateButtonText:SetText(DONATE) - donateButton:SetWidth(_G.AceAddon20AboutFrameDonateButtonText:GetWidth()+20) - donateButton:SetScript("OnClick", function() - aboutFrame.currentAddon:OpenDonationFrame() - end) - - local text = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") - aboutFrame.title = text - text:SetPoint("TOP", 0, -5) - - aboutFrame:Hide() - - aboutFrame.lefts = {} - aboutFrame.rights = {} - aboutFrame.textLefts = {} - aboutFrame.textRights = {} - function aboutFrame:Clear() - self.title:SetText("") - for i = 1, #self.lefts do - self.lefts[i] = nil - self.rights[i] = nil - end - end - - function aboutFrame:AddLine(left, right) - aboutFrame.lefts[#aboutFrame.lefts+1] = left - aboutFrame.rights[#aboutFrame.rights+1] = right - end - - local aboutFrame_Show = aboutFrame.Show - function aboutFrame:Show(...) - local maxLeftWidth = 0 - local maxRightWidth = 0 - local textHeight = 0 - for i = 1, #self.lefts do - if not self.textLefts[i] then - local left = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") - self.textLefts[i] = left - local right = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") - self.textRights[i] = right - if i == 1 then - left:SetPoint("TOPRIGHT", aboutFrame, "TOPLEFT", 75, -35) - else - left:SetPoint("TOPRIGHT", self.textLefts[i-1], "BOTTOMRIGHT", 0, -5) - end - right:SetPoint("LEFT", left, "RIGHT", 5, 0) - end - self.textLefts[i]:SetText(self.lefts[i] .. ":") - self.textRights[i]:SetText(self.rights[i]) - local leftWidth = self.textLefts[i]:GetWidth() - local rightWidth = self.textRights[i]:GetWidth() - textHeight = self.textLefts[i]:GetHeight() - if maxLeftWidth < leftWidth then - maxLeftWidth = leftWidth - end - if maxRightWidth < rightWidth then - maxRightWidth = rightWidth - end - end - for i = #self.lefts+1, #self.textLefts do - self.textLefts[i]:SetText('') - self.textRights[i]:SetText('') - end - aboutFrame:SetWidth(75 + maxRightWidth + 20) - aboutFrame:SetHeight(#self.lefts * (textHeight + 5) + 100) - - aboutFrame_Show(self, ...) - end - aboutFrame:Hide() - - createAboutFrame = nil -end -local donateFrame - -local function unobfuscateEmail(email) - return email:gsub(" AT ", "@"):gsub(" DOT ", ".") -end - -local function isGoodVariable(var) - return type(var) == "string" or type(var) == "number" -end -function AceAddon.prototype:PrintAddonInfo() - if createAboutFrame then - createAboutFrame() - end - aboutFrame:Clear() - local x - if isGoodVariable(self.title) then - x = tostring(self.title) - elseif isGoodVariable(self.name) then - x = tostring(self.name) - else - x = "<" .. tostring(self.class) .. " instance>" - end - if type(self.IsActive) == "function" then - if not self:IsActive() then - x = x .. " " .. STANDBY - end - end - aboutFrame.title:SetText(x) - - if isGoodVariable(self.version) then - aboutFrame:AddLine(VERSION, tostring(self.version)) - end - if isGoodVariable(self.notes) then - aboutFrame:AddLine(NOTES, tostring(self.notes)) - end - if isGoodVariable(self.author) then - aboutFrame:AddLine(AUTHOR, tostring(self.author)) - end - if isGoodVariable(self.credits) then - aboutFrame:AddLine(CREDITS, tostring(self.credits)) - end - if isGoodVariable(self.date) then - aboutFrame:AddLine(DATE, tostring(self.date)) - end - if self.category then - local category = CATEGORIES[self.category] - if category then - aboutFrame:AddLine(CATEGORY, tostring(self.category)) - end - end - if isGoodVariable(self.email) then - aboutFrame:AddLine(EMAIL, unobfuscateEmail(tostring(self.email))) - end - if isGoodVariable(self.website) then - aboutFrame:AddLine(WEBSITE, tostring(self.website)) - end - if isGoodVariable(self.license) then - aboutFrame:AddLine(LICENSE, tostring(self.license)) - end - - if donateFrame and donateFrame:IsShown() then - donateFrame:Hide() - end - - aboutFrame.currentAddon = self - - aboutFrame:Show() - - if self.donate then - aboutFrame.donateButton:Show() - else - aboutFrame.donateButton:Hide() - end -end - -local function createDonateFrame() - donateFrame = CreateFrame("Frame", "AceAddon20Frame", UIParent, "DialogBoxFrame") - - donateFrame:SetWidth(500) - donateFrame:SetHeight(200) - donateFrame:SetPoint("CENTER") - donateFrame:SetBackdrop({ - bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], - edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], - tile = true, tileSize = 16, edgeSize = 16, - insets = { left = 5, right = 5, top = 5, bottom = 5 } - }) - donateFrame:SetBackdropColor(0,0,0,1) - - local text = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") - text:SetPoint("TOP", 0, -5) - text:SetText(DONATE) - - local howto = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") - howto:SetPoint("TOP", text, "BOTTOM", 0, -5) - howto:SetPoint("LEFT", 16, 0) - howto:SetPoint("RIGHT", -16, 0) - if not IsMacClient() then - -- Windows or Linux - howto:SetText(HOWTO_DONATE_WINDOWS) - else - howto:SetText(HOWTO_DONATE_MAC) - end - - local scrollFrame = CreateFrame("ScrollFrame", "AceAddon20FrameScrollFrame", donateFrame, "UIPanelScrollFrameTemplate") - scrollFrame:SetToplevel(true) - scrollFrame:SetPoint("TOP", -10, -76) - scrollFrame:SetWidth(455) - scrollFrame:SetHeight(70) - howto:SetPoint("BOTTOM", scrollFrame, "TOP") - - local editBox = CreateFrame("EditBox", nil, scrollFrame) - donateFrame.editBox = editBox - scrollFrame:SetScrollChild(editBox) - editBox:SetFontObject(ChatFontNormal) - editBox:SetMultiLine(true) - editBox:SetMaxLetters(99999) - editBox:SetWidth(450) - editBox:SetHeight(54) - editBox:SetPoint("BOTTOM", 5, 0) - editBox:SetJustifyH("LEFT") - editBox:SetJustifyV("TOP") - editBox:SetAutoFocus(false) - editBox:SetScript("OnTextChanged", function(this) - if this:GetText() ~= this.text then - this:SetText(this.text) - end - end) - editBox:SetScript("OnEscapePressed", function(this) - this:ClearFocus() - end) - createDonateFrame = nil -end - -local function fix(char) - return ("%%%02x"):format(char:byte()) -end - -local function urlencode(text) - return text:gsub("[^0-9A-Za-z]", fix) -end - -function AceAddon.prototype:OpenDonationFrame() - if createDonateFrame then - createDonateFrame() - end - local donate = self.donate - if type(donate) ~= "string" then - donate = "Wowace" - end - local style, data = (":"):split(donate, 2) - style = style:lower() - if style ~= "website" and style ~= "paypal" then - style = "wowace" - end - if style == "wowace" then - donateFrame.editBox.text = "http://www.wowace.com/wiki/Donations" - elseif style == "website" then - donateFrame.editBox.text = data - else -- PayPal - local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data)) - local name - if type(self.title) == "string" then - name = self.title - elseif type(self.name) == "string" then - name = self.name - end - if name then - name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "") - text = text .. "&item_name=" .. urlencode(name) - end - donateFrame.editBox.text = text - end - donateFrame.editBox:SetText(donateFrame.editBox.text) - - if aboutFrame and aboutFrame:IsShown() then - aboutFrame:Hide() - end - - donateFrame:Show() - - donateFrame.editBox:SetFocus() -end - -local options -function AceAddon:GetAceOptionsDataTable(target) - return { - about = { - name = ABOUT, - desc = PRINT_ADDON_INFO, - type = "execute", - func = "PrintAddonInfo", - order = -1, - }, - donate = { - name = DONATE, - desc = DONATE_DESC, - type = "execute", - func = "OpenDonationFrame", - order = -1, - hidden = function() - return not target.donate - end - } - } -end - -function AceAddon:PLAYER_LOGIN() - self.playerLoginFired = true - if self.addonsToOnEnable then - while #self.addonsToOnEnable > 0 do - local addon = table.remove(self.addonsToOnEnable, 1) - self.addonsStarted[addon] = true - if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then - AceAddon:ManualEnable(addon) - end - end - self.addonsToOnEnable = nil - end -end - -function AceAddon.prototype:Inject(t) - AceAddon:argCheck(t, 2, "table") - for k,v in pairs(t) do - self[k] = v - end -end - -function AceAddon.prototype:init() - if not AceEvent then - error(MAJOR_VERSION .. " requires AceEvent-2.0", 4) - end - AceAddon.super.prototype.init(self) - - self.super = self.class.prototype - - AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED") - local names = {} - for i = 1, GetNumAddOns() do - if IsAddOnLoaded(i) then names[GetAddOnInfo(i)] = true end - end - self.possibleNames = names - table.insert(AceAddon.nextAddon, self) -end - -function AceAddon.prototype:ToString() - local x - if type(self.title) == "string" then - x = self.title - elseif type(self.name) == "string" then - x = self.name - else - x = "<" .. tostring(self.class) .. " instance>" - end - if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then - x = x .. " " .. STANDBY - end - return x -end - -AceAddon.new = function(self, ...) - local class = AceAddon:pcall(AceOO.Classpool, self, ...) - return class:new() -end - -function AceAddon:ManualEnable(addon) - AceAddon:argCheck(addon, 2, "table") - local first = nil - if AceOO.inherits(addon, "AceAddon-2.0") then - if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[addon] then - first = true - AceAddon.addonsEnabled[addon] = true - end - end - local current = addon.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, addon, first) - end - end - end - current = current.super - end - if type(addon.OnEnable) == "function" then - safecall(addon.OnEnable, addon, first) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", addon, first) - end -end - -function AceAddon:ManualDisable(addon) - AceAddon:argCheck(addon, 2, "table") - local current = addon.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, addon) - end - end - end - current = current.super - end - if type(module.OnDisable) == "function" then - safecall(module.OnDisable, addon) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", addon) - end -end - -local function external(self, major, instance) - if major == "AceEvent-2.0" then - AceEvent = instance - - AceEvent:embed(self) - - self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) - elseif major == "AceConsole-2.0" then - AceConsole = instance - - local slashCommands = { "/ace2" } - local _,_,_,enabled,loadable = GetAddOnInfo("Ace") - if not enabled or not loadable then - table.insert(slashCommands, "/ace") - end - local function listAddon(addon, depth) - if not depth then - depth = 0 - end - - local s = (" "):rep(depth) .. " - " .. tostring(addon) - if rawget(addon, 'version') then - s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r" - end - if rawget(addon, 'slashCommand') then - s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r" - end - print(s) - if type(rawget(addon, 'modules')) == "table" then - local i = 0 - for k,v in pairs(addon.modules) do - i = i + 1 - if i == 6 then - print((" "):rep(depth + 1) .. " - more...") - break - else - listAddon(v, depth + 1) - end - end - end - end - local function listNormalAddon(i) - local name,_,_,enabled,loadable = GetAddOnInfo(i) - if not loadable then - enabled = false - end - if self.addons[name] then - listAddon(self.addons[name]) - else - local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name) - local version = GetAddOnMetadata(i, "Version") - if version then - if version:find("%$Revision: (%d+) %$") then - version = version:gsub("%$Revision: (%d+) %$", "%1") - elseif version:find("%$Rev: (%d+) %$") then - version = version:gsub("%$Rev: (%d+) %$", "%1") - elseif version:find("%$LastChangedRevision: (%d+) %$") then - version = version:gsub("%$LastChangedRevision: (%d+) %$", "%1") - end - s = s .. " - |cffffff7f" .. version .. "|r" - end - if not enabled then - s = s .. " |cffff0000(disabled)|r" - end - if IsAddOnLoadOnDemand(i) then - s = s .. " |cff00ff00[LoD]|r" - end - print(s) - end - end - local function mySort(alpha, bravo) - return tostring(alpha) < tostring(bravo) - end - AceConsole.RegisterChatCommand(self, slashCommands, { - desc = "AddOn development framework", - name = "Ace2", - type = "group", - args = { - about = { - desc = "Get information about Ace2", - name = "About", - type = "execute", - func = function() - print("|cffffff7fAce2|r - |cffffff7f2.0." .. MINOR_VERSION:gsub("%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework") - print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team") - print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/") - end - }, - list = { - desc = "List addons", - name = "List", - type = "group", - args = { - ace2 = { - desc = "List addons using Ace2", - name = "Ace2", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - table.sort(self.addons, mySort) - for _,v in ipairs(self.addons) do - listAddon(v) - end - end - }, - all = { - desc = "List all addons", - name = "All", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local count = GetNumAddOns() - for i = 1, count do - listNormalAddon(i) - end - end - }, - enabled = { - desc = "List all enabled addons", - name = "Enabled", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local count = GetNumAddOns() - for i = 1, count do - local _,_,_,enabled,loadable = GetAddOnInfo(i) - if enabled and loadable then - listNormalAddon(i) - end - end - end - }, - disabled = { - desc = "List all disabled addons", - name = "Disabled", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local count = GetNumAddOns() - for i = 1, count do - local _,_,_,enabled,loadable = GetAddOnInfo(i) - if not enabled or not loadable then - listNormalAddon(i) - end - end - end - }, - lod = { - desc = "List all LoadOnDemand addons", - name = "LoadOnDemand", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local count = GetNumAddOns() - for i = 1, count do - if IsAddOnLoadOnDemand(i) then - listNormalAddon(i) - end - end - end - }, - ace1 = { - desc = "List all addons using Ace1", - name = "Ace 1.x", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local count = GetNumAddOns() - for i = 1, count do - local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) - if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then - listNormalAddon(i) - end - end - end - }, - libs = { - desc = "List all libraries using AceLibrary", - name = "Libraries", - type = "execute", - func = function() - if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then - print("|cffffff7fLibrary list:|r") - for name, data in pairs(AceLibrary.libs) do - local s - if data.minor then - s = " - " .. tostring(name) .. "." .. tostring(data.minor) - else - s = " - " .. tostring(name) - end - if rawget(AceLibrary(name), 'slashCommand') then - s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)" - end - print(s) - end - end - end - }, - search = { - desc = "Search by name", - name = "Search", - type = "text", - usage = "<keyword>", - input = true, - get = false, - set = function(...) - local arg = { ... } - for i,v in ipairs(arg) do - arg[i] = v:gsub('%*', '.*'):gsub('%%', '%%%%'):lower() - end - local count = GetNumAddOns() - for i = 1, count do - local name = GetAddOnInfo(i) - local good = true - for _,v in ipairs(arg) do - if not name:lower():find(v) then - good = false - break - end - end - if good then - listNormalAddon(i) - end - end - end - } - }, - }, - enable = { - desc = "Enable addon(s).", - name = "Enable", - type = "text", - usage = "<addon 1> <addon 2> ...", - get = false, - input = true, - set = function(...) - for i = 1, select("#", ...) do - local addon = select(i, ...) - local name, title, _, enabled, _, reason = GetAddOnInfo(addon) - if reason == "MISSING" then - print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) - elseif not enabled then - EnableAddOn(addon) - print(("|cffffff7fAce2:|r %s is now enabled."):format(addon or name)) - else - print(("|cffffff7fAce2:|r %s is already enabled."):format(addon or name)) - end - end - end, - }, - disable = { - desc = "Disable addon(s).", - name = "Disable", - type = "text", - usage = "<addon 1> <addon 2> ...", - get = false, - input = true, - set = function(...) - for i = 1, select("#", ...) do - local addon = select(i, ...) - local name, title, _, enabled, _, reason = GetAddOnInfo(addon) - if reason == "MISSING" then - print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) - elseif enabled then - DisableAddOn(addon) - print(("|cffffff7fAce2:|r %s is now disabled."):format(addon or name)) - else - print(("|cffffff7fAce2:|r %s is already disabled."):format(addon or name)) - end - end - end, - }, - load = { - desc = "Load addon(s).", - name = "Load", - type = "text", - usage = "<addon 1> <addon 2> ...", - get = false, - input = true, - set = function(...) - for i = 1, select("#", ...) do - local addon = select(i, ...) - local name, title, _, _, loadable, reason = GetAddOnInfo(addon) - if reason == "MISSING" then - print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) - elseif not loadable then - print(("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s."):format(addon, reason)) - else - LoadAddOn(addon) - print(("|cffffff7fAce2:|r %s is now loaded."):format(addon or name)) - end - end - end - }, - info = { - desc = "Display information", - name = "Information", - type = "execute", - func = function() - local mem, threshold = gcinfo() - print((" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r"):format(mem / 1024)) - if threshold then - print((" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r"):format(threshold / 1024)) - end - print((" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r"):format(GetFramerate())) - local bandwidthIn, bandwidthOut, latency = GetNetStats() - bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024) - print((" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r"):format(latency)) - print((" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r"):format(bandwidthIn)) - print((" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r"):format(bandwidthOut)) - print((" - |cffffff7fTotal addons [|r%d|cffffff7f]|r"):format(GetNumAddOns())) - print((" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r"):format(#self.addons)) - local ace = 0 - local enabled = 0 - local disabled = 0 - local lod = 0 - for i = 1, GetNumAddOns() do - local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) - if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then - ace = ace + 1 - end - if IsAddOnLoadOnDemand(i) then - lod = lod + 1 - end - local isActive, loadable = select(4, GetAddOnInfo(i)) - if not isActive or not loadable then - disabled = disabled + 1 - else - enabled = enabled + 1 - end - end - print((" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r"):format(ace)) - print((" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r"):format(lod)) - print((" - |cffffff7fenabled addons [|r%d|cffffff7f]|r"):format(enabled)) - print((" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r"):format(disabled)) - local libs = 0 - if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then - for _ in pairs(AceLibrary.libs) do - libs = libs + 1 - end - end - print((" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r"):format(libs)) - end - } - } - }) - elseif major == "AceModuleCore-2.0" then - AceModuleCore = instance - end -end - -local function activate(self, oldLib, oldDeactivate) - AceAddon = self - - self.playerLoginFired = oldLib and oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage - self.addonsToOnEnable = oldLib and oldLib.addonsToOnEnable - self.addons = oldLib and oldLib.addons or {} - self.nextAddon = oldLib and oldLib.nextAddon or {} - self.skipAddon = oldLib and oldLib.skipAddon or {} - self.addonsStarted = oldLib and oldLib.addonsStarted or {} - self.addonsEnabled = oldLib and oldLib.addonsEnabled or {} - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/lib/AceAddon-2.0/AceAddon-2.0.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceAddon-2.0 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary, AceOO-2.0 - -AceAddon-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceAddon-3.0/AceAddon-3.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,412 @@ +--[[ $Id: AceAddon-3.0.lua 63220 2008-02-29 11:29:58Z nevcairiel $ ]] +local MAJOR, MINOR = "AceAddon-3.0", 3 +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 + +local tinsert, tconcat = table.insert, table.concat +local fmt = string.format +local pairs, next, type = pairs, next, type + +--[[ + xpcall safecall implementation +]] +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local xpcall, eh = ... + local method, ARGS + local function call() return method(ARGS) end + + local function dispatch(func, ...) + method = func + if not method then return end + ARGS = ... + return xpcall(call, eh) + end + + return dispatch + ]] + + local ARGS = {} + for i = 1, argCount do ARGS[i] = "arg"..i end + code = code:gsub("ARGS", tconcat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) +Dispatchers[0] = function(func) + return xpcall(func, errorhandler) +end + +local function safecall(func, ...) + -- we check to see if the func is passed is actually a function here and don't error when it isn't + -- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not + -- present execution should continue without hinderance + if type(func) == "function" then + return Dispatchers[select('#', ...)](func, ...) + end +end + +-- local functions that will be implemented further down +local 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 + +-- AceAddon:NewAddon( name, [lib, lib, lib, ...] ) +-- name (string) - unique addon object name +-- [lib] (string) - optional libs to embed in the addon object +-- +-- returns the addon object when succesful +function AceAddon:NewAddon(name, ...) + if type(name) ~= "string" then error(("Usage: NewAddon(name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end + + if self.addons[name] then error(("Usage: NewAddon(name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2) end + + local addon = setmetatable( {name = name}, { __tostring = addontostring } ) + self.addons[name] = addon + addon.modules = {} + addon.defaultModuleLibraries = {} + Embed( addon ) -- embed NewModule, GetModule methods + self:EmbedLibraries(addon, ...) + + -- add to queue of addons to be initialized upon ADDON_LOADED + tinsert(self.initializequeue, addon) + return addon +end + +-- AceAddon:GetAddon( name, [silent]) +-- name (string) - unique addon object name +-- silent (boolean) - if true, addon is optional, silently return nil if its not found +-- +-- throws an error if the addon object can not be found (except silent is set) +-- returns the addon object if found +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 + +-- AceAddon:EmbedLibraries( addon, [lib, lib, lib, ...] ) +-- addon (object) - addon to embed the libs in +-- [lib] (string) - optional libs to embed +function AceAddon:EmbedLibraries(addon, ...) + for i=1,select("#", ... ) do + local libname = select(i, ...) + self:EmbedLibrary(addon, libname, false, 4) + end +end + +-- AceAddon:EmbedLibrary( addon, libname, silent, offset ) +-- addon (object) - addon to embed the libs in +-- libname (string) - lib to embed +-- [silent] (boolean) - optional, marks an embed to fail silently if the library doesn't exist. +-- [offset] (number) - will push the error messages back to said offset defaults to 2 +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 + +-- addon:GetModule( name, [silent]) +-- name (string) - unique module object name +-- silent (boolean) - if true, module is optional, silently return nil if its not found +-- +-- throws an error if the addon object can not be found (except silent is set) +-- returns the module object if found +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 + +-- addon:NewModule( name, [prototype, [lib, lib, lib, ...] ) +-- name (string) - unique module object name for this addon +-- prototype (object) - object to derive this module from, methods and values from this table will be mixed into the module, if a string is passed a lib is assumed +-- [lib] (string) - optional libs to embed in the addon object +-- +-- returns the addon object when succesful +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 + + return module +end + +--addon:GetName() +-- Returns the real name of the addon or module, without any prefix +function GetName(self) + return self.moduleName or self.name +end + +--addon:Enable() +-- Enables the Addon if possible, return true or false depending on success +function Enable(self) + self:SetEnabledState(true) + return AceAddon:EnableAddon(self) +end + +--addon:Disable() +-- Disables the Addon if possible, return true or false depending on success +function Disable(self) + self:SetEnabledState(false) + return AceAddon:DisableAddon(self) +end + +-- addon:EnableModule( name ) +-- name (string) - unique module object name +-- +-- Enables the Module if possible, return true or false depending on success +function EnableModule(self, name) + local module = self:GetModule( name ) + return module:Enable() +end + +-- addon:DisableModule( name ) +-- name (string) - unique module object name +-- +-- Disables the Module if possible, return true or false depending on success +function DisableModule(self, name) + local module = self:GetModule( name ) + return module:Disable() +end + +-- addon:SetDefaultModuleLibraries( [lib, lib, lib, ...] ) +-- [lib] (string) - libs to embed in every module +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 + +-- addon:SetDefaultModuleState( state ) +-- state (boolean) - default state for new modules (enabled=true, disabled=false) +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 + +-- addon:SetDefaultModulePrototype( prototype ) +-- prototype (string or table) - the default prototype to use if none is specified on module creation +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 + +-- addon:SetEnabledState ( state ) +-- state ( boolean ) - set the state of an addon or module (enabled=true, disabled=false) +-- +-- should only be called before any Enabling actually happend, aka in OnInitialize +function SetEnabledState(self, state) + self.enabledState = state +end + + +local function IterateModules(self) return pairs(self.modules) end +local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) 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) + for k, v in pairs(mixins) do + target[k] = v + end + for k, v in pairs(pmixins) do + target[k] = target[k] or v + end +end + + +-- AceAddon:IntializeAddon( addon ) +-- addon (object) - addon to intialize +-- +-- calls OnInitialize on the addon object if available +-- calls OnEmbedInitialize on embedded libs in the addon object if available +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 + +-- AceAddon:EnableAddon( addon ) +-- addon (object) - addon to enable +-- +-- calls OnEnable on the addon object if available +-- calls OnEmbedEnable on embedded libs in the addon object if available +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 + -- TODO: handle 'first'? Or let addons do it on their own? + safecall(addon.OnEnable, addon) + 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 + self.statuses[addon.name] = addon.enabledState + + -- enable possible modules. + for name, module in pairs(addon.modules) do + self:EnableAddon(module) + end + + return true +end + +-- AceAddon:DisableAddon( addon ) +-- addon (object|string) - addon to disable +-- +-- calls OnDisable on the addon object if available +-- calls OnEmbedDisable on embedded libs in the addon object if available +function AceAddon:DisableAddon(addon) + if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end + if not self.statuses[addon.name] then return false end + safecall( addon.OnDisable, addon ) + 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 + self.statuses[addon.name] = addon.enabledState + + -- disable possible modules. + for name, module in pairs(addon.modules) do + self:DisableAddon(module) + end + + return true +end + +--The next few funcs are just because no one should be reaching into the internal registries +--Thoughts? +function AceAddon:IterateAddons() return pairs(self.addons) end +function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end +function AceAddon:IterateAddonStatus() return pairs(self.statuses) end +function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end + +-- Event Handling +local function onEvent(this, event, arg1) + if event == "ADDON_LOADED" 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) +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceAddon-3.0/AceAddon-3.0.xml Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceAddon-3.0.lua"/> +</Ui> \ No newline at end of file
--- a/lib/AceConsole-2.0/AceConsole-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2675 +0,0 @@ ---[[ -Name: AceConsole-2.0 -Revision: $Rev: 48940 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceConsole-2.0 -SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceConsole-2.0 -Description: Mixin to allow for input/output capabilities. This uses the - AceOptions data table format to determine input. - http://www.wowace.com/index.php/AceOptions_data_table -Dependencies: AceLibrary, AceOO-2.0 -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceConsole-2.0" -local MINOR_VERSION = "$Revision: 48940 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end - --- #AUTODOC_NAMESPACE AceConsole - -local MAP_ONOFF, USAGE, IS_CURRENTLY_SET_TO, IS_NOW_SET_TO, IS_NOT_A_VALID_OPTION_FOR, IS_NOT_A_VALID_VALUE_FOR, NO_OPTIONS_AVAILABLE, OPTION_HANDLER_NOT_FOUND, OPTION_HANDLER_NOT_VALID, OPTION_IS_DISABLED, KEYBINDING_USAGE, DEFAULT_CONFIRM_MESSAGE -if GetLocale() == "deDE" then - MAP_ONOFF = { [false] = "|cffff0000Aus|r", [true] = "|cff00ff00An|r" } - USAGE = "Benutzung" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r steht momentan auf |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r ist nun auf |cffffff7f[|r%s|cffffff7f]|r gesetzt" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] ist keine g\195\188ltige Option f\195\188r |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] ist kein g\195\188ltiger Wert f\195\188r |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "Keine Optionen verfügbar" - OPTION_HANDLER_NOT_FOUND = "Optionen handler |cffffff7f%q|r nicht gefunden." - OPTION_HANDLER_NOT_VALID = "Optionen handler nicht g\195\188ltig." - OPTION_IS_DISABLED = "Option |cffffff7f%s|r deaktiviert." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix - DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix -elseif GetLocale() == "frFR" then - MAP_ONOFF = { [false] = "|cffff0000Inactif|r", [true] = "|cff00ff00Actif|r" } - USAGE = "Utilisation" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est actuellement positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r est maintenant positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] n'est pas une option valide pour |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] n'est pas une valeur valide pour |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "Pas d'options disponibles" - OPTION_HANDLER_NOT_FOUND = "Le gestionnaire d'option |cffffff7f%q|r n'a pas \195\169t\195\169 trouv\195\169." - OPTION_HANDLER_NOT_VALID = "Le gestionnaire d'option n'est pas valide." - OPTION_IS_DISABLED = "L'option |cffffff7f%s|r est d\195\169sactiv\195\169e." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix - DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix -elseif GetLocale() == "koKR" then - MAP_ONOFF = { [false] = "|cffff0000끔|r", [true] = "|cff00ff00켬|r" } - USAGE = "사용법" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r|1은;는; 현재 상태는 |cffffff7f[|r%s|cffffff7f]|r|1으로;로; 설정되어 있습니다." - IS_NOW_SET_TO = "|cffffff7f%s|r|1을;를; |cffffff7f[|r%s|cffffff7f]|r 상태로 변경합니다." - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용 불가능한 설정입니다." - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용 불가능한 설정 값입니다." - NO_OPTIONS_AVAILABLE = "가능한 설정이 없습니다." - OPTION_HANDLER_NOT_FOUND = "설정 조정 값인 |cffffff7f%q|r|1을;를; 찾지 못했습니다." - OPTION_HANDLER_NOT_VALID = "설정 조정 값이 올바르지 않습니다." - OPTION_IS_DISABLED = "|cffffff7f%s|r 설정은 사용할 수 없습니다." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" - DEFAULT_CONFIRM_MESSAGE = "정말 당신은 `%s'|1을;를; 하시겠습니까?" -elseif GetLocale() == "zhCN" then - MAP_ONOFF = { [false] = "|cffff0000\229\133\179\233\151\173|r", [true] = "|cff00ff00\229\188\128\229\144\175|r" } - USAGE = "\231\148\168\230\179\149" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r \229\189\147\229\137\141\232\162\171\232\174\190\231\189\174 |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r \231\142\176\229\156\168\232\162\171\232\174\190\231\189\174\228\184\186 |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\231\154\132\233\128\137\233\161\185 \228\184\186 |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\229\128\188 \228\184\186 |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "\230\178\161\230\156\137\233\128\137\233\161\185\229\143\175\231\148\168" - OPTION_HANDLER_NOT_FOUND = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 |cffffff7f%q|r \230\178\161\230\159\165\230\137\190." - OPTION_HANDLER_NOT_VALID = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 \230\151\160\230\149\136." - OPTION_IS_DISABLED = "\233\128\137\233\161\185 |cffffff7f%s|r \228\184\141\229\174\140\230\149\180." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix - DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix -elseif GetLocale() == "zhTW" then - MAP_ONOFF = { [false] = "|cffff0000關閉|r", [true] = "|cff00ff00開啟|r" } - USAGE = "用法" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r目前的設定為|cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r現在被設定為|cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "對於|cffffff7f%2$s|r,[|cffffff7f%1$s|r]是一個不符合規定的選項" - IS_NOT_A_VALID_VALUE_FOR = "對於|cffffff7f%2$s|r,[|cffffff7f%1$s|r]是一個不符合規定的數值" - NO_OPTIONS_AVAILABLE = "沒有可用的選項" - OPTION_HANDLER_NOT_FOUND = "找不到|cffffff7f%q|r選項處理器。" - OPTION_HANDLER_NOT_VALID = "選項處理器不符合規定。" - OPTION_IS_DISABLED = "|cffffff7f%s|r已被停用。" - KEYBINDING_USAGE = "<Alt-Ctrl-Shift-鍵>" - DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" -elseif GetLocale() == "esES" then - MAP_ONOFF = { [false] = "|cffff0000Desactivado|r", [true] = "|cff00ff00Activado|r" } - USAGE = "Uso" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est\195\161 establecido actualmente a |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r se ha establecido a |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] no es una opci\195\179n valida para |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] no es un valor v\195\161lido para |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "No hay opciones disponibles" - OPTION_HANDLER_NOT_FOUND = "Gestor de opciones |cffffff7f%q|r no encontrado." - OPTION_HANDLER_NOT_VALID = "Gestor de opciones no v\195\161lido." - OPTION_IS_DISABLED = "La opci\195\179n |cffffff7f%s|r est\195\161 desactivada." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" - DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix -else -- enUS - MAP_ONOFF = { [false] = "|cffff0000Off|r", [true] = "|cff00ff00On|r" } - USAGE = "Usage" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r is currently set to |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r is now set to |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] is not a valid option for |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] is not a valid value for |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "No options available" - OPTION_HANDLER_NOT_FOUND = "Option handler |cffffff7f%q|r not found." - OPTION_HANDLER_NOT_VALID = "Option handler not valid." - OPTION_IS_DISABLED = "Option |cffffff7f%s|r is disabled." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" - DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -end - -local NONE = NONE or "None" - -local AceOO = AceLibrary("AceOO-2.0") -local AceEvent - -local AceConsole = AceOO.Mixin { "Print", "PrintComma", "PrintLiteral", "CustomPrint", "RegisterChatCommand" } -local Dewdrop - -local _G = getfenv(0) - -local function print(text, name, r, g, b, frame, delay) - if not text or text:len() == 0 then - text = " " - end - if not name or name == AceConsole then - else - text = "|cffffff78" .. tostring(name) .. ":|r " .. text - end - local last_color - for t in text:gmatch("[^\n]+") do - (frame or DEFAULT_CHAT_FRAME):AddMessage(last_color and "|cff" .. last_color .. t or t, r, g, b, nil, delay or 5) - if not last_color or t:find("|r") or t:find("|c") then - last_color = t:match(".*|c[fF][fF](%x%x%x%x%x%x)[^|]-$") - end - end - return text -end - -local real_tostring = tostring - -local function tostring(t) - if type(t) == "table" then - if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then - return ("<%s:%s>"):format(t:GetObjectType(), t:GetName() or "(anon)") - end - end - return real_tostring(t) -end - -local getkeystring - -local function isList(t) - local n = #t - for k,v in pairs(t) do - if type(k) ~= "number" then - return false - elseif k < 1 or k > n then - return false - end - end - return true -end - -local findGlobal = setmetatable({}, {__index=function(self, t) - for k,v in pairs(_G) do - if v == t then - k = tostring(k) - self[v] = k - return k - end - end - self[t] = false - return false -end}) - -local recurse = {} -local timeToEnd -local GetTime = GetTime -local type = type - -local new, del -do - local cache = setmetatable({},{__mode='k'}) - function new() - local t = next(cache) - if t then - cache[t] = nil - return t - else - return {} - end - end - - function del(t) - for k in pairs(t) do - t[k] = nil - end - cache[t] = true - return nil - end -end - -local function ignoreCaseSort(alpha, bravo) - if not alpha or not bravo then - return false - end - return tostring(alpha):lower() < tostring(bravo):lower() -end - -local function specialSort(alpha, bravo) - if alpha == nil or bravo == nil then - return false - end - local type_alpha, type_bravo = type(alpha), type(bravo) - if type_alpha ~= type_bravo then - return type_alpha < type_bravo - end - if type_alpha == "string" then - return alpha:lower() < bravo:lower() - elseif type_alpha == "number" then - return alpha < bravo - elseif type_alpha == "table" then - return #alpha < #bravo - elseif type_alpha == "boolean" then - return not alpha - else - return false - end -end - -local function escapeChar(c) - return ("\\%03d"):format(c:byte()) -end - -local function literal_tostring_prime(t, depth) - if type(t) == "string" then - return ("|cff00ff00%q|r"):format((t:gsub("|", "||"))):gsub("[\001-\012\014-\031\128-\255]", escapeChar) - elseif type(t) == "table" then - if t == _G then - return "|cffffea00_G|r" - end - if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then - return ("|cffffea00<%s:%s>|r"):format(t:GetObjectType(), t:GetName() or "(anon)") - end - if next(t) == nil then - local mt = getmetatable(t) - if type(mt) == "table" and type(mt.__raw) == "table" then - t = mt.__raw - end - end - if recurse[t] then - local g = findGlobal[t] - if g then - return ("|cff9f9f9f<Recursion _G[%q]>|r"):format(g) - else - return ("|cff9f9f9f<Recursion %s>|r"):format(real_tostring(t):gsub("|", "||")) - end - elseif GetTime() > timeToEnd then - local g = findGlobal[t] - if g then - return ("|cff9f9f9f<Timeout _G[%q]>|r"):format(g) - else - return ("|cff9f9f9f<Timeout %s>|r"):format(real_tostring(t):gsub("|", "||")) - end - elseif depth >= 2 then - local g = findGlobal[t] - if g then - return ("|cff9f9f9f<_G[%q]>|r"):format(g) - else - return ("|cff9f9f9f<%s>|r"):format(real_tostring(t):gsub("|", "||")) - end - end - recurse[t] = true - if next(t) == nil then - return "{}" - elseif next(t, (next(t))) == nil then - local k, v = next(t) - if k == 1 then - return "{ " .. literal_tostring_prime(v, depth+1) .. " }" - else - return "{ " .. getkeystring(k, depth+1) .. " = " .. literal_tostring_prime(v, depth+1) .. " }" - end - end - local s - local g = findGlobal[t] - if g then - s = ("{ |cff9f9f9f-- _G[%q]|r\n"):format(g) - else - s = "{ |cff9f9f9f-- " .. real_tostring(t):gsub("|", "||") .. "|r\n" - end - if isList(t) then - for i = 1, #t do - s = s .. (" "):rep(depth+1) .. literal_tostring_prime(t[i], depth+1) .. (i == #t and "\n" or ",\n") - end - else - local tmp = new() - for k in pairs(t) do - tmp[#tmp+1] = k - end - table.sort(tmp, specialSort) - for i,k in ipairs(tmp) do - tmp[i] = nil - local v = t[k] - s = s .. (" "):rep(depth+1) .. getkeystring(k, depth+1) .. " = " .. literal_tostring_prime(v, depth+1) .. (tmp[i+1] == nil and "\n" or ",\n") - end - tmp = del(tmp) - end - if g then - s = s .. (" "):rep(depth) .. string.format("} |cff9f9f9f-- _G[%q]|r", g) - else - s = s .. (" "):rep(depth) .. "} |cff9f9f9f-- " .. real_tostring(t):gsub("|", "||") - end - return s - end - if type(t) == "number" then - return "|cffff7fff" .. real_tostring(t) .. "|r" - elseif type(t) == "boolean" then - return "|cffff9100" .. real_tostring(t) .. "|r" - elseif t == nil then - return "|cffff7f7f" .. real_tostring(t) .. "|r" - else - return "|cffffea00" .. real_tostring(t) .. "|r" - end -end - -function getkeystring(t, depth) - if type(t) == "string" then - if t:find("^[%a_][%a%d_]*$") then - return "|cff7fd5ff" .. t .. "|r" - end - end - return "[" .. literal_tostring_prime(t, depth) .. "]" -end - -local get_stringed_args -do - local function g(value, ...) - if select('#', ...) == 0 then - return literal_tostring_prime(value, 1) - end - return literal_tostring_prime(value, 1) .. ", " .. g(...) - end - - local function f(success, ...) - if not success then - return - end - return g(...) - end - - function get_stringed_args(func, ...) - return f(pcall(func, ...)) - end -end - -local function literal_tostring_frame(t) - local s = ("|cffffea00<%s:%s|r\n"):format(t:GetObjectType(), t:GetName() or "(anon)") - local __index = getmetatable(t).__index - local tmp, tmp2, tmp3 = new(), new(), new() - for k in pairs(t) do - if k ~= 0 then - tmp3[k] = true - tmp2[k] = true - end - end - for k in pairs(__index) do - tmp2[k] = true - end - for k in pairs(tmp2) do - tmp[#tmp+1] = k - tmp2[k] = nil - end - table.sort(tmp, ignoreCaseSort) - local first = true - for i,k in ipairs(tmp) do - local v = t[k] - local good = true - if k == "GetPoint" then - for i = 1, t:GetNumPoints() do - if not first then - s = s .. ",\n" - else - first = false - end - s = s .. " " .. getkeystring(k, 1) .. "(" .. literal_tostring_prime(i, 1) .. ") => " .. get_stringed_args(v, t, i) - end - elseif type(v) == "function" and type(k) == "string" and (k:find("^Is") or k:find("^Get") or k:find("^Can")) then - local q = get_stringed_args(v, t) - if q then - if not first then - s = s .. ",\n" - else - first = false - end - s = s .. " " .. getkeystring(k, 1) .. "() => " .. q - end - elseif type(v) ~= "function" or (type(v) == "function" and type(k) == "string" and tmp3[k]) then - if not first then - s = s .. ",\n" - else - first = false - end - s = s .. " " .. getkeystring(k, 1) .. " = " .. literal_tostring_prime(v, 1) - else - good = false - end - end - tmp, tmp2, tmp3 = del(tmp), del(tmp2), del(tmp3) - s = s .. "\n|cffffea00>|r" - return s -end - -local function literal_tostring(t, only) - timeToEnd = GetTime() + 0.2 - local s - if only and type(t) == "table" and type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then - s = literal_tostring_frame(t) - else - s = literal_tostring_prime(t, 0) - end - for k,v in pairs(recurse) do - recurse[k] = nil - end - for k,v in pairs(findGlobal) do - findGlobal[k] = nil - end - return s -end - -local function tostring_args(a1, ...) - if select('#', ...) < 1 then - return tostring(a1) - end - return tostring(a1), tostring_args(...) -end - -local function literal_tostring_args(a1, ...) - if select('#', ...) < 1 then - return literal_tostring(a1) - end - return literal_tostring(a1), literal_tostring_args(...) -end - -function AceConsole:CustomPrint(r, g, b, frame, delay, connector, a1, ...) - if connector == true then - local s - if select('#', ...) == 0 then - s = literal_tostring(a1, true) - else - s = (", "):join(literal_tostring_args(a1, ...)) - end - return print(s, self, r, g, b, frame or self.printFrame, delay) - elseif tostring(a1):find("%%") and select('#', ...) >= 1 then - local success, text = pcall(string.format, tostring_args(a1, ...)) - if success then - return print(text, self, r, g, b, frame or self.printFrame, delay) - end - end - return print((connector or " "):join(tostring_args(a1, ...)), self, r, g, b, frame or self.printFrame, delay) -end - -function AceConsole:Print(...) - return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, " ", ...) -end - -function AceConsole:PrintComma(...) - return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, ", ", ...) -end - -function AceConsole:PrintLiteral(...) - return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, true, ...) -end - -local work -local argwork - -local function findTableLevel(self, options, chat, text, index, passTable) - if not index then - index = 1 - if work then - for k,v in pairs(work) do - work[k] = nil - end - for k,v in pairs(argwork) do - argwork[k] = nil - end - else - work = {} - argwork = {} - end - local len = text:len() - local count - repeat - text, count = text:gsub("(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[[^%]]-) (.-%]|h|r)", "%1\001%2") - until count == 0 - text = text:gsub("(%]|h|r)(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[)", "%1 %2") - for token in text:gmatch("([^%s]+)") do - local token = token - local num = tonumber(token) - if num then - token = num - else - token = token:gsub("\001", " ") - end - table.insert(work, token) - end - end - - local path = chat - for i = 1, index - 1 do - path = path .. " " .. tostring(work[i]) - end - - local passValue = options.passValue or (passTable and work[index-1]) - passTable = passTable or options - - if type(options.args) == "table" then - local disabled, hidden = options.disabled, options.cmdHidden or options.hidden - if hidden then - if type(hidden) == "function" then - hidden = hidden(passValue) - elseif type(hidden) == "string" then - local handler = options.handler or self - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - hidden = handler[f](handler, passValue) - if neg then - hidden = not hidden - end - end - end - if hidden then - disabled = true - elseif disabled then - if type(disabled) == "function" then - disabled = disabled(passValue) - elseif type(disabled) == "string" then - local handler = options.handler or self - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - disabled = handler[f](handler, passValue) - if neg then - disabled = not disabled - end - end - end - if not disabled then - local next = work[index] and tostring(work[index]):lower() - local next_num = tonumber(next) - if next then - for k,v in pairs(options.args) do - local good = false - if tostring(k):gsub("%s", "-"):lower() == next then - good = true - elseif k == next_num then - good = true - elseif type(v.aliases) == "table" then - for _,alias in ipairs(v.aliases) do - if alias:gsub("%s", "-"):lower() == next then - good = true - break - end - end - elseif type(v.aliases) == "string" and v.aliases:gsub("%s", "-"):lower() == next then - good = true - end - if good then - work[index] = k -- revert it back to its original form as supplied in args - if options.pass then - passTable = passTable or options - if options.get and options.set then - passTable = options - end - else - passTable = nil - end - return findTableLevel(options.handler or self, v, chat, text, index + 1, passTable) - end - end - end - end - end - for i = index, #work do - table.insert(argwork, work[i]) - end - return options, path, argwork, options.handler or self, passTable, passValue -end - -local function validateOptionsMethods(self, options, position) - if type(options) ~= "table" then - return "Options must be a table.", position - end - self = options.handler or self - if options.type == "execute" then - if options.func and type(options.func) ~= "string" and type(options.func) ~= "function" then - return "func must be a string or function", position - end - if options.func and type(options.func) == "string" and type(self[options.func]) ~= "function" then - return ("%q is not a proper function"):format(tostring(options.func)), position - end - else - if options.get then - if type(options.get) ~= "string" and type(options.get) ~= "function" then - return "get must be a string or function", position - end - if type(options.get) == "string" then - local f = options.get - if options.type == "toggle" then - f = f:match("^~(.-)$") or f - end - if type(self[f]) ~= "function" then - return ("%q is not a proper function"):format(tostring(f)), position - end - end - end - if options.set then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return "set must be a string or function", position - end - if type(options.set) == "string" and type(self[options.set]) ~= "function" then - return ("%q is not a proper function"):format(tostring(options.set)), position - end - end - if options.validate and type(options.validate) ~= "table" and options.validate ~= "keybinding" then - if type(options.validate) ~= "string" and type(options.validate) ~= "function" then - return "validate must be a string or function", position - end - if type(options.validate) == "string" and type(self[options.validate]) ~= "function" then - return ("%q is not a proper function"):format(tostring(options.validate)), position - end - end - end - if options.disabled and type(options.disabled) == "string" then - local f = options.disabled - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return ("%q is not a proper function"):format(tostring(f)), position - end - end - if options.cmdHidden and type(options.cmdHidden) == "string" then - local f = options.cmdHidden - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return ("%q is not a proper function"):format(tostring(f)), position - end - end - if options.guiHidden and type(options.guiHidden) == "string" then - local f = options.guiHidden - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return ("%q is not a proper function"):format(tostring(f)), position - end - end - if options.hidden and type(options.hidden) == "string" then - local f = options.hidden - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return ("%q is not a proper function"):format(tostring(f)), position - end - end - if options.type == "group" and type(options.args) == "table" then - for k,v in pairs(options.args) do - if type(v) == "table" then - local newposition - if position then - newposition = position .. ".args." .. k - else - newposition = "args." .. k - end - local err, pos = validateOptionsMethods(self, v, newposition) - if err then - return err, pos - end - end - end - end -end - -local function validateOptions(options, position, baseOptions, fromPass) - if not baseOptions then - baseOptions = options - end - if type(options) ~= "table" then - return "Options must be a table.", position - end - local kind = options.type - if type(kind) ~= "string" then - return '"type" must be a string.', position - elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then - return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position - end - if options.aliases then - if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then - return '"alias" must be a table or string', position - end - end - if not fromPass then - if kind == "execute" then - if type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - elseif kind == "range" or kind == "text" or kind == "toggle" then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if kind == "text" and options.get == false then - elseif type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif kind == "group" and options.pass then - if options.pass ~= true then - return '"pass" must be either nil, true, or false', position - end - if not options.func then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - end - end - if options ~= baseOptions then - if kind == "header" then - elseif type(options.desc) ~= "string" then - return '"desc" must be a string', position - elseif options.desc:len() == 0 then - return '"desc" cannot be a 0-length string', position - end - end - - if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then - if options.type == "header" and not options.cmdName and not options.name then - elseif options.cmdName then - if type(options.cmdName) ~= "string" then - return '"cmdName" must be a string or nil', position - elseif options.cmdName:len() == 0 then - return '"cmdName" cannot be a 0-length string', position - end - if type(options.guiName) ~= "string" then - if not options.guiNameIsMap then - return '"guiName" must be a string or nil', position - end - elseif options.guiName:len() == 0 then - return '"guiName" cannot be a 0-length string', position - end - else - if type(options.name) ~= "string" then - return '"name" must be a string', position - elseif options.name:len() == 0 then - return '"name" cannot be a 0-length string', position - end - end - end - if options.guiNameIsMap then - if type(options.guiNameIsMap) ~= "boolean" then - return '"guiNameIsMap" must be a boolean or nil', position - elseif options.type ~= "toggle" then - return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position - elseif type(options.map) ~= "table" then - return '"map" must be a table', position - end - end - if options.message and type(options.message) ~= "string" then - return '"message" must be a string or nil', position - end - if options.error and type(options.error) ~= "string" then - return '"error" must be a string or nil', position - end - if options.current and type(options.current) ~= "string" then - return '"current" must be a string or nil', position - end - if options.order then - if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then - return '"order" must be a non-zero number or nil', position - end - end - if options.disabled then - if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then - return '"disabled" must be a function, string, or boolean', position - end - end - if options.cmdHidden then - if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then - return '"cmdHidden" must be a function, string, or boolean', position - end - end - if options.guiHidden then - if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then - return '"guiHidden" must be a function, string, or boolean', position - end - end - if options.hidden then - if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then - return '"hidden" must be a function, string, or boolean', position - end - end - if kind == "text" then - if type(options.validate) == "table" then - local t = options.validate - local iTable = nil - for k,v in pairs(t) do - if type(k) == "number" then - if iTable == nil then - iTable = true - elseif not iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - elseif k < 1 or k > #t then - return '"validate" numeric keys must be indexed properly. >= 1 and <= #validate', position - end - else - if iTable == nil then - iTable = false - elseif iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - end - end - if type(v) ~= "string" then - return '"validate" values must all be strings', position - end - end - if options.multiToggle and options.multiToggle ~= true then - return '"multiToggle" must be a boolean or nil if "validate" is a table', position - end - elseif options.validate == "keybinding" then - - else - if type(options.usage) ~= "string" then - return '"usage" must be a string', position - elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then - return '"validate" must be a string, function, or table', position - end - end - if options.multiToggle and type(options.validate) ~= "table" then - return '"validate" must be a table if "multiToggle" is true', position - end - elseif kind == "range" then - if options.min or options.max then - if type(options.min) ~= "number" then - return '"min" must be a number', position - elseif type(options.max) ~= "number" then - return '"max" must be a number', position - elseif options.min >= options.max then - return '"min" must be less than "max"', position - end - end - if options.step then - if type(options.step) ~= "number" then - return '"step" must be a number', position - elseif options.step < 0 then - return '"step" must be nonnegative', position - end - end - if options.isPercent and options.isPercent ~= true then - return '"isPercent" must either be nil, true, or false', position - end - elseif kind == "toggle" then - if options.map then - if type(options.map) ~= "table" then - return '"map" must be a table', position - elseif type(options.map[true]) ~= "string" then - return '"map[true]" must be a string', position - elseif type(options.map[false]) ~= "string" then - return '"map[false]" must be a string', position - end - end - elseif kind == "color" then - if options.hasAlpha and options.hasAlpha ~= true then - return '"hasAlpha" must be nil, true, or false', position - end - elseif kind == "group" then - if options.pass and options.pass ~= true then - return '"pass" must be nil, true, or false', position - end - if type(options.args) ~= "table" then - return '"args" must be a table', position - end - for k,v in pairs(options.args) do - if type(k) ~= "number" then - if type(k) ~= "string" then - return '"args" keys must be strings or numbers', position - elseif k:len() == 0 then - return '"args" keys must not be 0-length strings.', position - end - end - if type(v) ~= "table" then - if type(k) == "number" then - return '"args" values must be tables', position and position .. "[" .. k .. "]" or "[" .. k .. "]" - else - return '"args" values must be tables', position and position .. "." .. k or k - end - end - local newposition - if type(k) == "number" then - newposition = position and position .. ".args[" .. k .. "]" or "args[" .. k .. "]" - else - newposition = position and position .. ".args." .. k or "args." .. k - end - local err, pos = validateOptions(v, newposition, baseOptions, options.pass) - if err then - return err, pos - end - end - elseif kind == "execute" then - if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then - return '"confirm" must be a string, boolean, or nil', position - end - end -end - -local colorTable -local colorFunc -local colorCancelFunc - -local function keybindingValidateFunc(text) - if text == nil or text == "NONE" then - return nil - end - text = text:upper() - local shift, ctrl, alt - local modifier - while true do - if text == "-" then - break - end - modifier, text = strsplit('-', text, 2) - if text then - if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then - return false - end - if modifier == "SHIFT" then - if shift then - return false - end - shift = true - end - if modifier == "CTRL" then - if ctrl then - return false - end - ctrl = true - end - if modifier == "ALT" then - if alt then - return false - end - alt = true - end - else - text = modifier - break - end - end - if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then - return false - end - local s = text - if shift then - s = "SHIFT-" .. s - end - if ctrl then - s = "CTRL-" .. s - end - if alt then - s = "ALT-" .. s - end - return s -end -AceConsole.keybindingValidateFunc = keybindingValidateFunc - -local order - -local mysort_args -local mysort - -local function icaseSort(alpha, bravo) - if type(alpha) == "number" and type(bravo) == "number" then - return alpha < bravo - end - return tostring(alpha):lower() < tostring(bravo):lower() -end - -local tmp = {} -local function printUsage(self, handler, realOptions, options, path, args, passValue, quiet, filter) - if filter then - filter = "^" .. filter:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") - end - local hidden, disabled = options.cmdHidden or options.hidden, options.disabled - if hidden then - if type(hidden) == "function" then - hidden = hidden(options.passValue) - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - hidden = handler[f](handler, options.passValue) - if neg then - hidden = not hidden - end - end - end - if hidden then - disabled = true - elseif disabled then - if type(disabled) == "function" then - disabled = disabled(options.passValue) - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - disabled = handler[f](handler, options.passValue) - if neg then - disabled = not disabled - end - end - end - local kind = (options.type or "group"):lower() - if disabled then - print(OPTION_IS_DISABLED:format(path), realOptions.cmdName or realOptions.name or self) - elseif kind == "text" then - local var - local multiToggle - for k in pairs(tmp) do - tmp[k] = nil - end - if passTable then - multiToggle = passTable.multiToggle - if not passTable.get then - elseif type(passTable.get) == "function" then - if not multiToggle then - var = passTable.get(passValue) - else - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue == nil then - var[val] = passTable.get(val) or nil - else - var[val] = passTable.get(passValue, val) or nil - end - end - end - else - local handler = passTable.handler or handler - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(passTable.get))) - end - var = handler[passTable.get](handler, passValue) - if not multiToggle then - var = handler[passTable.get](handler, passValue) - else - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue == nil then - var[val] = handler[passTable.get](handler, val) or nil - else - var[val] = handler[passTable.get](handler, passValue, val) or nil - end - end - end - end - else - multiToggle = options.multiToggle - if not options.get then - elseif type(options.get) == "function" then - if not multiToggle then - var = options.get(passValue) - else - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue == nil then - var[val] = options.get(val) or nil - else - var[val] = options.get(passValue, val) or nil - end - end - end - else - local handler = options.handler or handler - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.get))) - end - if not multiToggle then - var = handler[options.get](handler, passValue) - else - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue == nil then - var[val] = handler[options.get](handler, val) or nil - else - var[val] = handler[options.get](handler, passValue, val) or nil - end - end - end - end - end - - local usage - if type(options.validate) == "table" then - if filter then - if not order then - order = {} - end - for k,v in pairs(options.validate) do - if v:find(filter) then - table.insert(order, v) - end - end - table.sort(order, icaseSort) - usage = "{" .. table.concat(order, " || ") .. "}" - for k in pairs(order) do - order[k] = nil - end - else - if not order then - order = {} - end - for k,v in pairs(options.validate) do - table.insert(order, v) - end - table.sort(order, icaseSort) - usage = "{" .. table.concat(order, " || ") .. "}" - for k in pairs(order) do - order[k] = nil - end - end - if multiToggle then - if not next(var) then - var = NONE - else - if not order then - order = {} - end - for k in pairs(var) do - if options.validate[k] then - order[#order+1] = options.validate[k] - else - for _,v in pairs(options.validate) do - if v == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then - order[#order+1] = v - break - end - end - end - end - table.sort(order, icaseSort) - var = table.concat(order, ", ") - for k in pairs(order) do - order[k] = nil - end - end - else - var = options.validate[var] or var - end - elseif options.validate == "keybinding" then - usage = KEYBINDING_USAGE - else - usage = options.usage or "<value>" - end - if not quiet then - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage), realOptions.cmdName or realOptions.name or self) - end - if (passTable and passTable.get) or options.get then - print((options.current or IS_CURRENTLY_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE))) - end - elseif kind == "range" then - local var - if passTable then - if type(passTable.get) == "function" then - var = passTable.get(passValue) - else - local handler = passTable.handler or handler - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(passTable.get))) - end - var = handler[passTable.get](handler, passValue) - end - else - if type(options.get) == "function" then - var = options.get(passValue) - else - local handler = options.handler or handler - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.get))) - end - var = handler[options.get](handler, passValue) - end - end - - local usage - local min = options.min or 0 - local max = options.max or 1 - if options.isPercent then - min, max = min * 100, max * 100 - var = tostring(var * 100) .. "%" - end - local bit = "-" - if min < 0 or max < 0 then - bit = " - " - end - usage = ("(%s%s%s)"):format(min, bit, max) - if not quiet then - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage), realOptions.cmdName or realOptions.name or self) - end - print((options.current or IS_CURRENTLY_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE))) - elseif kind == "group" then - local usage - if next(options.args) then - if not order then - order = {} - end - for k,v in pairs(options.args) do - if v.type ~= "header" then - local hidden = v.cmdHidden or v.hidden - if hidden then - if type(hidden) == "function" then - hidden = hidden() - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - hidden = handler[f](handler) - if neg then - hidden = not hidden - end - end - end - if not hidden then - if filter then - if k:find(filter) then - table.insert(order, k) - elseif type(v.aliases) == "table" then - for _,bit in ipairs(v.aliases) do - if bit:find(filter) then - table.insert(order, k) - break - end - end - elseif type(v.aliases) == "string" then - if v.aliases:find(filter) then - table.insert(order, k) - end - end - else - table.insert(order, k) - end - end - end - end - if not mysort then - mysort = function(a, b) - local alpha, bravo = mysort_args[a], mysort_args[b] - local alpha_order = alpha and alpha.order or 100 - local bravo_order = bravo and bravo.order or 100 - if alpha_order == bravo_order then - return tostring(a):lower() < tostring(b):lower() - else - if alpha_order < 0 then - if bravo_order > 0 then - return false - end - else - if bravo_order < 0 then - return true - end - end - if alpha_order > 0 and bravo_order > 0 then - return tostring(a):lower() < tostring(b):lower() - end - return alpha_order < bravo_order - end - end - end - mysort_args = options.args - table.sort(order, mysort) - mysort_args = nil - if not quiet then - if options == realOptions then - if options.desc then - print(tostring(options.desc), realOptions.cmdName or realOptions.name or self) - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}")) - elseif self.description or self.notes then - print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}")) - else - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) - end - else - if options.desc then - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) - print(tostring(options.desc)) - else - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) - end - end - end - local passTable = options.pass and options or nil - for _,k in ipairs(order) do - local passValue = passTable and k or nil - local real_k = k - local v = options.args[k] - if v then - local v_p = passTable or v - if v.get and v.set then - v_p = v - passValue = nil - end - if v.passValue then - passValue = v.passValue - end - local k = tostring(k):gsub("%s", "-") - local disabled = v.disabled - if disabled then - if type(disabled) == "function" then - disabled = disabled(passValue) - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - disabled = handler[f](handler, passValue) - if neg then - disabled = not disabled - end - end - end - if type(v.aliases) == "table" then - for _,s in ipairs(v.aliases) do - k = k .. " || " .. s:gsub("%s", "-") - end - elseif type(v.aliases) == "string" then - k = k .. " || " .. v.aliases:gsub("%s", "-") - end - if v_p.get then - local a1,a2,a3,a4 - local multiToggle = v_p.type == "text" and v_p.multiToggle - for k in pairs(tmp) do - tmp[k] = nil - end - if type(v_p.get) == "function" then - if multiToggle then - a1 = tmp - for k,v in pairs(v.validate) do - local val = type(k) ~= "number" and k or v - if passValue == nil then - a1[val] = v_p.get(val) or nil - else - a1[val] = v_p.get(passValue, val) or nil - end - end - else - a1,a2,a3,a4 = v_p.get(passValue) - end - else - local handler = v_p.handler or handler - local f = v_p.get - local neg - if v.type == "toggle" then - neg = f:match("^~(.-)$") - if neg then - f = neg - end - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - if multiToggle then - a1 = tmp - for k,v in pairs(v.validate) do - local val = type(k) ~= "number" and k or v - if passValue == nil then - a1[val] = handler[f](handler, val) or nil - else - a1[val] = handler[f](handler, passValue, val) or nil - end - end - else - a1,a2,a3,a4 = handler[f](handler, passValue) - end - if neg then - a1 = not a1 - end - end - local s - if v.type == "color" then - if v.hasAlpha then - if not a1 or not a2 or not a3 or not a4 then - s = NONE - else - s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a4*255, a1*255, a2*255, a3*255, a4*255, a1*255, a2*255, a3*255) - end - else - if not a1 or not a2 or not a3 then - s = NONE - else - s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(a1*255, a2*255, a3*255, a1*255, a2*255, a3*255) - end - end - elseif v.type == "toggle" then - if v.map then - s = tostring(v.map[a1 and true or false] or NONE) - else - s = tostring(MAP_ONOFF[a1 and true or false] or NONE) - end - elseif v.type == "range" then - if v.isPercent then - s = tostring(a1 * 100) .. "%" - else - s = tostring(a1) - end - elseif v.type == "text" and type(v.validate) == "table" then - if multiToggle then - if not next(a1) then - s = NONE - else - s = '' - for k in pairs(a1) do - if v.validate[k] then - if s == '' then - s = v.validate[k] - else - s = s .. ', ' .. v.validate[k] - end - else - for _,u in pairs(v.validate) do - if u == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then - if s == '' then - s = u - else - s = s .. ', ' .. u - end - break - end - end - end - end - end - else - s = tostring(v.validate[a1] or a1 or NONE) - end - else - s = tostring(a1 or NONE) - end - if disabled then - local s = s:gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") - local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") - print(("|cffcfcfcf - %s: [%s] %s|r"):format(k, s, desc)) - else - print((" - |cffffff7f%s: [|r%s|cffffff7f]|r %s"):format(k, s, v.desc or NONE)) - end - else - if disabled then - local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") - print(("|cffcfcfcf - %s: %s"):format(k, desc)) - else - print((" - |cffffff7f%s:|r %s"):format(k, v.desc or NONE)) - end - end - end - end - for k in pairs(order) do - order[k] = nil - end - else - if options.desc then - print(("|cffffff7f%s:|r %s"):format(USAGE, path), realOptions.cmdName or realOptions.name or self) - print(tostring(options.desc)) - elseif options == realOptions and (self.description or self.notes) then - print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) - print(("|cffffff7f%s:|r %s"):format(USAGE, path)) - else - print(("|cffffff7f%s:|r %s"):format(USAGE, path), realOptions.cmdName or realOptions.name or self) - end - print(NO_OPTIONS_AVAILABLE) - end - end -end - -local function confirmPopup(message, func, ...) - if not StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] then - StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] = {} - end - local t = StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] - for k in pairs(t) do - t[k] = nil - end - t.text = message - t.button1 = ACCEPT or "Accept" - t.button2 = CANCEL or "Cancel" - t.OnAccept = function() - func(unpack(t)) - end - for i = 1, select('#', ...) do - t[i] = select(i, ...) - end - t.timeout = 0 - t.whileDead = 1 - t.hideOnEscape = 1 - - StaticPopup_Show("ACECONSOLE20_CONFIRM_DIALOG") -end - -local function handlerFunc(self, chat, msg, options) - if not msg then - msg = "" - else - msg = msg:gsub("^%s*(.-)%s*$", "%1") - msg = msg:gsub("%s+", " ") - end - - local realOptions = options - local options, path, args, handler, passTable, passValue = findTableLevel(self, options, chat, msg) - if options.type == "execute" then - if options.func then - passTable = nil - end - else - if options.get and options.set then - passTable = nil - end - end - passValue = options.passValue or passTable and passValue - - local hidden, disabled = options.cmdHidden or options.hidden, options.disabled - if hidden then - if type(hidden) == "function" then - hidden = hidden(passValue) - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - hidden = handler[f](handler, passValue) - if neg then - hidden = not hidden - end - end - end - if hidden then - disabled = true - elseif disabled then - if type(disabled) == "function" then - disabled = disabled(passValue) - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - disabled = handler[f](handler, passValue) - if neg then - disabled = not disabled - end - end - end - local _G_this = this - local kind = (options.type or "group"):lower() - local options_p = passTable or options - if disabled then - print(OPTION_IS_DISABLED:format(path), realOptions.cmdName or realOptions.name or self) - elseif kind == "text" then - if #args > 0 then - if (type(options.validate) == "table" and #args > 1) or (type(options.validate) ~= "table" and not options.input) then - local arg = table.concat(args, " ") - for k,v in pairs(args) do - args[k] = nil - end - args[1] = arg - end - if options.validate then - local good - if type(options.validate) == "function" then - good = options.validate(unpack(args)) - elseif type(options.validate) == "table" then - local arg = args[1] - arg = tostring(arg):lower() - for k,v in pairs(options.validate) do - if v:lower() == arg then - args[1] = type(k) == "string" and k or v - good = true - break - end - end - if not good and type((next(options.validate))) == "string" then - for k,v in pairs(options.validate) do - if type(k) == "string" and k:lower() == arg then - args[1] = k - good = true - break - end - end - end - elseif options.validate == "keybinding" then - good = keybindingValidateFunc(unpack(args)) - if good ~= false then - args[1] = good - end - else - if type(handler[options.validate]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.validate))) - end - good = handler[options.validate](handler, unpack(args)) - end - if not good then - local usage - if type(options.validate) == "table" then - if not order then - order = {} - end - for k,v in pairs(options.validate) do - table.insert(order, v) - end - usage = "{" .. table.concat(order, " || ") .. "}" - for k in pairs(order) do - order[k] = nil - end - elseif options.validate == "keybinding" then - usage = KEYBINDING_USAGE - else - usage = options.usage or "<value>" - end - print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(tostring(table.concat(args, " ")), path), realOptions.cmdName or realOptions.name or self) - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage)) - return - end - end - - local var - local multiToggle - for k in pairs(tmp) do - tmp[k] = nil - end - multiToggle = options_p.multiToggle - if not options_p.get then - elseif type(options_p.get) == "function" then - if multiToggle then - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue then - var[val] = options_p.get(passValue, val) or nil - else - var[val] = options_p.get(val) or nil - end - end - else - var = options_p.get(passValue) - end - else - if type(handler[options_p.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) - end - if multiToggle then - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue then - var[val] = handler[options_p.get](handler, passValue, val) or nil - else - var[val] = handler[options_p.get](handler, val) or nil - end - end - else - var = handler[options_p.get](handler, passValue) - end - end - - if multiToggle or var ~= args[1] then - if multiToggle then - local current = var[args[1]] - if current == nil and type(args[1]) == "string" then - for k in pairs(var) do - if type(k) == "string" and k:lower() == args[1]:lower() then - current = true - break - end - end - end - args[2] = not current - end - if type(options_p.set) == "function" then - if passValue then - options_p.set(passValue, unpack(args)) - else - options_p.set(unpack(args)) - end - else - if type(handler[options_p.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) - end - if passValue then - handler[options_p.set](handler, passValue, unpack(args)) - else - handler[options_p.set](handler, unpack(args)) - end - end - end - end - - if #args > 0 then - local var - local multiToggle - for k in pairs(tmp) do - tmp[k] = nil - end - multiToggle = options_p.multiToggle - if not options_p.get then - elseif type(options_p.get) == "function" then - if multiToggle then - var = tmp - for k,v in pairs(options_p.validate) do - local val = type(k) ~= "number" and k or v - if passValue then - var[val] = options_p.get(passValue, val) or nil - else - var[val] = options_p.get(val) or nil - end - end - else - var = options_p.get(passValue) - end - else - if type(handler[options_p.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) - end - if multiToggle then - var = tmp - for k,v in pairs(options.validate) do - local val = type(k) ~= "number" and k or v - if passValue then - var[val] = handler[options_p.get](handler, passValue, val) or nil - else - var[val] = handler[options_p.get](handler, val) or nil - end - end - else - var = handler[options_p.get](handler, passValue) - end - end - if multiToggle then - if not next(var) then - var = NONE - else - if not order then - order = {} - end - for k in pairs(var) do - if options.validate[k] then - order[#order+1] = options.validate[k] - else - for _,v in pairs(options.validate) do - if v == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then - order[#order+1] = v - break - end - end - end - end - table.sort(order, icaseSort) - var = table.concat(order, ", ") - for k in pairs(order) do - order[k] = nil - end - end - elseif type(options.validate) == "table" then - var = options.validate[var] or var - end - if options_p.get then - print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) - end - if var == args[1] then - return - end - else - printUsage(self, handler, realOptions, options, path, args, passValue) - return - end - elseif kind == "execute" then - local confirm = options.confirm - if confirm == true then - confirm = DEFAULT_CONFIRM_MESSAGE:format(options.desc or options.name or UNKNOWN or "Unknown") - end - if type(options_p.func) == "function" then - if confirm then - confirmPopup(confirm, options_p.func, passValue) - else - options_p.func(passValue) - end - else - if type(handler[options_p.func]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.func))) - end - if confirm then - confirmPopup(confirm, handler[options_p.func], handler, passValue) - else - handler[options_p.func](handler, passValue) - end - end - elseif kind == "toggle" then - local var - if type(options_p.get) == "function" then - var = options_p.get(passValue) - else - local f = options_p.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - var = handler[f](handler, passValue) - if neg then - var = not var - end - end - if type(options_p.set) == "function" then - if passValue then - options_p.set(passValue, not var) - else - options_p.set(not var) - end - else - if type(handler[options_p.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) - end - if passValue then - handler[options_p.set](handler, passValue, not var) - else - handler[options_p.set](handler, not var) - end - end - if type(options_p.get) == "function" then - var = options_p.get(passValue) - else - local f = options_p.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - var = handler[f](handler, passValue) - if neg then - var = not var - end - end - - print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), (options.map or MAP_ONOFF)[var and true or false] or NONE), realOptions.cmdName or realOptions.name or self) - elseif kind == "range" then - local arg - if #args <= 1 then - arg = args[1] - else - arg = table.concat(args, " ") - end - - if arg then - local min = options.min or 0 - local max = options.max or 1 - local good = false - if type(arg) == "number" then - if options.isPercent then - arg = arg / 100 - end - - if arg >= min and arg <= max then - good = true - end - - if good and type(options.step) == "number" and options.step > 0 then - local step = options.step - arg = math.floor((arg - min) / step + 0.5) * step + min - if arg > max then - arg = max - elseif arg < min then - arg = min - end - end - end - if not good then - local usage - local min = options.min or 0 - local max = options.max or 1 - if options.isPercent then - min, max = min * 100, max * 100 - end - local bit = "-" - if min < 0 or max < 0 then - bit = " - " - end - usage = ("(%s%s%s)"):format(min, bit, max) - print((options.error or IS_NOT_A_VALID_VALUE_FOR):format(tostring(arg), path), realOptions.cmdName or realOptions.name or self) - print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage)) - return - end - - local var - if type(options_p.get) == "function" then - var = options_p.get(passValue) - else - if type(handler[options_p.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) - end - var = handler[options_p.get](handler, passValue) - end - - if var ~= arg then - if type(options_p.set) == "function" then - if passValue then - options_p.set(passValue, arg) - else - options_p.set(arg) - end - else - if type(handler[options_p.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) - end - if passValue then - handler[options_p.set](handler, passValue, arg) - else - handler[options_p.set](handler, arg) - end - end - end - end - - if arg then - local var - if type(options_p.get) == "function" then - var = options_p.get(passValue) - else - if type(handler[options_p.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) - end - var = handler[options_p.get](handler, passValue) - end - - if var and options.isPercent then - var = tostring(var * 100) .. "%" - end - print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) - if var == arg then - return - end - else - printUsage(self, handler, realOptions, options, path, args, passValue) - return - end - elseif kind == "color" then - if #args > 0 then - local r,g,b,a - if #args == 1 then - local arg = tostring(args[1]) - if options.hasAlpha then - if arg:len() == 8 and arg:find("^%x*$") then - r,g,b,a = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255, tonumber(arg:sub(7, 8), 16) / 255 - end - else - if arg:len() == 6 and arg:find("^%x*$") then - r,g,b = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255 - end - end - elseif #args == 4 and options.hasAlpha then - local a1,a2,a3,a4 = args[1], args[2], args[3], args[4] - if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and type(a4) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 and a4 <= 1 then - r,g,b,a = a1,a2,a3,a4 - elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") and (type(a4) == "number" or a4:len() == 2) and a4:find("^%x*$") then - r,g,b,a = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255, tonumber(a4, 16) / 255 - end - elseif #args == 3 and not options.hasAlpha then - local a1,a2,a3 = args[1], args[2], args[3] - if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 then - r,g,b = a1,a2,a3 - elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") then - r,g,b = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255 - end - end - if not r then - print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(table.concat(args, ' '), path), realOptions.cmdName or realOptions.name or self) - print(("|cffffff7f%s:|r %s {0-1} {0-1} {0-1}%s"):format(USAGE, path, options.hasAlpha and " {0-1}" or "")) - return - end - - if type(options_p.set) == "function" then - if passValue then - options_p.set(passValue, r,g,b,a) - else - options_p.set(r,g,b,a) - end - else - if type(handler[options_p.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) - end - if passValue then - handler[options_p.set](handler, passValue, r,g,b,a) - else - handler[options_p.set](handler, r,g,b,a) - end - end - - local r,g,b,a - if type(options_p.get) == "function" then - r,g,b,a = options_p.get(passValue) - else - if type(handler[options_p.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) - end - r,g,b,a = handler[options_p.get](handler, passValue) - end - - local s - if type(r) == "number" and type(g) == "number" and type(b) == "number" then - if options.hasAlpha and type(a) == "number" then - s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) - else - s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(r*255, g*255, b*255, r*255, g*255, b*255) - end - else - s = NONE - end - print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), s), realOptions.cmdName or realOptions.name or self) - else - local r,g,b,a - if type(options_p.get) == "function" then - r,g,b,a = options_p.get(passValue) - else - if type(handler[options_p.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) - end - r,g,b,a = handler[options_p.get](handler, passValue) - end - - if not colorTable then - colorTable = {} - local t = colorTable - - if ColorPickerOkayButton then - local ColorPickerOkayButton_OnClick = ColorPickerOkayButton:GetScript("OnClick") - ColorPickerOkayButton:SetScript("OnClick", function() - if ColorPickerOkayButton_OnClick then - ColorPickerOkayButton_OnClick() - end - if t.active then - ColorPickerFrame.cancelFunc = nil - ColorPickerFrame.func = nil - ColorPickerFrame.opacityFunc = nil - local r,g,b,a - if t.passValue then - if type(t.get) == "function" then - r,g,b,a = t.get(t.passValue) - else - if type(t.handler[t.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get))) - end - r,g,b,a = t.handler[t.get](t.handler, t.passValue) - end - else - if type(t.get) == "function" then - r,g,b,a = t.get() - else - if type(t.handler[t.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get))) - end - r,g,b,a = t.handler[t.get](t.handler) - end - end - if r ~= t.r or g ~= t.g or b ~= t.b or (t.hasAlpha and a ~= t.a) then - local s - if type(r) == "number" and type(g) == "number" and type(b) == "number" then - if t.hasAlpha and type(a) == "number" then - s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) - else - s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(r*255, g*255, b*255, r*255, g*255, b*255) - end - else - s = NONE - end - print(t.message:format(tostring(t.name), s), t.realOptions.cmdName or t.realOptions.name or self) - end - for k,v in pairs(t) do - t[k] = nil - end - end - end) - end - else - for k,v in pairs(colorTable) do - colorTable[k] = nil - end - end - - if type(r) ~= "number" or type(g) ~= "number" or type(b) ~= "number" then - r,g,b = 1, 1, 1 - end - if type(a) ~= "number" then - a = 1 - end - local t = colorTable - t.r = r - t.g = g - t.b = b - if hasAlpha then - t.a = a - end - t.realOptions = realOptions - t.hasAlpha = options.hasAlpha - t.handler = handler - t.set = options_p.set - t.get = options_p.get - t.name = options.cmdName or options.name - t.message = options.message or IS_NOW_SET_TO - t.passValue = passValue - t.active = true - - if not colorFunc then - colorFunc = function() - local r,g,b = ColorPickerFrame:GetColorRGB() - if t.hasAlpha then - local a = 1 - OpacitySliderFrame:GetValue() - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, r,g,b,a) - else - t.set(r,g,b,a) - end - else - if type(t.handler[t.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set))) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, r,g,b,a) - else - t.handler[t.set](t.handler, r,g,b,a) - end - end - else - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, r,g,b) - else - t.set(r,g,b) - end - else - if type(t.handler[t.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set))) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, r,g,b) - else - t.handler[t.set](t.handler, r,g,b) - end - end - end - end - end - - ColorPickerFrame.func = colorFunc - ColorPickerFrame.hasOpacity = options.hasAlpha - if options.hasAlpha then - ColorPickerFrame.opacityFunc = ColorPickerFrame.func - ColorPickerFrame.opacity = 1 - a - end - ColorPickerFrame:SetColorRGB(r,g,b) - - if not colorCancelFunc then - colorCancelFunc = function() - if t.hasAlpha then - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, t.r,t.g,t.b,t.a) - else - t.set(t.r,t.g,t.b,t.a) - end - else - if type(t.handler[t.get]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get))) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b,t.a) - else - t.handler[t.set](t.handler, t.r,t.g,t.b,t.a) - end - end - else - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, t.r,t.g,t.b) - else - t.set(t.r,t.g,t.b) - end - else - if type(t.handler[t.set]) ~= "function" then - AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set))) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b) - else - t.handler[t.set](t.handler, t.r,t.g,t.b) - end - end - end - for k,v in pairs(t) do - t[k] = nil - end - ColorPickerFrame.cancelFunc = nil - ColorPickerFrame.func = nil - ColorPickerFrame.opacityFunc = nil - end - end - - ColorPickerFrame.cancelFunc = colorCancelFunc - - ShowUIPanel(ColorPickerFrame) - end - return - elseif kind == "group" then - if #args == 0 then - printUsage(self, handler, realOptions, options, path, args, passValue) - else - -- invalid argument - print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(args[1], path), realOptions.cmdName or realOptions.name or self) - end - return - end - this = _G_this - if Dewdrop then - Dewdrop:Refresh() - end -end - -local external -local tmp -function AceConsole:RegisterChatCommand(...) -- slashCommands, options, name - local slashCommands, options, name - if type((...)) == "string" then - if not tmp then - tmp = {} - else - for i in ipairs(tmp) do - tmp[i] = nil - end - end - for i = 1, select('#', ...)+1 do - local v = select(i, ...) - if type(v) == "string" then - tmp[#tmp+1] = v - else - slashCommands = tmp - options = v - name = select(i+1, ...) - break - end - end - else - slashCommands, options, name = ... - end - if type(slashCommands) ~= "table" and slashCommands ~= false then - AceConsole:error("Bad argument #2 to `RegisterChatCommand' (expected table, got %s)", type(slashCommands)) - end - if not slashCommands and type(name) ~= "string" then - AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string, got %s)", type(name)) - end - if type(options) ~= "table" and type(options) ~= "function" and options ~= nil then - AceConsole:error("Bad argument #3 to `RegisterChatCommand' (expected table, function, or nil, got %s)", type(options)) - end - if name then - if type(name) ~= "string" then - AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string or nil, got %s)", type(name)) - elseif not name:find("^%w+$") or name:upper() ~= name or name:len() == 0 then - AceConsole:error("Argument #4 must be an uppercase, letters-only string with at least 1 character") - end - end - if slashCommands then - if #slashCommands == 0 then - AceConsole:error("Argument #2 to `RegisterChatCommand' must include at least one string") - end - - for k,v in pairs(slashCommands) do - if type(k) ~= "number" then - AceConsole:error("All keys in argument #2 to `RegisterChatCommand' must be numbers") - end - if type(v) ~= "string" then - AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be strings") - elseif not v:find("^/[A-Za-z][A-Za-z0-9_]*$") then - AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be in the form of \"/word\"") - end - end - end - - if not options then - options = { - type = 'group', - args = {}, - handler = self - } - end - - if type(options) == "table" then - local err, position = validateOptions(options) - if err then - if position then - AceConsole:error(position .. ": " .. err) - else - AceConsole:error(err) - end - end - - if not options.handler then - options.handler = self - end - - if options.handler == self and options.type:lower() == "group" and self.class then - AceConsole:InjectAceOptionsTable(self, options) - end - end - - local chat - if slashCommands then - chat = slashCommands[1] - else - chat = _G["SLASH_"..name..1] - end - - local handler - if type(options) == "function" then - handler = options - for k,v in pairs(_G) do - if handler == v then - local k = k - handler = function(msg) - return _G[k](msg) - end - end - end - else - function handler(msg) - handlerFunc(self, chat, msg, options) - end - end - - if not _G.SlashCmdList then - _G.SlashCmdList = {} - end - - if not name and type(slashCommands) == "table" and type(slashCommands[1]) == "string" then - name = slashCommands[1]:gsub("%A", ""):upper() - end - - if not name then - local A = ('A'):byte() - repeat - name = string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) - until not _G.SlashCmdList[name] - end - - if slashCommands then - if _G.SlashCmdList[name] then - local i = 0 - while true do - i = i + 1 - if _G["SLASH_"..name..i] then - _G["SLASH_"..name..i] = nil - else - break - end - end - end - - local i = 0 - for _,command in ipairs(slashCommands) do - i = i + 1 - _G["SLASH_"..name..i] = command - if command:lower() ~= command then - i = i + 1 - _G["SLASH_"..name..i] = command:lower() - end - end - end - _G.SlashCmdList[name] = handler - if self ~= AceConsole and self.slashCommand == nil then - self.slashCommand = chat - end - - if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then - external(AceConsole, "AceEvent-2.0", AceLibrary("AceEvent-2.0")) - end - if AceEvent then - if not AceConsole.nextAddon then - AceConsole.nextAddon = {} - end - if type(options) == "table" then - AceConsole.nextAddon[self] = options - if not self.playerLogin then - AceConsole:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) - end - end - end - - AceConsole.registry[name] = options - - if slashCommands == tmp then - for i in ipairs(tmp) do - tmp[i] = nil - end - end -end - -function AceConsole:InjectAceOptionsTable(handler, options) - self:argCheck(handler, 2, "table") - self:argCheck(options, 3, "table") - if options.type:lower() ~= "group" then - self:error('Cannot inject into options table argument #3 if its type is not "group"') - end - if options.handler ~= nil and options.handler ~= handler then - self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") - end - options.handler = handler - local class = handler.class - if not AceLibrary:HasInstance("AceOO-2.0") or not class then - if Rock then - -- possible Rock object - for mixin in Rock:IterateObjectMixins(handler) do - if type(mixin.GetAceOptionsDataTable) == "function" then - local t = mixin:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - end - end - else - -- Ace2 object - while class and class ~= AceLibrary("AceOO-2.0").Class do - if type(class.GetAceOptionsDataTable) == "function" then - local t = class:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - local mixins = class.mixins - if mixins then - for mixin in pairs(mixins) do - if type(mixin.GetAceOptionsDataTable) == "function" then - local t = mixin:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - end - end - class = class.super - end - end - - return options -end - -function AceConsole:PLAYER_LOGIN() - self.playerLogin = true - for addon, options in pairs(self.nextAddon) do - local err, position = validateOptionsMethods(addon, options) - if err then - if position then - geterrorhandler()(tostring(addon) .. ": AceConsole: " .. position .. ": " .. err) - else - geterrorhandler()(tostring(addon) .. ": AceConsole: " .. err) - end - end - self.nextAddon[addon] = nil - end -end - -function AceConsole:TabCompleteInfo(cmdpath) - local cmd = cmdpath:match("(/%S+)") - if not cmd then - return - end - local path = cmdpath:sub(cmd:len() + 2) - for name in pairs(SlashCmdList) do --global - if AceConsole.registry[name] then - local i = 0 - while true do - i = i + 1 - local scmd = _G["SLASH_"..name..i] - if not scmd then break end - if cmd == scmd then - return name, cmd, path - end - end - end - end -end - -function external(self, major, instance) - if major == "AceEvent-2.0" then - if not AceEvent then - AceEvent = instance - - AceEvent:embed(self) - end - elseif major == "AceTab-2.0" then - instance:RegisterTabCompletion("AceConsole", "%/.*", function(t, cmdpath, pos) - local name, cmd, path = self:TabCompleteInfo(cmdpath:sub(1, pos)) - - if not self.registry[name] then - return false - else - local validArgs, _, _, handler = findTableLevel(self, self.registry[name], cmd, path or "") - if validArgs.args then - for arg, v in pairs(validArgs.args) do - local hidden = v.hidden - local handler = v.handler or handler - if hidden then - if type(hidden) == "function" then - hidden = hidden(v.passValue) - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - self:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - hidden = handler[f](handler, v.passValue) - if neg then - hidden = not hidden - end - end - end - local disabled = hidden or v.disabled - if disabled then - if type(disabled) == "function" then - disabled = disabled(v.passValue) - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - self:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) - end - disabled = handler[f](handler, v.passValue) - if neg then - disabled = not disabled - end - end - end - if not hidden and not disabled and v.type ~= "header" then - table.insert(t, (tostring(arg):gsub("%s", "-"))) - end - end - end - end - end, function(u, matches, gcs, cmdpath) - local name, cmd, path = self:TabCompleteInfo(cmdpath) - if self.registry[name] then - local validArgs, path2, argwork, handler = findTableLevel(self, self.registry[name], cmd, path) - printUsage(self, validArgs.handler or handler, self.registry[name], validArgs, path2, argwork, argwork[#argwork], not gcs or gcs ~= "", gcs) - end - end) - elseif major == "Dewdrop-2.0" then - Dewdrop = instance - end -end - -local function activate(self, oldLib, oldDeactivate) - AceConsole = self - - if oldLib then - self.registry = oldLib.registry - self.nextAddon = oldLib.nextAddon - end - - if not self.registry then - self.registry = {} - else - for name,options in pairs(self.registry) do - self:RegisterChatCommand(false, options, name) - end - end - - self:RegisterChatCommand("/reload", "/rl", "/reloadui", ReloadUI, "RELOAD") - self:RegisterChatCommand("/gm", ToggleHelpFrame, "GM") - local t = { "/print", "/echo" } - local _,_,_,enabled,loadable = GetAddOnInfo("DevTools") - if not enabled and not loadable then - table.insert(t, "/dump") - end - self:RegisterChatCommand(t, function(text) - text = text:trim():match("^(.-);*$") - local f, err = loadstring("AceLibrary('AceConsole-2.0'):PrintLiteral(" .. text .. ")") - if not f then - self:Print("|cffff0000Error:|r", err) - else - f() - end - end, "PRINT") - - self:activate(oldLib, oldDeactivate) - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceConsole, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/lib/AceConsole-2.0/AceConsole-2.0.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceConsole-2.0 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary, AceEvent-2.0, AceOO-2.0 - -AceConsole-2.0.lua
--- a/lib/AceDB-2.0/AceDB-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2187 +0,0 @@ ---[[ -Name: AceDB-2.0 -Revision: $Rev: 46764 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceDB-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceDB-2.0 -Description: Mixin to allow for fast, clean, and featureful saved variable - access. -Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0 -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceDB-2.0" -local MINOR_VERSION = "$Revision: 46764 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end - -local function safecall(func,...) - local success, err = pcall(func,...) - if not success then geterrorhandler()(err) end -end - -local ACTIVE, ENABLED, STATE, TOGGLE_ACTIVE, MAP_ACTIVESUSPENDED, SET_PROFILE, SET_PROFILE_USAGE, PROFILE, PLAYER_OF_REALM, CHOOSE_PROFILE_DESC, CHOOSE_PROFILE_GUI, COPY_PROFILE_DESC, COPY_PROFILE_GUI, OTHER_PROFILE_DESC, OTHER_PROFILE_GUI, OTHER_PROFILE_USAGE, RESET_PROFILE, RESET_PROFILE_DESC, CHARACTER_COLON, REALM_COLON, CLASS_COLON, DEFAULT, ALTERNATIVE - --- Move these into "enUS" when they've been translated in all other locales -local DELETE_PROFILE = "Delete" -local DELETE_PROFILE_DESC = "Deletes a profile. Note that no check is made whether this profile is in use by other characters or not." -local DELETE_PROFILE_USAGE = "<profile name>" - -if GetLocale() == "deDE" then - ACTIVE = "Aktiv" - ENABLED = "Aktiviert" - STATE = "Status" - TOGGLE_ACTIVE = "Stoppt/Aktiviert dieses Addon." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Aktiv|r", [false] = "|cffff0000Gestoppt|r" } - SET_PROFILE = "Setzt das Profil f\195\188r dieses Addon." - SET_PROFILE_USAGE = "{Charakter || Klasse || Realm || <Profilname>}" - PROFILE = "Profil" - PLAYER_OF_REALM = "%s von %s" - CHOOSE_PROFILE_DESC = "W\195\164hle ein Profil." - CHOOSE_PROFILE_GUI = "W\195\164hle" - COPY_PROFILE_DESC = "Kopiert Einstellungen von einem anderem Profil." - COPY_PROFILE_GUI = "Kopiere von" - OTHER_PROFILE_DESC = "W\195\164hle ein anderes Profil." - OTHER_PROFILE_GUI = "Anderes" - OTHER_PROFILE_USAGE = "<Profilname>" - RESET_PROFILE = "Reset profile" -- fix - RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix - - CHARACTER_COLON = "Charakter: " - REALM_COLON = "Realm: " - CLASS_COLON = "Klasse: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "frFR" then - ACTIVE = "Actif" - ENABLED = "Activ\195\169" - STATE = "Etat" - TOGGLE_ACTIVE = "Suspend/active cet addon." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Actif|r", [false] = "|cffff0000Suspendu|r" } - SET_PROFILE = "S\195\169lectionne le profil pour cet addon." - SET_PROFILE_USAGE = "{perso || classe || royaume || <nom de profil>}" - PROFILE = "Profil" - PLAYER_OF_REALM = "%s de %s" - CHOOSE_PROFILE_DESC = "Choisissez un profil." - CHOOSE_PROFILE_GUI = "Choix" - COPY_PROFILE_DESC = "Copier les param\195\168tres d'un autre profil." - COPY_PROFILE_GUI = "Copier \195\160 partir de" - OTHER_PROFILE_DESC = "Choisissez un autre profil." - OTHER_PROFILE_GUI = "Autre" - OTHER_PROFILE_USAGE = "<nom de profil>" - RESET_PROFILE = "Reset profile" -- fix - RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix - - CHARACTER_COLON = "Personnage: " - REALM_COLON = "Royaume: " - CLASS_COLON = "Classe: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "koKR" then - DELETE_PROFILE = "삭제" - DELETE_PROFILE_DESC = "프로필을 삭제합니다." - DELETE_PROFILE_USAGE = "<프로필명>" - - ACTIVE = "사용" - ENABLED = "사용" - STATE = "상태" - TOGGLE_ACTIVE = "이 애드온 중지/다시 시작" - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00사용|r", [false] = "|cffff0000중지|r" } - SET_PROFILE = "이 애드온에 프로필 설정" - SET_PROFILE_USAGE = "{캐릭터명 || 직업 || 서버명 || <프로필명>}" - PROFILE = "프로필" - PLAYER_OF_REALM = "%s (%s 서버)" - CHOOSE_PROFILE_DESC = "프로필을 선택합니다." - CHOOSE_PROFILE_GUI = "선택" - COPY_PROFILE_DESC = "다른 프로필 설정을 복사합니다." - COPY_PROFILE_GUI = "복사" - OTHER_PROFILE_DESC = "다른 프로필을 선택합니다." - OTHER_PROFILE_GUI = "기타" - OTHER_PROFILE_USAGE = "<프로필명>" - RESET_PROFILE = "프로필 초기화" - RESET_PROFILE_DESC = "모든 세팅에서 현재 프로필을 초기화 합니다." - - CHARACTER_COLON = "캐릭터: " - REALM_COLON = "서버: " - CLASS_COLON = "직업: " - - DEFAULT = "기본값" - ALTERNATIVE = "대체" -elseif GetLocale() == "zhTW" then - DELETE_PROFILE = "刪除" - DELETE_PROFILE_DESC = "刪除記錄檔。注意,有可能別的角色也使用這個記錄檔。" - DELETE_PROFILE_USAGE = "<記錄檔名稱>" - - ACTIVE = "啟動" - ENABLED = "啟用" - STATE = "狀態" - TOGGLE_ACTIVE = "暫停/繼續使用這個插件。" - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00啟動|r", [false] = "|cffff0000已暫停|r" } - SET_PROFILE = "設定這插件的記錄檔。" - SET_PROFILE_USAGE = "{角色 || 職業 || 伺服器 || <記錄檔名稱>}" - PROFILE = "記錄檔" - PLAYER_OF_REALM = "%s - %s" - CHOOSE_PROFILE_DESC = "選擇一個記錄檔。" - CHOOSE_PROFILE_GUI = "選擇" - COPY_PROFILE_DESC = "由其他記錄檔複製設定。" - COPY_PROFILE_GUI = "複製自" - OTHER_PROFILE_DESC = "選擇其他記錄檔。" - OTHER_PROFILE_GUI = "其他" - OTHER_PROFILE_USAGE = "<記錄檔名稱>" - RESET_PROFILE = "重設記錄檔" - RESET_PROFILE_DESC = "清除目前的記錄檔上的所有設定。" - - CHARACTER_COLON = "角色: " - REALM_COLON = "伺服器: " - CLASS_COLON = "職業: " - - DEFAULT = "預設" - ALTERNATIVE = "替代" -elseif GetLocale() == "zhCN" then - ACTIVE = "\230\156\137\230\149\136" - ENABLED = "\229\144\175\231\148\168" - STATE = "\231\138\182\230\128\129" - TOGGLE_ACTIVE = "\230\154\130\229\129\156/\230\129\162\229\164\141 \230\173\164\230\143\146\228\187\182." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00\230\156\137\230\149\136|r", [false] = "|cffff0000\230\154\130\229\129\156|r" } - SET_PROFILE = "\232\174\190\231\189\174\233\133\141\231\189\174\230\150\135\228\187\182\228\184\186\232\191\153\230\143\146\228\187\182." - SET_PROFILE_USAGE = "{\229\173\151\231\172\166 || \233\128\137\228\187\182\231\177\187 || \229\159\159 || <\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>}" - PROFILE = "\233\133\141\231\189\174\230\150\135\228\187\182" - PLAYER_OF_REALM = "%s \231\154\132 %s" - CHOOSE_PROFILE_DESC = "\233\128\137\230\139\169\233\133\141\231\189\174\230\150\135\228\187\182." - CHOOSE_PROFILE_GUI = "\233\128\137\230\139\169" - COPY_PROFILE_DESC = "\229\164\141\229\136\182\232\174\190\231\189\174\228\187\142\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182." - COPY_PROFILE_GUI = "\229\164\141\229\136\182\228\187\142" - OTHER_PROFILE_DESC = "\233\128\137\230\139\169\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182." - OTHER_PROFILE_GUI = "\229\133\182\228\187\150" - OTHER_PROFILE_USAGE = "<\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>" - RESET_PROFILE = "Reset profile" -- fix - RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix - - CHARACTER_COLON = "\229\173\151\231\172\166: " - REALM_COLON = "\229\159\159: " - CLASS_COLON = "\233\128\137\228\187\182\231\177\187: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "esES" then - ACTIVE = "Activo" - ENABLED = "Activado" - STATE = "Estado" - TOGGLE_ACTIVE = "Parar/Continuar este accesorio" - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Activo|r", [false] = "|cffff0000Parado|r" } - SET_PROFILE = "Selecciona el perfil para este accesorio." - SET_PROFILE_USAGE = "{perso || clase || reino || <nombre del perfil>}" - PROFILE = "Perfil" - PLAYER_OF_REALM = "%s de %s" - CHOOSE_PROFILE_DESC = "Elige un perfil." - CHOOSE_PROFILE_GUI = "Elige" - COPY_PROFILE_DESC = "Copiar de un perfil a otro" - COPY_PROFILE_GUI = "Copiar desde" - OTHER_PROFILE_DESC = "Elige otro perfil." - OTHER_PROFILE_GUI = "Otro" - OTHER_PROFILE_USAGE = "<nombre del perfil>" - RESET_PROFILE = "Reset profile" -- fix - RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix - - CHARACTER_COLON = "Personaje: " - REALM_COLON = "Reino: " - CLASS_COLON = "Clase: " - - DEFAULT = "Por defecto" - ALTERNATIVE = "Alternativo" -else -- enUS - ACTIVE = "Active" - ENABLED = "Enabled" - STATE = "State" - TOGGLE_ACTIVE = "Suspend/resume this addon." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" } - SET_PROFILE = "Set profile for this addon." - SET_PROFILE_USAGE = "{char || class || realm || <profile name>}" - PROFILE = "Profile" - PLAYER_OF_REALM = "%s of %s" - CHOOSE_PROFILE_DESC = "Choose a profile." - CHOOSE_PROFILE_GUI = "Choose" - COPY_PROFILE_DESC = "Copy settings from another profile." - COPY_PROFILE_GUI = "Copy from" - OTHER_PROFILE_DESC = "Choose another profile." - OTHER_PROFILE_GUI = "Other" - OTHER_PROFILE_USAGE = "<profile name>" - RESET_PROFILE = "Reset profile" - RESET_PROFILE_DESC = "Clear all settings of the current profile." - - CHARACTER_COLON = "Character: " - REALM_COLON = "Realm: " - CLASS_COLON = "Class: " - - DEFAULT = "Default" - ALTERNATIVE = "Alternative" -end -local convertFromOldCharID -do - local matchStr = "^" .. PLAYER_OF_REALM:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1"):gsub("%%s", "(.+)") .. "$" - function convertFromOldCharID(str) - local player, realm = str:match(matchStr) - if not player then - return str - end - return player .. " - " .. realm - end -end - -local AceOO = AceLibrary("AceOO-2.0") -local AceEvent -local Mixin = AceOO.Mixin -local AceDB = Mixin { - "RegisterDB", - "RegisterDefaults", - "ResetDB", - "SetProfile", - "GetProfile", - "CopyProfileFrom", - "DeleteProfile", - "ToggleActive", - "IsActive", - "AcquireDBNamespace", - } -local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0") - -local _G = getfenv(0) - -local function inheritDefaults(t, defaults) - if not defaults then - return t - end - for k,v in pairs(defaults) do - if k == "*" or k == "**" then - local v = v - if type(v) == "table" then - setmetatable(t, { - __index = function(self, key) - if key == nil then - return nil - end - self[key] = {} - inheritDefaults(self[key], v) - return self[key] - end - } ) - else - setmetatable(t, { - __index = function(self, key) - if key == nil then - return nil - end - self[key] = v - return self[key] - end - } ) - end - for key in pairs(t) do - if (defaults[key] == nil or key == k) and type(t[key]) == "table" then - inheritDefaults(t[key], v) - end - end - else - if type(v) == "table" then - if type(rawget(t, k)) ~= "table" then - t[k] = {} - end - inheritDefaults(t[k], v) - if defaults["**"] then - inheritDefaults(t[k], defaults["**"]) - end - elseif rawget(t, k) == nil then - t[k] = v - end - end - end - return t -end - -local _,race = UnitRace("player") -local faction -if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" or race == "BloodElf" then - faction = FACTION_HORDE -else - faction = FACTION_ALLIANCE -end -local server = GetRealmName():trim() -local charID = UnitName("player") .. " - " .. server -local realmID = server .. " - " .. faction -local classID = UnitClass("player") - -AceDB.CHAR_ID = charID -AceDB.REALM_ID = realmID -AceDB.CLASS_ID = classID - -AceDB.FACTION = faction -AceDB.REALM = server -AceDB.NAME = UnitName("player") - -local new, del -do - local list = setmetatable({}, {__mode="k"}) - function new() - local t = next(list) - if t then - list[t] = nil - return t - else - return {} - end - end - - function del(t) - setmetatable(t, nil) - for k in pairs(t) do - t[k] = nil - end - list[t] = true - end -end - -local caseInsensitive_mt = { - __index = function(self, key) - if type(key) ~= "string" then - return nil - end - local lowerKey = key:lower() - for k,v in pairs(self) do - if k:lower() == lowerKey then - return self[k] - end - end - end, - __newindex = function(self, key, value) - if type(key) ~= "string" then - return error("table index is nil", 2) - end - local lowerKey = key:lower() - for k in pairs(self) do - if k:lower() == lowerKey then - rawset(self, k, nil) - rawset(self, key, value) - return - end - end - rawset(self, key, value) - end -} - -local db_mt = { __index = function(db, key) - if key == "char" then - if db.charName then - if type(_G[db.charName]) ~= "table" then - _G[db.charName] = {} - end - if type(_G[db.charName].global) ~= "table" then - _G[db.charName].global = {} - end - rawset(db, 'char', _G[db.charName].global) - else - if type(db.raw.chars) ~= "table" then - db.raw.chars = {} - end - local id = charID - if type(db.raw.chars[id]) ~= "table" then - db.raw.chars[id] = {} - end - rawset(db, 'char', db.raw.chars[id]) - end - if db.defaults and db.defaults.char then - inheritDefaults(db.char, db.defaults.char) - end - return db.char - elseif key == "realm" then - if type(db.raw.realms) ~= "table" then - db.raw.realms = {} - end - local id = realmID - if type(db.raw.realms[id]) ~= "table" then - db.raw.realms[id] = {} - end - rawset(db, 'realm', db.raw.realms[id]) - if db.defaults and db.defaults.realm then - inheritDefaults(db.realm, db.defaults.realm) - end - return db.realm - elseif key == "server" then - if type(db.raw.servers) ~= "table" then - db.raw.servers = {} - end - local id = server - if type(db.raw.servers[id]) ~= "table" then - db.raw.servers[id] = {} - end - rawset(db, 'server', db.raw.servers[id]) - if db.defaults and db.defaults.server then - inheritDefaults(db.server, db.defaults.server) - end - return db.server - elseif key == "account" then - if type(db.raw.account) ~= "table" then - db.raw.account = {} - end - rawset(db, 'account', db.raw.account) - if db.defaults and db.defaults.account then - inheritDefaults(db.account, db.defaults.account) - end - return db.account - elseif key == "faction" then - if type(db.raw.factions) ~= "table" then - db.raw.factions = {} - end - local id = faction - if type(db.raw.factions[id]) ~= "table" then - db.raw.factions[id] = {} - end - rawset(db, 'faction', db.raw.factions[id]) - if db.defaults and db.defaults.faction then - inheritDefaults(db.faction, db.defaults.faction) - end - return db.faction - elseif key == "class" then - if type(db.raw.classes) ~= "table" then - db.raw.classes = {} - end - local id = classID - if type(db.raw.classes[id]) ~= "table" then - db.raw.classes[id] = {} - end - rawset(db, 'class', db.raw.classes[id]) - if db.defaults and db.defaults.class then - inheritDefaults(db.class, db.defaults.class) - end - return db.class - elseif key == "profile" then - if type(db.raw.profiles) ~= "table" then - db.raw.profiles = setmetatable({}, caseInsensitive_mt) - else - setmetatable(db.raw.profiles, caseInsensitive_mt) - end - local id = db.raw.currentProfile[charID] - if id == "char" then - id = "char/" .. charID - elseif id == "class" then - id = "class/" .. classID - elseif id == "realm" then - id = "realm/" .. realmID - end - if type(db.raw.profiles[id]) ~= "table" then - db.raw.profiles[id] = {} - end - rawset(db, 'profile', db.raw.profiles[id]) - if db.defaults and db.defaults.profile then - inheritDefaults(db.profile, db.defaults.profile) - end - return db.profile - elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then - return nil - end - error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) -end, __newindex = function(db, key, value) - error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) -end } - -local function RecalculateAceDBCopyFromList(target) - local db = target.db - local t = target['acedb-profile-copylist'] - for k,v in pairs(t) do - t[k] = nil - end - local _,currentProfile = AceDB.GetProfile(target) - if db and db.raw then - if db.raw.profiles then - for k in pairs(db.raw.profiles) do - if currentProfile ~= k then - if k:find("^char/") then - local name = k:sub(6) - local player, realm = name:match("^(.*) %- (.*)$") - if player then - name = PLAYER_OF_REALM:format(player, realm) - end - t[k] = CHARACTER_COLON .. name - elseif k:find("^realm/") then - local name = k:sub(7) - t[k] = REALM_COLON .. name - elseif k:find("^class/") then - local name = k:sub(7) - t[k] = CLASS_COLON .. name - else - t[k] = k - end - end - end - end - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles then - for k in pairs(n.profiles) do - if currentProfile ~= k then - if k:find('^char/') then - local name = k:sub(6) - local player, realm = name:match("^(.*) %- (.*)$") - if player then - name = PLAYER_OF_REALM:format(player, realm) - end - t[k] = CHARACTER_COLON .. name - elseif k:find('^realm/') then - local name = k:sub(7) - t[k] = REALM_COLON .. name - elseif k:find('^class/') then - local name = k:sub(7) - t[k] = CLASS_COLON .. name - else - t[k] = k - end - end - end - end - end - end - end - if t.Default then - t.Default = DEFAULT - end - if t.Alternative then - t.Alternative = ALTERNATIVE - end -end - -local function RecalculateAceDBProfileList(target) - local t = target['acedb-profile-list'] - for k,v in pairs(t) do - t[k] = nil - end - t.char = CHARACTER_COLON .. PLAYER_OF_REALM:format(UnitName("player"), server) - t.realm = REALM_COLON .. realmID - t.class = CLASS_COLON .. classID - t.Default = DEFAULT - local db = target.db - if db and db.raw then - if db.raw.profiles then - for k in pairs(db.raw.profiles) do - if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then - t[k] = k - end - end - end - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles then - for k in pairs(n.profiles) do - if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then - t[k] = k - end - end - end - end - end - local curr = db.raw.currentProfile and db.raw.currentProfile[charID] - if curr and not t[curr] then - t[curr] = curr - end - end - if t.Alternative then - t.Alternative = ALTERNATIVE - end -end - -local CrawlForSerialization -local CrawlForDeserialization - -local function SerializeObject(o) - local t = { o:Serialize() } - CrawlForSerialization(t) - t[0] = o.class:GetLibraryVersion() - return t -end - -local function DeserializeObject(t) - CrawlForDeserialization(t) - local className = t[0] - t[0] = nil - return AceLibrary(className):Deserialize(unpack(t)) -end - -local function IsSerializable(t) - return AceOO.inherits(t, AceOO.Class) and t.class and type(t.class.Deserialize) == "function" and type(t.Serialize) == "function" and type(t.class.GetLibraryVersion) == "function" -end - -function CrawlForSerialization(t) - local tmp = new() - for k,v in pairs(t) do - tmp[k] = v - end - for k,v in pairs(tmp) do - if type(v) == "table" and type(rawget(v, 0)) ~= "userdata" then - if IsSerializable(v) then - v = SerializeObject(v) - t[k] = v - else - CrawlForSerialization(v) - end - end - if type(k) == "table" and type(rawget(k, 0)) ~= "userdata" then - if IsSerializable(k) then - t[k] = nil - t[SerializeObject(k)] = v - else - CrawlForSerialization(k) - end - end - tmp[k] = nil - k = nil - end - tmp = del(tmp) -end - -local function IsDeserializable(t) - return type(rawget(t, 0)) == "string" and AceLibrary:HasInstance(rawget(t, 0)) -end - -function CrawlForDeserialization(t) - local tmp = new() - for k,v in pairs(t) do - tmp[k] = v - end - for k,v in pairs(tmp) do - if type(v) == "table" then - if IsDeserializable(v) then - t[k] = DeserializeObject(v) - del(v) - v = t[k] - elseif type(rawget(v, 0)) ~= "userdata" then - CrawlForDeserialization(v) - end - end - if type(k) == "table" then - if IsDeserializable(k) then - t[k] = nil - t[DeserializeObject(k)] = v - del(k) - elseif type(rawget(k, 0)) ~= "userdata" then - CrawlForDeserialization(k) - end - end - tmp[k] = nil - k = nil - end - tmp = del(tmp) -end - -local namespace_mt = { __index = function(namespace, key) - local db = namespace.db - local name = namespace.name - if key == "char" then - if db.charName then - if type(_G[db.charName]) ~= "table" then - _G[db.charName] = {} - end - if type(_G[db.charName].namespaces) ~= "table" then - _G[db.charName].namespaces = {} - end - if type(_G[db.charName].namespaces[name]) ~= "table" then - _G[db.charName].namespaces[name] = {} - end - rawset(namespace, 'char', _G[db.charName].namespaces[name]) - else - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].chars) ~= "table" then - db.raw.namespaces[name].chars = {} - end - local id = charID - if type(db.raw.namespaces[name].chars[id]) ~= "table" then - db.raw.namespaces[name].chars[id] = {} - end - rawset(namespace, 'char', db.raw.namespaces[name].chars[id]) - end - if namespace.defaults and namespace.defaults.char then - inheritDefaults(namespace.char, namespace.defaults.char) - end - return namespace.char - elseif key == "realm" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].realms) ~= "table" then - db.raw.namespaces[name].realms = {} - end - local id = realmID - if type(db.raw.namespaces[name].realms[id]) ~= "table" then - db.raw.namespaces[name].realms[id] = {} - end - rawset(namespace, 'realm', db.raw.namespaces[name].realms[id]) - if namespace.defaults and namespace.defaults.realm then - inheritDefaults(namespace.realm, namespace.defaults.realm) - end - return namespace.realm - elseif key == "server" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].servers) ~= "table" then - db.raw.namespaces[name].servers = {} - end - local id = server - if type(db.raw.namespaces[name].servers[id]) ~= "table" then - db.raw.namespaces[name].servers[id] = {} - end - rawset(namespace, 'server', db.raw.namespaces[name].servers[id]) - if namespace.defaults and namespace.defaults.server then - inheritDefaults(namespace.server, namespace.defaults.server) - end - return namespace.server - elseif key == "account" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].account) ~= "table" then - db.raw.namespaces[name].account = {} - end - rawset(namespace, 'account', db.raw.namespaces[name].account) - if namespace.defaults and namespace.defaults.account then - inheritDefaults(namespace.account, namespace.defaults.account) - end - return namespace.account - elseif key == "faction" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].factions) ~= "table" then - db.raw.namespaces[name].factions = {} - end - local id = faction - if type(db.raw.namespaces[name].factions[id]) ~= "table" then - db.raw.namespaces[name].factions[id] = {} - end - rawset(namespace, 'faction', db.raw.namespaces[name].factions[id]) - if namespace.defaults and namespace.defaults.faction then - inheritDefaults(namespace.faction, namespace.defaults.faction) - end - return namespace.faction - elseif key == "class" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].classes) ~= "table" then - db.raw.namespaces[name].classes = {} - end - local id = classID - if type(db.raw.namespaces[name].classes[id]) ~= "table" then - db.raw.namespaces[name].classes[id] = {} - end - rawset(namespace, 'class', db.raw.namespaces[name].classes[id]) - if namespace.defaults and namespace.defaults.class then - inheritDefaults(namespace.class, namespace.defaults.class) - end - return namespace.class - elseif key == "profile" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].profiles) ~= "table" then - db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt) - else - setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt) - end - local id = db.raw.currentProfile[charID] - if id == "char" then - id = "char/" .. charID - elseif id == "class" then - id = "class/" .. classID - elseif id == "realm" then - id = "realm/" .. realmID - end - if type(db.raw.namespaces[name].profiles[id]) ~= "table" then - db.raw.namespaces[name].profiles[id] = {} - end - rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id]) - if namespace.defaults and namespace.defaults.profile then - inheritDefaults(namespace.profile, namespace.defaults.profile) - end - return namespace.profile - elseif key == "defaults" or key == "name" or key == "db" then - return nil - end - error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) -end, __newindex = function(db, key, value) - error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) -end } - -local tmp = {} -function AceDB:InitializeDB(addonName) - local db = self.db - - if not db then - if addonName then - AceDB.addonsLoaded[addonName] = true - end - return - end - - if db.raw then - -- someone manually initialized - return - end - - if type(_G[db.name]) ~= "table" then - _G[db.name] = {} - else - CrawlForDeserialization(_G[db.name]) - end - if db.charName then - if type(_G[db.charName]) ~= "table" then - _G[db.charName] = {} - else - CrawlForDeserialization(_G[db.charName]) - end - end - rawset(db, 'raw', _G[db.name]) - if not db.raw.currentProfile then - db.raw.currentProfile = {} - else - for k,v in pairs(db.raw.currentProfile) do - tmp[convertFromOldCharID(k)] = v - db.raw.currentProfile[k] = nil - end - for k,v in pairs(tmp) do - db.raw.currentProfile[k] = v - tmp[k] = nil - end - end - if not db.raw.currentProfile[charID] then - db.raw.currentProfile[charID] = AceDB.registry[self] or "Default" - end - if db.raw.profiles then - for k,v in pairs(db.raw.profiles) do - local new_k = k - if k:find("^char/") then - new_k = "char/" .. convertFromOldCharID(k:sub(6)) - end - tmp[new_k] = v - db.raw.profiles[k] = nil - end - for k,v in pairs(tmp) do - db.raw.profiles[k] = v - tmp[k] = nil - end - end - if db.raw.disabledModules then -- AceModuleCore-2.0 - for k,v in pairs(db.raw.disabledModules) do - local new_k = k - if k:find("^char/") then - new_k = "char/" .. convertFromOldCharID(k:sub(6)) - end - tmp[new_k] = v - db.raw.disabledModules[k] = nil - end - for k,v in pairs(tmp) do - db.raw.disabledModules[k] = v - tmp[k] = nil - end - end - if db.raw.chars then - for k,v in pairs(db.raw.chars) do - tmp[convertFromOldCharID(k)] = v - db.raw.chars[k] = nil - end - for k,v in pairs(tmp) do - db.raw.chars[k] = v - tmp[k] = nil - end - end - if db.raw.namespaces then - for l,u in pairs(db.raw.namespaces) do - if u.chars then - for k,v in pairs(u.chars) do - tmp[convertFromOldCharID(k)] = v - u.chars[k] = nil - end - for k,v in pairs(tmp) do - u.chars[k] = v - tmp[k] = nil - end - end - end - end - if db.raw.disabled then - setmetatable(db.raw.disabled, caseInsensitive_mt) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - setmetatable(db, db_mt) -end - -function AceDB:OnEmbedInitialize(target, name) - if name then - self:ADDON_LOADED(name) - end - self.InitializeDB(target, name) -end - -function AceDB:RegisterDB(name, charName, defaultProfile) - AceDB:argCheck(name, 2, "string") - AceDB:argCheck(charName, 3, "string", "nil") - AceDB:argCheck(defaultProfile, 4, "string", "nil") - if self.db then - AceDB:error("Cannot call \"RegisterDB\" if self.db is set.") - end - local stack = debugstack() - local addonName = stack:gsub(".-\n.-\\AddOns\\(.-)\\.*", "%1") - self.db = { - name = name, - charName = charName - } - AceDB.registry[self] = defaultProfile or "Default" - if AceDB.addonsLoaded[addonName] then - AceDB.InitializeDB(self, addonName) - else - AceDB.addonsToBeInitialized[self] = addonName - end -end - -function AceDB:RegisterDefaults(kind, defaults, a3) - local name - if a3 then - name, kind, defaults = kind, defaults, a3 - AceDB:argCheck(name, 2, "string") - AceDB:argCheck(kind, 3, "string") - AceDB:argCheck(defaults, 4, "table") - else - AceDB:argCheck(kind, 2, "string") - AceDB:argCheck(defaults, 3, "table") - end - if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then - AceDB:error("Bad argument #%d to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", \"realm\", \"server\", or \"faction\" expected, got %q)", a3 and 3 or 2, kind) - end - if type(self.db) ~= "table" or type(self.db.name) ~= "string" then - AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.") - end - local db - if name then - local namespace = self:AcquireDBNamespace(name) - if namespace.defaults and namespace.defaults[kind] then - AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind) - end - db = namespace - else - if self.db.defaults and self.db.defaults[kind] then - AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind) - end - db = self.db - end - if not db.defaults then - rawset(db, 'defaults', {}) - end - db.defaults[kind] = defaults - if rawget(db, kind) then - inheritDefaults(db[kind], defaults) - end -end - -function AceDB:ResetDB(kind, a2) - local name - if a2 then - name, kind = kind, a2 - AceDB:argCheck(name, 2, "nil", "string") - AceDB:argCheck(kind, 3, "nil", "string") - else - AceDB:argCheck(kind, 2, "nil", "string") - if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then - name, kind = kind, nil - end - end - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - if not kind then - if not name then - if db.charName then - _G[db.charName] = nil - end - _G[db.name] = nil - rawset(db, 'raw', nil) - AceDB.InitializeDB(self) - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'account', nil) - rawset(v, 'char', nil) - rawset(v, 'class', nil) - rawset(v, 'profile', nil) - rawset(v, 'realm', nil) - rawset(v, 'server', nil) - rawset(v, 'faction', nil) - end - end - else - if db.raw.namespaces then - db.raw.namespaces[name] = nil - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'account', nil) - rawset(v, 'char', nil) - rawset(v, 'class', nil) - rawset(v, 'profile', nil) - rawset(v, 'realm', nil) - rawset(v, 'server', nil) - rawset(v, 'faction', nil) - end - end - end - elseif kind == "account" then - if name then - db.raw.account = nil - rawset(db, 'account', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - v.account = nil - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'account', nil) - end - end - else - if db.raw.namespaces and db.raw.namespaces[name] then - db.raw.namespaces[name].account = nil - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'account', nil) - end - end - end - elseif kind == "char" then - if name then - if db.charName then - _G[db.charName] = nil - else - if db.raw.chars then - db.raw.chars[charID] = nil - end - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.chars then - v.chars[charID] = nil - end - end - end - end - rawset(db, 'char', nil) - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'char', nil) - end - end - else - if db.charName then - local x = _G[db.charName] - if x.namespaces then - x.namespaces[name] = nil - end - else - if db.raw.namespaces then - local v = db.namespaces[name] - if v and v.chars then - v.chars[charID] = nil - end - end - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'char', nil) - end - end - end - elseif kind == "realm" then - if not name then - if db.raw.realms then - db.raw.realms[realmID] = nil - end - rawset(db, 'realm', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.realms then - v.realms[realmID] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'realm', nil) - end - end - else - if db.raw.namespaces then - local v = db.raw.namespaces[name] - if v and v.realms then - v.realms[realmID] = nil - end - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'realm', nil) - end - end - end - elseif kind == "server" then - if not name then - if db.raw.servers then - db.raw.servers[server] = nil - end - rawset(db, 'server', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.servers then - v.servers[server] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'server', nil) - end - end - else - if db.raw.namespaces then - local v = db.raw.namespaces[name] - if v and v.servers then - v.servers[server] = nil - end - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'server', nil) - end - end - end - elseif kind == "faction" then - if not name then - if db.raw.factions then - db.raw.factions[faction] = nil - end - rawset(db, 'faction', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.factions then - v.factions[faction] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'faction', nil) - end - end - else - if db.raw.namespaces then - local v = db.raw.namespaces[name] - if v and v.factions then - v.factions[faction] = nil - end - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'faction', nil) - end - end - end - elseif kind == "class" then - if not name then - if db.raw.realms then - db.raw.realms[classID] = nil - end - rawset(db, 'class', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.classes then - v.classes[classID] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'class', nil) - end - end - else - if db.raw.namespaces then - local v = db.raw.namespaces[name] - if v and v.classes then - v.classes[classID] = nil - end - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'class', nil) - end - end - end - elseif kind == "profile" then - local id = db.raw.currentProfile and db.raw.currentProfile[charID] or AceDB.registry[self] or "Default" - if id == "char" then - id = "char/" .. charID - elseif id == "class" then - id = "class/" .. classID - elseif id == "realm" then - id = "realm/" .. realmID - end - - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileDisable) == "function" then - safecall(mixin.OnEmbedProfileDisable, mixin, self, id) - end - end - end - current = current.super - end - if type(self.OnProfileDisable) == "function" then - safecall(self.OnProfileDisable, self, id) - end - local active = self:IsActive() - - if not name then - if db.raw.profiles then - db.raw.profiles[id] = nil - end - rawset(db, 'profile', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.profiles then - v.profiles[id] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'profile', nil) - end - end - else - if db.raw.namespaces then - local v = db.raw.namespaces[name] - if v and v.profiles then - v.profiles[id] = nil - end - end - if db.namespaces then - local v = db.namespaces[name] - if v then - rawset(v, 'profile', nil) - end - end - end - - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileEnable) == "function" then - safecall(mixin.OnEmbedProfileEnable, mixin, self, id) - end - end - end - current = current.super - end - if type(self.OnProfileEnable) == "function" then - safecall(self.OnProfileEnable, self, id) - end - local newactive = self:IsActive() - if active ~= newactive then - if newactive then - local first = nil - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then - AceAddon.addonsEnabled[self] = true - first = true - end - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self, first) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self, first) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - end - else - return -- skip event - end - if AceEvent then - AceEvent:TriggerEvent("AceDB20_ResetDB", self, self.db.name, kind) - end -end - -local function cleanDefaults(t, defaults, blocker) - if defaults then - for k,v in pairs(t) do - if (not blocker or (blocker[k] == nil and blocker['*'] == nil and blocker['**'] == nil)) and (defaults[k] ~= nil or defaults['*'] ~= nil or defaults['**'] ~= nil) then - local u = defaults[k] - if u == nil then - u = defaults['*'] - if u == nil then - u = defaults['**'] - end - end - if v == u then - t[k] = nil - elseif type(v) == "table" and type(u) == "table" then - if cleanDefaults(v, u) then - t[k] = nil - else - local w = defaults['**'] - if w ~= u then - if cleanDefaults(v, w, u) then - t[k] = nil - end - end - end - end - end - end - end - return t and next(t) == nil -end - -function AceDB:GetProfile() - if not self.db or not self.db.raw then - return nil - end - if not self.db.raw.currentProfile then - self.db.raw.currentProfile = {} - end - if not self.db.raw.currentProfile[charID] then - self.db.raw.currentProfile[charID] = AceDB.registry[self] or "Default" - end - local profile = self.db.raw.currentProfile[charID] - if profile == "char" then - return "char", "char/" .. charID - elseif profile == "class" then - return "class", "class/" .. classID - elseif profile == "realm" then - return "realm", "realm/" .. realmID - end - return profile, profile -end - -local function copyTable(to, from) - setmetatable(to, nil) - for k,v in pairs(from) do - if type(k) == "table" then - k = copyTable({}, k) - end - if type(v) == "table" then - v = copyTable({}, v) - end - to[k] = v - end - setmetatable(to, from) - return to -end - -function AceDB:SetProfile(name) - AceDB:argCheck(name, 2, "string") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - local lowerName = name:lower() - if lowerName:find("^char/") or lowerName:find("^realm/") or lowerName:find("^class/") then - if lowerName:find("^char/") then - name = "char" - else - name = lowerName:sub(1, 5) - end - lowerName = name:lower() - end - local oldName = db.raw.currentProfile[charID] - if oldName:lower() == name:lower() then - return - end - local oldProfileData = db.profile - local realName = name - if lowerName == "char" then - realName = name .. "/" .. charID - elseif lowerName == "realm" then - realName = name .. "/" .. realmID - elseif lowerName == "class" then - realName = name .. "/" .. classID - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileDisable) == "function" then - safecall(mixin.OnEmbedProfileDisable, mixin, self, realName) - end - end - end - current = current.super - end - if type(self.OnProfileDisable) == "function" then - safecall(self.OnProfileDisable, self, realName) - end - local active = self:IsActive() - db.raw.currentProfile[charID] = name - rawset(db, 'profile', nil) - if db.namespaces then - for k,v in pairs(db.namespaces) do - rawset(v, 'profile', nil) - end - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileEnable) == "function" then - safecall(mixin.OnEmbedProfileEnable, mixin, self, oldName, oldProfileData) - end - end - end - current = current.super - end - if type(self.OnProfileEnable) == "function" then - safecall(self.OnProfileEnable, self, oldName, oldProfileData) - end - if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then - db.raw.profiles[oldName] = nil - if not next(db.raw.profiles) then - db.raw.profiles = nil - end - end - local newactive = self:IsActive() - if active ~= newactive then - local first = nil - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then - first = true - end - end - if newactive then - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self, first) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self, first) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - end - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - if Dewdrop then - Dewdrop:Refresh() - end -end - -function AceDB:CopyProfileFrom(copyFrom) - AceDB:argCheck(copyFrom, 2, "string") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"CopyProfileFrom\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - local lowerCopyFrom = copyFrom:lower() - if not db.raw.profiles or not db.raw.profiles[copyFrom] then - local good = false - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles and n.profiles[copyFrom] then - good = true - break - end - end - end - if not good then - AceDB:error("Cannot copy from profile %q, it does not exist.", copyFrom) - end - end - local currentProfile = db.raw.currentProfile[charID] - if currentProfile:lower() == lowerCopyFrom then - AceDB:error("Cannot copy from profile %q, it is currently in use.", copyFrom) - end - local oldProfileData = db.profile - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileDisable) == "function" then - safecall(mixin.OnEmbedProfileDisable, mixin, self, currentProfile) - end - end - end - current = current.super - end - if type(self.OnProfileDisable) == "function" then - safecall(self.OnProfileDisable, self, realName) - end - local active = self:IsActive() - for k,v in pairs(db.profile) do - db.profile[k] = nil - end - if db.raw.profiles[copyFrom] then - copyTable(db.profile, db.raw.profiles[copyFrom]) - end - inheritDefaults(db.profile, db.defaults and db.defaults.profile) - if db.namespaces then - for l,u in pairs(db.namespaces) do - for k,v in pairs(u.profile) do - u.profile[k] = nil - end - if db.raw.namespaces[l].profiles[copyFrom] then - copyTable(u.profile, db.raw.namespaces[l].profiles[copyFrom]) - end - inheritDefaults(u.profile, u.defaults and u.defaults.profile) - end - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileEnable) == "function" then - safecall(mixin.OnEmbedProfileEnable, mixin, self, copyFrom, oldProfileData, copyFrom) - end - end - end - current = current.super - end - if type(self.OnProfileEnable) == "function" then - safecall(self.OnProfileEnable, self, copyFrom, oldProfileData, copyFrom) - end - local newactive = self:IsActive() - if active ~= newactive then - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - end - if newactive then - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - end - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - if Dewdrop then - Dewdrop:Refresh() - end -end - -function AceDB:DeleteProfile(profile, noconfirm) - AceDB:argCheck(profile , 2, "string") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"DeleteProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - - local currentProfile = db.raw.currentProfile[charID] - if currentProfile:lower() == profile:lower() then - AceDB:error("Cannot delete profile %q, it is currently in use.", profile) - end - - if not (noconfirm or IsShiftKeyDown()) then - if not StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] then - StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] = {} - end - local t = StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] - t.text = format("%s: %s?", DELETE_PROFILE, profile) - t.button1 = DELETE_PROFILE - t.button2 = CANCEL or "Cancel" - t.OnAccept = function() - self:DeleteProfile(profile, true) - end - t.timeout = 0 - t.whileDead = 1 - t.hideOnEscape = 1 - - StaticPopup_Show("ACEDB20_CONFIRM_DELETE_DIALOG") - return; - end - - local good = false - if db.raw.profiles and db.raw.profiles[profile] then - good = true; - db.raw.profiles[profile] = nil; - end - - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles and n.profiles[profile] then - n.profiles[profile] = nil; - good = true - end - end - end - - if not good then - AceDB:error("Cannot delete profile %q, it does not exist.", profile) - end - - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - - if Dewdrop then - Dewdrop:Refresh() - end -end - -function AceDB:IsActive() - return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]] -end - -function AceDB:ToggleActive(state) - AceDB:argCheck(state, 2, "boolean", "nil") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - if not db.raw.disabled then - db.raw.disabled = setmetatable({}, caseInsensitive_mt) - end - local profile = db.raw.currentProfile[charID] - local disable - if state == nil then - disable = not db.raw.disabled[profile] - else - disable = not state - if disable == db.raw.disabled[profile] then - return - end - end - db.raw.disabled[profile] = disable or nil - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - end - if not disable then - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - return not disable -end - -function AceDB:embed(target) - self.super.embed(self, target) - if not AceEvent then - AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0") - end -end - -function AceDB:ADDON_LOADED(name) - AceDB.addonsLoaded[name] = true - for addon, addonName in pairs(AceDB.addonsToBeInitialized) do - if name == addonName then - AceDB.InitializeDB(addon, name) - AceDB.addonsToBeInitialized[addon] = nil - end - end -end - -function AceDB:PLAYER_LOGOUT() - for addon, defaultProfile in pairs(AceDB.registry) do - local db = addon.db - if db then - if type(addon.OnDatabaseCleanup) == "function" then - safecall(addon.OnDatabaseCleanup, addon) - end - setmetatable(db, nil) - CrawlForSerialization(db.raw) - if type(_G[db.charName]) == "table" then - CrawlForSerialization(_G[db.charName]) - end - if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then - if db.charName and _G[db.charName] and _G[db.charName].global == db.char then - _G[db.charName].global = nil - if not next(_G[db.charName]) then - _G[db.charName] = nil - end - else - if db.raw.chars then - db.raw.chars[charID] = nil - if not next(db.raw.chars) then - db.raw.chars = nil - end - end - end - end - if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then - if db.raw.realms then - db.raw.realms[realmID] = nil - if not next(db.raw.realms) then - db.raw.realms = nil - end - end - end - if db.server and cleanDefaults(db.server, db.defaults and db.defaults.server) then - if db.raw.servers then - db.raw.servers[server] = nil - if not next(db.raw.servers) then - db.raw.servers = nil - end - end - end - if db.faction and cleanDefaults(db.faction, db.defaults and db.defaults.faction) then - if db.raw.factions then - db.raw.factions[faction] = nil - if not next(db.raw.factions) then - db.raw.factions = nil - end - end - end - if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then - if db.raw.classes then - db.raw.classes[classID] = nil - if not next(db.raw.classes) then - db.raw.classes = nil - end - end - end - if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then - db.raw.account = nil - end - if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then - if db.raw.profiles then - db.raw.profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil - if not next(db.raw.profiles) then - db.raw.profiles = nil - end - end - end - if db.namespaces and db.raw.namespaces then - for name,v in pairs(db.namespaces) do - if db.raw.namespaces[name] then - setmetatable(v, nil) - if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then - if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then - _G[db.charName].namespaces[name] = nil - if not next(_G[db.charName].namespaces) then - _G[db.charName].namespaces = nil - if not next(_G[db.charName]) then - _G[db.charName] = nil - end - end - else - if db.raw.namespaces[name].chars then - db.raw.namespaces[name].chars[charID] = nil - if not next(db.raw.namespaces[name].chars) then - db.raw.namespaces[name].chars = nil - end - end - end - end - if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then - if db.raw.namespaces[name].realms then - db.raw.namespaces[name].realms[realmID] = nil - if not next(db.raw.namespaces[name].realms) then - db.raw.namespaces[name].realms = nil - end - end - end - if v.server and cleanDefaults(v.server, v.defaults and v.defaults.server) then - if db.raw.namespaces[name].servers then - db.raw.namespaces[name].servers[server] = nil - if not next(db.raw.namespaces[name].servers) then - db.raw.namespaces[name].servers = nil - end - end - end - if v.faction and cleanDefaults(v.faction, v.defaults and v.defaults.faction) then - if db.raw.namespaces[name].factions then - db.raw.namespaces[name].factions[faction] = nil - if not next(db.raw.namespaces[name].factions) then - db.raw.namespaces[name].factions = nil - end - end - end - if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then - if db.raw.namespaces[name].classes then - db.raw.namespaces[name].classes[classID] = nil - if not next(db.raw.namespaces[name].classes) then - db.raw.namespaces[name].classes = nil - end - end - end - if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then - db.raw.namespaces[name].account = nil - end - if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then - if db.raw.namespaces[name].profiles then - db.raw.namespaces[name].profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil - if not next(db.raw.namespaces[name].profiles) then - db.raw.namespaces[name].profiles = nil - end - end - end - if not next(db.raw.namespaces[name]) then - db.raw.namespaces[name] = nil - end - end - end - if not next(db.raw.namespaces) then - db.raw.namespaces = nil - end - end - if db.raw.disabled and not next(db.raw.disabled) then - db.raw.disabled = nil - end - if db.raw.currentProfile then - for k,v in pairs(db.raw.currentProfile) do - if v:lower() == (defaultProfile or "Default"):lower() then - db.raw.currentProfile[k] = nil - end - end - if not next(db.raw.currentProfile) then - db.raw.currentProfile = nil - end - end - if _G[db.name] and not next(_G[db.name]) then - _G[db.name] = nil - end - end - end -end - -function AceDB:AcquireDBNamespace(name) - AceDB:argCheck(name, 2, "string") - local db = self.db - if not db then - AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2) - end - if not db.namespaces then - rawset(db, 'namespaces', {}) - end - if not db.namespaces[name] then - local namespace = {} - db.namespaces[name] = namespace - namespace.db = db - namespace.name = name - setmetatable(namespace, namespace_mt) - end - return db.namespaces[name] -end - -function AceDB:GetAceOptionsDataTable(target) - if not target['acedb-profile-list'] then - target['acedb-profile-list'] = setmetatable({}, caseInsensitive_mt) - RecalculateAceDBProfileList(target) - end - if not target['acedb-profile-copylist'] then - target['acedb-profile-copylist'] = setmetatable({}, caseInsensitive_mt) - RecalculateAceDBCopyFromList(target) - end - return { - standby = { - cmdName = STATE, - guiName = ENABLED, - name = ACTIVE, - desc = TOGGLE_ACTIVE, - type = "toggle", - get = "IsActive", - set = "ToggleActive", - map = MAP_ACTIVESUSPENDED, - order = -3, - }, - profile = { - type = 'group', - name = PROFILE, - desc = SET_PROFILE, - order = -3.5, - get = "GetProfile", - args = { - choose = { - guiName = CHOOSE_PROFILE_GUI, - cmdName = PROFILE, - desc = CHOOSE_PROFILE_DESC, - type = 'text', - get = "GetProfile", - set = "SetProfile", - validate = target['acedb-profile-list'] - }, - copy = { - guiName = COPY_PROFILE_GUI, - cmdName = PROFILE, - desc = COPY_PROFILE_DESC, - type = 'text', - get = false, - set = "CopyProfileFrom", - validate = target['acedb-profile-copylist'], - disabled = function() - return not next(target['acedb-profile-copylist']) - end, - }, - other = { - guiName = OTHER_PROFILE_GUI, - cmdName = PROFILE, - desc = OTHER_PROFILE_DESC, - usage = OTHER_PROFILE_USAGE, - type = 'text', - get = "GetProfile", - set = "SetProfile", - }, - delete = { - name = DELETE_PROFILE, - desc = DELETE_PROFILE_DESC, - usage = DELETE_PROFILE_USAGE, - type = 'text', - set = "DeleteProfile", - get = false, - validate = target['acedb-profile-copylist'], - disabled = function() - return not next(target['acedb-profile-copylist']) - end, - }, - reset = { - name = RESET_PROFILE, - desc = RESET_PROFILE_DESC, - type = 'execute', - func = function() - target:ResetDB('profile') - end, - confirm = true, - } - } - }, - } -end - -local function activate(self, oldLib, oldDeactivate) - AceDB = self - AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0") - - self.addonsToBeInitialized = oldLib and oldLib.addonsToBeInitialized or {} - self.addonsLoaded = oldLib and oldLib.addonsLoaded or {} - self.registry = oldLib and oldLib.registry or {} - for k, v in pairs(self.registry) do - if v == true then - self.registry[k] = "Default" - end - end - - self:activate(oldLib, oldDeactivate) - - for t in pairs(self.embedList) do - if t.db then - rawset(t.db, 'char', nil) - rawset(t.db, 'realm', nil) - rawset(t.db, 'class', nil) - rawset(t.db, 'account', nil) - rawset(t.db, 'server', nil) - rawset(t.db, 'faction', nil) - rawset(t.db, 'profile', nil) - setmetatable(t.db, db_mt) - end - end - - if oldLib then - oldDeactivate(oldLib) - end -end - -local function external(self, major, instance) - if major == "AceEvent-2.0" then - AceEvent = instance - - AceEvent:embed(self) - - self:RegisterEvent("ADDON_LOADED") - self:RegisterEvent("PLAYER_LOGOUT") - elseif major == "Dewdrop-2.0" then - Dewdrop = instance - end -end - -AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) -AceDB = AceLibrary(MAJOR_VERSION)
--- a/lib/AceDB-2.0/AceDB-2.0.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceDB-2.0 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary, AceEvent-2.0, AceOO-2.0 - -AceDB-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceDB-3.0/AceDB-3.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,623 @@ +--[[ $Id: AceDB-3.0.lua 63886 2008-03-08 12:43:31Z nevcairiel $ ]] +local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 5 +local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR) + +if not AceDB then return end -- No upgrade needed + +local type = type +local pairs, next = pairs, next +local rawget, rawset = rawget, rawset +local setmetatable = setmetatable + +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,k) + if k == nil then return nil end + local tbl = {} + copyDefaults(tbl, v) + rawset(t, k, 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,k) return k~=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) + 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 then + removeDefaults(value, v) + -- if the table is empty afterwards, remove it + if not next(value) 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 not next(db[k]) 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 + -- remove all metatables from the db + setmetatable(db, nil) +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 +-- Actual database initialization function +local function initdb(sv, defaults, defaultProfile, olddb, parent) + -- Generate the database keys for each section + + -- Make a container for profile keys + if not sv.profileKeys then sv.profileKeys = {} end + + -- Try to get the profile selected from the char db + local profileKey = sv.profileKeys[charKey] or defaultProfile or charKey + sv.profileKeys[charKey] = profileKey + + -- 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, + ["profile"] = profileKey, + ["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 + 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 +local function logoutHandler(frame, event) + if event == "PLAYER_LOGOUT" then + for db in pairs(AceDB.db_registry) do + db.callbacks:Fire("OnDatabaseShutdown", db) + for section, key in pairs(db.keys) do + if db.defaults and db.defaults[section] and rawget(db, section) then + removeDefaults(db[section], db.defaults[section]) + end + end + end + end +end + +AceDB.frame:RegisterEvent("PLAYER_LOGOUT") +AceDB.frame:SetScript("OnEvent", logoutHandler) + + +--[[------------------------------------------------------------------------- + AceDB Object Method Definitions +---------------------------------------------------------------------------]] + +-- DBObject:RegisterDefaults(defaults) +-- defaults (table) - A table of defaults for this database +-- +-- Sets the defaults table for the given database object by clearing any +-- that are currently set, and then setting the new defaults. +function DBObjectLib:RegisterDefaults(defaults) + if defaults and type(defaults) ~= "table" then + error("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected.", 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 + +-- DBObject:SetProfile(name) +-- name (string) - The name of the profile to set as the current profile +-- +-- Changes the profile of the database and all of it's namespaces to the +-- supplied named profile +function DBObjectLib:SetProfile(name) + if type(name) ~= "string" then + error("Usage: AceDBObject:SetProfile(name): 'name' - string expected.", 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 + + if oldProfile and defaults then + -- Remove the defaults from the old profile + removeDefaults(oldProfile, defaults) + end + + self.profile = nil + self.keys["profile"] = name + self.sv.profileKeys[charKey] = name + + -- Callback: OnProfileChanged, database, newProfileKey + self.callbacks:Fire("OnProfileChanged", self, name) + + -- populate to child namespaces + if self.children then + for _, db in pairs(self.children) do + DBObjectLib.SetProfile(db, name) + end + end +end + +-- DBObject:GetProfiles(tbl) +-- tbl (table) - A table to store the profile names in (optional) +-- +-- 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. +function DBObjectLib:GetProfiles(tbl) + if tbl and type(tbl) ~= "table" then + error("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected.", 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 + +-- DBObject:GetCurrentProfile() +-- +-- Returns the current profile name used by the database +function DBObjectLib:GetCurrentProfile() + return self.keys.profile +end + +-- DBObject:DeleteProfile(name) +-- name (string) - The name of the profile to be deleted +-- +-- Deletes a named profile. This profile must not be the active profile. +function DBObjectLib:DeleteProfile(name, silent) + if type(name) ~= "string" then + error("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected.", 2) + end + + if self.keys.profile == name then + error("Cannot delete the active profile in an AceDBObject.", 2) + end + + if not rawget(self.sv.profiles, name) and not silent then + error("Cannot delete profile '" .. name .. "'. It does not exist.", 2) + end + + self.sv.profiles[name] = nil + -- Callback: OnProfileDeleted, database, profileKey + self.callbacks:Fire("OnProfileDeleted", self, name) + + -- populate to child namespaces + if self.children then + for _, db in pairs(self.children) do + DBObjectLib.DeleteProfile(db, name, true) + end + end +end + +-- DBObject:CopyProfile(name) +-- name (string) - The name of the profile to be copied into the current profile +-- +-- Copies a named profile into the current profile, overwriting any conflicting +-- settings. +function DBObjectLib:CopyProfile(name, silent) + if type(name) ~= "string" then + error("Usage: AceDBObject:CopyProfile(name): 'name' - string expected.", 2) + end + + if name == self.keys.profile then + error("Cannot have the same source and destination profiles.", 2) + end + + if not rawget(self.sv.profiles, name) and not silent then + error("Cannot copy profile '" .. name .. "'. It does not exist.", 2) + end + + -- Reset the profile before copying + DBObjectLib.ResetProfile(self) + + local profile = self.profile + local source = self.sv.profiles[name] + + copyTable(source, profile) + + -- Callback: OnProfileCopied, database, sourceProfileKey + self.callbacks:Fire("OnProfileCopied", self, name) + + -- populate to child namespaces + if self.children then + for _, db in pairs(self.children) do + DBObjectLib.CopyProfile(db, name, true) + end + end +end + +-- DBObject:ResetProfile() +-- +-- Resets the current profile +function DBObjectLib:ResetProfile() + 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 + + -- Callback: OnProfileReset, database + self.callbacks:Fire("OnProfileReset", self) + + -- populate to child namespaces + if self.children then + for _, db in pairs(self.children) do + DBObjectLib.ResetProfile(db) + end + end +end + +-- DBObject:ResetDB(defaultProfile) +-- defaultProfile (string) - The profile name to use as the default +-- +-- Resets the entire database, using the string defaultProfile as the default +-- profile. +function DBObjectLib:ResetDB(defaultProfile) + if defaultProfile and type(defaultProfile) ~= "string" then + error("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected.", 2) + end + + local sv = self.sv + for k,v in pairs(sv) do + sv[k] = nil + end + + local parent = self.parent + + initdb(sv, self.defaults, defaultProfile, self) + + -- Callback: OnDatabaseReset, database + self.callbacks:Fire("OnDatabaseReset", self) + -- Callback: OnProfileChanged, database, profileKey + self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"]) + + -- 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 + + return self +end + +-- DBObject:RegisterNamespace(name [, defaults]) +-- name (string) - The name of the new namespace +-- defaults (table) - A table of values to use as defaults +-- +-- 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 +function DBObjectLib:RegisterNamespace(name, defaults) + if type(name) ~= "string" then + error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected.", 2) + end + if defaults and type(defaults) ~= "table" then + error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected.", 2) + end + if self.children and self.children[name] then + error ("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace with that name already exists.", 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 + +--[[------------------------------------------------------------------------- + AceDB Exposed Methods +---------------------------------------------------------------------------]] + +-- AceDB:New(name, defaults, defaultProfile) +-- name (table or string) - The name of variable, or table to use for the database +-- defaults (table) - A table of database defaults +-- defaultProfile (string) - The name of the default profile +-- +-- Creates a new database object that can be used to handle database settings +-- and profiles. +function AceDB:New(tbl, defaults, defaultProfile) + if type(tbl) == "string" then + local name = tbl + tbl = getglobal(name) + if not tbl then + tbl = {} + setglobal(name, tbl) + end + end + + if type(tbl) ~= "table" then + error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected.", 2) + end + + if defaults and type(defaults) ~= "table" then + error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected.", 2) + end + + if defaultProfile and type(defaultProfile) ~= "string" then + error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string expected.", 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 + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceDB-3.0/AceDB-3.0.xml Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceDB-3.0.lua"/> +</Ui> \ No newline at end of file
--- a/lib/AceEvent-2.0/AceEvent-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1082 +0,0 @@ ---[[ -Name: AceEvent-2.0 -Revision: $Rev: 49307 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceEvent-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0 -Description: Mixin to allow for event handling, scheduling, and inter-addon - communication. -Dependencies: AceLibrary, AceOO-2.0 -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceEvent-2.0" -local MINOR_VERSION = "$Revision: 49307 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end - -local AceOO = AceLibrary:GetInstance("AceOO-2.0") -local Mixin = AceOO.Mixin -local AceEvent = Mixin { - "RegisterEvent", - "RegisterAllEvents", - "UnregisterEvent", - "UnregisterAllEvents", - "TriggerEvent", - "ScheduleEvent", - "ScheduleRepeatingEvent", - "CancelScheduledEvent", - "CancelAllScheduledEvents", - "IsEventRegistered", - "IsEventScheduled", - "RegisterBucketEvent", - "UnregisterBucketEvent", - "UnregisterAllBucketEvents", - "IsBucketEventRegistered", - "ScheduleLeaveCombatAction", - "CancelAllCombatSchedules", -} - -local weakKey = {__mode="k"} - -local FAKE_NIL -local RATE - -local eventsWhichHappenOnce = { - PLAYER_LOGIN = true, - AceEvent_FullyInitialized = true, - VARIABLES_LOADED = true, - PLAYER_LOGOUT = true, -} -local next = next -local pairs = pairs -local pcall = pcall -local type = type -local GetTime = GetTime -local gcinfo = gcinfo -local unpack = unpack -local geterrorhandler = geterrorhandler - -local build = GetBuildInfo() -local useTablesAsIDs = build:find("^2%.0%.") or build:find("^2%.1%.") or build:find("^0%.1%.") - -local new, del -do - local cache = setmetatable({}, {__mode='k'}) - function new(...) - local t = next(cache) - if t then - cache[t] = nil - for i = 1, select('#', ...) do - t[i] = select(i, ...) - end - return t - else - return { ... } - end - end - function del(t) - for k in pairs(t) do - t[k] = nil - end - cache[t] = true - return nil - end -end - -local registeringFromAceEvent ---[[---------------------------------------------------------------------------------- -Notes: - * Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered. -Arguments: - string - name of the event to register - [optional] string or function - name of the method or function to call. Default: same name as "event". - [optional] boolean - whether to have method called only once. Default: false -------------------------------------------------------------------------------------]] -function AceEvent:RegisterEvent(event, method, once) - AceEvent:argCheck(event, 2, "string") - if self == AceEvent and not registeringFromAceEvent then - AceEvent:argCheck(method, 3, "function") - self = method - else - AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number") - if type(method) == "boolean" or type(method) == "number" then - AceEvent:argCheck(once, 4, "nil") - once, method = method, event - end - end - AceEvent:argCheck(once, 4, "number", "boolean", "nil") - if eventsWhichHappenOnce[event] then - once = true - end - local throttleRate - if type(once) == "number" then - throttleRate, once = once - end - if not method then - method = event - end - if type(method) == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) - else - assert(type(method) == "function" or type(method) == "string") - end - - local AceEvent_registry = AceEvent.registry - if not AceEvent_registry[event] then - AceEvent_registry[event] = new() - AceEvent.frame:RegisterEvent(event) - end - - local remember = true - if AceEvent_registry[event][self] then - remember = false - end - AceEvent_registry[event][self] = method - - local AceEvent_onceRegistry = AceEvent.onceRegistry - if once then - if not AceEvent_onceRegistry then - AceEvent.onceRegistry = {} - AceEvent_onceRegistry = AceEvent.onceRegistry - end - if not AceEvent_onceRegistry[event] then - AceEvent_onceRegistry[event] = new() - end - AceEvent_onceRegistry[event][self] = true - else - if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then - AceEvent_onceRegistry[event][self] = nil - if not next(AceEvent_onceRegistry[event]) then - AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) - end - end - end - - local AceEvent_throttleRegistry = AceEvent.throttleRegistry - if throttleRate then - if not AceEvent_throttleRegistry then - AceEvent.throttleRegistry = {} - AceEvent_throttleRegistry = AceEvent.throttleRegistry - end - if not AceEvent_throttleRegistry[event] then - AceEvent_throttleRegistry[event] = new() - end - if AceEvent_throttleRegistry[event][self] then - AceEvent_throttleRegistry[event][self] = nil - end - AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey) - local t = AceEvent_throttleRegistry[event][self] - t[RATE] = throttleRate - else - if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then - if AceEvent_throttleRegistry[event][self] then - AceEvent_throttleRegistry[event][self] = nil - end - if not next(AceEvent_throttleRegistry[event]) then - AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) - end - end - end - - if remember then - AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event) - end -end - -local ALL_EVENTS - ---[[---------------------------------------------------------------------------------- -Notes: - * Registers all events to the given method - * To access the current event, check AceEvent.currentEvent - * To access the current event's unique identifier, check AceEvent.currentEventUID - * This is only for debugging purposes. -Arguments: - [optional] string or function - name of the method or function to call. Default: same name as "event". -------------------------------------------------------------------------------------]] -function AceEvent:RegisterAllEvents(method) - if self == AceEvent then - AceEvent:argCheck(method, 1, "function") - self = method - else - AceEvent:argCheck(method, 1, "string", "function") - if type(method) == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot register all events to method %q, it does not exist", method) - end - end - - local AceEvent_registry = AceEvent.registry - if not AceEvent_registry[ALL_EVENTS] then - AceEvent_registry[ALL_EVENTS] = new() - AceEvent.frame:RegisterAllEvents() - end - - local remember = not AceEvent_registry[ALL_EVENTS][self] - AceEvent_registry[ALL_EVENTS][self] = method - if remember then - AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all") - end -end - ---[[---------------------------------------------------------------------------------- -Notes: - * Trigger a custom AceEvent. - * This should never be called to simulate fake Blizzard events. - * Custom events should be in the form of AddonName_SpecificEvent -Arguments: - string - name of the event - tuple - list of arguments to pass along -------------------------------------------------------------------------------------]] -function AceEvent:TriggerEvent(event, ...) - if type(event) ~= "string" then - DEFAULT_CHAT_FRAME:AddMessage(debugstack()) - end - AceEvent:argCheck(event, 2, "string") - local AceEvent_registry = AceEvent.registry - if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then - return - end - local lastEvent = AceEvent.currentEvent - AceEvent.currentEvent = event - local lastEventUID = AceEvent.currentEventUID - local uid = AceEvent.UID_NUM + 1 - AceEvent.UID_NUM = uid - AceEvent.currentEventUID = uid - - local tmp = new() - - local AceEvent_onceRegistry = AceEvent.onceRegistry - if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then - for obj, method in pairs(AceEvent_onceRegistry[event]) do - tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil - end - local obj = next(tmp) - while obj do - local method = tmp[obj] - AceEvent.UnregisterEvent(obj, event) - if type(method) == "string" then - local obj_method = obj[method] - if obj_method then - local success, err = pcall(obj_method, obj, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - elseif method then -- function - local success, err = pcall(method, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - tmp[obj] = nil - obj = next(tmp) - end - end - - local AceEvent_throttleRegistry = AceEvent.throttleRegistry - local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] - if AceEvent_registry[event] then - for obj, method in pairs(AceEvent_registry[event]) do - tmp[obj] = method - end - local obj = next(tmp) - while obj do - local method = tmp[obj] - local continue = false - if throttleTable and throttleTable[obj] then - local a1 = ... - if a1 == nil then - a1 = FAKE_NIL - end - if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then - throttleTable[obj][a1] = GetTime() - else - continue = true - end - end - if not continue then - if type(method) == "string" then - local obj_method = obj[method] - if obj_method then - local success, err = pcall(obj_method, obj, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - elseif method then -- function - local success, err = pcall(method, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - end - tmp[obj] = nil - obj = next(tmp) - end - end - if AceEvent_registry[ALL_EVENTS] then - for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do - tmp[obj] = method - end - local obj = next(tmp) - while obj do - local method = tmp[obj] - if type(method) == "string" then - local obj_method = obj[method] - if obj_method then - local success, err = pcall(obj_method, obj, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - elseif method then -- function - local success, err = pcall(method, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - tmp[obj] = nil - obj = next(tmp) - end - end - tmp = del(tmp) - AceEvent.currentEvent = lastEvent - AceEvent.currentEventUID = lastEventUID -end - -local delayRegistry -local OnUpdate -do - local tmp = {} - OnUpdate = function() - local t = GetTime() - for k,v in pairs(delayRegistry) do - tmp[k] = true - end - for k in pairs(tmp) do - local v = delayRegistry[k] - if v then - local v_time = v.time - if not v_time then - delayRegistry[k] = nil - elseif v_time <= t then - local v_repeatDelay = v.repeatDelay - if v_repeatDelay then - -- use the event time, not the current time, else timing inaccuracies add up over time - v.time = v_time + v_repeatDelay - end - local event = v.event - if type(event) == "function" then - local uid = AceEvent.UID_NUM + 1 - AceEvent.UID_NUM = uid - AceEvent.currentEventUID = uid - local success, err = pcall(event, unpack(v, 1, v.n)) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - AceEvent.currentEventUID = nil - else - AceEvent:TriggerEvent(event, unpack(v, 1, v.n)) - end - if not v_repeatDelay then - local x = delayRegistry[k] - if x and x.time == v_time then -- check if it was manually reset - if not useTablesAsIDs or type(k) == "string" then - del(delayRegistry[k]) - end - delayRegistry[k] = nil - end - end - end - end - end - for k in pairs(tmp) do - tmp[k] = nil - end - if not next(delayRegistry) then - AceEvent.frame:Hide() - end - end -end - -local function ScheduleEvent(self, repeating, event, delay, ...) - local id - if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then - if useTablesAsIDs and type(event) == "table" then - if not delayRegistry or not delayRegistry[event] then - AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") - end - end - if type(delay) ~= "number" then - id, event, delay = event, delay, ... - AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number") - AceEvent:argCheck(delay, 4, "number") - self:CancelScheduledEvent(id) - end - else - AceEvent:argCheck(event, 2, "string", "function") - AceEvent:argCheck(delay, 3, "number") - end - - if not delayRegistry then - AceEvent.delayRegistry = {} - delayRegistry = AceEvent.delayRegistry - AceEvent.frame:SetScript("OnUpdate", OnUpdate) - end - local t - if useTablesAsIDs and type(id) == "table" then - for k in pairs(id) do - id[k] = nil - end - t = id - for i = 2, select('#', ...) do - t[i-1] = select(i, ...) - end - t.n = select('#', ...) - 1 - elseif id then - t = new(select(2, ...)) - t.n = select('#', ...) - 1 - else - t = new(...) - t.n = select('#', ...) - end - t.event = event - t.time = GetTime() + delay - t.self = self - t.id = id or t - t.repeatDelay = repeating and delay - delayRegistry[t.id] = t - AceEvent.frame:Show() - if useTablesAsIDs then - return t.id - else - return - end -end - ---[[---------------------------------------------------------------------------------- -Notes: - * Schedule an event to fire. - * To fire on the next frame, specify a delay of 0. -Arguments: - string or function - name of the event to fire, or a function to call. - number - the amount of time to wait until calling. - tuple - a list of arguments to pass along. -------------------------------------------------------------------------------------]] -function AceEvent:ScheduleEvent(event, delay, ...) - if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then - if useTablesAsIDs and type(event) == "table" then - if not delayRegistry or not delayRegistry[event] then - AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") - end - end - if type(delay) ~= "number" then - AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") - AceEvent:argCheck(..., 4, "number") - end - else - AceEvent:argCheck(event, 2, "string", "function") - AceEvent:argCheck(delay, 3, "number") - end - - return ScheduleEvent(self, false, event, delay, ...) -end - -function AceEvent:ScheduleRepeatingEvent(event, delay, ...) - if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then - if useTablesAsIDs and type(event) == "table" then - if not delayRegistry or not delayRegistry[event] then - AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") - end - end - if type(delay) ~= "number" then - AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") - AceEvent:argCheck(..., 4, "number") - end - else - AceEvent:argCheck(event, 2, "string", "function") - AceEvent:argCheck(delay, 3, "number") - end - - return ScheduleEvent(self, true, event, delay, ...) -end - -function AceEvent:CancelScheduledEvent(t) - if useTablesAsIDs then - AceEvent:argCheck(t, 2, "string", "table") - else - AceEvent:argCheck(t, 2, "string") - end - if delayRegistry then - local v = delayRegistry[t] - if v then - if not useTablesAsIDs or type(t) == "string" then - del(delayRegistry[t]) - end - delayRegistry[t] = nil - if not next(delayRegistry) then - AceEvent.frame:Hide() - end - return true - end - end - return false -end - -function AceEvent:IsEventScheduled(t) - if useTablesAsIDs then - AceEvent:argCheck(t, 2, "string", "table") - else - AceEvent:argCheck(t, 2, "string") - end - if delayRegistry then - local v = delayRegistry[t] - if v then - return true, v.time - GetTime() - end - end - return false, nil -end - -function AceEvent:UnregisterEvent(event) - AceEvent:argCheck(event, 2, "string") - local AceEvent_registry = AceEvent.registry - if AceEvent_registry[event] and AceEvent_registry[event][self] then - AceEvent_registry[event][self] = nil - local AceEvent_onceRegistry = AceEvent.onceRegistry - if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then - AceEvent_onceRegistry[event][self] = nil - if not next(AceEvent_onceRegistry[event]) then - AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) - end - end - local AceEvent_throttleRegistry = AceEvent.throttleRegistry - if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then - AceEvent_throttleRegistry[event][self] = nil - if not next(AceEvent_throttleRegistry[event]) then - AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) - end - end - if not next(AceEvent_registry[event]) then - AceEvent_registry[event] = del(AceEvent_registry[event]) - if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then - AceEvent.frame:UnregisterEvent(event) - end - end - else - if self == AceEvent then - error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2) - else - AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self) - end - end - AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) -end - -function AceEvent:UnregisterAllEvents() - local AceEvent_registry = AceEvent.registry - if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then - AceEvent_registry[ALL_EVENTS][self] = nil - if not next(AceEvent_registry[ALL_EVENTS]) then - AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS]) - AceEvent.frame:UnregisterAllEvents() - for k,v in pairs(AceEvent_registry) do - AceEvent.frame:RegisterEvent(k) - end - end - end - if AceEvent_registry.AceEvent_EventUnregistered then - local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered - local x = data[self] - data[self] = nil - if x then - if not next(data) then - if not AceEvent_registry[ALL_EVENTS] then - AceEvent.frame:UnregisterEvent(event) - end - AceEvent_registry[event] = del(AceEvent_registry[event]) - end - AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) - end - end - for event, data in pairs(AceEvent_registry) do - local x = data[self] - data[self] = nil - if x and event ~= ALL_EVENTS then - if not next(data) then - if not AceEvent_registry[ALL_EVENTS] then - AceEvent.frame:UnregisterEvent(event) - end - AceEvent_registry[event] = del(AceEvent_registry[event]) - end - AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) - end - end - if AceEvent.onceRegistry then - for event, data in pairs(AceEvent.onceRegistry) do - data[self] = nil - end - end -end - -function AceEvent:CancelAllScheduledEvents() - if delayRegistry then - for k,v in pairs(delayRegistry) do - if v.self == self then - if not useTablesAsIDs or type(k) == "string" then - del(delayRegistry[k]) - end - delayRegistry[k] = nil - end - end - if not next(delayRegistry) then - AceEvent.frame:Hide() - end - end -end - -function AceEvent:IsEventRegistered(event) - AceEvent:argCheck(event, 2, "string") - local AceEvent_registry = AceEvent.registry - if self == AceEvent then - return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false - end - if AceEvent_registry[event] and AceEvent_registry[event][self] then - return true, AceEvent_registry[event][self] - end - if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then - return true, AceEvent_registry[ALL_EVENTS][self] - end - return false, nil -end - -local UnitExists = UnitExists -local bucketfunc -function AceEvent:RegisterBucketEvent(event, delay, method, ...) - AceEvent:argCheck(event, 2, "string", "table") - if type(event) == "table" then - for k,v in pairs(event) do - if type(k) ~= "number" then - AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.") - elseif type(v) ~= "string" then - AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.") - end - end - end - AceEvent:argCheck(delay, 3, "number") - if AceEvent == self then - AceEvent:argCheck(method, 4, "function") - self = method - else - if type(event) == "string" then - AceEvent:argCheck(method, 4, "string", "function", "nil") - if not method then - method = event - end - else - AceEvent:argCheck(method, 4, "string", "function") - end - - if type(method) == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) - end - end - local buckets = AceEvent.buckets - if not buckets[event] then - buckets[event] = new() - end - if not buckets[event][self] then - local t = new() - t.current = new() - t.self = self - buckets[event][self] = t - else - AceEvent.CancelScheduledEvent(self, buckets[event][self].id) - end - local bucket = buckets[event][self] - bucket.method = method - - local n = select('#', ...) - if n > 0 then - for i = 1, n do - bucket[i] = select(i, ...) - end - end - bucket.n = n - - local func = function(arg1) - bucket.run = true - if arg1 then - bucket.current[arg1] = true - end - end - buckets[event][self].func = func - local isUnitBucket = true - if type(event) == "string" then - AceEvent.RegisterEvent(self, event, func) - if not event:find("^UNIT_") then - isUnitBucket = false - end - else - for _,v in ipairs(event) do - AceEvent.RegisterEvent(self, v, func) - if isUnitBucket and not v:find("^UNIT_") then - isUnitBucket = false - end - end - end - bucket.unit = isUnitBucket - if not bucketfunc then - bucketfunc = function(bucket) - local current = bucket.current - local method = bucket.method - local self = bucket.self - if bucket.run then - if bucket.unit then - for unit in pairs(current) do - if not UnitExists(unit) then - current[unit] = nil - end - end - end - if type(method) == "string" then - self[method](self, current, unpack(bucket, 1, bucket.n)) - elseif method then -- function - method(current, unpack(bucket, 1, bucket.n)) - end - for k in pairs(current) do - current[k] = nil - k = nil - end - bucket.run = false - end - end - end - bucket.id = "AceEvent-Bucket-" .. tostring(bucket) - AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket) -end - -function AceEvent:IsBucketEventRegistered(event) - AceEvent:argCheck(event, 2, "string", "table") - return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self] -end - -function AceEvent:UnregisterBucketEvent(event) - AceEvent:argCheck(event, 2, "string", "table") - if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then - AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self) - end - - local bucket = AceEvent.buckets[event][self] - - if type(event) == "string" then - AceEvent.UnregisterEvent(self, event) - else - for _,v in ipairs(event) do - AceEvent.UnregisterEvent(self, v) - end - end - AceEvent:CancelScheduledEvent(bucket.id) - - bucket.current = del(bucket.current) - AceEvent.buckets[event][self] = del(bucket) - if not next(AceEvent.buckets[event]) then - AceEvent.buckets[event] = del(AceEvent.buckets[event]) - end -end - -function AceEvent:UnregisterAllBucketEvents() - if not AceEvent.buckets or not next(AceEvent.buckets) then - return - end - for k,v in pairs(AceEvent.buckets) do - if v == self then - AceEvent.UnregisterBucketEvent(self, k) - k = nil - end - end -end - -local combatSchedules -function AceEvent:CancelAllCombatSchedules() - local i = 0 - while true do - i = i + 1 - if not combatSchedules[i] then - break - end - local v = combatSchedules[i] - if v.self == self then - v = del(v) - table.remove(combatSchedules, i) - i = i - 1 - end - end -end - -local inCombat = false - -function AceEvent:PLAYER_REGEN_DISABLED() - inCombat = true -end - -do - local tmp = {} - function AceEvent:PLAYER_REGEN_ENABLED() - inCombat = false - for i, v in ipairs(combatSchedules) do - tmp[i] = v - combatSchedules[i] = nil - end - for i, v in ipairs(tmp) do - local func = v.func - if func then - local success, err = pcall(func, unpack(v, 1, v.n)) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - else - local obj = v.obj or v.self - local method = v.method - local obj_method = obj[method] - if obj_method then - local success, err = pcall(obj_method, obj, unpack(v, 1, v.n)) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - end - end - tmp[i] = del(v) - end - end -end - -function AceEvent:ScheduleLeaveCombatAction(method, ...) - local style = type(method) - if self == AceEvent then - if style == "table" then - local func = (...) - AceEvent:argCheck(func, 3, "string") - if type(method[func]) ~= "function" then - AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func) - end - else - AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table") - end - self = method - else - AceEvent:argCheck(method, 2, "function", "string", "table") - if style == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method) - elseif style == "table" then - local func = (...) - AceEvent:argCheck(func, 3, "string") - if type(method[func]) ~= "function" then - AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func) - end - end - end - - if not inCombat then - local success, err - if type(method) == "function" then - success, err = pcall(method, ...) - elseif type(method) == "table" then - local func = (...) - success, err = pcall(method[func], method, select(2, ...)) - else - success, err = pcall(self[method], self, ...) - end - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end - return - end - local t - local n = select('#', ...) - if style == "table" then - t = new(select(2, ...)) - t.obj = method - t.method = (...) - t.n = n-1 - else - t = new(...) - t.n = n - if style == "function" then - t.func = method - else - t.method = method - end - end - t.self = self - table.insert(combatSchedules, t) -end - -function AceEvent:OnEmbedDisable(target) - self.UnregisterAllEvents(target) - - self.CancelAllScheduledEvents(target) - - self.UnregisterAllBucketEvents(target) - - self.CancelAllCombatSchedules(target) -end - -function AceEvent:IsFullyInitialized() - return self.postInit or false -end - -function AceEvent:IsPostPlayerLogin() - return IsLoggedIn() and true or false -end - -local function activate(self, oldLib, oldDeactivate) - AceEvent = self - - self.onceRegistry = oldLib and oldLib.onceRegistry or {} - self.throttleRegistry = oldLib and oldLib.throttleRegistry or {} - self.delayRegistry = oldLib and oldLib.delayRegistry or {} - self.buckets = oldLib and oldLib.buckets or {} - self.registry = oldLib and oldLib.registry or {} - self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame") - self.playerLogin = IsLoggedIn() and true - self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true - self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy() - self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy() - self.RATE = oldLib and oldLib.RATE or _G.newproxy() - self.combatSchedules = oldLib and oldLib.combatSchedules or {} - self.UID_NUM = oldLib and oldLib.UID_NUM or 0 - - -- Delete this down the road. Makes sure that the addonframes from revisions 33121 - 36174 get their events unregistered. - local addonframes = oldLib and oldLib.addonframes - if addonframes then - for _, v in pairs(addonframes) do - v:UnregisterAllEvents() - end - end - - combatSchedules = self.combatSchedules - ALL_EVENTS = self.ALL_EVENTS - FAKE_NIL = self.FAKE_NIL - RATE = self.RATE - local inPlw = false - local blacklist = { - UNIT_INVENTORY_CHANGED = true, - BAG_UPDATE = true, - ITEM_LOCK_CHANGED = true, - ACTIONBAR_SLOT_CHANGED = true, - } - self.frame:SetScript("OnEvent", function(_, event, ...) - if event == "PLAYER_ENTERING_WORLD" then - inPlw = false - elseif event == "PLAYER_LEAVING_WORLD" then - inPlw = true - end - if event and (not inPlw or not blacklist[event]) then - self:TriggerEvent(event, ...) - end - end) - if self.delayRegistry then - delayRegistry = self.delayRegistry - self.frame:SetScript("OnUpdate", OnUpdate) - end - - self:UnregisterAllEvents() - self:CancelAllScheduledEvents() - - registeringFromAceEvent = true - self:RegisterEvent("LOOT_OPENED", function() - SendAddonMessage("LOOT_OPENED", "", "RAID") - end) - registeringFromAceEvent = nil - - local function handleFullInit() - if not self.postInit then - local function func() - self.postInit = true - self:TriggerEvent("AceEvent_FullyInitialized") - if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then - self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") - end - if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then - self:UnregisterEvent("MEETINGSTONE_CHANGED") - end - if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then - self:UnregisterEvent("MINIMAP_ZONE_CHANGED") - end - if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then - self:UnregisterEvent("LANGUAGE_LIST_CHANGED") - end - collectgarbage('collect') - end - registeringFromAceEvent = true - local f = function() - self.playerLogin = true - self:ScheduleEvent("AceEvent_FullyInitialized", func, 1) - end - self:RegisterEvent("MEETINGSTONE_CHANGED", f, true) - self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function() - self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15) - end) - self:RegisterEvent("LANGUAGE_LIST_CHANGED", function() - if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then - registeringFromAceEvent = true - self:UnregisterEvent("MEETINGSTONE_CHANGED") - self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true) - registeringFromAceEvent = nil - end - end) - self:ScheduleEvent("AceEvent_FullyInitialized", func, 10) - registeringFromAceEvent = nil - end - end - - if not self.playerLogin then - registeringFromAceEvent = true - self:RegisterEvent("PLAYER_LOGIN", function() - self.playerLogin = true - handleFullInit() - handleFullInit = nil - collectgarbage('collect') - end, true) - registeringFromAceEvent = nil - else - handleFullInit() - handleFullInit = nil - end - - if not AceEvent20EditBox then - CreateFrame("Editbox", "AceEvent20EditBox") - end - local editbox = AceEvent20EditBox - function editbox:Execute(line) - local defaulteditbox = DEFAULT_CHAT_FRAME.editBox - self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType")) - self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget")) - self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget")) - self:SetText(line) - ChatEdit_SendText(self) - end - editbox:Hide() - _G["SLASH_IN1"] = "/in" - SlashCmdList["IN"] = function(msg) - local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$") - seconds = tonumber(seconds) - if not seconds then - DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'") - return - end - if IsSecureCmd(command) then - DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command)) - return - end - self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest) - end - registeringFromAceEvent = true - self:RegisterEvent("PLAYER_REGEN_ENABLED") - self:RegisterEvent("PLAYER_REGEN_DISABLED") - inCombat = InCombatLockdown() - registeringFromAceEvent = nil - - -- another hack to make sure that we clean up properly from rev 33121 - 36174 - if self.registry[ALL_EVENTS] then - self.frame:RegisterAllEvents() - else - for event in pairs(self.registry) do - self.frame:RegisterEvent(event) - end - end - - self:activate(oldLib, oldDeactivate) - if oldLib then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
--- a/lib/AceEvent-2.0/AceEvent-2.0.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceEvent-2.0 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary, AceOO-2.0 - -AceEvent-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceEvent-3.0/AceEvent-3.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,76 @@ +--[[ $Id: AceEvent-3.0.lua 60131 2008-02-03 13:03:56Z nevcairiel $ ]] +local MAJOR, MINOR = "AceEvent-3.0", 3 +local AceEvent = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceEvent then return end + +local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") + + +AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame +AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib + + +-- APIs and registry for blizzard events, using CallbackHandler lib +if not AceEvent.events then + AceEvent.events = CallbackHandler:New(AceEvent, + "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", +} + +-- AceEvent:Embed( target ) +-- target (object) - target object to embed AceEvent in +-- +-- Embeds AceEvent into the target object making the functions from the mixins list available on target:.. +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceEvent-3.0/AceEvent-3.0.xml Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceEvent-3.0.lua"/> +</Ui> \ No newline at end of file
--- a/lib/AceLibrary/AceLibrary.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,856 +0,0 @@ ---[[ -Name: AceLibrary -Revision: $Rev: 49421 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Iriel (iriel@vigilance-committee.org) - Tekkub (tekkub@gmail.com) - Revision: $Rev: 49421 $ -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceLibrary -SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary -Description: Versioning library to handle other library instances, upgrading, - and proper access. - It also provides a base for libraries to work off of, providing - proper error tools. It is handy because all the errors occur in the - file that called it, not in the library file itself. -Dependencies: None -License: LGPL v2.1 -]] - -local ACELIBRARY_MAJOR = "AceLibrary" -local ACELIBRARY_MINOR = "$Revision: 49421 $" - -local _G = getfenv(0) -local previous = _G[ACELIBRARY_MAJOR] -if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end - -do - -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info - -- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke - local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! - local LibStub = _G[LIBSTUB_MAJOR] - - if not LibStub or LibStub.minor < LIBSTUB_MINOR then - LibStub = LibStub or {libs = {}, minors = {} } - _G[LIBSTUB_MAJOR] = LibStub - LibStub.minor = LIBSTUB_MINOR - - function LibStub:NewLibrary(major, minor) - assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") - minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") - local oldminor = self.minors[major] - if oldminor and oldminor >= minor then return nil end - self.minors[major], self.libs[major] = minor, self.libs[major] or {} - return self.libs[major], oldminor - end - - function LibStub:GetLibrary(major, silent) - if not self.libs[major] and not silent then - error(("Cannot find a library instance of %q."):format(tostring(major)), 2) - end - return self.libs[major], self.minors[major] - end - - function LibStub:IterateLibraries() return pairs(self.libs) end - setmetatable(LibStub, { __call = LibStub.GetLibrary }) - end -end -local LibStub = _G.LibStub - --- If you don't want AceLibrary to enable libraries that are LoadOnDemand but --- disabled in the addon screen, set this to true. -local DONT_ENABLE_LIBRARIES = nil - -local function safecall(func,...) - local success, err = pcall(func,...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end -end - -local WoW22 = false -if type(GetBuildInfo) == "function" then - local success, buildinfo = pcall(GetBuildInfo) - if success and type(buildinfo) == "string" then - local num = tonumber(buildinfo:match("^(%d+%.%d+)")) - if num and num >= 2.2 then - WoW22 = true - end - end -end - --- @table AceLibrary --- @brief System to handle all versioning of libraries. -local AceLibrary = {} -local AceLibrary_mt = {} -setmetatable(AceLibrary, AceLibrary_mt) - -local function error(self, message, ...) - if type(self) ~= "table" then - return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2) - end - - local stack = debugstack() - if not message then - local second = stack:match("\n(.-)\n") - message = "error raised! " .. second - else - local arg = { ... } -- not worried about table creation, as errors don't happen often - - for i = 1, #arg do - arg[i] = tostring(arg[i]) - end - for i = 1, 10 do - table.insert(arg, "nil") - end - message = message:format(unpack(arg)) - end - - if getmetatable(self) and getmetatable(self).__tostring then - message = ("%s: %s"):format(tostring(self), message) - elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then - message = ("%s: %s"):format(self:GetLibraryVersion(), message) - elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then - message = ("%s: %s"):format(self.class:GetLibraryVersion(), message) - end - - local first = stack:gsub("\n.*", "") - local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1") - file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") - - - local i = 0 - for s in stack:gmatch("\n([^\n]*)") do - i = i + 1 - if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then - file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1") - file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") - break - end - end - local j = 0 - for s in stack:gmatch("\n([^\n]*)") do - j = j + 1 - if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then - return _G.error(message, j+1) - end - end - return _G.error(message, 2) -end - -local assert -if not WoW22 then - function assert(self, condition, message, ...) - if not condition then - if not message then - local stack = debugstack() - local second = stack:match("\n(.-)\n") - message = "assertion failed! " .. second - end - return error(self, message, ...) - end - return condition - end -end - -local type = type -local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5) - if type(num) ~= "number" then - return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num)) - elseif type(kind) ~= "string" then - return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) - end - arg = type(arg) - if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then - local stack = debugstack() - local func = stack:match("`argCheck'.-([`<].-['>])") - if not func then - func = stack:match("([`<].-['>])") - end - if kind5 then - return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg) - elseif kind4 then - return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg) - elseif kind3 then - return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg) - elseif kind2 then - return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg) - else - return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg) - end - end -end - -local pcall -do - local function check(self, ret, ...) - if not ret then - local s = ... - return error(self, (s:gsub(".-%.lua:%d-: ", ""))) - else - return ... - end - end - - function pcall(self, func, ...) - return check(self, _G.pcall(func, ...)) - end -end - -local recurse = {} -local function addToPositions(t, major) - if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then - rawset(t, recurse, true) - AceLibrary.positions[t] = major - for k,v in pairs(t) do - if type(v) == "table" and not rawget(v, recurse) then - addToPositions(v, major) - end - if type(k) == "table" and not rawget(k, recurse) then - addToPositions(k, major) - end - end - local mt = getmetatable(t) - if mt and not rawget(mt, recurse) then - addToPositions(mt, major) - end - rawset(t, recurse, nil) - end -end - -local function svnRevisionToNumber(text) - local kind = type(text) - if kind == "number" or tonumber(text) then - return tonumber(text) - elseif kind == "string" then - if text:find("^%$Revision: (%d+) %$$") then - return tonumber((text:match("^%$Revision: (%d+) %$$"))) - elseif text:find("^%$Rev: (%d+) %$$") then - return tonumber((text:match("^%$Rev: (%d+) %$$"))) - elseif text:find("^%$LastChangedRevision: (%d+) %$$") then - return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$"))) - end - end - return nil -end - -local crawlReplace -do - local recurse = {} - local function func(t, to, from) - if recurse[t] then - return - end - recurse[t] = true - local mt = getmetatable(t) - setmetatable(t, nil) - rawset(t, to, rawget(t, from)) - rawset(t, from, nil) - for k,v in pairs(t) do - if v == from then - t[k] = to - elseif type(v) == "table" then - if not recurse[v] then - func(v, to, from) - end - end - - if type(k) == "table" then - if not recurse[k] then - func(k, to, from) - end - end - end - setmetatable(t, mt) - if mt then - if mt == from then - setmetatable(t, to) - elseif not recurse[mt] then - func(mt, to, from) - end - end - end - function crawlReplace(t, to, from) - func(t, to, from) - for k in pairs(recurse) do - recurse[k] = nil - end - end -end - --- @function destroyTable --- @brief remove all the contents of a table --- @param t table to destroy -local function destroyTable(t) - setmetatable(t, nil) - for k,v in pairs(t) do - t[k] = nil - end -end - -local function isFrame(frame) - return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function" -end - --- @function copyTable --- @brief Create a shallow copy of a table and return it. --- @param from The table to copy from --- @return A shallow copy of the table -local function copyTable(from, to) - if not to then - to = {} - end - for k,v in pairs(from) do - to[k] = v - end - setmetatable(to, getmetatable(from)) - return to -end - --- @function deepTransfer --- @brief Fully transfer all data, keeping proper previous table --- backreferences stable. --- @param to The table with which data is to be injected into --- @param from The table whose data will be injected into the first --- @param saveFields If available, a shallow copy of the basic data is saved --- in here. --- @param list The account of table references --- @param list2 The current status on which tables have been traversed. -local deepTransfer -do - -- @function examine - -- @brief Take account of all the table references to be shared - -- between the to and from tables. - -- @param to The table with which data is to be injected into - -- @param from The table whose data will be injected into the first - -- @param list An account of the table references - local function examine(to, from, list, major) - list[from] = to - for k,v in pairs(from) do - if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then - if from[k] == to[k] then - list[from[k]] = to[k] - elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then - list[from[k]] = from[k] - elseif not list[from[k]] then - examine(to[k], from[k], list, major) - end - end - end - return list - end - - function deepTransfer(to, from, saveFields, major, list, list2) - setmetatable(to, nil) - if not list then - list = {} - list2 = {} - examine(to, from, list, major) - end - list2[to] = to - for k,v in pairs(to) do - if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then - if saveFields then - saveFields[k] = v - end - to[k] = nil - elseif v ~= _G then - if saveFields then - saveFields[k] = copyTable(v) - end - end - end - for k in pairs(from) do - if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then - if not list2[to[k]] then - deepTransfer(to[k], from[k], nil, major, list, list2) - end - to[k] = list[to[k]] or list2[to[k]] - else - rawset(to, k, from[k]) - end - end - setmetatable(to, getmetatable(from)) - local mt = getmetatable(to) - if mt then - if list[mt] then - setmetatable(to, list[mt]) - elseif mt.__index and list[mt.__index] then - mt.__index = list[mt.__index] - end - end - destroyTable(from) - end -end - -local function TryToEnable(addon) - if DONT_ENABLE_LIBRARIES then return end - local isondemand = IsAddOnLoadOnDemand(addon) - if isondemand then - local _, _, _, enabled = GetAddOnInfo(addon) - EnableAddOn(addon) - local _, _, _, _, loadable = GetAddOnInfo(addon) - if not loadable and not enabled then - DisableAddOn(addon) - end - - return loadable - end -end - --- @method TryToLoadStandalone --- @brief Attempt to find and load a standalone version of the requested library --- @param major A string representing the major version --- @return If library is found and loaded, true is return. If not loadable, false is returned. --- If the library has been requested previously, nil is returned. -local function TryToLoadStandalone(major) - if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end - if AceLibrary.scannedlibs[major] then return end - - AceLibrary.scannedlibs[major] = true - - local name, _, _, enabled, loadable = GetAddOnInfo(major) - - loadable = (enabled and loadable) or TryToEnable(name) - - local loaded = false - if loadable then - loaded = true - LoadAddOn(name) - end - - local field = "X-AceLibrary-" .. major - for i = 1, GetNumAddOns() do - if GetAddOnMetadata(i, field) then - name, _, _, enabled, loadable = GetAddOnInfo(i) - - loadable = (enabled and loadable) or TryToEnable(name) - if loadable then - loaded = true - LoadAddOn(name) - end - end - end - return loaded -end - --- @method IsNewVersion --- @brief Obtain whether the supplied version would be an upgrade to the --- current version. This allows for bypass code in library --- declaration. --- @param major A string representing the major version --- @param minor An integer or an svn revision string representing the minor version --- @return whether the supplied version would be newer than what is --- currently available. -function AceLibrary:IsNewVersion(major, minor) - argCheck(self, major, 2, "string") - TryToLoadStandalone(major) - - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 3, "number") - local lib, oldMinor = LibStub:GetLibrary(major, true) - if lib then - return oldMinor < minor - end - local data = self.libs[major] - if not data then - return true - end - return data.minor < minor -end - --- @method HasInstance --- @brief Returns whether an instance exists. This allows for optional support of a library. --- @param major A string representing the major version. --- @param minor (optional) An integer or an svn revision string representing the minor version. --- @return Whether an instance exists. -function AceLibrary:HasInstance(major, minor) - argCheck(self, major, 2, "string") - if minor ~= false then - TryToLoadStandalone(major) - end - - local lib, ver = LibStub:GetLibrary(major, true) - if not lib and self.libs[major] then - lib, ver = self.libs[major].instance, self.libs[major].minor - end - if minor then - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 3, "number") - if not lib then - return false - end - return ver == minor - end - return not not lib -end - --- @method GetInstance --- @brief Returns the library with the given major/minor version. --- @param major A string representing the major version. --- @param minor (optional) An integer or an svn revision string representing the minor version. --- @return The library with the given major/minor version. -function AceLibrary:GetInstance(major, minor) - argCheck(self, major, 2, "string") - if minor ~= false then - TryToLoadStandalone(major) - end - - local data, ver = LibStub:GetLibrary(major, true) - if not data then - if self.libs[major] then - data, ver = self.libs[major].instance, self.libs[major].minor - else - _G.error(("Cannot find a library instance of %s."):format(major), 2) - return - end - end - if minor then - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 2, "number") - if ver ~= minor then - _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2) - end - end - return data -end - --- Syntax sugar. AceLibrary("FooBar-1.0") -AceLibrary_mt.__call = AceLibrary.GetInstance - -local donothing = function() end - -local AceEvent - -local tmp = {} - --- @method Register --- @brief Registers a new version of a given library. --- @param newInstance the library to register --- @param major the major version of the library --- @param minor the minor version of the library --- @param activateFunc (optional) A function to be called when the library is --- fully activated. Takes the arguments --- (newInstance [, oldInstance, oldDeactivateFunc]). If --- oldInstance is given, you should probably call --- oldDeactivateFunc(oldInstance). --- @param deactivateFunc (optional) A function to be called by a newer library's --- activateFunc. --- @param externalFunc (optional) A function to be called whenever a new --- library is registered. -function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc) - argCheck(self, newInstance, 2, "table") - argCheck(self, major, 3, "string") - if major ~= ACELIBRARY_MAJOR then - for k,v in pairs(_G) do - if v == newInstance then - geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) - end - end - end - if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then - _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) - end - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 4, "number") - if math.floor(minor) ~= minor or minor < 0 then - error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) - end - argCheck(self, activateFunc, 5, "function", "nil") - argCheck(self, deactivateFunc, 6, "function", "nil") - argCheck(self, externalFunc, 7, "function", "nil") - if not deactivateFunc then - deactivateFunc = donothing - end - local data = self.libs[major] - if not data then - -- This is new - if LibStub:GetLibrary(major, true) then - error(self, "Cannot register library %q. It is already registered with LibStub.", major) - end - local instance = LibStub:NewLibrary(major, minor) - copyTable(newInstance, instance) - crawlReplace(instance, instance, newInstance) - destroyTable(newInstance) - if AceLibrary == newInstance then - self = instance - AceLibrary = instance - end - self.libs[major] = { - instance = instance, - minor = minor, - deactivateFunc = deactivateFunc, - externalFunc = externalFunc, - } - rawset(instance, 'GetLibraryVersion', function(self) - return major, minor - end) - if not rawget(instance, 'error') then - rawset(instance, 'error', error) - end - if not WoW22 and not rawget(instance, 'assert') then - rawset(instance, 'assert', assert) - end - if not rawget(instance, 'argCheck') then - rawset(instance, 'argCheck', argCheck) - end - if not rawget(instance, 'pcall') then - rawset(instance, 'pcall', pcall) - end - addToPositions(instance, major) - if activateFunc then - safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil - ---[[ if major ~= ACELIBRARY_MAJOR then - for k,v in pairs(_G) do - if v == instance then - geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) - end - end - end]] - end - - if externalFunc then - for k, data_instance in LibStub:IterateLibraries() do -- all libraries - tmp[k] = data_instance - end - for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub - tmp[k] = data.instance - end - for k, data_instance in pairs(tmp) do - if k ~= major then - safecall(externalFunc, instance, k, data_instance) - end - tmp[k] = nil - end - end - - for k,data in pairs(self.libs) do -- only Ace libraries - if k ~= major and data.externalFunc then - safecall(data.externalFunc, data.instance, major, instance) - end - end - if major == "AceEvent-2.0" then - AceEvent = instance - end - if AceEvent then - AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance) - end - - return instance - end - if minor <= data.minor then - -- This one is already obsolete, raise an error. - _G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2) - return - end - local instance = data.instance - -- This is an update - local oldInstance = {} - - local libStubInstance = LibStub:GetLibrary(major, true) - if not libStubInstance then -- non-LibStub AceLibrary registered the library - -- pass - elseif libStubInstance ~= instance then - error(self, "Cannot register library %q. It is already registered with LibStub.", major) - else - LibStub:NewLibrary(major, minor) -- upgrade the minor version - end - - addToPositions(newInstance, major) - local isAceLibrary = (AceLibrary == newInstance) - local old_error, old_assert, old_argCheck, old_pcall - if isAceLibrary then - self = instance - AceLibrary = instance - - old_error = instance.error - if not WoW22 then - old_assert = instance.assert - end - old_argCheck = instance.argCheck - old_pcall = instance.pcall - - self.error = error - if not WoW22 then - self.assert = assert - end - self.argCheck = argCheck - self.pcall = pcall - end - deepTransfer(instance, newInstance, oldInstance, major) - crawlReplace(instance, instance, newInstance) - local oldDeactivateFunc = data.deactivateFunc - data.minor = minor - data.deactivateFunc = deactivateFunc - data.externalFunc = externalFunc - rawset(instance, 'GetLibraryVersion', function() - return major, minor - end) - if not rawget(instance, 'error') then - rawset(instance, 'error', error) - end - if not WoW22 and not rawget(instance, 'assert') then - rawset(instance, 'assert', assert) - end - if not rawget(instance, 'argCheck') then - rawset(instance, 'argCheck', argCheck) - end - if not rawget(instance, 'pcall') then - rawset(instance, 'pcall', pcall) - end - if isAceLibrary then - for _,v in pairs(self.libs) do - local i = type(v) == "table" and v.instance - if type(i) == "table" then - if not rawget(i, 'error') or i.error == old_error then - rawset(i, 'error', error) - end - if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then - rawset(i, 'assert', assert) - end - if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then - rawset(i, 'argCheck', argCheck) - end - if not rawget(i, 'pcall') or i.pcall == old_pcall then - rawset(i, 'pcall', pcall) - end - end - end - end - if activateFunc then - safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) - ---[[ if major ~= ACELIBRARY_MAJOR then - for k,v in pairs(_G) do - if v == instance then - geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) - end - end - end]] - else - safecall(oldDeactivateFunc, oldInstance) - end - oldInstance = nil - - if externalFunc then - for k, data_instance in LibStub:IterateLibraries() do -- all libraries - tmp[k] = data_instance - end - for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub - tmp[k] = data.instance - end - for k, data_instance in pairs(tmp) do - if k ~= major then - safecall(externalFunc, instance, k, data_instance) - end - tmp[k] = nil - end - end - - return instance -end - -function AceLibrary:IterateLibraries() - local t = {} - for major, instance in LibStub:IterateLibraries() do - t[major] = instance - end - for major, data in pairs(self.libs) do - t[major] = data.instance - end - return pairs(t) -end - -local function manuallyFinalize(major, instance) - if AceLibrary.libs[major] then - -- don't work on Ace libraries - return - end - local finalizedExternalLibs = AceLibrary.finalizedExternalLibs - if finalizedExternalLibs[major] then - return - end - finalizedExternalLibs[major] = true - - for k,data in pairs(AceLibrary.libs) do -- only Ace libraries - if k ~= major and data.externalFunc then - safecall(data.externalFunc, data.instance, major, instance) - end - end -end - --- @function Activate --- @brief The activateFunc for AceLibrary itself. Called when --- AceLibrary properly registers. --- @param self Reference to AceLibrary --- @param oldLib (optional) Reference to an old version of AceLibrary --- @param oldDeactivate (optional) Function to deactivate the old lib -local function activate(self, oldLib, oldDeactivate) - AceLibrary = self - if not self.libs then - self.libs = oldLib and oldLib.libs or {} - self.scannedlibs = oldLib and oldLib.scannedlibs or {} - end - if not self.positions then - self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" }) - end - self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {} - self.frame = oldLib and oldLib.frame or CreateFrame("Frame") - self.frame:UnregisterAllEvents() - self.frame:RegisterEvent("ADDON_LOADED") - self.frame:SetScript("OnEvent", function() - for major, instance in LibStub:IterateLibraries() do - manuallyFinalize(major, instance) - end - end) - for major, instance in LibStub:IterateLibraries() do - manuallyFinalize(major, instance) - end - - -- Expose the library in the global environment - _G[ACELIBRARY_MAJOR] = self - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -if not previous then - previous = AceLibrary -end -if not previous.libs then - previous.libs = {} -end -AceLibrary.libs = previous.libs -if not previous.positions then - previous.positions = setmetatable({}, { __mode = "k" }) -end -AceLibrary.positions = previous.positions -AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- a/lib/AceLibrary/AceLibrary.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceLibrary -## Notes: AddOn development framework -## Author: Ace Development Team -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 - -AceLibrary.lua
--- a/lib/AceLocale-2.2/AceLocale-2.2.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,669 +0,0 @@ ---[[ -Name: AceLocale-2.2 -Revision: $Rev: 40629 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceLocale-2.2 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2 -Description: Localization library for addons to use to handle proper - localization and internationalization. -Dependencies: AceLibrary -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceLocale-2.2" -local MINOR_VERSION = "$Revision: 40629 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local AceLocale = {} -AceLocale.prototype = { class = AceLocale } - -local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME - -local _G = _G -local rawget = rawget -local rawset = rawset -local type = type -local pairs = pairs -local next = next -local getmetatable = getmetatable -local setmetatable = setmetatable -local GetTime = GetTime -local geterrorhandler = geterrorhandler -local pcall = pcall -local ipairs = ipairs -local GetLocale = GetLocale - -local newRegistries = {} -local scheduleClear - -local lastSelf -local strict__index = function(self, key) - lastSelf = self - local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key] - rawset(self, key, value) - return value -end -local nonstrict__index = function(self, key) - lastSelf = self - local t = rawget(self, TRANSLATIONS) - if t then - local value = rawget(t, key) - if value then - rawset(self, key, value) - return value - end - end - local value = (rawget(self, BASE_TRANSLATIONS) or AceLocale.prototype)[key] - rawset(self, key, value) - return value -end - -local __newindex = function(self, k, v) - if type(v) ~= "function" and type(k) ~= "table" then - AceLocale.error(self, "Cannot change the values of an AceLocale instance.") - end - rawset(self, k, v) -end - -local __tostring = function(self) - if type(rawget(self, 'GetLibraryVersion')) == "function" then - return self:GetLibraryVersion() - else - return "AceLocale(" .. self[NAME] .. ")" - end -end - -local function clearCache(self) - for k, v in pairs(AceLocale.prototype) do - if type(v) == "function" and type(rawget(self, k)) == "function" then - self[k] = nil - end - end - if not rawget(self, BASE_TRANSLATIONS) then - return - end - - local cache = self[BASE_TRANSLATIONS] - rawset(self, REVERSE_TRANSLATIONS, nil) - - for k in pairs(self) do - if rawget(cache, k) ~= nil then - self[k] = nil - end - end - rawset(self, 'tmp', true) - self.tmp = nil -end - -local strict_instance_mt, nonstrict_instance_mt -local baseTranslations_mt - -local function refixInstance(instance) - if getmetatable(instance) then - setmetatable(instance, nil) - end - local translations = instance[TRANSLATIONS] - if translations then - if getmetatable(translations) then - setmetatable(translations, nil) - end - local baseTranslations = instance[BASE_TRANSLATIONS] - if getmetatable(baseTranslations) then - setmetatable(baseTranslations, nil) - end - if translations == baseTranslations or instance[STRICTNESS] then - setmetatable(instance, strict_instance_mt) - - setmetatable(translations, baseTranslations_mt) - else - setmetatable(instance, nonstrict_instance_mt) - - setmetatable(baseTranslations, baseTranslations_mt) - end - else - setmetatable(instance, strict_instance_mt) - end - clearCache(instance) - newRegistries[instance] = true - scheduleClear() - return instance -end - -function AceLocale:new(name) - self:argCheck(name, 2, "string") - - if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then - return self.registry[name] - end - - AceLocale.registry[name] = refixInstance({ - [STRICTNESS] = false, - [NAME] = name, - }) - newRegistries[AceLocale.registry[name]] = true - return AceLocale.registry[name] -end - -function AceLocale.prototype:EnableDebugging() - if rawget(self, BASE_TRANSLATIONS) then - AceLocale.error(self, "Cannot enable debugging after a translation has been registered.") - end - rawset(self, DEBUGGING, true) -end - -function AceLocale.prototype:EnableDynamicLocales(override) - AceLocale.argCheck(self, override, 2, "boolean", "nil") - if not override and rawget(self, BASE_TRANSLATIONS) then - AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.") - end - if not rawget(self, DYNAMIC_LOCALES) then - rawset(self, DYNAMIC_LOCALES, true) - if rawget(self, BASE_LOCALE) then - if not rawget(self, TRANSLATION_TABLES) then - rawset(self, TRANSLATION_TABLES, {}) - end - self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS] - self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS] - end - end -end - -function AceLocale.prototype:RegisterTranslations(locale, func) - AceLocale.argCheck(self, locale, 2, "string") - AceLocale.argCheck(self, func, 3, "function") - - if locale == rawget(self, BASE_LOCALE) then - AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) - end - - if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then - if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then - if not rawget(self, TRANSLATION_TABLES) then - rawset(self, TRANSLATION_TABLES, {}) - end - if self[TRANSLATION_TABLES][locale] then - AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) - end - local t = func() - func = nil - if type(t) ~= "table" then - AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) - end - self[TRANSLATION_TABLES][locale] = t - t = nil - end - func = nil - return - end - local t = func() - func = nil - if type(t) ~= "table" then - AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) - end - - rawset(self, TRANSLATIONS, t) - if not rawget(self, BASE_TRANSLATIONS) then - rawset(self, BASE_TRANSLATIONS, t) - rawset(self, BASE_LOCALE, locale) - for key,value in pairs(t) do - if value == true then - t[key] = key - end - end - else - for key, value in pairs(self[TRANSLATIONS]) do - if not rawget(self[BASE_TRANSLATIONS], key) then - AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale) - end - if value == true then - AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale) - end - end - end - rawset(self, CURRENT_LOCALE, locale) - if not rawget(self, 'reverse') then - rawset(self, 'reverse', setmetatable({}, { __index = function(self2, key) - local self = AceLocale.reverseToBase[self2] - if not rawget(self, REVERSE_TRANSLATIONS) then - self:GetReverseTranslation(key) - end - self.reverse = self[REVERSE_TRANSLATIONS] - return self.reverse[key] - end })) - AceLocale.reverseToBase[self.reverse] = self - end - refixInstance(self) - if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then - if not rawget(self, TRANSLATION_TABLES) then - rawset(self, TRANSLATION_TABLES, {}) - end - self[TRANSLATION_TABLES][locale] = t - end - t = nil -end - -function AceLocale.prototype:SetLocale(locale) - AceLocale.argCheck(self, locale, 2, "string", "boolean") - if not rawget(self, DYNAMIC_LOCALES) then - AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.") - end - if not rawget(self, TRANSLATION_TABLES) then - AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.") - end - if locale == true then - locale = GetLocale() - if not self[TRANSLATION_TABLES][locale] then - locale = self[BASE_LOCALE] - end - end - - if self[CURRENT_LOCALE] == locale then - return - end - - if not self[TRANSLATION_TABLES][locale] then - AceLocale.error(self, "Locale %q not registered.", locale) - end - - self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale] - self[CURRENT_LOCALE] = locale - refixInstance(self) -end - -function AceLocale.prototype:GetLocale() - if not rawget(self, TRANSLATION_TABLES) then - AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.") - end - return self[CURRENT_LOCALE] -end - -local function iter(t, position) - return (next(t, position)) -end - -function AceLocale.prototype:IterateAvailableLocales() - if not rawget(self, DYNAMIC_LOCALES) then - AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.") - end - if not rawget(self, TRANSLATION_TABLES) then - AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.") - end - return iter, self[TRANSLATION_TABLES], nil -end - -function AceLocale.prototype:HasLocale(locale) - if not rawget(self, DYNAMIC_LOCALES) then - AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.") - end - AceLocale.argCheck(self, locale, 2, "string") - return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil -end - -function AceLocale.prototype:SetStrictness(strict) - AceLocale.argCheck(self, strict, 2, "boolean") - local mt = getmetatable(self) - if not mt then - AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.") - end - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered.") - end - rawset(self, STRICTNESS, strict) - refixInstance(self) -end - -local function initReverse(self) - rawset(self, REVERSE_TRANSLATIONS, setmetatable({}, { __index = function(_, key) - AceLocale.error(self, "Reverse translation for %q does not exist", key) - end })) - local alpha = self[TRANSLATIONS] - local bravo = self[REVERSE_TRANSLATIONS] - for base, localized in pairs(alpha) do - bravo[localized] = base - end -end - -function AceLocale.prototype:GetTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - return self[text] -end - -function AceLocale.prototype:GetStrictTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - local x = rawget(self, TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - local value = rawget(x, text) - if value == nil then - local _, ret = pcall(AceLocale.error, self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE]) - geterrorhandler()(ret) - return text - end - return value -end - -function AceLocale.prototype:GetReverseTranslation(text) - local x = rawget(self, REVERSE_TRANSLATIONS) - if not x then - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - initReverse(self) - x = self[REVERSE_TRANSLATIONS] - end - local translation = x[text] - if not translation then - local _, ret = pcall(AceLocale.error, self, "Reverse translation for %q does not exist", text) - geterrorhandler()(ret) - return text - end - return translation -end - -function AceLocale.prototype:GetIterator() - local x = rawget(self, TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - return next, x, nil -end - -function AceLocale.prototype:GetReverseIterator() - local x = rawget(self, REVERSE_TRANSLATIONS) - if not x then - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - initReverse(self) - x = self[REVERSE_TRANSLATIONS] - end - return next, x, nil -end - -function AceLocale.prototype:HasTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - local x = rawget(self, TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - return rawget(x, text) and true -end - -function AceLocale.prototype:HasBaseTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - local x = rawget(self, BASE_TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - return rawget(x, text) and true -end - -function AceLocale.prototype:HasReverseTranslation(text) - local x = rawget(self, REVERSE_TRANSLATIONS) - if not x then - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - initReverse(self) - x = self[REVERSE_TRANSLATIONS] - end - return rawget(x, text) and true -end - -function AceLocale.prototype:Debug() - if not rawget(self, DEBUGGING) then - return - end - local words = {} - local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"} - local localizations = {} - DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---") - for _,locale in ipairs(locales) do - if not self[TRANSLATION_TABLES][locale] then - DEFAULT_CHAT_FRAME:AddMessage(("Locale %q not found"):format(locale)) - else - localizations[locale] = self[TRANSLATION_TABLES][locale] - end - end - local localeDebug = {} - for locale, localization in pairs(localizations) do - localeDebug[locale] = {} - for word in pairs(localization) do - if type(localization[word]) == "table" then - if type(words[word]) ~= "table" then - words[word] = {} - end - for bit in pairs(localization[word]) do - if type(localization[word][bit]) == "string" then - words[word][bit] = true - end - end - elseif type(localization[word]) == "string" then - words[word] = true - end - end - end - for word in pairs(words) do - if type(words[word]) == "table" then - for bit in pairs(words[word]) do - for locale, localization in pairs(localizations) do - if not rawget(localization, word) or not localization[word][bit] then - localeDebug[locale][word .. "::" .. bit] = true - end - end - end - else - for locale, localization in pairs(localizations) do - if not rawget(localization, word) then - localeDebug[locale][word] = true - end - end - end - end - for locale, t in pairs(localeDebug) do - if not next(t) then - DEFAULT_CHAT_FRAME:AddMessage(("Locale %q complete"):format(locale)) - else - DEFAULT_CHAT_FRAME:AddMessage(("Locale %q missing:"):format(locale)) - for word in pairs(t) do - DEFAULT_CHAT_FRAME:AddMessage((" %q"):format(word)) - end - end - end - DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---") -end - -setmetatable(AceLocale.prototype, { - __index = function(self, k) - if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later. - local _, ret = pcall(AceLocale.error, lastSelf or self, "Translation %q does not exist.", k) - geterrorhandler()(ret) - return k - end - return nil - end -}) - -local function activate(self, oldLib, oldDeactivate) - AceLocale = self - - self.frame = oldLib and oldLib.frame or CreateFrame("Frame") - self.registry = oldLib and oldLib.registry or {} - self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {} - self.DEBUGGING = oldLib and oldLib.DEBUGGING or {} - self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {} - self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {} - self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {} - self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {} - self.STRICTNESS = oldLib and oldLib.STRICTNESS or {} - self.NAME = oldLib and oldLib.NAME or {} - self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {} - self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {} - self.reverseToBase = oldLib and oldLib.reverseToBase or {} - - BASE_TRANSLATIONS = self.BASE_TRANSLATIONS - DEBUGGING = self.DEBUGGING - TRANSLATIONS = self.TRANSLATIONS - BASE_LOCALE = self.BASE_LOCALE - TRANSLATION_TABLES = self.TRANSLATION_TABLES - REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS - STRICTNESS = self.STRICTNESS - NAME = self.NAME - DYNAMIC_LOCALES = self.DYNAMIC_LOCALES - CURRENT_LOCALE = self.CURRENT_LOCALE - - strict_instance_mt = { - __index = strict__index, - __newindex = __newindex, - __tostring = __tostring - } - - nonstrict_instance_mt = { - __index = nonstrict__index, - __newindex = __newindex, - __tostring = __tostring - } - - baseTranslations_mt = { - __index = AceLocale.prototype - } - - local GetTime = GetTime - local timeUntilClear = GetTime() + 5 - scheduleClear = function() - if next(newRegistries) then - self.frame:Show() - timeUntilClear = GetTime() + 5 - end - end - - for name, instance in pairs(self.registry) do - local name = name - setmetatable(instance, nil) - instance[NAME] = name - local strict - if instance[STRICTNESS] ~= nil then - strict = instance[STRICTNESS] - elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then - if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then - strict = true - end - end - instance[STRICTNESS] = strict and true or false - refixInstance(instance) - end - - self.frame:SetScript("OnEvent", scheduleClear) - self.frame:SetScript("OnUpdate", function() -- (this, elapsed) - if timeUntilClear - GetTime() <= 0 then - self.frame:Hide() - for k in pairs(newRegistries) do - clearCache(k) - newRegistries[k] = nil - k = nil - end - end - end) - self.frame:UnregisterAllEvents() - self.frame:RegisterEvent("ADDON_LOADED") - self.frame:RegisterEvent("PLAYER_ENTERING_WORLD") - self.frame:Show() - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate) ---[[ -if true then -- debug - local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG" or "AceLocale_DEBUG3") - L:RegisterTranslations("enUS", function() return { - Monkey = true, - House = true, - } end) - - L:RegisterTranslations("deDE", function() return { - Monkey = "Affe" - } end) - - L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG" or "AceLocale_DEBUG3") - assert(L.Monkey == "Monkey") - assert(L.House == "House") - if not L.Debug then - local pants = L.Pants - assert(not pants) - end - assert(L.Debug) - assert(L.Debug == AceLocale.prototype.Debug) - - if MINOR_VERSION == 100000 then - L = AceLocale:new("AceLocale_DEBUG") - assert(L.Monkey == "Monkey") - assert(L.House == "House") - assert(L.Debug) - assert(type(L.Debug) == "function") - assert(AceLocale.prototype.Debug) - assert(type(AceLocale.prototype.Debug) == "function") - assert(L.Debug == AceLocale.prototype.Debug) - end - - local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG2" or "AceLocale_DEBUG4") - L:RegisterTranslations("deDE", function() return { - Affe = true, - Haus = true, - } end) - - L:RegisterTranslations("enUS", function() return { - Affe = "Monkey" - } end) - - L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG2" or "AceLocale_DEBUG4") - assert(L.Affe == "Monkey") - assert(L.Haus == "Haus") - assert(L.Debug) - assert(L.Debug == AceLocale.prototype.Debug) - - if MINOR_VERSION == 100000 then - L = AceLocale:new("AceLocale_DEBUG2") - assert(L.Affe == "Monkey") - assert(L.Haus == "Haus") - assert(L.Debug) - assert(L.Debug == AceLocale.prototype.Debug) - end - - local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG5" or "AceLocale_DEBUG6") - L:RegisterTranslations("deDE", function() return { - Affe = true, - Haus = true, - } end) - - L:RegisterTranslations("enUS", function() return { - Affe = "Monkey" - } end) - - L:SetStrictness(true) - - L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG5" or "AceLocale_DEBUG6") - assert(L.Affe == "Monkey") - assert(L.Haus == "Haus") - assert(L.Debug) - assert(L.Debug == AceLocale.prototype.Debug) - - if MINOR_VERSION == 100000 then - L = AceLocale:new("AceLocale_DEBUG5") - assert(L.Affe == "Monkey") - assert(L.Haus == "Haus") - assert(L.Debug) - assert(L.Debug == AceLocale.prototype.Debug) - end -end -]] \ No newline at end of file
--- a/lib/AceLocale-2.2/AceLocale-2.2.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceLocale-2.2 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary - -AceLocale-2.2.lua -AceLocale-2.2-2.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceLocale-3.0/AceLocale-3.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,103 @@ +--[[ $Id: AceLocale-3.0.lua 60131 2008-02-03 13:03:56Z nevcairiel $ ]] +local MAJOR,MINOR = "AceLocale-3.0", 1 + +local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR) + +if not AceLocale then return end -- no upgrade needed + +local gameLocale = GetLocale() +if gameLocale == "enGB" then + gameLocale = "enUS" +end + +AceLocale.apps = AceLocale.apps or {} -- array of ["AppName"]=localetableref +AceLocale.appnames = AceLocale.appnames or {} -- array of [localetableref]="AppName" + +-- This metatable is used on all tables returned from GetLocale +local readmeta = { + __index = function(self, key) -- requesting totally unknown entries: fire off a nonbreaking error and return key + geterrorhandler()(MAJOR..": "..tostring(AceLocale.appnames[self])..": Missing entry for '"..tostring(key).."'") + rawset(self, key, key) -- only need to see the warning once, really + return key + end +} + +-- Remember the locale table being registered right now (it gets set by :NewLocale()) +local registering + +-- local assert false function +local assertfalse = function() assert(false) end + +-- This metatable proxy is used when registering nondefault locales +local writeproxy = setmetatable({}, { + __newindex = function(self, key, value) + rawset(registering, key, value == true and key or value) -- assigning values: replace 'true' with key string + end, + __index = assertfalse +}) + +-- This metatable proxy is used when registering the default locale. +-- It refuses to overwrite existing values +-- Reason 1: Allows loading locales in any order +-- Reason 2: If 2 modules have the same string, but only the first one to be +-- loaded has a translation for the current locale, the translation +-- doesn't get overwritten. +-- +local writedefaultproxy = setmetatable({}, { + __newindex = function(self, key, value) + if not rawget(registering, key) then + rawset(registering, key, value == true and key or value) + end + end, + __index = assertfalse +}) + +-- AceLocale:NewLocale(application, locale, isDefault) +-- +-- application (string) - unique name of addon / module +-- locale (string) - name of locale to register, e.g. "enUS", "deDE", etc... +-- isDefault (string) - if this is the default locale being registered +-- +-- Returns a table where localizations can be filled out, or nil if the locale is not needed +function AceLocale:NewLocale(application, locale, isDefault) + + -- GAME_LOCALE allows translators to test translations of addons without having that wow client installed + -- Ammo: I still think this is a bad idea, for instance an addon that checks for some ingame string will fail, just because some other addon + -- gives the user the illusion that they can run in a different locale? Ditch this whole thing or allow a setting per 'application'. I'm of the + -- opinion to remove this. + local gameLocale = GAME_LOCALE or gameLocale + + if locale ~= gameLocale and not isDefault then + return -- nop, we don't need these translations + end + + local app = AceLocale.apps[application] + + if not app then + app = setmetatable({}, readmeta) + AceLocale.apps[application] = app + AceLocale.appnames[app] = application + end + + registering = app -- remember globally for writeproxy and writedefaultproxy + + if isDefault then + return writedefaultproxy + end + + return writeproxy +end + +-- AceLocale:GetLocale(application [, silent]) +-- +-- application (string) - unique name of addon +-- silent (boolean) - if true, the locale is optional, silently return nil if it's not found +-- +-- Returns localizations for the current locale (or default locale if translations are missing) +-- Errors if nothing is registered (spank developer, not just a missing translation) +function AceLocale:GetLocale(application, silent) + if not silent and not AceLocale.apps[application] then + error("Usage: GetLocale(application[, silent]): 'application' - No locales registered for '"..tostring(application).."'", 2) + end + return AceLocale.apps[application] +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceLocale-3.0/AceLocale-3.0.xml Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="AceLocale-3.0.lua"/> +</Ui> \ No newline at end of file
--- a/lib/AceModuleCore-2.0/AceModuleCore-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,688 +0,0 @@ ---[[ -Name: AceModuleCore-2.0 -Revision: $Rev: 43318 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceModuleCore-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceModuleCore-2.0 -Description: Mixin to provide a module system so that modules or plugins can - use an addon as its core. -Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0 (optional) -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceModuleCore-2.0" -local MINOR_VERSION = "$Revision: 43318 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end - -local function safecall(func, ...) - local success, err = pcall(func, ...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end -end - -local AceEvent -local AceOO = AceLibrary:GetInstance("AceOO-2.0") -local AceModuleCore = AceOO.Mixin { - "NewModule", - "HasModule", - "GetModule", - "IsModule", - "IterateModules", - "IterateModulesWithMethod", - "CallMethodOnAllModules", - "SetModuleMixins", - "SetModuleClass", - "IsModuleActive", - "ToggleModuleActive", - "SetModuleDefaultState", - } -local AceAddon - -local function getlibrary(lib) - if type(lib) == "string" then - return AceLibrary(lib) - else - return lib - end -end - -local new, del -do - local list = setmetatable({}, {__mode='k'}) - function new() - local t = next(list) - if t then - list[t] = nil - return t - else - return {} - end - end - function del(t) - for k in pairs(t) do - t[k] = nil - end - list[t] = true - return nil - end -end - -local iterList = setmetatable({}, {__mode='v'}) -local modulesWithMethod = setmetatable({}, {__mode='kv'}) -do - local function func(t) - local i = t.i + 1 - local l = t.l - local k = l[i] - if k then - t.i = i - return k, l.m[k] - else - t = del(t) - end - end - function AceModuleCore:IterateModules() - local list = iterList[self] - if not list then - list = new() - for k in pairs(self.modules) do - list[#list+1] = k - end - table.sort(list) - list.m = self.modules - iterList[self] = list - end - local t = new() - t.i = 0 - t.l = list - return func, t, nil - end - - function AceModuleCore:IterateModulesWithMethod(method) - local masterList = modulesWithMethod[self] - if not masterList then - masterList = new() - modulesWithMethod[self] = masterList - end - local list = masterList[method] - if not list then - list = new() - for k, v in pairs(self.modules) do - if self:IsModuleActive(k) and type(v[method]) == "function" then - list[#list+1] = k - end - end - table.sort(list) - list.m = self.modules - masterList[method] = list - end - local t = new() - t.i = 0 - t.l = list - return func, t, nil - end - ---[[---------------------------------------------------------------------------------- -Notes: - Safely calls the given method on all active modules if it exists on said modules. This will automatically subvert any errors that occur in the modules. -Arguments: - string - the name of the method. - tuple - the list of arguments to call the method with. -Example: - core:CallMethodOnAllModules("OnSomething") - core:CallMethodOnAllModules("OnSomethingElse", 1, 2, 3, 4) -------------------------------------------------------------------------------------]] - function AceModuleCore:CallMethodOnAllModules(method, ...) - for name, module in self:IterateModulesWithMethod(method) do - local success, ret = pcall(module[method], module, ...) - if not success then - geterrorhandler()(ret) - end - end - end -end - ---[[---------------------------------------------------------------------------- -Notes: - Create a new module, parented to self. - The module created does, in fact, inherit from AceAddon-2.0. -Arguments: - string - name/title of the Module. - list of mixins the module is to inherit from. -Example: - MyModule = core:NewModule('MyModule', "AceEvent-2.0", "AceHook-2.1") -------------------------------------------------------------------------------]] -local tmp = {} -function AceModuleCore:NewModule(name, ...) - if not self.modules then - AceModuleCore:error("CreatePrototype() must be called before attempting to create a new module.", 2) - end - AceModuleCore:argCheck(name, 2, "string") - if name:len() == 0 then - AceModuleCore:error("Bad argument #2 to `NewModule`, string must not be empty") - end - if self.modules[name] then - AceModuleCore:error("The module %q has already been registered", name) - end - - if iterList[self] then - iterList[self] = del(iterList[self]) - end - - for i = 1, select('#', ...) do - tmp[i] = getlibrary((select(i, ...))) - end - - if self.moduleMixins then - for _,mixin in ipairs(self.moduleMixins) do - local exists = false - for _,v in ipairs(tmp) do - if mixin == v then - exists = true - break - end - end - if not exists then - tmp[#tmp+1] = mixin - end - end - end - - local module = AceOO.Classpool(self.moduleClass, unpack(tmp)):new(name) - self.modules[name] = module - module.name = name - module.title = name - - AceModuleCore.totalModules[module] = self - - if modulesWithMethod[self] then - for k,v in pairs(modulesWithMethod[self]) do - modulesWithMethod[self] = del(v) - end - end - - if type(self.OnModuleCreated) == "function" then - safecall(self.OnModuleCreated, self, name, module) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_ModuleCreated", module) - end - - local num = #tmp - for i = 1, num do - tmp[i] = nil - end - return module -end ---[[---------------------------------------------------------------------------------- -Notes: - Return whether the module names given are all available in the core. -Arguments: - list of strings that are the names of the modules. (typically you'd only check for one) -Returns: - * boolean - Whether all the modules are available in the core. -Example: - if core:HasModule('Bank') then - -- do banking - end -------------------------------------------------------------------------------------]] -function AceModuleCore:HasModule(...) - for i = 1, select('#', ...) do - if not self.modules[select(i, ...)] then - return false - end - end - - return true -end - ---[[------------------------------------------------------------------------------------ -Notes: - Return the module "name" if it exists. - If the module doesnot exist, an error is thrown. -Arguments: - string - the name of the module. -Returns: - The module requested, if it exists. -Example: - local bank = core:GetModule('Bank') -------------------------------------------------------------------------------------]] -function AceModuleCore:GetModule(name) - if not self.modules then - AceModuleCore:error("Error initializing class. Please report error.") - end - if not self.modules[name] then - AceModuleCore:error("Cannot find module %q.", name) - end - return self.modules[name] -end - ---[[---------------------------------------------------------------------------------- -Notes: - Return whether the given module is actually a module. -Arguments: - reference to the module -Returns: - * boolean - whether the given module is actually a module. -Example: - if core:IsModule(module) then - -- do something - end - -- alternatively - if AceModuleCore:IsModule(module) then - -- checks all modules, no matter the parent - end -------------------------------------------------------------------------------------]] -function AceModuleCore:IsModule(module) - if self == AceModuleCore then - return AceModuleCore.totalModules[module] - elseif type(module) == "table" then - if module.name and self.modules[module.name] and self.modules[module.name].name == module.name then - return true - end - for k,v in pairs(self.modules) do - if v == module then - return true - end - end - return false - end -end - ---[[---------------------------------------------------------------------------------- -Notes: - * Sets the default mixins for a given module. - * This cannot be called after :NewModule() has been called. - * This should really only be called if you use the mixins in your prototype. -Arguments: - list of mixins (up to 20) -Example: - core:SetModuleMixins("AceEvent-2.0", "AceHook-2.0") -------------------------------------------------------------------------------------]] -function AceModuleCore:SetModuleMixins(...) - if self.moduleMixins then - AceModuleCore:error('Cannot call "SetModuleMixins" twice') - elseif not self.modules then - AceModuleCore:error("Error initializing class. Please report error.") - elseif next(self.modules) then - AceModuleCore:error('Cannot call "SetModuleMixins" after "NewModule" has been called.') - end - - self.moduleMixins = { ... } - for i,v in ipairs(self.moduleMixins) do - self.moduleMixins[i] = getlibrary(v) - end -end - --- #NODOC -function AceModuleCore:SetModuleClass(class) - class = getlibrary(class) - if not AceOO.inherits(class, AceOO.Class) then - AceModuleCore:error("Bad argument #2 to `SetModuleClass' (Class expected)") - end - if not self.modules then - AceModuleCore:error("Error initializing class. Please report error.") - end - if self.customModuleClass then - AceModuleCore:error("Cannot call `SetModuleClass' twice.") - end - self.customModuleClass = true - self.moduleClass = class - self.modulePrototype = class.prototype -end - -local mt = {__index=function(self, key) - self[key] = false - return false -end} -local defaultState = setmetatable({}, {__index=function(self, key) - local t = setmetatable({}, mt) - self[key] = t - return t -end}) - -local function isDisabled(core, module) - local moduleName - if type(module) == "table" then - moduleName = module.name - else - moduleName = module - end - local disabled - if type(module) == "table" and type(module.IsActive) == "function" then - return not module:IsActive() - elseif AceOO.inherits(core, "AceDB-2.0") then - local _,profile = core:GetProfile() - disabled = core.db and core.db.raw and core.db.raw.disabledModules and core.db.raw.disabledModules[profile] and core.db.raw.disabledModules[profile][moduleName] - else - disabled = core.disabledModules and core.disabledModules[moduleName] - end - if disabled == nil then - return defaultState[core][moduleName] - else - return disabled - end -end - ---[[---------------------------------------------------------------------------------- -Notes: - Sets the default active state of a module. This should be called before the ADDON_LOADED of the module. -Arguments: - string - name of the module. - table - reference to the module. - boolean - new state. false means disabled by default, true means enabled by default (true is the default). -Example: - self:SetModuleDefaultState('bank', false) -------------------------------------------------------------------------------------]] -function AceModuleCore:SetModuleDefaultState(module, state) - AceModuleCore:argCheck(module, 2, "table", "string") - AceModuleCore:argCheck(state, 3, "boolean") - - if type(module) == "table" then - if not self:IsModule(module) then - AceModuleCore:error("%q is not a module", module) - end - module = module.name - end - - defaultState[self][module] = not state -end - ---[[---------------------------------------------------------------------------------- -Notes: -Toggles the active state of a module. - -This calls module:ToggleActive([state]) if available. - -If suspending, This will call :OnDisable() on the module if it is available. Also, it will iterate through the addon's mixins and call :OnEmbedDisable(module) if available. - this in turn will, through AceEvent and others, unregister events/hooks/etc. depending on the mixin. Also, it will call :OnModuleDisable(module) on the core if it is available. - -If resuming, This will call :OnEnable(first) on the module if it is available. Also, it will iterate through the addon's mixins and call :OnEmbedEnable(module) if available. - this in turn will, through AceEvent and others, unregister events/hooks/etc. depending on the mixin. Also, it will call :OnModuleEnable(module) on the core if it is available. - -If you call :ToggleModuleActive("name or module, true) and it is already active, it silently returns, same if you pass false and it is inactive. - -Arguments: - string/table - name of the module or a reference to the module - [optional] boolean - new state. (default not :IsModuleActive("name" or module)) -Returns: - * boolean - Whether the module is now in an active (enabled) state. -Example: - self:ToggleModuleActive('bank') -------------------------------------------------------------------------------------]] -function AceModuleCore:ToggleModuleActive(module, state) - AceModuleCore:argCheck(module, 2, "table", "string") - AceModuleCore:argCheck(state, 3, "nil", "boolean") - - if type(module) == "string" then - if not self:HasModule(module) then - AceModuleCore:error("Cannot find module %q", module) - end - module = self:GetModule(module) - elseif not self:IsModule(module) then - AceModuleCore:error("%q is not a module", module) - end - - local disable - if state == nil then - disable = self:IsModuleActive(module) - else - disable = not state - if disable ~= self:IsModuleActive(module) then - return - end - end - - if type(module.ToggleActive) == "function" then - return module:ToggleActive(not disable) - elseif AceOO.inherits(self, "AceDB-2.0") then - if not self.db or not self.db.raw then - AceModuleCore:error("Cannot toggle a module until `RegisterDB' has been called and `ADDON_LOADED' has been fired.") - end - if type(self.db.raw.disabledModules) ~= "table" then - self.db.raw.disabledModules = {} - end - local _,profile = self:GetProfile() - if type(self.db.raw.disabledModules[profile]) ~= "table" then - self.db.raw.disabledModules[profile] = {} - end - if type(self.db.raw.disabledModules[profile][module.name]) ~= "table" then - local value = nil - if disable ~= defaultState[self][module.name] then - value = disable - end - self.db.raw.disabledModules[profile][module.name] = value - end - if not disable then - if not next(self.db.raw.disabledModules[profile]) then - self.db.raw.disabledModules[profile] = nil - end - if not next(self.db.raw.disabledModules) then - self.db.raw.disabledModules = nil - end - end - else - if type(self.disabledModules) ~= "table" then - self.disabledModules = {} - end - local value = nil - if disable ~= defaultState[self][module.name] then - value = disable - end - self.disabledModules[module.name] = value - end - if AceOO.inherits(module, "AceAddon-2.0") then - if not AceAddon.addonsStarted[module] then - return - end - end - if not disable then - local first = nil - if AceOO.inherits(module, "AceAddon-2.0") then - if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[module] then - AceAddon.addonsEnabled[module] = true - first = true - end - end - local current = module.class - while true do - if current == AceOO.Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, module, first) - end - end - end - current = current.super - end - if type(module.OnEnable) == "function" then - safecall(module.OnEnable, module, first) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", module, first) - end - else - local current = module.class - while true do - if current == AceOO.Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, module) - end - end - end - current = current.super - end - if type(module.OnDisable) == "function" then - safecall(module.OnDisable, module) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", module) - end - end - return not disable -end - ---[[----------------------------------------------------------------------- -Notes: - Returns whether the module is in an active (enabled) state. This calls module:IsActive() if available. if notLoaded is set, then "name" must be a string. -Arguments: - string/table - name of the module or a reference to the module - [optional] - boolean - if set, this will check modules that are not loaded as well. (default: false) -Returns: - * boolean - Whether the module is in an active (enabled) state. -Example: - assert(self:IsModuleActive('bank')) -------------------------------------------------------------------------]] -function AceModuleCore:IsModuleActive(module, notLoaded) - AceModuleCore:argCheck(module, 2, "table", "string") - AceModuleCore:argCheck(notLoaded, 3, "nil", "boolean") - if notLoaded then - AceModuleCore:argCheck(module, 2, "string") - end - - if AceModuleCore == self then - self:argCheck(module, 2, "table") - - local core = AceModuleCore.totalModules[module] - if not core then - self:error("Bad argument #2 to `IsModuleActive'. Not a module") - end - return core:IsModuleActive(module) - end - - if type(module) == "string" then - if not notLoaded and not self:HasModule(module) then - AceModuleCore:error("Cannot find module %q", module) - end - if not notLoaded then - module = self:GetModule(module) - else - module = self:HasModule(module) and self:GetModule(module) or module - end - else - if not self:IsModule(module) then - AceModuleCore:error("%q is not a module", module) - end - end - - return not isDisabled(self, module) -end - --- #NODOC -function AceModuleCore:OnInstanceInit(target) - if target.modules then - do return end - AceModuleCore:error("OnInstanceInit cannot be called twice") - end - - if not AceAddon then - if AceLibrary:HasInstance("AceAddon-2.0") then - AceAddon = AceLibrary("AceAddon-2.0") - else - self:error(MAJOR_VERSION .. " requires AceAddon-2.0") - end - end - target.modules = {} - - target.moduleClass = AceOO.Class("AceAddon-2.0") - target.modulePrototype = target.moduleClass.prototype -end - -AceModuleCore.OnManualEmbed = AceModuleCore.OnInstanceInit - -function AceModuleCore.OnEmbedProfileDisable(AceModuleCore, self, newProfile) - if not AceOO.inherits(self, "AceDB-2.0") then - return - end - local _,currentProfile = self:GetProfile() - for k, module in pairs(self.modules) do - if type(module.IsActive) == "function" or type(module.ToggleActive) == "function" then - -- continue - else - local currentActive = not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[currentProfile] or not self.db.raw.disabledModules[currentProfile][module.name] - local newActive = not self.db or not self.db.raw or not self.db.raw.disabledModules or not self.db.raw.disabledModules[newProfile] or not self.db.raw.disabledModules[newProfile][module.name] - if currentActive ~= newActive then - self:ToggleModuleActive(module) - if not self.db.raw.disabledModules then - self.db.raw.disabledModules = {} - end - if not self.db.raw.disabledModules[currentProfile] then - self.db.raw.disabledModules[currentProfile] = {} - end - self.db.raw.disabledModules[currentProfile][module.name] = not currentActive or nil - end - end - end -end - --- #NODOC -function AceModuleCore:Ace2_AddonEnabled(module, first) - local addon = self.totalModules[module] - if not addon then - return - end - - if modulesWithMethod[addon] then - for k,v in pairs(modulesWithMethod[addon]) do - modulesWithMethod[addon] = del(v) - end - end - if type(addon.OnModuleEnable) == "function" then - safecall(addon.OnModuleEnable, addon, module, first) - end -end - --- #NODOC -function AceModuleCore:Ace2_AddonDisabled(module) - local addon = self.totalModules[module] - if not addon then - return - end - - if modulesWithMethod[addon] then - for k,v in pairs(modulesWithMethod[addon]) do - modulesWithMethod[addon] = del(v) - end - end - if type(addon.OnModuleDisable) == "function" then - safecall(addon.OnModuleDisable, addon, module) - end -end - -local function activate(self, oldLib, oldDeactivate) - AceModuleCore = self - - self.totalModules = oldLib and oldLib.totalModules or {} - - self:activate(oldLib, oldDeactivate) - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -local function external(self, major, instance) - if major == "AceEvent-2.0" then - AceEvent = instance - AceEvent:embed(self) - - self:UnregisterAllEvents() - self:RegisterEvent("Ace2_AddonEnabled") - self:RegisterEvent("Ace2_AddonDisabled") - elseif major == "AceAddon-2.0" then - AceAddon = instance - end -end - -AceLibrary:Register(AceModuleCore, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) -AceModuleCore = AceLibrary(MAJOR_VERSION)
--- a/lib/AceModuleCore-2.0/AceModuleCore-2.0.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceModuleCore-2.0 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary, AceOO-2.0, AceAddon-2.0, AceEvent-2.0 - -AceModuleCore-2.0.lua
--- a/lib/AceOO-2.0/AceOO-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,980 +0,0 @@ ---[[ -Name: AceOO-2.0 -Revision: $Rev: 38641 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceOO-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0 -Description: Library to provide an object-orientation framework. -Dependencies: AceLibrary -License: MIT -]] - -local MAJOR_VERSION = "AceOO-2.0" -local MINOR_VERSION = "$Revision: 38641 $" - --- This ensures the code is only executed if the libary doesn't already exist, or is a newer version -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local AceOO = { - error = AceLibrary.error, - argCheck = AceLibrary.argCheck -} - --- @function getuid --- @brief Obtain a unique string identifier for the object in question. --- @param t The object to obtain the uid for. --- @return The uid string. -local function getuid(t) - local mt = getmetatable(t) - setmetatable(t, nil) - local str = tostring(t) - setmetatable(t, mt) - local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$") - if cap then - return ("0"):rep(8 - #cap) .. cap - end -end - -local function getlibrary(o) - if type(o) == "table" then - return o - elseif type(o) == "string" then - if not AceLibrary:HasInstance(o) then - AceOO:error("Library %q does not exist.", o) - end - return AceLibrary(o) - end -end - -local function deeprawget(self, k) - while true do - local v = rawget(self, k) - if v ~= nil then - return v - end - local mt = getmetatable(self) - if not mt or type(mt.__index) ~= "table" then - return nil - end - self = mt.__index - end -end - --- @function Factory --- @brief Construct a factory for the creation of objects. --- @param obj The object whose init method will be called on the new factory --- object. --- @param newobj The object whose init method will be called on the new --- objects that the Factory creates, to initialize them. --- @param (...) Arguments which will be passed to obj.init() in addition --- to the Factory object. --- @return The new factory which creates a newobj when its new method is called, --- or when it is called directly (__call metamethod). -local Factory -do - local function getlibraries(...) - if select('#', ...) == 0 then - return - end - return getlibrary((select(1, ...))), getlibraries(select(2, ...)) - end - local arg = {} - local function new(obj, ...) - local t = {} - local uid = getuid(t) - obj:init(t, getlibraries(...)) - t.uid = uid - return t - end - - local function createnew(self, ...) - local o = self.prototype - local x = new(o, getlibraries(...)) - return x - end - - function Factory(obj, newobj, ...) - local t = new(obj, ...) - t.prototype = newobj - t.new = createnew - getmetatable(t).__call = t.new - return t - end -end - - -local function objtostring(self) - if self.ToString then - return self:ToString() - elseif self.GetLibraryVersion then - return (self:GetLibraryVersion()) - elseif self.super then - local s = "Sub-" .. tostring(self.super) - local first = true - if self.interfaces then - for interface in pairs(self.interfaces) do - if first then - s = s .. "(" .. tostring(interface) - first = false - else - s = s .. ", " .. tostring(interface) - end - end - end - if self.mixins then - for mixin in pairs(self.mixins) do - if first then - s = s .. tostring(mixin) - first = false - else - s = s .. ", " .. tostring(mixin) - end - end - end - if first then - if self.uid then - return s .. ":" .. self.uid - else - return s - end - else - return s .. ")" - end - else - return self.uid and 'Subclass:' .. self.uid or 'Subclass' - end -end - --- @table Object --- @brief Base of all objects, including Class. --- --- @method init --- @brief Initialize a new object. --- @param newobject The object to initialize --- @param class The class to make newobject inherit from -local Object -do - Object = {} - function Object:init(newobject, class) - local parent = class or self - if not rawget(newobject, 'uid') then - newobject.uid = getuid(newobject) - end - local mt = { - __index = parent, - __tostring = objtostring, - } - setmetatable(newobject, mt) - end - Object.uid = getuid(Object) - setmetatable(Object, { __tostring = function() return 'Object' end }) -end - -local Interface - -local function validateInterface(object, interface) - if not object.class and object.prototype then - object = object.prototype - end - for k,v in pairs(interface.interface) do - if tostring(type(object[k])) ~= v then - return false - end - end - if interface.superinterfaces then - for superinterface in pairs(interface.superinterfaces) do - if not validateInterface(object, superinterface) then - return false - end - end - end - if type(object.class) == "table" and rawequal(object.class.prototype, object) then - if not object.class.interfaces then - rawset(object.class, 'interfaces', {}) - end - object.class.interfaces[interface] = true - elseif type(object.class) == "table" and type(object.class.prototype) == "table" then - validateInterface(object.class.prototype, interface) - -- check if class is proper, thus preventing future checks. - end - return true -end - --- @function inherits --- @brief Return whether an Object or Class inherits from a given --- parent. --- @param object Object or Class to check --- @param parent Parent to test inheritance from --- @return whether an Object or Class inherits from a given --- parent. -local function inherits(object, parent) - object = getlibrary(object) - if type(parent) == "string" then - if not AceLibrary:HasInstance(parent) then - return false - else - parent = AceLibrary(parent) - end - end - AceOO:argCheck(parent, 2, "table") - if type(object) ~= "table" then - return false - end - local current - local class = deeprawget(object, 'class') - if class then - current = class - else - current = object - end - if type(current) ~= "table" then - return false - end - if rawequal(current, parent) then - return true - end - if parent.class then - while true do - if rawequal(current, Object) then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if rawequal(mixin, parent) then - return true - end - end - end - if current.interfaces then - for interface in pairs(current.interfaces) do - if rawequal(interface, parent) then - return true - end - end - end - current = deeprawget(current, 'super') - if type(current) ~= "table" then - break - end - end - - local isInterface = false - local curr = parent.class - while true do - if rawequal(curr, Object) then - break - elseif rawequal(curr, Interface) then - isInterface = true - break - end - curr = deeprawget(curr, 'super') - if type(curr) ~= "table" then - break - end - end - return isInterface and validateInterface(object, parent) - else - while true do - if rawequal(current, parent) then - return true - elseif rawequal(current, Object) then - return false - end - current = deeprawget(current, 'super') - if type(current) ~= "table" then - return false - end - end - end -end - --- @table Class --- @brief An object factory which sets up inheritence and supports --- 'mixins'. --- --- @metamethod Class call --- @brief Call ClassFactory:new() to create a new class. --- --- @method Class new --- @brief Construct a new object. --- @param (...) Arguments to pass to the object init function. --- @return The new object. --- --- @method Class init --- @brief Initialize a new class. --- @param parent Superclass. --- @param (...) Mixins. --- --- @method Class ToString --- @return A string representing the object, in this case 'Class'. -local initStatus -local Class -local Mixin -local autoEmbed = false -local function traverseInterfaces(bit, total) - if bit.superinterfaces then - for interface in pairs(bit.superinterfaces) do - if not total[interface] then - total[interface] = true - traverseInterfaces(interface, total) - end - end - end -end -local class_new -do - Class = Factory(Object, setmetatable({}, {__index = Object}), Object) - Class.super = Object - - local function protostring(t) - return '<' .. tostring(t.class) .. ' prototype>' - end - local function classobjectstring(t) - if t.ToString then - return t:ToString() - elseif t.GetLibraryVersion then - return (t:GetLibraryVersion()) - else - return '<' .. tostring(t.class) .. ' instance>' - end - end - local function classobjectequal(self, other) - if type(self) == "table" and self.Equals then - return self:Equals(other) - elseif type(other) == "table" and other.Equals then - return other:Equals(self) - elseif type(self) == "table" and self.CompareTo then - return self:CompareTo(other) == 0 - elseif type(other) == "table" and other.CompareTo then - return other:CompareTo(self) == 0 - else - return rawequal(self, other) - end - end - local function classobjectlessthan(self, other) - if type(self) == "table" and self.IsLessThan then - return self:IsLessThan(other) - elseif type(other) == "table" and other.IsLessThanOrEqualTo then - return not other:IsLessThanOrEqualTo(self) - elseif type(self) == "table" and self.CompareTo then - return self:CompareTo(other) < 0 - elseif type(other) == "table" and other.CompareTo then - return other:CompareTo(self) > 0 - elseif type(other) == "table" and other.IsLessThan and other.Equals then - return other:Equals(self) or other:IsLessThan(self) - else - AceOO:error("cannot compare two objects") - end - end - local function classobjectlessthanequal(self, other) - if type(self) == "table" and self.IsLessThanOrEqualTo then - return self:IsLessThanOrEqualTo(other) - elseif type(other) == "table" and other.IsLessThan then - return not other:IsLessThan(self) - elseif type(self) == "table" and self.CompareTo then - return self:CompareTo(other) <= 0 - elseif type(other) == "table" and other.CompareTo then - return other:CompareTo(self) >= 0 - elseif type(self) == "table" and self.IsLessThan and self.Equals then - return self:Equals(other) or self:IsLessThan(other) - else - AceOO:error("cannot compare two incompatible objects") - end - end - local function classobjectadd(self, other) - if type(self) == "table" and self.Add then - return self:Add(other) - else - AceOO:error("cannot add two incompatible objects") - end - end - local function classobjectsub(self, other) - if type(self) == "table" and self.Subtract then - return self:Subtract(other) - else - AceOO:error("cannot subtract two incompatible objects") - end - end - local function classobjectunm(self, other) - if type(self) == "table" and self.UnaryNegation then - return self:UnaryNegation(other) - else - AceOO:error("attempt to negate an incompatible object") - end - end - local function classobjectmul(self, other) - if type(self) == "table" and self.Multiply then - return self:Multiply(other) - else - AceOO:error("cannot multiply two incompatible objects") - end - end - local function classobjectdiv(self, other) - if type(self) == "table" and self.Divide then - return self:Divide(other) - else - AceOO:error("cannot divide two incompatible objects") - end - end - local function classobjectpow(self, other) - if type(self) == "table" and self.Exponent then - return self:Exponent(other) - else - AceOO:error("cannot exponentiate two incompatible objects") - end - end - local function classobjectconcat(self, other) - if type(self) == "table" and self.Concatenate then - return self:Concatenate(other) - else - AceOO:error("cannot concatenate two incompatible objects") - end - end - function class_new(self, ...) - if self.virtual then - AceOO:error("Cannot instantiate a virtual class.") - end - - local o = self.prototype - local newobj = {} - if o.class and o.class.instancemeta then - setmetatable(newobj, o.class.instancemeta) - else - Object:init(newobj, o) - end - - if self.interfaces and not self.interfacesVerified then - -- Verify the interfaces - - for interface in pairs(self.interfaces) do - for field,kind in pairs(interface.interface) do - if tostring(type(newobj[field])) ~= kind then - AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field]))) - end - end - end - self.interfacesVerified = true - end - local tmp = initStatus - initStatus = newobj - newobj:init(...) - if initStatus then - initStatus = tmp - AceOO:error("Initialization not completed, be sure to call the superclass's init method.") - return - end - initStatus = tmp - return newobj - end - local classmeta = { - __tostring = objtostring, - __call = function(self, ...) - return self:new(...) - end, - } - function Class:init(newclass, parent, ...) - parent = parent or self - - local total - - if parent.class then - total = { parent, ... } - parent = self - else - total = { ... } - end - if not inherits(parent, Class) then - AceOO:error("Classes must inherit from a proper class") - end - if parent.sealed then - AceOO:error("Cannot inherit from a sealed class") - end - for i,v in ipairs(total) do - if inherits(v, Mixin) and v.class then - if v.__deprecated then - AceOO:error(v.__deprecated) - end - if not newclass.mixins then - newclass.mixins = {} - end - if newclass.mixins[v] then - AceOO:error("Cannot explicitly inherit from the same mixin twice") - end - newclass.mixins[v] = true - elseif inherits(v, Interface) and v.class then - if not newclass.interfaces then - newclass.interfaces = {} - end - if newclass.interfaces[v] then - AceOO:error("Cannot explicitly inherit from the same interface twice") - end - newclass.interfaces[v] = true - else - AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces") - end - end - if parent.interfaces then - if not newclass.interfaces then - newclass.interfaces = {} - end - for interface in pairs(parent.interfaces) do - newclass.interfaces[interface] = true - end - end - for k in pairs(total) do - total[k] = nil - end - - newclass.super = parent - - newclass.prototype = setmetatable(total, { - __index = parent.prototype, - __tostring = protostring, - }) - total = nil - - newclass.instancemeta = { - __index = newclass.prototype, - __tostring = classobjectstring, - __eq = classobjectequal, - __lt = classobjectlessthan, - __le = classobjectlessthanequal, - __add = classobjectadd, - __sub = classobjectsub, - __unm = classobjectunm, - __mul = classobjectmul, - __div = classobjectdiv, - __pow = classobjectpow, - __concat = classobjectconcat, - } - - setmetatable(newclass, classmeta) - - newclass.new = class_new - - if newclass.mixins then - -- Fold in the mixins - local err, msg - for mixin in pairs(newclass.mixins) do - local ret - autoEmbed = true - ret, msg = pcall(mixin.embed, mixin, newclass.prototype) - autoEmbed = false - if not ret then - err = true - break - end - end - - if err then - local pt = newclass.prototype - for k,v in pairs(pt) do - pt[k] = nil - end - - -- method conflict - AceOO:error(msg) - end - end - - newclass.prototype.class = newclass - - if newclass.interfaces then - for interface in pairs(newclass.interfaces) do - traverseInterfaces(interface, newclass.interfaces) - end - end - if newclass.mixins then - for mixin in pairs(newclass.mixins) do - if mixin.interfaces then - if not newclass.interfaces then - newclass.interfaces = {} - end - for interface in pairs(mixin.interfaces) do - newclass.interfaces[interface] = true - end - end - end - end - end - function Class:ToString() - if type(self.GetLibraryVersion) == "function" then - return (self:GetLibraryVersion()) - else - return "Class" - end - end - - local tmp - function Class.prototype:init() - if rawequal(self, initStatus) then - initStatus = nil - else - AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2) - end - self.uid = getuid(self) - local current = self.class - while true do - if current == Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnInstanceInit) == "function" then - mixin:OnInstanceInit(self) - end - end - end - current = current.super - end - end -end - - --- @object ClassFactory --- @brief A factory for creating classes. Rarely used directly. -local ClassFactory = Factory(Object, Class, Object) - -function Class:new(...) - local x = ClassFactory:new(...) - if AceOO.classes then - AceOO.classes[x] = true - end - return x -end -getmetatable(Class).__call = Class.new - --- @class Mixin --- @brief A class to create mixin objects, which contain methods that get --- "mixed in" to class prototypes. --- --- @object Mixin prototype --- @brief The prototype that mixin objects inherit their methods from. --- --- @method Mixin prototype embed --- @brief Mix in the methods of our object which are listed in our interface --- to the supplied target table. --- --- @method Mixin prototype init --- @brief Initialize the mixin object. --- @param newobj The new object we're initializing. --- @param interface The interface we implement (the list of methods our --- prototype provides which should be mixed into the target --- table by embed). -do - Mixin = Class() - function Mixin:ToString() - if self.GetLibraryVersion then - return (self:GetLibraryVersion()) - else - return 'Mixin' - end - end - local function _Embed(state, field, target) - field = next(state.export, field) - if field == nil then - return - end - - if rawget(target, field) or (target[field] and target[field] ~= state[field]) then - AceOO:error("Method conflict in attempt to mixin. Field %q", field) - end - - target[field] = state[field] - - local ret,msg = pcall(_Embed, state, field, target) - if not ret then - -- Mix in the next method according to the defined interface. If that - -- fails due to a conflict, re-raise to back out the previous mixed - -- methods. - - target[field] = nil - AceOO:error(msg) - end - end - function Mixin.prototype:embed(target) - if self.__deprecated then - AceOO:error(self.__deprecated) - end - local mt = getmetatable(target) - setmetatable(target, nil) - local err, msg = pcall(_Embed, self, nil, target) - if not err then - setmetatable(target, mt) - AceOO:error(msg) - return - end - if type(self.embedList) == "table" then - self.embedList[target] = true - end - if type(target.class) ~= "table" then - target[self] = true - end - if not autoEmbed and type(self.OnManualEmbed) == "function" then - self:OnManualEmbed(target) - end - setmetatable(target, mt) - end - - function Mixin.prototype:activate(oldLib, oldDeactivate) - if oldLib and oldLib.embedList then - for target in pairs(oldLib.embedList) do - local mt = getmetatable(target) - setmetatable(target, nil) - for field in pairs(oldLib.export) do - target[field] = nil - end - setmetatable(target, mt) - end - self.embedList = oldLib.embedList - for target in pairs(self.embedList) do - self:embed(target) - end - else - self.embedList = setmetatable({}, {__mode="k"}) - end - end - - function Mixin.prototype:init(export, ...) - AceOO:argCheck(export, 2, "table") - for k,v in pairs(export) do - if type(k) ~= "number" then - AceOO:error("All keys to argument #2 must be numbers.") - elseif type(v) ~= "string" then - AceOO:error("All values to argument #2 must be strings.") - end - end - local num = #export - for i = 1, num do - local v = export[i] - export[i] = nil - export[v] = true - end - - local interfaces - if select('#', ...) >= 1 then - interfaces = { ... } - for i,v in ipairs(interfaces) do - v = getlibrary(v) - interfaces[i] = v - if not v.class or not inherits(v, Interface) then - AceOO:error("Mixins can inherit only from interfaces") - end - end - local num = #interfaces - for i = 1, num do - local v = interfaces[i] - interfaces[i] = nil - interfaces[v] = true - end - for interface in pairs(interfaces) do - traverseInterfaces(interface, interfaces) - end - for interface in pairs(interfaces) do - for field,kind in pairs(interface.interface) do - if kind ~= "nil" then - local good = false - for bit in pairs(export) do - if bit == field then - good = true - break - end - end - if not good then - AceOO:error("Mixin does not fully accommodate field %q", field) - end - end - end - end - end - self.super = Mixin.prototype - Mixin.super.prototype.init(self) - self.export = export - self.interfaces = interfaces - end -end - --- @class Interface --- @brief A class to create interfaces, which contain contracts that classes --- which inherit from this must comply with. --- --- @object Interface prototype --- @brief The prototype that interface objects must adhere to. --- --- @method Interface prototype init --- @brief Initialize the mixin object. --- @param interface The interface we contract (the hash of fields forced). --- @param (...) Superinterfaces -do - Interface = Class() - function Interface:ToString() - if self.GetLibraryVersion then - return (self:GetLibraryVersion()) - else - return 'Instance' - end - end - function Interface.prototype:init(interface, ...) - Interface.super.prototype.init(self) - AceOO:argCheck(interface, 2, "table") - for k,v in pairs(interface) do - if type(k) ~= "string" then - AceOO:error("All keys to argument #2 must be numbers.") - elseif type(v) ~= "string" then - AceOO:error("All values to argument #2 must be strings.") - elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then - AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".') - end - end - if select('#', ...) >= 1 then - self.superinterfaces = { ... } - for i,v in ipairs(self.superinterfaces) do - v = getlibrary(v) - self.superinterfaces[i] = v - if not inherits(v, Interface) or not v.class then - AceOO:error('Cannot provide a non-Interface to inherit from') - end - end - local num = #self.superinterfaces - for i = 1, num do - local v = self.superinterfaces[i] - self.superinterfaces[i] = nil - self.superinterfaces[v] = true - end - end - self.interface = interface - end -end - --- @function Classpool --- @brief Obtain a read only class from our pool of classes, indexed by the --- superclass and mixins. --- @param sc The superclass of the class we want. --- @param (m1..m20) Mixins of the class we want's objects. --- @return A read only class from the class pool. -local Classpool -do - local pool = setmetatable({}, {__mode = 'v'}) - local function newindex(k, v) - AceOO:error('Attempt to modify a read-only class.') - end - local function protonewindex(k, v) - AceOO:error('Attempt to modify a read-only class prototype.') - end - local function ts(bit) - if type(bit) ~= "table" then - return tostring(bit) - elseif getmetatable(bit) and bit.__tostring then - return tostring(bit) - elseif type(bit.GetLibraryVersion) == "function" then - return bit:GetLibraryVersion() - else - return tostring(bit) - end - end - local t = {} - local function getcomplexuid(sc, ...) - if sc then - if sc.uid then - table.insert(t, sc.uid) - else - AceOO:error("%s is not an appropriate class/mixin", ts(sc)) - end - end - for i = 1, select('#', ...) do - local m = select(i, ...) - if m.uid then - table.insert(t, m.uid) - else - AceOO:error("%s is not an appropriate mixin", ts(m)) - end - end - table.sort(t) - local uid = table.concat(t, '') - local num = #t - for i = 1, num do - t[i] = nil - end - return uid - end - local classmeta - local arg = {} - function Classpool(superclass, ...) - local l = getlibrary - superclass = getlibrary(superclass) - arg = { ... } - for i, v in ipairs(arg) do - arg[i] = getlibrary(v) - end - if superclass then - if superclass.class then -- mixin - table.insert(arg, 1, superclass) - superclass = Class - end - else - superclass = Class - end - local key = getcomplexuid(superclass, unpack(arg)) - if not pool[key] then - local class = Class(superclass, unpack(arg)) - if not classmeta then - classmeta = {} - local mt = getmetatable(class) - for k,v in pairs(mt) do - classmeta[k] = v - end - classmeta.__newindex = newindex - end - -- Prevent the user from adding methods to this class. - -- NOTE: I'm not preventing modifications of existing class members, - -- but it's likely that only a truly malicious user will be doing so. - class.sealed = true - setmetatable(class, classmeta) - getmetatable(class.prototype).__newindex = protonewindex - pool[key] = class - end - return pool[key] - end -end - -AceOO.Factory = Factory -AceOO.Object = Object -AceOO.Class = Class -AceOO.Mixin = Mixin -AceOO.Interface = Interface -AceOO.Classpool = Classpool -AceOO.inherits = inherits - --- Library handling bits - -local function activate(self, oldLib, oldDeactivate) - AceOO = self - Factory = self.Factory - Object = self.Object - Class = self.Class - ClassFactory.prototype = Class - Mixin = self.Mixin - Interface = self.Interface - Classpool = self.Classpool - - if oldLib then - self.classes = oldLib.classes - end - if not self.classes then - self.classes = setmetatable({}, {__mode="k"}) - else - for class in pairs(self.classes) do - class.new = class_new - end - end - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate) -AceOO = AceLibrary(MAJOR_VERSION)
--- a/lib/AceOO-2.0/AceOO-2.0.toc Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -## Interface: 20200 - -## Title: Lib: AceOO-2.0 -## Notes: AddOn development framework -## Author: Ace Development Team -## LoadOnDemand: 1 -## X-Website: http://www.wowace.com -## X-Category: Library -## X-License: LGPL v2.1 + MIT for AceOO-2.0 -## Dependencies: AceLibrary - -AceOO-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/CallbackHandler-1.0/CallbackHandler-1.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,239 @@ +--[[ $Id: CallbackHandler-1.0.lua 60697 2008-02-09 16:51:20Z nevcairiel $ ]] +local MAJOR, MINOR = "CallbackHandler-1.0", 3 +local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) + +if not CallbackHandler then return end -- No upgrade needed + +local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} + +local type = type +local pcall = pcall +local pairs = pairs +local assert = assert +local concat = table.concat +local loadstring = loadstring +local next = next +local select = select +local type = type +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function CreateDispatcher(argCount) + local code = [[ + local next, xpcall, eh = ... + + local method, ARGS + local function call() method(ARGS) end + + local function dispatch(handlers, ...) + local index + index, method = next(handlers) + if not method then return end + local OLD_ARGS = ARGS + ARGS = ... + repeat + xpcall(call, eh) + index, method = next(handlers, index) + until not method + ARGS = OLD_ARGS + end + + return dispatch + ]] + + local ARGS, OLD_ARGS = {}, {} + for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end + code = code:gsub("OLD_ARGS", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(ARGS, ", ")) + return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler) +end + +local Dispatchers = setmetatable({}, {__index=function(self, argCount) + local dispatcher = CreateDispatcher(argCount) + rawset(self, argCount, dispatcher) + return dispatcher +end}) + +-------------------------------------------------------------------------- +-- CallbackHandler:New +-- +-- target - target object to embed public APIs in +-- RegisterName - name of the callback registration API, default "RegisterCallback" +-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" +-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. + +function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused) + -- TODO: Remove this after beta has gone out + assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused") + + RegisterName = RegisterName or "RegisterCallback" + UnregisterName = UnregisterName or "UnregisterCallback" + if UnregisterAllName==nil then -- false is used to indicate "don't want this method" + UnregisterAllName = "UnregisterAllCallbacks" + end + + -- we declare all objects and exported APIs inside this closure to quickly gain access + -- to e.g. function names, the "target" parameter, etc + + + -- Create the registry object + local events = setmetatable({}, meta) + local registry = { recurse=0, events=events } + + -- registry:Fire() - fires the given event/message into the registry + function registry:Fire(eventname, ...) + if not rawget(events, eventname) or not next(events[eventname]) then return end + local oldrecurse = registry.recurse + registry.recurse = oldrecurse + 1 + + Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...) + + registry.recurse = oldrecurse + + if registry.insertQueue and oldrecurse==0 then + -- Something in one of our callbacks wanted to register more callbacks; they got queued + for eventname,callbacks in pairs(registry.insertQueue) do + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + for self,func in pairs(callbacks) do + events[eventname][self] = func + -- fire OnUsed callback? + if first and registry.OnUsed then + registry.OnUsed(registry, target, eventname) + first = nil + end + end + end + registry.insertQueue = nil + end + end + + -- Registration of a callback, handles: + -- self["method"], leads to self["method"](self, ...) + -- self with function ref, leads to functionref(...) + -- "addonId" (instead of self) with function ref, leads to functionref(...) + -- all with an optional arg, which, if present, gets passed as first argument (after self if present) + target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) + if type(eventname) ~= "string" then + error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) + end + + method = method or eventname + + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + + if type(method) ~= "string" and type(method) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) + end + + local regfunc + + if type(method) == "string" then + -- self["method"] calling style + if type(self) ~= "table" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) + elseif self==target then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) + elseif type(self[method]) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) self[method](self,arg,...) end + else + regfunc = function(...) self[method](self,...) end + end + else + -- function ref with self=object or self="addonId" + if type(self)~="table" and type(self)~="string" then + error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) method(arg,...) end + else + regfunc = method + end + end + + + if events[eventname][self] or registry.recurse<1 then + -- if registry.recurse<1 then + -- we're overwriting an existing entry, or not currently recursing. just set it. + events[eventname][self] = regfunc + -- fire OnUsed callback? + if registry.OnUsed and first then + registry.OnUsed(registry, target, eventname) + end + else + -- we're currently processing a callback in this registry, so delay the registration of this new entry! + -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency + registry.insertQueue = registry.insertQueue or setmetatable({},meta) + registry.insertQueue[eventname][self] = regfunc + end + end + + -- Unregister a callback + target[UnregisterName] = function(self, eventname) + if not self or self==target then + error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) + end + if type(eventname) ~= "string" then + error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) + end + if rawget(events, eventname) and events[eventname][self] then + events[eventname][self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(events[eventname]) then + registry.OnUnused(registry, target, eventname) + end + end + if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then + registry.insertQueue[eventname][self] = nil + end + end + + -- OPTIONAL: Unregister all callbacks for given selfs/addonIds + if UnregisterAllName then + target[UnregisterAllName] = function(...) + if select("#",...)<1 then + error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) + end + if select("#",...)==1 and ...==target then + error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) + end + + + for i=1,select("#",...) do + local self = select(i,...) + if registry.insertQueue then + for eventname, callbacks in pairs(registry.insertQueue) do + if callbacks[self] then + callbacks[self] = nil + end + end + end + for eventname, callbacks in pairs(events) do + if callbacks[self] then + callbacks[self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(callbacks) then + registry.OnUnused(registry, target, eventname) + end + end + end + end + end + end + + return registry +end + + +-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it +-- try to upgrade old implicit embeds since the system is selfcontained and +-- relies on closures to work. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/CallbackHandler-1.0/CallbackHandler-1.0.xml Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,4 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ +..\FrameXML\UI.xsd"> + <Script file="CallbackHandler-1.0.lua"/> +</Ui> \ No newline at end of file
--- a/lib/Dewdrop-2.0/Dewdrop-2.0.lua Tue Mar 11 21:39:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3487 +0,0 @@ ---[[ -Name: Dewdrop-2.0 -Revision: $Rev: 48630 $ -Author(s): ckknight (ckknight@gmail.com) -Website: http://ckknight.wowinterface.com/ -Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0 -SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0 -Description: A library to provide a clean dropdown menu interface. -Dependencies: AceLibrary -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "Dewdrop-2.0" -local MINOR_VERSION = "$Revision: 48630 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local Dewdrop = {} - -local SharedMedia - -local CLOSE = "Close" -local CLOSE_DESC = "Close the menu." -local VALIDATION_ERROR = "Validation error." -local USAGE_TOOLTIP = "Usage: %s." -local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one." -local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." -local KEY_BUTTON1 = "Left Mouse" -local KEY_BUTTON2 = "Right Mouse" -local DISABLED = "Disabled" -local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" - -if GetLocale() == "deDE" then - CLOSE = "Schlie\195\159en" - CLOSE_DESC = "Men\195\188 schlie\195\159en." - VALIDATION_ERROR = "Validierungsfehler." - USAGE_TOOLTIP = "Benutzung: %s." - RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen." - RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen." - KEY_BUTTON1 = "Linke Maustaste" - KEY_BUTTON2 = "Rechte Maustaste" - DISABLED = "Deaktiviert" - DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?" -elseif GetLocale() == "koKR" then - CLOSE = "닫기" - CLOSE_DESC = "메뉴를 닫습니다." - VALIDATION_ERROR = "오류 확인." - USAGE_TOOLTIP = "사용법: %s." - RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다." - RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요." - KEY_BUTTON1 = "왼쪽 마우스" - KEY_BUTTON2 = "오른쪽 마우스" - DISABLED = "비활성화됨" - DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?" -elseif GetLocale() == "frFR" then - CLOSE = "Fermer" - CLOSE_DESC = "Ferme le menu." - VALIDATION_ERROR = "Erreur de validation." - USAGE_TOOLTIP = "Utilisation : %s." - RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement." - RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci." - KEY_BUTTON1 = "Clic gauche" - KEY_BUTTON2 = "Clic droit" - DISABLED = "D\195\169sactiv\195\169" - DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?" -elseif GetLocale() == "esES" then - CLOSE = "Cerrar" - CLOSE_DESC = "Cierra el menú." - VALIDATION_ERROR = "Error de validación." - USAGE_TOOLTIP = "Uso: %s." - RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador." - RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla." - KEY_BUTTON1 = "Clic Izquierdo" - KEY_BUTTON2 = "Clic Derecho" - DISABLED = "Desactivado" - DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?" -elseif GetLocale() == "zhTW" then - CLOSE = "關閉" - CLOSE_DESC = "關閉選單。" - VALIDATION_ERROR = "驗證錯誤。" - USAGE_TOOLTIP = "用法: %s。" - RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。" - RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。" - KEY_BUTTON1 = "滑鼠左鍵" - KEY_BUTTON2 = "滑鼠右鍵" - DISABLED = "停用" - DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" -elseif GetLocale() == "zhCN" then - CLOSE = "关闭" - CLOSE_DESC = "关闭菜单" - VALIDATION_ERROR = "验证错误." - USAGE_TOOLTIP = "用法: %s." - RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页." - RESET_KEYBINDING_DESC = "按ESC键清除按键绑定" - KEY_BUTTON1 = "鼠标左键" - KEY_BUTTON2 = "鼠标右键" - DISABLED = "禁用" - DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?" -end - -Dewdrop.KEY_BUTTON1 = KEY_BUTTON1 -Dewdrop.KEY_BUTTON2 = KEY_BUTTON2 - -local function new(...) - local t = {} - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t -end - -local tmp -do - local t = {} - function tmp(...) - for k in pairs(t) do - t[k] = nil - end - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t - end -end -local tmp2 -do - local t = {} - function tmp2(...) - for k in pairs(t) do - t[k] = nil - end - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t - end -end -local levels -local buttons - - --- Secure frame handling: --- Rather than using secure buttons in the menu (has problems), we have one --- master secureframe that we pop onto menu items on mouseover. This requires --- some dark magic with OnLeave etc, but it's not too bad. - -local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate") -secureFrame:Hide() - -local function secureFrame_Show(self) - local owner = self.owner - - if self.secure then -- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..) - for k,v in pairs(self.secure) do - self:SetAttribute(k, nil) - end - end - self.secure = owner.secure; -- Grab hold of new secure data - - local scale = owner:GetEffectiveScale() - - self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale) - self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale) - self:EnableMouse(true) - for k,v in pairs(self.secure) do - self:SetAttribute(k, v) - end - - secureFrame:SetFrameStrata(owner:GetFrameStrata()) - secureFrame:SetFrameLevel(owner:GetFrameLevel()+1) - - self:Show() -end - -local function secureFrame_Hide(self) - self:Hide() - if self.secure then - for k,v in pairs(self.secure) do - self:SetAttribute(k, nil) - end - end - self.secure = nil -end - -secureFrame:SetScript("OnEvent", - function() - if event=="PLAYER_REGEN_ENABLED" then - this.combat = false - if not this:IsShown() and this.owner then - secureFrame_Show(this) - end - elseif event=="PLAYER_REGEN_DISABLED" then - this.combat = true - if this:IsShown() then - secureFrame_Hide(this) - end - end - end -) -secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED") -secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED") - -secureFrame:SetScript("OnLeave", - function() - local owner=this.owner - this:Deactivate() - owner:GetScript("OnLeave")() - end -) - -secureFrame:HookScript("OnClick", - function() - local realthis = this - this = this.owner - this:GetScript("OnClick")() - end -) - -function secureFrame:IsOwnedBy(frame) - return self.owner == frame -end - -function secureFrame:Activate(owner) - if self.owner then -- "Shouldn't" happen but apparently it does and I cba to troubleshoot... - if not self.combat then - secureFrame_Hide(self) - end - end - self.owner = owner - if not self.combat then - secureFrame_Show(self) - end -end - -function secureFrame:Deactivate() - if not self.combat then - secureFrame_Hide(self) - end - self.owner = nil -end - --- END secure frame utilities - - --- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies -local underlineFrame = CreateFrame("Frame", nil) -underlineFrame.tx = underlineFrame:CreateTexture() -underlineFrame.tx:SetTexture(1,1,0.5,0.75) -underlineFrame:SetScript("OnHide", function(this) this:Hide(); end) -underlineFrame:SetScript("OnShow", function(this) -- change sizing on the fly to catch runtime uiscale changes - underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale()) - underlineFrame.tx:SetPoint("RIGHT", 1,0) - underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale()); -end) -underlineFrame:SetHeight(1) - --- END underline on mouseover - - -local function GetScaledCursorPosition() - local x, y = GetCursorPosition() - local scale = UIParent:GetEffectiveScale() - return x / scale, y / scale -end - -local function StartCounting(self, level) - for i = level, 1, -1 do - if levels[i] then - levels[i].count = 3 - end - end -end - -local function StopCounting(self, level) - for i = level, 1, -1 do - if levels[i] then - levels[i].count = nil - end - end -end - -local function OnUpdate(self, elapsed) - for _,level in ipairs(levels) do - local count = level.count - if count then - count = count - elapsed - if count < 0 then - level.count = nil - self:Close(level.num) - else - level.count = count - end - end - end -end - -local function CheckDualMonitor(self, frame) - local ratio = GetScreenWidth() / GetScreenHeight() - if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then - local offsetx - if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then - offsetx = GetScreenWidth() / 2 - frame:GetRight() - else - offsetx = GetScreenWidth() / 2 - frame:GetLeft() - end - local point, parent, relativePoint, x, y = frame:GetPoint(1) - frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0) - end -end - -local function CheckSize(self, level) - if not level.buttons then - return - end - local height = 20 - for _, button in ipairs(level.buttons) do - height = height + button:GetHeight() - end - level:SetHeight(height) - local width = 160 - for _, button in ipairs(level.buttons) do - local extra = 1 - if button.hasArrow or button.hasColorSwatch then - extra = extra + 16 - end - if not button.notCheckable then - extra = extra + 24 - end - button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight) - if button.text:GetWidth() + extra > width then - width = button.text:GetWidth() + extra - end - end - level:SetWidth(width + 20) - if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then - level:ClearAllPoints() - local parent = level.parent or level:GetParent() - if type(parent) ~= "table" then - parent = UIParent - end - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - end - local dirty = false - if not level:GetRight() then - self:Close() - return - end - if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then - level.lastDirection = "LEFT" - dirty = true - elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then - level.lastDirection = "RIGHT" - dirty = true - end - if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then - level.lastVDirection = "DOWN" - dirty = true - elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then - level.lastVDirection = "UP" - dirty = true - end - if dirty then - level:ClearAllPoints() - local parent = level.parent or level:GetParent() - if type(parent) ~= "table" then - parent = UIParent - end - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - end - if level:GetTop() > GetScreenHeight() then - local top = level:GetTop() - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:ClearAllPoints() - level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top) - elseif level:GetBottom() < 0 then - local bottom = level:GetBottom() - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:ClearAllPoints() - level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom) - end - CheckDualMonitor(self, level) - if mod(level.num, 5) == 0 then - local left, bottom = level:GetLeft(), level:GetBottom() - level:ClearAllPoints() - level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - end -end - -local Open -local OpenSlider -local OpenEditBox -local Refresh -local Clear -local function ReleaseButton(self, level, index) - if not level.buttons then - return - end - if not level.buttons[index] then - return - end - local button = level.buttons[index] - button:Hide() - if button.highlight then - button.highlight:Hide() - end --- button.arrow:SetVertexColor(1, 1, 1) --- button.arrow:SetHeight(16) --- button.arrow:SetWidth(16) - table.remove(level.buttons, index) - table.insert(buttons, button) - for k in pairs(button) do - if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then - button[k] = nil - end - end - return true -end - -local function Scroll(self, level, down) - if down then - if level:GetBottom() < 0 then - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:SetPoint(point, parent, relativePoint, x, y + 50) - if level:GetBottom() > 0 then - level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom()) - end - end - else - if level:GetTop() > GetScreenHeight() then - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:SetPoint(point, parent, relativePoint, x, y - 50) - if level:GetTop() < GetScreenHeight() then - level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop()) - end - end - end -end - -local function getArgs(t, str, num, ...) - local x = t[str .. num] - if x == nil then - return ... - else - return x, getArgs(t, str, num + 1, ...) - end -end - -local sliderFrame -local editBoxFrame - -local normalFont -local lastSetFont -local justSetFont = false -local regionTmp = {} -local function fillRegionTmp(...) - for i = 1, select('#', ...) do - regionTmp[i] = select(i, ...) - end -end - -local function showGameTooltip(this) - if this.tooltipTitle or this.tooltipText then - GameTooltip_SetDefaultAnchor(GameTooltip, this) - local disabled = not this.isTitle and this.disabled - local font - if this.tooltipTitle then - if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then - font = SharedMedia:Fetch("font", this.tooltipTitle) - end - if disabled then - GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1) - else - GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1) - end - if this.tooltipText then - if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then - font = SharedMedia:Fetch("font", this.tooltipText) - end - if disabled then - GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1) - else - GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) - end - end - else - if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then - font = SharedMedia:Fetch("font", this.tooltipText) - end - if disabled then - GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1) - else - GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1) - end - end - if font then - fillRegionTmp(GameTooltip:GetRegions()) - lastSetFont = font - justSetFont = true - for i,v in ipairs(regionTmp) do - if v.SetFont then - local norm,size,outline = v:GetFont() - v:SetFont(font, size, outline) - if not normalFont then - normalFont = norm - end - end - regionTmp[i] = nil - end - elseif not normalFont then - fillRegionTmp(GameTooltip:GetRegions()) - for i,v in ipairs(regionTmp) do - if v.GetFont and not normalFont then - normalFont = v:GetFont() - end - regionTmp[i] = nil - end - end - GameTooltip:Show() - end - if this.tooltipFunc then - GameTooltip:SetOwner(this, "ANCHOR_NONE") - GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) - this.tooltipFunc(getArgs(this, 'tooltipArg', 1)) - GameTooltip:Show() - end -end - -local tmpt = setmetatable({}, {mode='v'}) -local numButtons = 0 -local function AcquireButton(self, level) - if not levels[level] then - return - end - level = levels[level] - if not level.buttons then - level.buttons = {} - end - local button - if #buttons == 0 then - numButtons = numButtons + 1 - button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) - button:SetFrameStrata("FULLSCREEN_DIALOG") - button:SetHeight(16) - local highlight = button:CreateTexture(nil, "BACKGROUND") - highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") - button.highlight = highlight - highlight:SetBlendMode("ADD") - highlight:SetAllPoints(button) - highlight:Hide() - local check = button:CreateTexture(nil, "ARTWORK") - button.check = check - check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") - check:SetPoint("CENTER", button, "LEFT", 12, 0) - check:SetWidth(24) - check:SetHeight(24) - local radioHighlight = button:CreateTexture(nil, "ARTWORK") - button.radioHighlight = radioHighlight - radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton") - radioHighlight:SetAllPoints(check) - radioHighlight:SetBlendMode("ADD") - radioHighlight:SetTexCoord(0.5, 0.75, 0, 1) - radioHighlight:Hide() - button:SetScript("OnEnter", function() - if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then - for i = 1, this.level.num do - Refresh(self, levels[i]) - end - return - end - self:Close(this.level.num + 1) - if not this.disabled then - if this.secure then - secureFrame:Activate(this) - elseif this.hasSlider then - OpenSlider(self, this) - elseif this.hasEditBox then - OpenEditBox(self, this) - elseif this.hasArrow then - Open(self, this, nil, this.level.num + 1, this.value) - end - end - if not this.level then -- button reclaimed - return - end - StopCounting(self, this.level.num + 1) - if not this.disabled then - highlight:Show() - if this.isRadio then - button.radioHighlight:Show() - end - if this.mouseoverUnderline then - underlineFrame:SetParent(this) - underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0) - underlineFrame:SetWidth(this.text:GetWidth()) - underlineFrame:Show() - end - end - showGameTooltip(this) - end) - button:SetScript("OnHide", function() - if this.secure and secureFrame:IsOwnedBy(this) then - secureFrame:Deactivate() - end - end) - button:SetScript("OnLeave", function() - if this.secure and secureFrame:IsShown() then - return; -- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it - end - underlineFrame:Hide() - if not this.selected then - highlight:Hide() - end - button.radioHighlight:Hide() - if this.level then - StartCounting(self, this.level.num) - end - GameTooltip:Hide() - end) - local first = true - button:SetScript("OnClick", function() - if not this.disabled then - if this.hasColorSwatch then - local func = button.colorFunc - local hasOpacity = this.hasOpacity - local this = this - for k in pairs(tmpt) do - tmpt[k] = nil - end - for i = 1, 1000 do - local x = this['colorArg'..i] - if x == nil then - break - else - tmpt[i] = x - end - end - ColorPickerFrame.func = function() - if func then - local r,g,b = ColorPickerFrame:GetColorRGB() - local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil - local n = #tmpt - tmpt[n+1] = r - tmpt[n+2] = g - tmpt[n+3] = b - tmpt[n+4] = a - func(unpack(tmpt)) - tmpt[n+1] = nil - tmpt[n+2] = nil - tmpt[n+3] = nil - tmpt[n+4] = nil - end - end - ColorPickerFrame.hasOpacity = this.hasOpacity - ColorPickerFrame.opacityFunc = ColorPickerFrame.func - ColorPickerFrame.opacity = 1 - this.opacity - ColorPickerFrame:SetColorRGB(this.r, this.g, this.b) - local r, g, b, a = this.r, this.g, this.b, this.opacity - ColorPickerFrame.cancelFunc = function() - if func then - local n = #tmpt - tmpt[n+1] = r - tmpt[n+2] = g - tmpt[n+3] = b - tmpt[n+4] = a - func(unpack(tmpt)) - for i = 1, n+4 do - tmpt[i] = nil - end - end - end - self:Close(1) - ShowUIPanel(ColorPickerFrame) - elseif this.func then - local level = this.level - if type(this.func) == "string" then - if type(this.arg1[this.func]) ~= "function" then - self:error("Cannot call method %q", this.func) - end - this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2)) - else - this.func(getArgs(this, 'arg', 1)) - end - if this.closeWhenClicked then - self:Close() - elseif level:IsShown() then - for i = 1, level.num do - Refresh(self, levels[i]) - end - local value = levels[level.num].value - for i = level.num-1, 1, -1 do - local level = levels[i] - local good = false - for _,button in ipairs(level.buttons) do - if button.value == value then - good = true - break - end - end - if not good then - Dewdrop:Close(i+1) - end - value = levels[i].value - end - end - elseif this.closeWhenClicked then - self:Close() - end - end - end) - local text = button:CreateFontString(nil, "ARTWORK") - button.text = text - text:SetFontObject(GameFontHighlightSmall) - button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) - button:SetScript("OnMouseDown", function() - if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then - text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1) - end - end) - button:SetScript("OnMouseUp", function() - if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then - text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0) - end - end) - local arrow = button:CreateTexture(nil, "ARTWORK") - button.arrow = arrow - arrow:SetPoint("LEFT", button, "RIGHT", -16, 0) - arrow:SetWidth(16) - arrow:SetHeight(16) - arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") - local colorSwatch = button:CreateTexture(nil, "ARTWORK") - button.colorSwatch = colorSwatch - colorSwatch:SetWidth(20) - colorSwatch:SetHeight(20) - colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") - local texture = button:CreateTexture(nil, "OVERLAY") - colorSwatch.texture = texture - texture:SetTexture("Interface\\Buttons\\WHITE8X8") - texture:SetWidth(11.5) - texture:SetHeight(11.5) - texture:Show() - texture:SetPoint("CENTER", colorSwatch, "CENTER") - colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) - else - button = table.remove(buttons) - end - button:ClearAllPoints() - button:SetParent(level) - button:SetFrameStrata(level:GetFrameStrata()) - button:SetFrameLevel(level:GetFrameLevel() + 1) - button:SetPoint("LEFT", level, "LEFT", 10, 0) - button:SetPoint("RIGHT", level, "RIGHT", -10, 0) - if #level.buttons == 0 then - button:SetPoint("TOP", level, "TOP", 0, -10) - else - button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0) - end - button.text:SetPoint("LEFT", button, "LEFT", 24, 0) - button:Show() - button.level = level - table.insert(level.buttons, button) - if not level.parented then - level.parented = true - level:ClearAllPoints() - if level.num == 1 then - if level.parent ~= UIParent and type(level.parent) == "table" then - level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") - else - level:SetPoint("CENTER", UIParent, "CENTER") - end - else - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10) - else - level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10) - else - level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10) - end - end - end - level:SetFrameStrata("FULLSCREEN_DIALOG") - end - button:SetAlpha(1) - return button -end - -local numLevels = 0 -local function AcquireLevel(self, level) - if not levels[level] then - for i = #levels + 1, level, -1 do - local i = i - numLevels = numLevels + 1 - local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) - if i == 1 then - local old_CloseSpecialWindows = CloseSpecialWindows - function CloseSpecialWindows() - local found = old_CloseSpecialWindows() - if levels[1]:IsShown() then - self:Close() - return 1 - end - return found - end - end - levels[i] = frame - frame.num = i - frame:SetParent(UIParent) - frame:SetFrameStrata("FULLSCREEN_DIALOG") - frame:Hide() - frame:SetWidth(180) - frame:SetHeight(10) - frame:SetFrameLevel(i * 3) - frame:SetScript("OnHide", function() - self:Close(level + 1) - end) - if frame.SetTopLevel then - frame:SetTopLevel(true) - end - frame:EnableMouse(true) - frame:EnableMouseWheel(true) - local backdrop = CreateFrame("Frame", nil, frame) - backdrop:SetAllPoints(frame) - backdrop:SetBackdrop(tmp( - 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'insets', tmp2( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ), - 'tileSize', 16, - 'edgeSize', 16 - )) - backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) - backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) - frame:SetScript("OnClick", function() - self:Close(i) - end) - frame:SetScript("OnEnter", function() - StopCounting(self, i) - end) - frame:SetScript("OnLeave", function() - StartCounting(self, i) - end) - frame:SetScript("OnMouseWheel", function() - Scroll(self, frame, arg1 < 0) - end) - if i == 1 then - frame:SetScript("OnUpdate", function(this, arg1) - OnUpdate(self, arg1) - end) - levels[1].lastDirection = "RIGHT" - levels[1].lastVDirection = "DOWN" - else - levels[i].lastDirection = levels[i - 1].lastDirection - levels[i].lastVDirection = levels[i - 1].lastVDirection - end - end - end - local fullscreenFrame = GetUIPanel("fullscreen") - local l = levels[level] - local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() - if fullscreenFrame then - l:SetParent(fullscreenFrame) - else - l:SetParent(UIParent) - end - l:SetFrameStrata(strata) - l:SetFrameLevel(framelevel) - l:SetAlpha(1) - return l -end - -local function validateOptions(options, position, baseOptions, fromPass) - if not baseOptions then - baseOptions = options - end - if type(options) ~= "table" then - return "Options must be a table.", position - end - local kind = options.type - if type(kind) ~= "string" then - return '"type" must be a string.', position - elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then - return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position - end - if options.aliases then - if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then - return '"alias" must be a table or string', position - end - end - if not fromPass then - if kind == "execute" then - if type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - elseif kind == "range" or kind == "text" or kind == "toggle" then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if kind == "text" and options.get == false then - elseif type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif kind == "group" and options.pass then - if options.pass ~= true then - return '"pass" must be either nil, true, or false', position - end - if not options.func then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - end - end - if options ~= baseOptions then - if kind == "header" then - elseif type(options.desc) ~= "string" then - return '"desc" must be a string', position - elseif options.desc:len() == 0 then - return '"desc" cannot be a 0-length string', position - end - end - if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then - if options.type == "header" and not options.cmdName and not options.name then - elseif options.cmdName then - if type(options.cmdName) ~= "string" then - return '"cmdName" must be a string or nil', position - elseif options.cmdName:len() == 0 then - return '"cmdName" cannot be a 0-length string', position - end - if type(options.guiName) ~= "string" then - if not options.guiNameIsMap then - return '"guiName" must be a string or nil', position - end - elseif options.guiName:len() == 0 then - return '"guiName" cannot be a 0-length string', position - end - else - if type(options.name) ~= "string" then - return '"name" must be a string', position - elseif options.name:len() == 0 then - return '"name" cannot be a 0-length string', position - end - end - end - if options.guiNameIsMap then - if type(options.guiNameIsMap) ~= "boolean" then - return '"guiNameIsMap" must be a boolean or nil', position - elseif options.type ~= "toggle" then - return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position - elseif type(options.map) ~= "table" then - return '"map" must be a table', position - end - end - if options.message and type(options.message) ~= "string" then - return '"message" must be a string or nil', position - end - if options.error and type(options.error) ~= "string" then - return '"error" must be a string or nil', position - end - if options.current and type(options.current) ~= "string" then - return '"current" must be a string or nil', position - end - if options.order then - if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then - return '"order" must be a non-zero number or nil', position - end - end - if options.disabled then - if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then - return '"disabled" must be a function, string, or boolean', position - end - end - if options.cmdHidden then - if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then - return '"cmdHidden" must be a function, string, or boolean', position - end - end - if options.guiHidden then - if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then - return '"guiHidden" must be a function, string, or boolean', position - end - end - if options.hidden then - if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then - return '"hidden" must be a function, string, or boolean', position - end - end - if kind == "text" then - if type(options.validate) == "table" then - local t = options.validate - local iTable = nil - for k,v in pairs(t) do - if type(k) == "number" then - if iTable == nil then - iTable = true - elseif not iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - elseif k < 1 or k > #t then - return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position - end - else - if iTable == nil then - iTable = false - elseif iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - end - end - if type(v) ~= "string" then - return '"validate" values must all be strings', position - end - end - if options.multiToggle and options.multiToggle ~= true then - return '"multiToggle" must be a boolean or nil if "validate" is a table', position - end - elseif options.validate == "keybinding" then - -- no other checks - else - if type(options.usage) ~= "string" then - return '"usage" must be a string', position - elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then - return '"validate" must be a string, function, or table', position - end - end - if options.multiToggle and type(options.validate) ~= "table" then - return '"validate" must be a table if "multiToggle" is true', position - end - elseif kind == "range" then - if options.min or options.max then - if type(options.min) ~= "number" then - return '"min" must be a number', position - elseif type(options.max) ~= "number" then - return '"max" must be a number', position - elseif options.min >= options.max then - return '"min" must be less than "max"', position - end - end - if options.step then - if type(options.step) ~= "number" then - return '"step" must be a number', position - elseif options.step < 0 then - return '"step" must be nonnegative', position - end - end - if options.bigStep then - if type(options.bigStep) ~= "number" then - return '"bigStep" must be a number', position - elseif options.bigStep < 0 then - return '"bigStep" must be nonnegative', position - end - end - if options.isPercent and options.isPercent ~= true then - return '"isPercent" must either be nil, true, or false', position - end - elseif kind == "toggle" then - if options.map then - if type(options.map) ~= "table" then - return '"map" must be a table', position - elseif type(options.map[true]) ~= "string" then - return '"map[true]" must be a string', position - elseif type(options.map[false]) ~= "string" then - return '"map[false]" must be a string', position - end - end - elseif kind == "color" then - if options.hasAlpha and options.hasAlpha ~= true then - return '"hasAlpha" must be nil, true, or false', position - end - elseif kind == "group" then - if options.pass and options.pass ~= true then - return '"pass" must be nil, true, or false', position - end - if type(options.args) ~= "table" then - return '"args" must be a table', position - end - for k,v in pairs(options.args) do - if type(k) ~= "number" then - if type(k) ~= "string" then - return '"args" keys must be strings or numbers', position - elseif k:len() == 0 then - return '"args" keys must not be 0-length strings.', position - end - end - if type(v) ~= "table" then - return '"args" values must be tables', position and position .. "." .. k or k - end - local newposition - if position then - newposition = position .. ".args." .. k - else - newposition = "args." .. k - end - local err, pos = validateOptions(v, newposition, baseOptions, options.pass) - if err then - return err, pos - end - end - elseif kind == "execute" then - if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then - return '"confirm" must be a string, boolean, or nil', position - end - end - if options.icon and type(options.icon) ~= "string" then - return'"icon" must be a string', position - end - if options.iconWidth or options.iconHeight then - if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then - return '"iconHeight" and "iconWidth" must be numbers', position - end - end - if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then - if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then - return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position - end - end -end - -local validatedOptions - -local values -local mysort_args -local mysort -local othersort -local othersort_validate - -local baseFunc, currentLevel - -local function confirmPopup(message, func, ...) - if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then - StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {} - end - local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] - for k in pairs(t) do - t[k] = nil - end - t.text = message - t.button1 = ACCEPT or "Accept" - t.button2 = CANCEL or "Cancel" - t.OnAccept = function() - func(unpack(t)) - end - for i = 1, select('#', ...) do - t[i] = select(i, ...) - end - t.timeout = 0 - t.whileDead = 1 - t.hideOnEscape = 1 - - Dewdrop:Close() - StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG") -end - - -local function getMethod(settingname, handler, v, methodName, ...) -- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222" - assert(v and type(v)=="table") - assert(methodName and type(methodName)=="string") - - local method = v[methodName] - if type(method)=="function" then - return method, ... - elseif type(method)=="string" then - if not handler then - Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) - elseif not handler[method] then - Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method) - end - return handler[method], handler, ... - end - - Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName) -end - -local function callMethod(settingname, handler, v, methodName, ...) - assert(v and type(v)=="table") - assert(methodName and type(methodName)=="string") - - local method = v[methodName] - if type(method)=="function" then - local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...) - if not success then - geterrorhandler()(ret) - return nil - end - return ret,ret2,ret3,ret4 - - elseif type(method)=="string" then - - local neg = method:match("^~(.-)$") - if neg then - method = neg - end - if not handler then - Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) - elseif not handler[method] then - Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method) - end - local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...) - if not success then - geterrorhandler()(ret) - return nil - end - if neg then - return not ret - end - return ret,ret2,ret3,ret4 - elseif method == false then - return nil - end - - Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)") -end - -local function skip1Nil(...) - if select(1,...)==nil then - return select(2,...) - end - return ... -end - -function Dewdrop:FeedAceOptionsTable(options, difference) - self:argCheck(options, 2, "table") - self:argCheck(difference, 3, "nil", "number") - if not currentLevel then - self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") - end - if not difference then - difference = 0 - end - if not validatedOptions then - validatedOptions = {} - end - if not validatedOptions[options] then - local err, position = validateOptions(options) - - if err then - if position then - Dewdrop:error(position .. ": " .. err) - else - Dewdrop:error(err) - end - end - - validatedOptions[options] = true - end - local level = levels[currentLevel] - if not level then - self:error("Improper level given") - end - if not values then - values = {} - else - for k,v in pairs(values) do - values[k] = nil - end - end - - local current = level - while current do -- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later - if current.num == difference + 1 then - break - end - table.insert(values, current.value) - current = levels[current.num - 1] - end - - local realOptions = options - local handler = options.handler - local passTable - local passValue - while #values > 0 do -- This loop traverses values from the END (trunk nodes first, then onto leaf nodes) - if options.pass then - if options.get and options.set then - passTable = options - elseif not passTable then - passTable = options - end - else - passTable = nil - end - local value = table.remove(values) - options = options.args and options.args[value] - if not options then - return - end - handler = options.handler or handler - passValue = passTable and value or nil - end - - if options.type == "group" then - local hidden = options.hidden - if type(hidden) == "function" or type(hidden) == "string" then - hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false - end - if hidden then - return - end - local disabled = options.disabled - if type(disabled) == "function" or type(disabled) == "string" then - disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false - end - if disabled then - self:AddLine( - 'text', DISABLED, - 'disabled', true - ) - return - end - for k in pairs(options.args) do - table.insert(values, k) - end - if options.pass then - if options.get and options.set then - passTable = options - elseif not passTable then - passTable = options - end - else - passTable = nil - end - if not mysort then - mysort = function(a, b) - local alpha, bravo = mysort_args[a], mysort_args[b] - local alpha_order = alpha.order or 100 - local bravo_order = bravo.order or 100 - local alpha_name = alpha.guiName or alpha.name - local bravo_name = bravo.guiName or bravo.name - if alpha_order == bravo_order then - if not alpha_name then - return bravo_name - elseif not bravo_name then - return false - else - return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() - end - else - if alpha_order < 0 then - if bravo_order > 0 then - return false - end - else - if bravo_order < 0 then - return true - end - end - return alpha_order < bravo_order - end - end - end - mysort_args = options.args - table.sort(values, mysort) - mysort_args = nil - local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0 - local last_order = 1 - for _,k in ipairs(values) do - local v = options.args[k] - local handler = v.handler or handler - if hasBoth and last_order > 0 and (v.order or 100) < 0 then - hasBoth = false - self:AddLine() - end - local hidden, disabled = v.guiHidden or v.hidden, v.disabled - - if type(hidden) == "function" or type(hidden) == "string" then - hidden = callMethod(k, handler, v, "hidden", v.passValue) or false - end - if not hidden then - if type(disabled) == "function" or type(disabled) == "string" then - disabled = callMethod(k, handler, v, "disabled", v.passValue) or false - end - local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) - local desc = v.guiDesc or v.desc - local iconHeight = v.iconHeight or 16 - local iconWidth = v.iconWidth or 16 - local iconCoordLeft = v.iconCoordLeft - local iconCoordRight = v.iconCoordRight - local iconCoordBottom = v.iconCoordBottom - local iconCoordTop = v.iconCoordTop - local tooltipTitle, tooltipText - tooltipTitle = name - if name ~= desc then - tooltipText = desc - end - if type(v.usage) == "string" and v.usage:trim():len() > 0 then - if tooltipText then - tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage) - else - tooltipText = USAGE_TOOLTIP:format(v.usage) - end - end - local v_p = passTable - if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then - v_p = v - end - local passValue = v.passValue or (v_p~=v and k) or nil - if v.type == "toggle" then - local checked = callMethod(name, handler, v_p, "get", passValue) or false - local checked_arg = checked - if type(v_p.get)=="string" and v_p.get:match("^~") then - checked_arg = not checked - end - local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set", skip1Nil(passValue, not checked_arg)) - if v.guiNameIsMap then - checked = checked and true or false - name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") - tooltipTitle = name - checked = true--nil - end - self:AddLine( - 'text', name, - 'checked', checked, - 'isRadio', v.isRadio, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'arg3', arg3, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - elseif v.type == "execute" then - local func, arg1, arg2, arg3, arg4 - local confirm = v.confirm - if confirm == true then - confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle) - func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) - elseif type(confirm) == "string" then - func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) - else - func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue) - end - self:AddLine( - 'text', name, - 'checked', checked, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'arg3', arg3, - 'arg4', arg4, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - elseif v.type == "range" then - local sliderValue - sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0 - local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set", passValue) - if tooltipText then - tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP) - else - tooltipText = RANGE_TOOLTIP - end - self:AddLine( - 'text', name, - 'hasArrow', true, - 'hasSlider', true, - 'sliderMin', v.min or 0, - 'sliderMax', v.max or 1, - 'sliderStep', v.step or 0, - 'sliderBigStep', v.bigStep or nil, - 'sliderIsPercent', v.isPercent or false, - 'sliderValue', sliderValue, - 'sliderFunc', sliderFunc, - 'sliderArg1', sliderArg1, - 'sliderArg2', sliderArg2, - 'fromAceOptions', true, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - elseif v.type == "color" then - local r,g,b,a = callMethod(name, handler, v_p, "get", passValue) - if not r then - r,g,b,a = 0,0,0,0 - end - local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set", passValue) - self:AddLine( - 'text', name, - 'hasArrow', true, - 'hasColorSwatch', true, - 'r', r, - 'g', g, - 'b', b, - 'opacity', v.hasAlpha and a or nil, - 'hasOpacity', v.hasAlpha, - 'colorFunc', colorFunc, - 'colorArg1', colorArg1, - 'colorArg2', colorArg2, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - elseif v.type == "text" then - if type(v.validate) == "table" then - local func,arg1,arg2 - if v.onClick then - func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) - end - local checked - if v.isChecked then - checked = callMethod(name, handler, v, "isChecked", passValue) or false - end - self:AddLine( - 'text', name, - 'hasArrow', true, - 'value', k, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'mouseoverUnderline', func and true or nil, - 'disabled', disabled, - 'checked', checked, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - else - local editBoxText - editBoxText = callMethod(name, handler, v_p, "get", passValue) or "" - local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set", passValue) - - local editBoxValidateFunc, editBoxValidateArg1 - - if v.validate and v.validate ~= "keybinding" then - if v.validate == "keybinding" then - if tooltipText then - tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC) - else - tooltipText = RESET_KEYBINDING_DESC - end - else - editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue! - end - end - - self:AddLine( - 'text', name, - 'hasArrow', true, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom, - 'hasEditBox', true, - 'editBoxText', editBoxText, - 'editBoxFunc', editBoxFunc, - 'editBoxArg1', editBoxArg1, - 'editBoxArg2', editBoxArg2, - 'editBoxValidateFunc', editBoxValidateFunc, - 'editBoxValidateArg1', editBoxValidateArg1, - 'editBoxIsKeybinding', v.validate == "keybinding", - 'editBoxKeybindingOnly', v.keybindingOnly, - 'editBoxKeybindingExcept', v.keybindingExcept, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - end - elseif v.type == "group" then - local func,arg1,arg2 - if v.onClick then - func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) - end - local checked - if v.isChecked then - checked = callMethod(name, handler, v, "isChecked", passValue) or false - end - self:AddLine( - 'text', name, - 'hasArrow', true, - 'value', k, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'mouseoverUnderline', func and true or nil, - 'disabled', disabled, - 'checked', checked, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - elseif v.type == "header" then - if name == "" or not name then - self:AddLine( - 'isTitle', true, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - else - self:AddLine( - 'text', name, - 'isTitle', true, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - end - end - end - last_order = v.order or 100 - end - elseif options.type == "text" and type(options.validate) == "table" then - local current - local options_p = passTable - if not options_p or (options.get and options.set) then - options_p = options - passTable = nil - passValue = nil - end - local multiToggle = options.multiToggle - local passValue = options.passValue or passValue - if not multiToggle then - current = callMethod(k, handler, options_p, "get", passValue) - end - local indexed = true - for k,v in pairs(options.validate) do - if type(k) ~= "number" then - indexed = false - end - table.insert(values, k) - end - if not indexed then - if not othersort then - othersort = function(alpha, bravo) - return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() - end - end - othersort_validate = options.validate - table.sort(values, othersort) - othersort_validate = nil - end - for _,k in ipairs(values) do - local v = options.validate[k] - if type(k) == "number" then - k = v - end - local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set", skip1Nil(passValue, k)) - local checked - if multiToggle then - checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false - if arg2 == nil then - arg2 = not checked - elseif arg3 == nil then - arg3 = not checked - else - arg4 = not checked - end - else - checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) - if checked then - func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil - end - end - local tooltipTitle - local tooltipText - if options.validateDesc then - tooltipTitle = v - tooltipText = options.validateDesc[k] - else - tooltipTitle = options.guiName or options.name - tooltipText = v - end - self:AddLine( - 'text', v, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'arg3', arg3, - 'arg4', arg4, - 'isRadio', not multiToggle, - 'checked', checked, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - end - for k in pairs(values) do - values[k] = nil - end - else - return false - end - return true -end - -function Dewdrop:FeedTable(s, difference) - self:argCheck(s, 2, "table") - self:argCheck(difference, 3, "nil", "number") - if not currentLevel then - self:error("Cannot call `FeedTable' outside of a Dewdrop declaration") - end - if not difference then - difference = 0 - end - local level = levels[currentLevel] - if not level then - self:error("Improper level given") - end - if not values then - values = {} - else - for k,v in pairs(values) do - values[k] = nil - end - end - local t = s.subMenu and s or {subMenu = s} - local current = level - while current do - if current.num == difference + 1 then - break - end - table.insert(values, current.value) - current = levels[current.num - 1] - end - - while #values > 0 do - local value = table.remove(values) - t = t.subMenu and t.subMenu[value] - if not t then - return - end - end - - if t.subMenu or current.num == 1 then - for k in pairs(t.subMenu) do - table.insert(values, k) - end - table.sort(values) - for _,k in ipairs(values) do - local argTable = {"value", k} - for key, val in pairs(t.subMenu[k]) do - table.insert(argTable, key) - table.insert(argTable, val) - end - self:AddLine(unpack(argTable)) - end - for k in pairs(values) do - values[k] = nil - end - return false - end - return true -end - -function Refresh(self, level) - if type(level) == "number" then - level = levels[level] - end - if not level then - return - end - if baseFunc then - Clear(self, level) - currentLevel = level.num - if type(baseFunc) == "table" then - if currentLevel == 1 then - local handler = baseFunc.handler - if handler then - local name = tostring(handler) - if not name:find('^table:') and not handler.hideMenuTitle then - name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") - self:AddLine( - 'text', name, - 'isTitle', true - ) - end - end --- elseif level.parentText then --- self:AddLine( --- 'text', level.parentText, --- 'tooltipTitle', level.parentTooltipTitle, --- 'tooltipText', level.parentTooltipText, --- 'tooltipFunc', level.parentTooltipFunc, --- 'isTitle', true --- ) - end - self:FeedAceOptionsTable(baseFunc) - if currentLevel == 1 then - self:AddLine( - 'text', CLOSE, - 'tooltipTitle', CLOSE, - 'tooltipText', CLOSE_DESC, - 'closeWhenClicked', true - ) - end - else --- if level.parentText then --- self:AddLine( --- 'text', level.parentText, --- 'tooltipTitle', level.parentTooltipTitle, --- 'tooltipText', level.parentTooltipText, --- 'tooltipFunc', level.parentTooltipFunc, --- 'isTitle', true --- ) --- end - baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value) - end - currentLevel = nil - CheckSize(self, level) - end -end - -function Dewdrop:Refresh(level) - self:argCheck(level, 2, "number", "nil") - if not level then - for k,v in pairs(levels) do - Refresh(self, v) - end - else - Refresh(self, levels[level]) - end -end - -function OpenSlider(self, parent) - if not sliderFrame then - sliderFrame = CreateFrame("Frame", nil, nil) - sliderFrame:SetWidth(100) - sliderFrame:SetHeight(170) - sliderFrame:SetScale(UIParent:GetScale()) - sliderFrame:SetBackdrop(tmp( - 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'insets', tmp2( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ), - 'tileSize', 16, - 'edgeSize', 16 - )) - sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG") - if sliderFrame.SetTopLevel then - sliderFrame:SetTopLevel(true) - end - sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) - sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) - sliderFrame:EnableMouse(true) - sliderFrame:EnableMouseWheel(true) - sliderFrame:Hide() - sliderFrame:SetPoint("CENTER", UIParent, "CENTER") - local slider = CreateFrame("Slider", nil, sliderFrame) - sliderFrame.slider = slider - slider:SetOrientation("VERTICAL") - slider:SetMinMaxValues(0, 1) - slider:SetValueStep(0.000000001) - slider:SetValue(0.5) - slider:SetWidth(16) - slider:SetHeight(128) - slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0) - slider:SetBackdrop(tmp( - 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", - 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", - 'tile', true, - 'edgeSize', 8, - 'tileSize', 8, - 'insets', tmp2( - 'left', 3, - 'right', 3, - 'top', 3, - 'bottom', 3 - ) - )) - local texture = slider:CreateTexture() - slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") - local text = slider:CreateFontString(nil, "ARTWORK") - sliderFrame.topText = text - text:SetFontObject(GameFontGreenSmall) - text:SetText("100%") - text:SetPoint("BOTTOM", slider, "TOP") - local text = slider:CreateFontString(nil, "ARTWORK") - sliderFrame.bottomText = text - text:SetFontObject(GameFontGreenSmall) - text:SetText("0%") - text:SetPoint("TOP", slider, "BOTTOM") - local editBox = CreateFrame("EditBox", nil, sliderFrame) - sliderFrame.currentText = editBox - editBox:SetFontObject(ChatFontNormal) - editBox:SetHeight(13) - editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0) - editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0) - editBox:SetText("50%") - editBox:SetJustifyH("CENTER") - - local width = editBox:GetWidth()/2 + 10 - local left = editBox:CreateTexture(nil, "BACKGROUND") - left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") - left:SetTexCoord(0, width / 256, 0, 1) - left:SetWidth(width) - left:SetHeight(32) - left:SetPoint("LEFT", editBox, "LEFT", -10, 0) - local right = editBox:CreateTexture(nil, "BACKGROUND") - right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") - right:SetTexCoord(1 - width / 256, 1, 0, 1) - right:SetWidth(width) - right:SetHeight(32) - right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) - - local changed = false - local inside = false - slider:SetScript("OnValueChanged", function() - if sliderFrame.changing then - return - end - changed = true - local done = false - if sliderFrame.parent and sliderFrame.parent.sliderFunc then - local min = sliderFrame.parent.sliderMin or 0 - local max = sliderFrame.parent.sliderMax or 1 - local step - if sliderFrame.fineStep then - step = sliderFrame.parent.sliderStep or (max - min) / 100 - else - step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 - end - local value = (1 - slider:GetValue()) * (max - min) + min - if step > 0 then - value = math.floor((value - min) / step + 0.5) * step + min - if value > max then - value = max - elseif value < min then - value = min - end - end - if value == sliderFrame.lastValue then - return - end - sliderFrame.lastValue = value - local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value)) - if sliderFrame.parent.fromAceOptions then - text = nil - elseif type(text) == "string" or type(text) == "number" then - sliderFrame.currentText:SetText(text) - done = true - end - end - if not done then - local min = sliderFrame.parent.sliderMin or 0 - local max = sliderFrame.parent.sliderMax or 1 - local step - if sliderFrame.fineStep then - step = sliderFrame.parent.sliderStep or (max - min) / 100 - else - step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 - end - local value = (1 - slider:GetValue()) * (max - min) + min - if step > 0 then - value = math.floor((value - min) / step + 0.5) * step + min - if value > max then - value = max - elseif value < min then - value = min - end - end - if sliderFrame.parent.sliderIsPercent then - sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100)) - else - if step < 0.1 then - sliderFrame.currentText:SetText(string.format("%.2f", value)) - elseif step < 1 then - sliderFrame.currentText:SetText(string.format("%.1f", value)) - else - sliderFrame.currentText:SetText(string.format("%.0f", value)) - end - end - end - end) - local function onEnter() - StopCounting(self, sliderFrame.level) - showGameTooltip(sliderFrame.parent) - end - local function onLeave() - GameTooltip:Hide() - end - sliderFrame:SetScript("OnEnter", onEnter) - sliderFrame:SetScript("OnLeave", function() - GameTooltip:Hide() - if changed then - local parent = sliderFrame.parent - local sliderFunc = parent.sliderFunc - for i = 1, sliderFrame.level - 1 do - Refresh(self, levels[i]) - end - local newParent - for _,button in ipairs(levels[sliderFrame.level-1].buttons) do - if button.sliderFunc == sliderFunc then - newParent = button - break - end - end - if newParent then - OpenSlider(self, newParent) - else - sliderFrame:Hide() - end - end - end) - editBox:SetScript("OnEnter", onEnter) - editBox:SetScript("OnLeave", onLeave) - slider:SetScript("OnMouseDown", function() - sliderFrame.mouseDown = true - GameTooltip:Hide() - end) - slider:SetScript("OnMouseUp", function() - sliderFrame.mouseDown = false - if changed--[[ and not inside]] then - local parent = sliderFrame.parent - local sliderFunc = parent.sliderFunc - for i = 1, sliderFrame.level - 1 do - Refresh(self, levels[i]) - end - local newParent - for _,button in ipairs(levels[sliderFrame.level-1].buttons) do - if button.sliderFunc == sliderFunc then - newParent = button - break - end - end - if newParent then - OpenSlider(self, newParent) - else - sliderFrame:Hide() - end - end - if inside then - showGameTooltip(sliderFrame.parent) - end - end) - slider:SetScript("OnEnter", function() - inside = true - StopCounting(self, sliderFrame.level) - showGameTooltip(sliderFrame.parent) - end) - slider:SetScript("OnLeave", function() - inside = false - GameTooltip:Hide() - if changed and not sliderFrame.mouseDown then - local parent = sliderFrame.parent - local sliderFunc = parent.sliderFunc - for i = 1, sliderFrame.level - 1 do - Refresh(self, levels[i]) - end - local newParent - for _,button in ipairs(levels[sliderFrame.level-1].buttons) do - if button.sliderFunc == sliderFunc then - newParent = button - break - end - end - if newParent then - OpenSlider(self, newParent) - else - sliderFrame:Hide() - end - - changed = false - end - end) - sliderFrame:SetScript("OnMouseWheel", function(t, a1) - local arg1 = a1 or arg1 - local up = arg1 > 0 - - local min = sliderFrame.parent.sliderMin or 0 - local max = sliderFrame.parent.sliderMax or 1 - local step = sliderFrame.parent.sliderStep or (max - min) / 100 - if step <= 0 then - step = (max - min) / 100 - end - - local value = (1 - slider:GetValue()) * (max - min) + min - if up then - value = value + step - else - value = value - step - end - if value > max then - value = max - elseif value < min then - value = min - end - sliderFrame.fineStep = true - if max<=min then - slider:SetValue(0) - else - slider:SetValue(1 - (value - min) / (max - min)) - end - sliderFrame.fineStep = nil - end) - slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel")) - editBox:SetScript("OnEnterPressed", function(t, a1) - local value = editBox:GetNumber() - - if sliderFrame.parent.sliderIsPercent then - value = value / 100 - end - - local min = sliderFrame.parent.sliderMin or 0 - local max = sliderFrame.parent.sliderMax or 1 - - if value > max then - value = max - elseif value < min then - value = min - end - sliderFrame.fineStep = true - if max <= min then - slider:SetValue(0) - else - slider:SetValue(1 - (value - min) / (max - min)) - end - sliderFrame.fineStep = nil - - StartCounting(self, sliderFrame.level) - end) - editBox:SetScript("OnEscapePressed", function() - self:Close(sliderFrame.level) - StartCounting(self, sliderFrame.level) - end) - editBox:SetAutoFocus(false) - end - sliderFrame.parent = parent - sliderFrame.level = parent.level.num + 1 - sliderFrame.parentValue = parent.level.value - sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) - sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) - sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) - sliderFrame.currentText:ClearFocus() - sliderFrame.changing = true - if not parent.sliderMin or not parent.sliderMax then - return - end - - if parent.arrow then --- parent.arrow:SetVertexColor(0.2, 0.6, 0) --- parent.arrow:SetHeight(24) --- parent.arrow:SetWidth(24) - parent.selected = true - parent.highlight:Show() - end - - sliderFrame:SetClampedToScreen(false) - if not parent.sliderValue then - parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 - end - if parent.sliderMax <= parent.sliderMin then - sliderFrame.slider:SetValue(0) - else - sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) - end - sliderFrame.changing = false - sliderFrame.bottomText:SetText(parent.sliderMinText or "0") - sliderFrame.topText:SetText(parent.sliderMaxText or "1") - local text - if parent.sliderFunc and not parent.fromAceOptions then - text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue)) - end - if type(text) == "number" or type(text) == "string" then - sliderFrame.currentText:SetText(text) - elseif parent.sliderIsPercent then - sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) - else - if parent.sliderStep < 0.1 then - sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue)) - elseif parent.sliderStep < 1 then - sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue)) - else - sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue)) - end - end - - - sliderFrame.lastValue = parent.sliderValue - - local level = parent.level - sliderFrame:Show() - sliderFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - local dirty - if level.lastDirection == "RIGHT" then - if sliderFrame:GetRight() > GetScreenWidth() then - level.lastDirection = "LEFT" - dirty = true - end - elseif sliderFrame:GetLeft() < 0 then - level.lastDirection = "RIGHT" - dirty = true - end - if level.lastVDirection == "DOWN" then - if sliderFrame:GetBottom() < 0 then - level.lastVDirection = "UP" - dirty = true - end - elseif sliderFrame:GetTop() > GetScreenWidth() then - level.lastVDirection = "DOWN" - dirty = true - end - if dirty then - sliderFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - end - local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom() - sliderFrame:ClearAllPoints() - sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - if mod(level.num, 5) == 0 then - local left, bottom = level:GetLeft(), level:GetBottom() - level:ClearAllPoints() - level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - end - sliderFrame:SetClampedToScreen(true) -end - -function OpenEditBox(self, parent) - if not editBoxFrame then - editBoxFrame = CreateFrame("Frame", nil, nil) - editBoxFrame:SetWidth(200) - editBoxFrame:SetHeight(40) - editBoxFrame:SetScale(UIParent:GetScale()) - editBoxFrame:SetBackdrop(tmp( - 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'insets', tmp2( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ), - 'tileSize', 16, - 'edgeSize', 16 - )) - editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG") - if editBoxFrame.SetTopLevel then - editBoxFrame:SetTopLevel(true) - end - editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) - editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) - editBoxFrame:EnableMouse(true) - editBoxFrame:EnableMouseWheel(true) - editBoxFrame:Hide() - editBoxFrame:SetPoint("CENTER", UIParent, "CENTER") - - local editBox = CreateFrame("EditBox", nil, editBoxFrame) - editBoxFrame.editBox = editBox - editBox:SetFontObject(ChatFontNormal) - editBox:SetWidth(160) - editBox:SetHeight(13) - editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0) - - local left = editBox:CreateTexture(nil, "BACKGROUND") - left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") - left:SetTexCoord(0, 100 / 256, 0, 1) - left:SetWidth(100) - left:SetHeight(32) - left:SetPoint("LEFT", editBox, "LEFT", -10, 0) - local right = editBox:CreateTexture(nil, "BACKGROUND") - right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") - right:SetTexCoord(156/256, 1, 0, 1) - right:SetWidth(100) - right:SetHeight(32) - right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) - - editBox:SetScript("OnEnterPressed", function() - if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then - local t = editBox.realText or editBox:GetText() or "" - local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t)) - if not result then - UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) - return - end - end - if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then - local t - if editBox.realText ~= "NONE" then - t = editBox.realText or editBox:GetText() or "" - end - editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t)) - end - self:Close(editBoxFrame.level) - for i = 1, editBoxFrame.level - 1 do - Refresh(self, levels[i]) - end - StartCounting(self, editBoxFrame.level-1) - end) - editBox:SetScript("OnEscapePressed", function() - self:Close(editBoxFrame.level) - StartCounting(self, editBoxFrame.level-1) - end) - editBox:SetScript("OnReceiveDrag", function(this) - if GetCursorInfo then - local type, alpha, bravo = GetCursorInfo() - local text - if type == "spell" then - text = GetSpellName(alpha, bravo) - elseif type == "item" then - text = bravo - end - if not text then - return - end - ClearCursor() - editBox:SetText(text) - end - end) - local changing = false - local skipNext = false - - function editBox:SpecialSetText(text) - local oldText = editBox:GetText() or "" - if not text then - text = "" - end - if text ~= oldText then - changing = true - self:SetText(tostring(text)) - changing = false - skipNext = true - end - end - - editBox:SetScript("OnTextChanged", function() - if skipNext then - skipNext = false - elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then - local t - if editBox.realText ~= "NONE" then - t = editBox.realText or editBox:GetText() or "" - end - local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t)) - if text then - editBox:SpecialSetText(text) - end - end - end) - editBoxFrame:SetScript("OnEnter", function() - StopCounting(self, editBoxFrame.level) - showGameTooltip(editBoxFrame.parent) - end) - editBoxFrame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - editBox:SetScript("OnEnter", function() - StopCounting(self, editBoxFrame.level) - showGameTooltip(editBoxFrame.parent) - end) - editBox:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - editBoxFrame:SetScript("OnKeyDown", function(this, a1) - if not editBox.keybinding then - return - end - local arg1 = a1 or arg1 - local screenshotKey = GetBindingKey("SCREENSHOT") - if screenshotKey and arg1 == screenshotKey then - Screenshot() - return - end - - if arg1 == "LeftButton" then - arg1 = "BUTTON1" - elseif arg1 == "RightButton" then - arg1 = "BUTTON2" - elseif arg1 == "MiddleButton" then - arg1 = "BUTTON3" - elseif arg1 == "Button4" then - arg1 = "BUTTON4" - elseif arg1 == "Button5" then - arg1 = "BUTTON5" - end - if arg1 == "UNKNOWN" then - return - elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then - return - elseif arg1 == "ENTER" then - if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then - return editBox:GetScript("OnEscapePressed")() - elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then - return editBox:GetScript("OnEscapePressed")() - else - return editBox:GetScript("OnEnterPressed")() - end - elseif arg1 == "ESCAPE" then - if editBox.realText == "NONE" then - return editBox:GetScript("OnEscapePressed")() - else - editBox:SpecialSetText(NONE or "NONE") - editBox.realText = "NONE" - return - end - elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then - return - elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then - return - end - local s = GetBindingText(arg1, "KEY_") - if s == "BUTTON1" then - s = KEY_BUTTON1 - elseif s == "BUTTON2" then - s = KEY_BUTTON2 - end - local real = arg1 - if IsShiftKeyDown() then - s = "Shift-" .. s - real = "SHIFT-" .. real - end - if IsControlKeyDown() then - s = "Ctrl-" .. s - real = "CTRL-" .. real - end - if IsAltKeyDown() then - s = "Alt-" .. s - real = "ALT-" .. real - end - if editBox:GetText() ~= s then - editBox:SpecialSetText("-") - editBox:SpecialSetText(s) - editBox.realText = real - return editBox:GetScript("OnTextChanged")() - end - end) - editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) - editBox:SetScript("OnMouseDown", function(this, ...) - if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then - return editBox:GetScript("OnReceiveDrag")(this, ...) - end - return editBoxFrame:GetScript("OnKeyDown")(this, ...) - end) - editBoxFrame:SetScript("OnMouseWheel", function(t, a1) - local arg1 = a1 or arg1 - local up = arg1 > 0 - arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" - return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1) - end) - editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel")) - end - editBoxFrame.parent = parent - editBoxFrame.level = parent.level.num + 1 - editBoxFrame.parentValue = parent.level.value - editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) - editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1) - editBoxFrame.editBox.realText = nil - editBoxFrame:SetClampedToScreen(false) - - editBoxFrame.editBox:SpecialSetText("") - if parent.editBoxIsKeybinding then - local s = parent.editBoxText - if s == "" then - s = "NONE" - end - editBoxFrame.editBox.realText = s - if s and s ~= "NONE" then - local alpha,bravo = s:match("^(.+)%-(.+)$") - if not bravo then - alpha = nil - bravo = s - end - bravo = GetBindingText(bravo, "KEY_") - if alpha then - editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) - else - editBoxFrame.editBox:SpecialSetText(bravo) - end - else - editBoxFrame.editBox:SpecialSetText(NONE or "NONE") - end - else - editBoxFrame.editBox:SpecialSetText(parent.editBoxText) - end - - editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding - editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly - editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept - editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) - editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) - - if parent.arrow then --- parent.arrow:SetVertexColor(0.2, 0.6, 0) --- parent.arrow:SetHeight(24) --- parent.arrow:SetWidth(24) - parent.selected = true - parent.highlight:Show() - end - - local level = parent.level - editBoxFrame:Show() - editBoxFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - local dirty - if level.lastDirection == "RIGHT" then - if editBoxFrame:GetRight() > GetScreenWidth() then - level.lastDirection = "LEFT" - dirty = true - end - elseif editBoxFrame:GetLeft() < 0 then - level.lastDirection = "RIGHT" - dirty = true - end - if level.lastVDirection == "DOWN" then - if editBoxFrame:GetBottom() < 0 then - level.lastVDirection = "UP" - dirty = true - end - elseif editBoxFrame:GetTop() > GetScreenWidth() then - level.lastVDirection = "DOWN" - dirty = true - end - if dirty then - editBoxFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - end - local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom() - editBoxFrame:ClearAllPoints() - editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - if mod(level.num, 5) == 0 then - local left, bottom = level:GetLeft(), level:GetBottom() - level:ClearAllPoints() - level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - end - editBoxFrame:SetClampedToScreen(true) -end - -function Dewdrop:EncodeKeybinding(text) - if text == nil or text == "NONE" then - return nil - end - text = tostring(text):upper() - local shift, ctrl, alt - local modifier - while true do - if text == "-" then - break - end - modifier, text = strsplit('-', text, 2) - if text then - if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then - return false - end - if modifier == "SHIFT" then - if shift then - return false - end - shift = true - end - if modifier == "CTRL" then - if ctrl then - return false - end - ctrl = true - end - if modifier == "ALT" then - if alt then - return false - end - alt = true - end - else - text = modifier - break - end - end - if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then - return false - end - local s = GetBindingText(text, "KEY_") - if s == "BUTTON1" then - s = KEY_BUTTON1 - elseif s == "BUTTON2" then - s = KEY_BUTTON2 - end - if shift then - s = "Shift-" .. s - end - if ctrl then - s = "Ctrl-" .. s - end - if alt then - s = "Alt-" .. s - end - return s -end - -function Dewdrop:IsOpen(parent) - self:argCheck(parent, 2, "table", "string", "nil") - return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent()) -end - -function Dewdrop:GetOpenedParent() - return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent()) -end - -function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY) - self:Close(level) - if DewdropLib then - local d = DewdropLib:GetInstance('1.0') - local ret, val = pcall(d, IsOpen, d) - if ret and val then - DewdropLib:GetInstance('1.0'):Close() - end - end - if type(parent) == "table" then - parent:GetCenter() - end - local frame = AcquireLevel(self, level) - if level == 1 then - frame.lastDirection = "RIGHT" - frame.lastVDirection = "DOWN" - else - frame.lastDirection = levels[level - 1].lastDirection - frame.lastVDirection = levels[level - 1].lastVDirection - end - frame:SetFrameStrata("FULLSCREEN_DIALOG") - frame:ClearAllPoints() - frame.parent = parent - frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0) - frame:Show() - if level == 1 then - baseFunc = func - end - levels[level].value = value --- levels[level].parentText = parent.text and parent.text:GetText() or nil --- levels[level].parentTooltipTitle = parent.tooltipTitle --- levels[level].parentTooltipText = parent.tooltipText --- levels[level].parentTooltipFunc = parent.tooltipFunc - if type(parent) == "table" and parent.arrow then --- parent.arrow:SetVertexColor(0.2, 0.6, 0) --- parent.arrow:SetHeight(24) --- parent.arrow:SetWidth(24) - parent.selected = true - parent.highlight:Show() - end - relativePoint = relativePoint or point - Refresh(self, levels[level]) - if point or (cursorX and cursorY) then - frame:ClearAllPoints() - if cursorX and cursorY then - local curX, curY = GetScaledCursorPosition() - if curY < GetScreenHeight() / 2 then - point, relativePoint = "BOTTOM", "BOTTOM" - else - point, relativePoint = "TOP", "TOP" - end - if curX < GetScreenWidth() / 2 then - point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT" - else - point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT" - end - end - frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint) - if cursorX and cursorY then - local left = frame:GetLeft() - local width = frame:GetWidth() - local bottom = frame:GetBottom() - local height = frame:GetHeight() - local curX, curY = GetScaledCursorPosition() - frame:ClearAllPoints() - relativePoint = relativePoint or point - if point == "BOTTOM" or point == "TOP" then - if curX < GetScreenWidth() / 2 then - point = point .. "LEFT" - else - point = point .. "RIGHT" - end - elseif point == "CENTER" then - if curX < GetScreenWidth() / 2 then - point = "LEFT" - else - point = "RIGHT" - end - end - local xOffset, yOffset = 0, 0 - if curY > GetScreenHeight() / 2 then - yOffset = -height - end - if curX > GetScreenWidth() / 2 then - xOffset = -width - end - frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset) - if level == 1 then - frame.lastDirection = "RIGHT" - end - elseif cursorX then - local left = frame:GetLeft() - local width = frame:GetWidth() - local curX, curY = GetScaledCursorPosition() - frame:ClearAllPoints() - relativePoint = relativePoint or point - if point == "BOTTOM" or point == "TOP" then - if curX < GetScreenWidth() / 2 then - point = point .. "LEFT" - else - point = point .. "RIGHT" - end - elseif point == "CENTER" then - if curX < GetScreenWidth() / 2 then - point = "LEFT" - else - point = "RIGHT" - end - end - frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0) - if level == 1 then - frame.lastDirection = "RIGHT" - end - elseif cursorY then - local bottom = frame:GetBottom() - local height = frame:GetHeight() - local curX, curY = GetScaledCursorPosition() - frame:ClearAllPoints() - relativePoint = relativePoint or point - if point == "LEFT" or point == "RIGHT" then - if curX < GetScreenHeight() / 2 then - point = point .. "BOTTOM" - else - point = point .. "TOP" - end - elseif point == "CENTER" then - if curX < GetScreenHeight() / 2 then - point = "BOTTOM" - else - point = "TOP" - end - end - frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2) - if level == 1 then - frame.lastDirection = "DOWN" - end - end - if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then - if frame:GetBottom() < 0 then - local point, parent, relativePoint, x, y = frame:GetPoint(1) - local change = GetScreenHeight() - frame:GetTop() - local otherChange = -frame:GetBottom() - if otherChange < change then - change = otherChange - end - frame:SetPoint(point, parent, relativePoint, x, y + change) - elseif frame:GetTop() > GetScreenHeight() then - local point, parent, relativePoint, x, y = frame:GetPoint(1) - local change = GetScreenHeight() - frame:GetTop() - local otherChange = -frame:GetBottom() - if otherChange < change then - change = otherChange - end - frame:SetPoint(point, parent, relativePoint, x, y + change) - end - end - end - CheckDualMonitor(self, frame) - frame:SetClampedToScreen(true) - frame:SetClampedToScreen(false) - StartCounting(self, level) -end - -function Dewdrop:IsRegistered(parent) - self:argCheck(parent, 2, "table", "string") - return not not self.registry[parent] -end - -function Dewdrop:Register(parent, ...) - self:argCheck(parent, 2, "table", "string") - if self.registry[parent] then - self:Unregister(parent) - end - local info = new(...) - if type(info.children) == "table" then - local err, position = validateOptions(info.children) - - if err then - if position then - Dewdrop:error(position .. ": " .. err) - else - Dewdrop:error(err) - end - end - end - self.registry[parent] = info - if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then - if parent:HasScript("OnMouseUp") then - local script = parent:GetScript("OnMouseUp") - parent:SetScript("OnMouseUp", function(this, ...) - if script then - script(this, ...) - end - if arg1 == "RightButton" and self.registry[parent] then - if self:IsOpen(parent) then - self:Close() - else - self:Open(parent) - end - end - end) - end - if parent:HasScript("OnMouseDown") then - local script = parent:GetScript("OnMouseDown") - parent:SetScript("OnMouseDown", function(this, ...) - if script then - script(this, ...) - end - if self.registry[parent] then - self:Close() - end - end) - end - end - self.onceRegistered[parent] = true -end - -function Dewdrop:Unregister(parent) - self:argCheck(parent, 2, "table", "string") - self.registry[parent] = nil -end - -function Dewdrop:Open(parent, ...) - self:argCheck(parent, 2, "table", "string") - local info - local k1 = ... - if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then - info = tmp(select(2, ...)) - for k,v in pairs(self.registry[k1]) do - if info[k] == nil then - info[k] = v - end - end - else - info = tmp(...) - if self.registry[parent] then - for k,v in pairs(self.registry[parent]) do - if info[k] == nil then - info[k] = v - end - end - end - end - local point = info.point - local relativePoint = info.relativePoint - local cursorX = info.cursorX - local cursorY = info.cursorY - if type(point) == "function" then - local b - point, b = point(parent) - if b then - relativePoint = b - end - end - if type(relativePoint) == "function" then - relativePoint = relativePoint(parent) - end - Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY) -end - -function Clear(self, level) - if level then - if level.buttons then - for i = #level.buttons, 1, -1 do - ReleaseButton(self, level, i) - end - end - end -end - -function Dewdrop:Close(level) - if DropDownList1:IsShown() then - DropDownList1:Hide() - end - if DewdropLib then - local d = DewdropLib:GetInstance('1.0') - local ret, val = pcall(d, IsOpen, d) - if ret and val then - DewdropLib:GetInstance('1.0'):Close() - end - end - self:argCheck(level, 2, "number", "nil") - if not level then - level = 1 - end - if level == 1 and levels[level] then - levels[level].parented = false - end - if level > 1 and levels[level-1].buttons then - local buttons = levels[level-1].buttons - for _,button in ipairs(buttons) do --- button.arrow:SetWidth(16) --- button.arrow:SetHeight(16) - button.selected = nil - button.highlight:Hide() --- button.arrow:SetVertexColor(1, 1, 1) - end - end - if sliderFrame and sliderFrame.level >= level then - sliderFrame:Hide() - end - if editBoxFrame and editBoxFrame.level >= level then - editBoxFrame:Hide() - end - for i = level, #levels do - Clear(self, levels[level]) - levels[i]:Hide() - levels[i]:ClearAllPoints() - levels[i]:SetPoint("CENTER", UIParent, "CENTER") - levels[i].value = nil - end -end - -function Dewdrop:AddSeparator(level) - level = levels[level or currentLevel] - if not level or not level.buttons then return; end - - local prevbutton = level.buttons[#level.buttons] - if not prevbutton then return; end - - if prevbutton.disabled and prevbutton.text:GetText() == "" then - return - end - self:AddLine("text", "", "disabled", true) -end - -function Dewdrop:AddLine(...) - local info = tmp(...) - local level = info.level or currentLevel - info.level = nil - local button = AcquireButton(self, level) - if not next(info) then - info.disabled = true - end - button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure) - button.isTitle = info.isTitle - button.notClickable = info.notClickable - if button.isTitle then - button.text:SetFontObject(GameFontNormalSmall) - elseif button.notClickable then - button.text:SetFontObject(GameFontHighlightSmall) - elseif button.disabled then - button.text:SetFontObject(GameFontDisableSmall) - else - button.text:SetFontObject(GameFontHighlightSmall) - end - if info.disabled then - button.arrow:SetDesaturated(true) - button.check:SetDesaturated(true) - else - button.arrow:SetDesaturated(false) - button.check:SetDesaturated(false) - end - if info.textR and info.textG and info.textB then - button.textR = info.textR - button.textG = info.textG - button.textB = info.textB - button.text:SetTextColor(button.textR, button.textG, button.textB) - else - button.text:SetTextColor(button.text:GetFontObject():GetTextColor()) - end - button.notCheckable = info.notCheckable - button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0) - button.checked = not info.notCheckable and info.checked - button.mouseoverUnderline = info.mouseoverUnderline - button.isRadio = not info.notCheckable and info.isRadio - if info.isRadio then - button.check:Show() - button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") - if button.checked then - button.check:SetTexCoord(0.25, 0.5, 0, 1) - button.check:SetVertexColor(1, 1, 1, 1) - else - button.check:SetTexCoord(0, 0.25, 0, 1) - button.check:SetVertexColor(1, 1, 1, 0.5) - end - button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") - button.check:SetWidth(16) - button.check:SetHeight(16) - elseif info.icon then - button.check:Show() - button.check:SetTexture(info.icon) - if info.iconWidth and info.iconHeight then - button.check:SetWidth(info.iconWidth) - button.check:SetHeight(info.iconHeight) - else - button.check:SetWidth(16) - button.check:SetHeight(16) - end - if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then - button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) - elseif info.icon:find("^Interface\\Icons\\") then - button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - button.check:SetTexCoord(0, 1, 0, 1) - end - button.check:SetVertexColor(1, 1, 1, 1) - else - if button.checked then - if info.checkIcon then - button.check:SetWidth(16) - button.check:SetHeight(16) - button.check:SetTexture(info.checkIcon) - if info.checkIcon:find("^Interface\\Icons\\") then - button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - button.check:SetTexCoord(0, 1, 0, 1) - end - else - button.check:SetWidth(24) - button.check:SetHeight(24) - button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") - button.check:SetTexCoord(0, 1, 0, 1) - end - button.check:SetVertexColor(1, 1, 1, 1) - else - button.check:SetVertexColor(1, 1, 1, 0) - end - end - if not button.disabled then - button.func = info.func - button.secure = info.secure - end - button.hasColorSwatch = info.hasColorSwatch - if button.hasColorSwatch then - button.colorSwatch:Show() - button.colorSwatch.texture:Show() - button.r = info.r or 1 - button.g = info.g or 1 - button.b = info.b or 1 - button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b) - button.checked = false - button.func = nil - button.colorFunc = info.colorFunc - local i = 1 - while true do - local k = "colorArg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - button.hasOpacity = info.hasOpacity - button.opacity = info.opacity or 1 - else - button.colorSwatch:Hide() - button.colorSwatch.texture:Hide() - end - button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow - if button.hasArrow then - button.arrow:SetAlpha(1) - if info.hasSlider then - button.hasSlider = true - button.sliderMin = info.sliderMin or 0 - button.sliderMax = info.sliderMax or 1 - button.sliderStep = info.sliderStep or 0 - button.sliderBigStep = info.sliderBigStep or button.sliderStep - if button.sliderBigStep < button.sliderStep then - button.sliderBigStep = button.sliderStep - end - button.sliderIsPercent = info.sliderIsPercent and true or false - button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin - button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax - button.sliderFunc = info.sliderFunc - button.sliderValue = info.sliderValue - button.fromAceOptions = info.fromAceOptions - local i = 1 - while true do - local k = "sliderArg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - elseif info.hasEditBox then - button.hasEditBox = true - button.editBoxText = info.editBoxText or "" - button.editBoxFunc = info.editBoxFunc - local i = 1 - while true do - local k = "editBoxArg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - button.editBoxChangeFunc = info.editBoxChangeFunc - local i = 1 - while true do - local k = "editBoxChangeArg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - button.editBoxValidateFunc = info.editBoxValidateFunc - local i = 1 - while true do - local k = "editBoxValidateArg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - button.editBoxIsKeybinding = info.editBoxIsKeybinding - button.editBoxKeybindingOnly = info.editBoxKeybindingOnly - button.editBoxKeybindingExcept = info.editBoxKeybindingExcept - else - button.value = info.value - local l = levels[level+1] - if l and info.value == l.value then --- button.arrow:SetWidth(24) --- button.arrow:SetHeight(24) - button.selected = true - button.highlight:Show() - end - end - else - button.arrow:SetAlpha(0) - end - local i = 1 - while true do - local k = "arg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - button.closeWhenClicked = info.closeWhenClicked - button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10 - local font,_ = button.text:GetFont() - button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight) - button:SetHeight(button.textHeight + 6) - button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT") - button.text:SetJustifyH(info.justifyH or "LEFT") - button.text:SetText(info.text) - button.tooltipTitle = info.tooltipTitle - button.tooltipText = info.tooltipText - button.tooltipFunc = info.tooltipFunc - local i = 1 - while true do - local k = "tooltipArg" .. i - local x = info[k] - if x == nil then - break - end - button[k] = x - i = i + 1 - end - if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then - button.tooltipTitle = info.text - end - if type(button.func) == "string" then - if type(button.arg1) ~= "table" then - self:error("Cannot call method %q on a non-table", button.func) - end - if type(button.arg1[button.func]) ~= "function" then - self:error("Method %q nonexistant.", button.func) - end - end -end - -function Dewdrop:InjectAceOptionsTable(handler, options) - self:argCheck(handler, 2, "table") - self:argCheck(options, 3, "table") - if tostring(options.type):lower() ~= "group" then - self:error('Cannot inject into options table argument #3 if its type is not "group"') - end - if options.handler ~= nil and options.handler ~= handler then - self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") - end - options.handler = handler - local class = handler.class - if not AceLibrary:HasInstance("AceOO-2.0") or not class then - if Rock then - -- possible Rock object - for mixin in Rock:IterateObjectMixins(handler) do - if type(mixin.GetAceOptionsDataTable) == "function" then - local t = mixin:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - end - end - else - -- Ace2 object - while class and class ~= AceLibrary("AceOO-2.0").Class do - if type(class.GetAceOptionsDataTable) == "function" then - local t = class:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - local mixins = class.mixins - if mixins then - for mixin in pairs(mixins) do - if type(mixin.GetAceOptionsDataTable) == "function" then - local t = mixin:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - end - end - class = class.super - end - end - return options -end - -function Dewdrop:OnTooltipHide() - if lastSetFont then - if lastSetFont == normalFont then - lastSetFont = nil - return - end - fillRegionTmp(GameTooltip:GetRegions()) - for i,v in ipairs(regionTmp) do - if v.GetFont then - local font,size,outline = v:GetFont() - if font == lastSetFont then - v:SetFont(normalFont, size, outline) - end - end - regionTmp[i] = nil - end - lastSetFont = nil - end -end - -local function activate(self, oldLib, oldDeactivate) - Dewdrop = self - if oldLib and oldLib.registry then - self.registry = oldLib.registry - self.onceRegistered = oldLib.onceRegistered - else - self.registry = {} - self.onceRegistered = {} - - local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown") - local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp") - local oldX, oldY, clickTime - WorldFrame:SetScript("OnMouseDown", function(this, ...) - oldX,oldY = GetCursorPosition() - clickTime = GetTime() - if WorldFrame_OnMouseDown then - WorldFrame_OnMouseDown(this, ...) - end - end) - - WorldFrame:SetScript("OnMouseUp", function(this, ...) - local x,y = GetCursorPosition() - if not oldX or not oldY or not x or not y or not clickTime then - self:Close() - if WorldFrame_OnMouseUp then - WorldFrame_OnMouseUp(this, ...) - end - return - end - local d = math.abs(x - oldX) + math.abs(y - oldY) - if d <= 5 and GetTime() - clickTime < 0.5 then - self:Close() - end - if WorldFrame_OnMouseUp then - WorldFrame_OnMouseUp(this, ...) - end - end) - - hooksecurefunc(DropDownList1, "Show", function() - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - end) - - hooksecurefunc("HideDropDownMenu", function() - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - end) - - hooksecurefunc("CloseDropDownMenus", function() - if levels[1] and levels[1]:IsVisible() then - local stack = debugstack() - if not stack:find("`TargetFrame_OnHide'") then - self:Close() - end - end - end) - end - self.frame = oldLib and oldLib.frame or CreateFrame("Frame") - self.frame:UnregisterAllEvents() - self.frame:RegisterEvent("PLAYER_REGEN_ENABLED") - self.frame:RegisterEvent("PLAYER_REGEN_DISABLED") - self.frame:Hide() - self.frame:SetScript("OnEvent", function(this, event) - this:Show() - if event=="PLAYER_REGEN_ENABLED" then -- track combat state for secure frame operations - self.combat = false - elseif event=="PLAYER_REGEN_DISABLED" then - self.combat = true - end - end) - self.frame:SetScript("OnUpdate", function(this) - this:Hide() - self:Refresh(1) - end) - self.hookedTooltip = true - if not oldLib or not oldLib.hookedTooltip then - local OnTooltipHide = GameTooltip:GetScript("OnHide") - GameTooltip:SetScript("OnHide", function(this, ...) - if OnTooltipHide then - OnTooltipHide(this, ...) - end - if type(self.OnTooltipHide) == "function" then - self:OnTooltipHide() - end - end) - end - levels = {} - buttons = {} - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -local function external(lib, major, instance) - if major == "SharedMedia-1.0" then - SharedMedia = instance - end -end - -AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/LibStub/LibStub.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +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(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end
--- a/lib/embeds.xml Tue Mar 11 21:39:34 2008 +0000 +++ b/lib/embeds.xml Mon Mar 17 18:24:53 2008 +0000 @@ -2,14 +2,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> - <Script file="AceLibrary\AceLibrary.lua"/> - <Script file="AceOO-2.0\AceOO-2.0.lua"/> - <Script file="AceAddon-2.0\AceAddon-2.0.lua"/> - <Script file="AceConsole-2.0\AceConsole-2.0.lua"/> - <Script file="AceDB-2.0\AceDB-2.0.lua"/> - <Script file="AceEvent-2.0\AceEvent-2.0.lua"/> - <Script file="AceLocale-2.2\AceLocale-2.2.lua"/> - <Script file="AceModuleCore-2.0\AceModuleCore-2.0.lua"/> - <Script file="Dewdrop-2.0\Dewdrop-2.0.lua"/> + <Script file="LibStub\LibStub.lua"/> + <Include file="CallbackHandler-1.0\CallbackHandler-1.0.xml"/> + <Include file="AceAddon-3.0\AceAddon-3.0.xml"/> + <Include file="AceLocale-3.0\AceLocale-3.0.xml"/> + <Include file="AceDB-3.0\AceDB-3.0.xml"/> + <Include file="AceEvent-3.0\AceEvent-3.0.xml"/> </Ui>
--- a/locale/enUS.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/locale/enUS.lua Mon Mar 17 18:24:53 2008 +0000 @@ -1,65 +1,61 @@ -AceLibrary("AceLocale-2.2"):new("ReAction"):RegisterTranslations( "enUS", -function() -return -{ --- ReAction -["ReAction"] = true, -["Toggle ReAction Bar Lock"] = true, -["ReAction Keybinding Mode"] = true, +local L = LibStub("AceLocale-3.0"):NewLocale("ReAction","enUS",true) +if L then --- ReAction_Bar -["Bar "] = true, -["Delete Bar"] = true, -["Remove the bar from the current profile"] = true, -["Rename Bar"] = true, -["Set a name for the bar"] = true, -["ReAction: name already in use"] = true, +-- bindings.lua +L["ReAction"] = true +L["Toggle ReAction Bar Lock"] = true +L["ReAction Keybinding Mode"] = true + +-- ReAction.lua +L["Bar "] = true +L["ReAction: name already in use"] = true -- modules/ReAction_HideBlizzard -["Hide Default Action Bars"] = true, -["Hide the default main bar and extra action bars"] = true, +L["Hide Default Action Bars"] = true +L["Hide the default main bar and extra action bars"] = true -- modules/ReAction_Action -["New Action Bar"] = true, -["Create a new bar of standard action buttons"] = true, +L["New Action Bar"] = true +L["Create a new bar of standard action buttons"] = true -- modules/ReAction_ConfigUI +L["Delete Bar"] = true +L["Remove the bar from the current profile"] = true +L["Rename Bar"] = true +L["Set a name for the bar"] = true -- console commands -["/reaction"] = true, -["/rxn"] = true, -["unlock"] = true, -["config"] = true, +L["/reaction"] = true +L["/rxn"] = true +L["unlock"] = true +L["config"] = true -- messages -["ReAction config mode disabled during combat."] = true, +L["ReAction config mode disabled during combat."] = true -- tooltips -["Drag to add/remove buttons"] = true, -["Drag to resize buttons"] = true, -["Right-click-drag"] = true, -["to change spacing"] = true, -["Size:"] = true, -["Spacing:"] = true, -["Drag to move"] = true, -["Shift-drag for sticky mode"] = true, -["Right-click for options"] = true, +L["Drag to add/remove buttons"] = true +L["Drag to resize buttons"] = true +L["Right-click-drag"] = true +L["to change spacing"] = true +L["Size:"] = true +L["Spacing:"] = true +L["Drag to move"] = true +L["Shift-drag for sticky mode"] = true +L["Right-click for options"] = true -- global options -["Unlock Bars"] = true, -["Unlock bars for dragging and resizing with the mouse"] = true, -["Configure..."] = true, -["Open the configuration dialogue"] = true, +L["Unlock Bars"] = true +L["Unlock bars for dragging and resizing with the mouse"] = true +L["Configure..."] = true +L["Open the configuration dialogue"] = true -- bar menu options -["Open the configuration dialogue for this bar"] = true, +L["Open the configuration dialogue for this bar"] = true -- waterfall options -["Global Settings"] = true, -["Global configuration settings"] = true, -["Module Settings"] = true, -["Configuration settings for each module"] = true, -["Bars"] = true, -["Configuration settings for bars"] = true, +L["Global Settings"] = true +L["Global configuration settings"] = true +L["Module Settings"] = true +L["Configuration settings for each module"] = true +L["Bars"] = true +L["Configuration settings for bars"] = true -- modules/ReAction_State -["Dynamic Behavior"] = true, +L["Dynamic Behavior"] = true - -} end -)
--- a/modules/FuBar_ReActionFu/FuBar_ReActionFu.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/FuBar_ReActionFu/FuBar_ReActionFu.lua Mon Mar 17 18:24:53 2008 +0000 @@ -12,9 +12,9 @@ -- module declaration local moduleID = "ReActionFu" -local module = ReAction:NewModule( moduleID, - "FuBarPlugin-2.0" -) +local rmodule = ReAction:NewModule( moduleID ) +local module = AceLibrary("AceAddon-2.0"):new("FuBarPlugin-2.0") +rmodule.fubar = module module.hasIcon = "Interface\\Icons\\INV_Qiraj_JewelEncased" module.hasNoColor = true @@ -25,39 +25,38 @@ module.defaultPosition = "LEFT" module.defaultMinimapPosition = 240 -- degrees -function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", +function rmodule:OnInitialize() + self.db = ReAction.db:RegisterNamespace(moduleID, { - requireFuBar = false + profile = { + requireFuBar = false + } } ) + self.db.RegisterCallback(self,"OnProfileChanged") if self.db.profile.requireFuBar == true then self:Hide() end -end - -function module:OnEnable() end -function module:OnDisable() +function rmodule:OnEnable() end -function module:OnProfileEnable() +function rmodule:OnDisable() + +end + +function rmodule:OnProfileChanged() if self.db.profile.requireFuBar == true then - self:Hide() + module:Hide() else self:Show() end end -function module:OnProfileDisable() - -end - function module:OnTooltipUpdate() end @@ -77,9 +76,11 @@ Dewdrop:InjectAceOptionsTable(ReAction,opts) self.aceOptionsTable = opts end - for _, m in ReAction:IterateModulesWithMethod("GetGlobalOptions") do - for k,v in pairs(m:GetGlobalOptions()) do - self.aceOptionsTable.args[k] = v + for _, m in ReAction:IterateModules() do + if m and type(m.GetGlobalOptions) == "function" then + for k,v in pairs(m:GetGlobalOptions()) do + self.aceOptionsTable.args[k] = v + end end end Dewdrop:FeedAceOptionsTable(self.aceOptionsTable)
--- a/modules/FuBar_ReActionFu/FuBar_ReActionFu.xml Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/FuBar_ReActionFu/FuBar_ReActionFu.xml Mon Mar 17 18:24:53 2008 +0000 @@ -2,8 +2,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> + <Script file="lib\AceLibrary\AceLibrary.lua"/> + <Script file="lib\AceOO-2.0\AceOO-2.0.lua"/> + <Script file="lib\AceEvent-2.0\AceEvent-2.0.lua"/> + <Script file="lib\AceAddon-2.0\AceAddon-2.0.lua"/> <Script file="lib\FuBarPlugin-2.0\FuBarPlugin-2.0.lua"/> <Script file="lib\Tablet-2.0\Tablet-2.0.lua"/> + <Script file="lib\Dewdrop-2.0\Dewdrop-2.0.lua"/> + <Script file="FuBar_ReActionFu.lua"/> </Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceAddon-2.0/AceAddon-2.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,1394 @@ +--[[ +Name: AceAddon-2.0 +Revision: $Rev: 46764 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/wiki/AceAddon-2.0 +SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceAddon-2.0 +Description: Base for all Ace addons to inherit from. +Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0 +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceAddon-2.0" +local MINOR_VERSION = "$Revision: 46764 $" + +-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end + +local function safecall(func,...) + local success, err = pcall(func,...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end +end +-- Localization +local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, CREDITS, WEBSITE, CATEGORIES, ABOUT, LICENSE, PRINT_ADDON_INFO, DONATE, DONATE_DESC, HOWTO_DONATE_WINDOWS, HOWTO_DONATE_MAC +if GetLocale() == "deDE" then + STANDBY = "|cffff5050(Standby)|r" -- capitalized + + TITLE = "Titel" + NOTES = "Anmerkung" + VERSION = "Version" + AUTHOR = "Autor" + DATE = "Datum" + CATEGORY = "Kategorie" + EMAIL = "E-Mail" + WEBSITE = "Webseite" + CREDITS = "Credits" -- fix + LICENSE = "License" -- fix + + ABOUT = "Über" + PRINT_ADDON_INFO = "Gibt Addondaten aus" + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "Aktionsleisten", + ["Auction"] = "Auktion", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Schlachtfeld/PvP", + ["Buffs"] = "Stärkungszauber", + ["Chat/Communication"] = "Chat/Kommunikation", + ["Druid"] = "Druide", + ["Hunter"] = "Jäger", + ["Mage"] = "Magier", + ["Paladin"] = "Paladin", + ["Priest"] = "Priester", + ["Rogue"] = "Schurke", + ["Shaman"] = "Schamane", + ["Warlock"] = "Hexenmeister", + ["Warrior"] = "Krieger", + ["Healer"] = "Heiler", + ["Tank"] = "Tank", + ["Caster"] = "Zauberer", + ["Combat"] = "Kampf", + ["Compilations"] = "Zusammenstellungen", + ["Data Export"] = "Datenexport", + ["Development Tools"] = "Entwicklungs Tools", + ["Guild"] = "Gilde", + ["Frame Modification"] = "Frame Veränderungen", + ["Interface Enhancements"] = "Interface Verbesserungen", + ["Inventory"] = "Inventar", + ["Library"] = "Bibliotheken", + ["Map"] = "Karte", + ["Mail"] = "Post", + ["Miscellaneous"] = "Diverses", + ["Quest"] = "Quest", + ["Raid"] = "Schlachtzug", + ["Tradeskill"] = "Beruf", + ["UnitFrame"] = "Einheiten-Fenster", + } +elseif GetLocale() == "frFR" then + STANDBY = "|cffff5050(attente)|r" + + TITLE = "Titre" + NOTES = "Notes" + VERSION = "Version" + AUTHOR = "Auteur" + DATE = "Date" + CATEGORY = "Catégorie" + EMAIL = "E-mail" + WEBSITE = "Site web" + CREDITS = "Credits" -- fix + LICENSE = "License" -- fix + + ABOUT = "A propos" + PRINT_ADDON_INFO = "Afficher les informations sur l'addon" + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "Barres d'action", + ["Auction"] = "Hôtel des ventes", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Champs de bataille/JcJ", + ["Buffs"] = "Buffs", + ["Chat/Communication"] = "Chat/Communication", + ["Druid"] = "Druide", + ["Hunter"] = "Chasseur", + ["Mage"] = "Mage", + ["Paladin"] = "Paladin", + ["Priest"] = "Prêtre", + ["Rogue"] = "Voleur", + ["Shaman"] = "Chaman", + ["Warlock"] = "Démoniste", + ["Warrior"] = "Guerrier", + ["Healer"] = "Soigneur", + ["Tank"] = "Tank", + ["Caster"] = "Casteur", + ["Combat"] = "Combat", + ["Compilations"] = "Compilations", + ["Data Export"] = "Exportation de données", + ["Development Tools"] = "Outils de développement", + ["Guild"] = "Guilde", + ["Frame Modification"] = "Modification des fenêtres", + ["Interface Enhancements"] = "Améliorations de l'interface", + ["Inventory"] = "Inventaire", + ["Library"] = "Bibliothèques", + ["Map"] = "Carte", + ["Mail"] = "Courrier", + ["Miscellaneous"] = "Divers", + ["Quest"] = "Quêtes", + ["Raid"] = "Raid", + ["Tradeskill"] = "Métiers", + ["UnitFrame"] = "Fenêtres d'unité", + } +elseif GetLocale() == "koKR" then + STANDBY = "|cffff5050(사용가능)|r" + + TITLE = "제목" + NOTES = "노트" + VERSION = "버전" + AUTHOR = "저작자" + DATE = "날짜" + CATEGORY = "분류" + EMAIL = "전자 우편" + WEBSITE = "웹 사이트" + CREDITS = "공로자" + LICENSE = "라이센스" + + ABOUT = "정보" + PRINT_ADDON_INFO = "애드온에 대한 정보를 출력합니다." + DONATE = "기부" + DONATE_DESC = "이 애드온의 저작자에게 기부를 합니다." + HOWTO_DONATE_WINDOWS = "Ctrl-A를 눌려 링크를 선택후, Ctrl-C로 복사합니다. Alt-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." + HOWTO_DONATE_MAC = "Cmd-A를 눌려 링크를 선택후, Cmd-C로 복사합니다. Cmd-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." + + CATEGORIES = { + ["Action Bars"] = "액션바", + ["Auction"] = "경매", + ["Audio"] = "음향", + ["Battlegrounds/PvP"] = "전장/PvP", + ["Buffs"] = "버프", + ["Chat/Communication"] = "대화/의사소통", + ["Druid"] = "드루이드", + ["Hunter"] = "사냥꾼", + ["Mage"] = "마법사", + ["Paladin"] = "성기사", + ["Priest"] = "사제", + ["Rogue"] = "도적", + ["Shaman"] = "주술사", + ["Warlock"] = "흑마법사", + ["Warrior"] = "전사", + ["Healer"] = "힐러", + ["Tank"] = "탱커", + ["Caster"] = "캐스터", + ["Combat"] = "전투", + ["Compilations"] = "복합", + ["Data Export"] = "자료 출력", + ["Development Tools"] = "개발 도구", + ["Guild"] = "길드", + ["Frame Modification"] = "구조 변경", + ["Interface Enhancements"] = "인터페이스 강화", + ["Inventory"] = "인벤토리", + ["Library"] = "라이브러리", + ["Map"] = "지도", + ["Mail"] = "우편", + ["Miscellaneous"] = "기타", + ["Quest"] = "퀘스트", + ["Raid"] = "공격대", + ["Tradeskill"] = "전문기술", + ["UnitFrame"] = "유닛 프레임", + } +elseif GetLocale() == "zhTW" then + STANDBY = "|cffff5050(待命)|r" + + TITLE = "標題" + NOTES = "註記" + VERSION = "版本" + AUTHOR = "作者" + DATE = "日期" + CATEGORY = "類別" + EMAIL = "電子郵件" + WEBSITE = "網站" + CREDITS = "特別感謝" + LICENSE = "版權" + + ABOUT = "關於" + PRINT_ADDON_INFO = "顯示插件資訊。" + DONATE = "捐贈" + DONATE_DESC = "捐贈金錢給插件作者。" + HOWTO_DONATE_WINDOWS = "請按Ctrl-A選擇網站連結,Ctrl-C複製網址,Alt-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" + HOWTO_DONATE_MAC = "請按Cmd-A選擇網站連結,Cmd-C複製網址,Cmd-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" + + CATEGORIES = { + ["Action Bars"] = "動作條", + ["Auction"] = "拍賣", + ["Audio"] = "音效", + ["Battlegrounds/PvP"] = "戰場/PvP", + ["Buffs"] = "增益", + ["Chat/Communication"] = "聊天/通訊", + ["Druid"] = "德魯伊", + ["Hunter"] = "獵人", + ["Mage"] = "法師", + ["Paladin"] = "聖騎士", + ["Priest"] = "牧師", + ["Rogue"] = "盜賊", + ["Shaman"] = "薩滿", + ["Warlock"] = "術士", + ["Warrior"] = "戰士", + ["Healer"] = "治療者", + ["Tank"] = "坦克", + ["Caster"] = "施法者", + ["Combat"] = "戰鬥", + ["Compilations"] = "整合", + ["Data Export"] = "資料匯出", + ["Development Tools"] = "開發工具", + ["Guild"] = "公會", + ["Frame Modification"] = "框架修改", + ["Interface Enhancements"] = "介面增強", + ["Inventory"] = "庫存", + ["Library"] = "程式庫", + ["Map"] = "地圖", + ["Mail"] = "郵件", + ["Miscellaneous"] = "雜項", + ["Quest"] = "任務", + ["Raid"] = "團隊", + ["Tradeskill"] = "交易技能", + ["UnitFrame"] = "單位框架", + } +elseif GetLocale() == "zhCN" then + STANDBY = "|cffff5050(暂挂)|r" + + TITLE = "标题" + NOTES = "附注" + VERSION = "版本" + AUTHOR = "作者" + DATE = "日期" + CATEGORY = "分类" + EMAIL = "电子邮件" + WEBSITE = "网站" + CREDITS = "Credits" -- fix + LICENSE = "License" -- fix + + ABOUT = "关于" + PRINT_ADDON_INFO = "印列出插件信息" + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "动作条", + ["Auction"] = "拍卖", + ["Audio"] = "音频", + ["Battlegrounds/PvP"] = "战场/PvP", + ["Buffs"] = "增益魔法", + ["Chat/Communication"] = "聊天/交流", + ["Druid"] = "德鲁伊", + ["Hunter"] = "猎人", + ["Mage"] = "法师", + ["Paladin"] = "圣骑士", + ["Priest"] = "牧师", + ["Rogue"] = "盗贼", + ["Shaman"] = "萨满祭司", + ["Warlock"] = "术士", + ["Warrior"] = "战士", +-- ["Healer"] = "治疗保障", +-- ["Tank"] = "近战控制", +-- ["Caster"] = "远程输出", + ["Combat"] = "战斗", + ["Compilations"] = "编译", + ["Data Export"] = "数据导出", + ["Development Tools"] = "开发工具", + ["Guild"] = "公会", + ["Frame Modification"] = "框架修改", + ["Interface Enhancements"] = "界面增强", + ["Inventory"] = "背包", + ["Library"] = "库", + ["Map"] = "地图", + ["Mail"] = "邮件", + ["Miscellaneous"] = "杂项", + ["Quest"] = "任务", + ["Raid"] = "团队", + ["Tradeskill"] = "商业技能", + ["UnitFrame"] = "头像框架", + } +elseif GetLocale() == "esES" then + STANDBY = "|cffff5050(espera)|r" + + TITLE = "Título" + NOTES = "Notas" + VERSION = "Versión" + AUTHOR = "Autor" + DATE = "Fecha" + CATEGORY = "Categoría" + EMAIL = "E-mail" + WEBSITE = "Web" + CREDITS = "Créditos" + LICENSE = "License" -- fix + + ABOUT = "Acerca de" + PRINT_ADDON_INFO = "Muestra información acerca del accesorio." + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "Barras de Acción", + ["Auction"] = "Subasta", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Campos de Batalla/JcJ", + ["Buffs"] = "Buffs", + ["Chat/Communication"] = "Chat/Comunicación", + ["Druid"] = "Druida", + ["Hunter"] = "Cazador", + ["Mage"] = "Mago", + ["Paladin"] = "Paladín", + ["Priest"] = "Sacerdote", + ["Rogue"] = "Pícaro", + ["Shaman"] = "Chamán", + ["Warlock"] = "Brujo", + ["Warrior"] = "Guerrero", + ["Healer"] = "Sanador", + ["Tank"] = "Tanque", + ["Caster"] = "Conjurador", + ["Combat"] = "Combate", + ["Compilations"] = "Compilaciones", + ["Data Export"] = "Exportar Datos", + ["Development Tools"] = "Herramientas de Desarrollo", + ["Guild"] = "Hermandad", + ["Frame Modification"] = "Modificación de Marcos", + ["Interface Enhancements"] = "Mejoras de la Interfaz", + ["Inventory"] = "Inventario", + ["Library"] = "Biblioteca", + ["Map"] = "Mapa", + ["Mail"] = "Correo", + ["Miscellaneous"] = "Misceláneo", + ["Quest"] = "Misión", + ["Raid"] = "Banda", + ["Tradeskill"] = "Habilidad de Comercio", + ["UnitFrame"] = "Marco de Unidades", + } +else -- enUS + STANDBY = "|cffff5050(standby)|r" + + TITLE = "Title" + NOTES = "Notes" + VERSION = "Version" + AUTHOR = "Author" + DATE = "Date" + CATEGORY = "Category" + EMAIL = "E-mail" + WEBSITE = "Website" + CREDITS = "Credits" + LICENSE = "License" + + ABOUT = "About" + PRINT_ADDON_INFO = "Show information about the addon." + DONATE = "Donate" + DONATE_DESC = "Give a much-needed donation to the author of this addon." + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." + + CATEGORIES = { + ["Action Bars"] = "Action Bars", + ["Auction"] = "Auction", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Battlegrounds/PvP", + ["Buffs"] = "Buffs", + ["Chat/Communication"] = "Chat/Communication", + ["Druid"] = "Druid", + ["Hunter"] = "Hunter", + ["Mage"] = "Mage", + ["Paladin"] = "Paladin", + ["Priest"] = "Priest", + ["Rogue"] = "Rogue", + ["Shaman"] = "Shaman", + ["Warlock"] = "Warlock", + ["Warrior"] = "Warrior", + ["Healer"] = "Healer", + ["Tank"] = "Tank", + ["Caster"] = "Caster", + ["Combat"] = "Combat", + ["Compilations"] = "Compilations", + ["Data Export"] = "Data Export", + ["Development Tools"] = "Development Tools", + ["Guild"] = "Guild", + ["Frame Modification"] = "Frame Modification", + ["Interface Enhancements"] = "Interface Enhancements", + ["Inventory"] = "Inventory", + ["Library"] = "Library", + ["Map"] = "Map", + ["Mail"] = "Mail", + ["Miscellaneous"] = "Miscellaneous", + ["Quest"] = "Quest", + ["Raid"] = "Raid", + ["Tradeskill"] = "Tradeskill", + ["UnitFrame"] = "UnitFrame", + } +end + +setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive + local lowerKey = key:lower() + for k,v in pairs(CATEGORIES) do + if k:lower() == lowerKey then + return v + end + end +end }) + +-- Create the library object + +local AceOO = AceLibrary("AceOO-2.0") +local AceAddon = AceOO.Class() +local AceEvent +local AceConsole +local AceModuleCore + +function AceAddon:GetLocalizedCategory(name) + self:argCheck(name, 2, "string") + return CATEGORIES[name] or UNKNOWN +end + +function AceAddon:ToString() + return "AceAddon" +end + +local function print(text) + DEFAULT_CHAT_FRAME:AddMessage(text) +end + +function AceAddon:ADDON_LOADED(name) + local unregister = true + local initAddon = {} + while #self.nextAddon > 0 do + local addon = table.remove(self.nextAddon, 1) + if addon.possibleNames[name] then + table.insert(initAddon, addon) + else + unregister = nil + table.insert(self.skipAddon, addon) + end + end + self.nextAddon, self.skipAddon = self.skipAddon, self.nextAddon + if unregister then + AceAddon:UnregisterEvent("ADDON_LOADED") + end + while #initAddon > 0 do + local addon = table.remove(initAddon, 1) + table.insert(self.addons, addon) + if not self.addons[name] then + self.addons[name] = addon + end + addon.possibleNames = nil + self:InitializeAddon(addon, name) + end +end + +local function RegisterOnEnable(self) + if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK + AceAddon.playerLoginFired = true + end + if AceAddon.playerLoginFired then + AceAddon.addonsStarted[self] = true + if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then + AceAddon:ManualEnable(self) + end + else + if not AceAddon.addonsToOnEnable then + AceAddon.addonsToOnEnable = {} + end + table.insert(AceAddon.addonsToOnEnable, self) + end +end + +function AceAddon:InitializeAddon(addon, name) + if addon.name == nil then + addon.name = name + end + if GetAddOnMetadata then + -- TOC checks + if addon.title == nil then + addon.title = GetAddOnMetadata(name, "Title") + end + if type(addon.title) == "string" then + local num = addon.title:find(" |cff7fff7f %-Ace2%-|r$") + if num then + addon.title = addon.title:sub(1, num - 1) + end + addon.title = addon.title:trim() + end + if addon.notes == nil then + addon.notes = GetAddOnMetadata(name, "Notes") + end + if type(addon.notes) == "string" then + addon.notes = addon.notes:trim() + end + if addon.version == nil then + addon.version = GetAddOnMetadata(name, "Version") + end + if type(addon.version) == "string" then + if addon.version:find("%$Revision: (%d+) %$") then + addon.version = addon.version:gsub("%$Revision: (%d+) %$", "%1") + elseif addon.version:find("%$Rev: (%d+) %$") then + addon.version = addon.version:gsub("%$Rev: (%d+) %$", "%1") + elseif addon.version:find("%$LastChangedRevision: (%d+) %$") then + addon.version = addon.version:gsub("%$LastChangedRevision: (%d+) %$", "%1") + end + addon.version = addon.version:trim() + end + if addon.author == nil then + addon.author = GetAddOnMetadata(name, "Author") + end + if type(addon.author) == "string" then + addon.author = addon.author:trim() + end + if addon.credits == nil then + addon.credits = GetAddOnMetadata(name, "X-Credits") + end + if type(addon.credits) == "string" then + addon.credits = addon.credits:trim() + end + if addon.donate == nil then + addon.donate = GetAddOnMetadata(name, "X-Donate") + end + if type(addon.donate) == "string" then + addon.donate = addon.donate:trim() + end + if addon.date == nil then + addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate") + end + if type(addon.date) == "string" then + if addon.date:find("%$Date: (.-) %$") then + addon.date = addon.date:gsub("%$Date: (.-) %$", "%1") + elseif addon.date:find("%$LastChangedDate: (.-) %$") then + addon.date = addon.date:gsub("%$LastChangedDate: (.-) %$", "%1") + end + addon.date = addon.date:trim() + end + + if addon.category == nil then + addon.category = GetAddOnMetadata(name, "X-Category") + end + if type(addon.category) == "string" then + addon.category = addon.category:trim() + end + if addon.email == nil then + addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email") + end + if type(addon.email) == "string" then + addon.email = addon.email:trim() + end + if addon.license == nil then + addon.license = GetAddOnMetadata(name, "X-License") + end + if type(addon.license) == "string" then + addon.license = addon.license:trim() + end + if addon.website == nil then + addon.website = GetAddOnMetadata(name, "X-Website") + end + if type(addon.website) == "string" then + addon.website = addon.website:trim() + end + end + local current = addon.class + while true do + if current == AceOO.Class or not current then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedInitialize) == "function" then + mixin:OnEmbedInitialize(addon, name) + end + end + end + current = current.super + end + local n = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0 + + if type(addon.OnInitialize) == "function" then + safecall(addon.OnInitialize, addon, name) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonInitialized", addon) + end + RegisterOnEnable(addon) + local n2 = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0 + if n2 - n > 1 then + local mine = table.remove(AceAddon.addonsToOnEnable) + table.insert(AceAddon.addonsToOnEnable, n+1, mine) + end +end + +local aboutFrame +local function createAboutFrame() + aboutFrame = CreateFrame("Frame", "AceAddon20AboutFrame", UIParent, "DialogBoxFrame") + aboutFrame:SetWidth(500) + aboutFrame:SetHeight(400) + aboutFrame:SetPoint("CENTER") + aboutFrame:SetBackdrop({ + bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], + edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], + tile = true, tileSize = 16, edgeSize = 16, + insets = { left = 5, right = 5, top = 5, bottom = 5 } + }) + aboutFrame:SetBackdropColor(0,0,0,1) + + local donateButton = CreateFrame("Button", "AceAddon20AboutFrameDonateButton", aboutFrame, "UIPanelButtonTemplate2") + aboutFrame.donateButton = donateButton + donateButton:SetPoint("BOTTOMRIGHT", -20, 20) + _G.AceAddon20AboutFrameDonateButtonText:SetText(DONATE) + donateButton:SetWidth(_G.AceAddon20AboutFrameDonateButtonText:GetWidth()+20) + donateButton:SetScript("OnClick", function() + aboutFrame.currentAddon:OpenDonationFrame() + end) + + local text = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") + aboutFrame.title = text + text:SetPoint("TOP", 0, -5) + + aboutFrame:Hide() + + aboutFrame.lefts = {} + aboutFrame.rights = {} + aboutFrame.textLefts = {} + aboutFrame.textRights = {} + function aboutFrame:Clear() + self.title:SetText("") + for i = 1, #self.lefts do + self.lefts[i] = nil + self.rights[i] = nil + end + end + + function aboutFrame:AddLine(left, right) + aboutFrame.lefts[#aboutFrame.lefts+1] = left + aboutFrame.rights[#aboutFrame.rights+1] = right + end + + local aboutFrame_Show = aboutFrame.Show + function aboutFrame:Show(...) + local maxLeftWidth = 0 + local maxRightWidth = 0 + local textHeight = 0 + for i = 1, #self.lefts do + if not self.textLefts[i] then + local left = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") + self.textLefts[i] = left + local right = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + self.textRights[i] = right + if i == 1 then + left:SetPoint("TOPRIGHT", aboutFrame, "TOPLEFT", 75, -35) + else + left:SetPoint("TOPRIGHT", self.textLefts[i-1], "BOTTOMRIGHT", 0, -5) + end + right:SetPoint("LEFT", left, "RIGHT", 5, 0) + end + self.textLefts[i]:SetText(self.lefts[i] .. ":") + self.textRights[i]:SetText(self.rights[i]) + local leftWidth = self.textLefts[i]:GetWidth() + local rightWidth = self.textRights[i]:GetWidth() + textHeight = self.textLefts[i]:GetHeight() + if maxLeftWidth < leftWidth then + maxLeftWidth = leftWidth + end + if maxRightWidth < rightWidth then + maxRightWidth = rightWidth + end + end + for i = #self.lefts+1, #self.textLefts do + self.textLefts[i]:SetText('') + self.textRights[i]:SetText('') + end + aboutFrame:SetWidth(75 + maxRightWidth + 20) + aboutFrame:SetHeight(#self.lefts * (textHeight + 5) + 100) + + aboutFrame_Show(self, ...) + end + aboutFrame:Hide() + + createAboutFrame = nil +end +local donateFrame + +local function unobfuscateEmail(email) + return email:gsub(" AT ", "@"):gsub(" DOT ", ".") +end + +local function isGoodVariable(var) + return type(var) == "string" or type(var) == "number" +end +function AceAddon.prototype:PrintAddonInfo() + if createAboutFrame then + createAboutFrame() + end + aboutFrame:Clear() + local x + if isGoodVariable(self.title) then + x = tostring(self.title) + elseif isGoodVariable(self.name) then + x = tostring(self.name) + else + x = "<" .. tostring(self.class) .. " instance>" + end + if type(self.IsActive) == "function" then + if not self:IsActive() then + x = x .. " " .. STANDBY + end + end + aboutFrame.title:SetText(x) + + if isGoodVariable(self.version) then + aboutFrame:AddLine(VERSION, tostring(self.version)) + end + if isGoodVariable(self.notes) then + aboutFrame:AddLine(NOTES, tostring(self.notes)) + end + if isGoodVariable(self.author) then + aboutFrame:AddLine(AUTHOR, tostring(self.author)) + end + if isGoodVariable(self.credits) then + aboutFrame:AddLine(CREDITS, tostring(self.credits)) + end + if isGoodVariable(self.date) then + aboutFrame:AddLine(DATE, tostring(self.date)) + end + if self.category then + local category = CATEGORIES[self.category] + if category then + aboutFrame:AddLine(CATEGORY, tostring(self.category)) + end + end + if isGoodVariable(self.email) then + aboutFrame:AddLine(EMAIL, unobfuscateEmail(tostring(self.email))) + end + if isGoodVariable(self.website) then + aboutFrame:AddLine(WEBSITE, tostring(self.website)) + end + if isGoodVariable(self.license) then + aboutFrame:AddLine(LICENSE, tostring(self.license)) + end + + if donateFrame and donateFrame:IsShown() then + donateFrame:Hide() + end + + aboutFrame.currentAddon = self + + aboutFrame:Show() + + if self.donate then + aboutFrame.donateButton:Show() + else + aboutFrame.donateButton:Hide() + end +end + +local function createDonateFrame() + donateFrame = CreateFrame("Frame", "AceAddon20Frame", UIParent, "DialogBoxFrame") + + donateFrame:SetWidth(500) + donateFrame:SetHeight(200) + donateFrame:SetPoint("CENTER") + donateFrame:SetBackdrop({ + bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], + edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], + tile = true, tileSize = 16, edgeSize = 16, + insets = { left = 5, right = 5, top = 5, bottom = 5 } + }) + donateFrame:SetBackdropColor(0,0,0,1) + + local text = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") + text:SetPoint("TOP", 0, -5) + text:SetText(DONATE) + + local howto = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + howto:SetPoint("TOP", text, "BOTTOM", 0, -5) + howto:SetPoint("LEFT", 16, 0) + howto:SetPoint("RIGHT", -16, 0) + if not IsMacClient() then + -- Windows or Linux + howto:SetText(HOWTO_DONATE_WINDOWS) + else + howto:SetText(HOWTO_DONATE_MAC) + end + + local scrollFrame = CreateFrame("ScrollFrame", "AceAddon20FrameScrollFrame", donateFrame, "UIPanelScrollFrameTemplate") + scrollFrame:SetToplevel(true) + scrollFrame:SetPoint("TOP", -10, -76) + scrollFrame:SetWidth(455) + scrollFrame:SetHeight(70) + howto:SetPoint("BOTTOM", scrollFrame, "TOP") + + local editBox = CreateFrame("EditBox", nil, scrollFrame) + donateFrame.editBox = editBox + scrollFrame:SetScrollChild(editBox) + editBox:SetFontObject(ChatFontNormal) + editBox:SetMultiLine(true) + editBox:SetMaxLetters(99999) + editBox:SetWidth(450) + editBox:SetHeight(54) + editBox:SetPoint("BOTTOM", 5, 0) + editBox:SetJustifyH("LEFT") + editBox:SetJustifyV("TOP") + editBox:SetAutoFocus(false) + editBox:SetScript("OnTextChanged", function(this) + if this:GetText() ~= this.text then + this:SetText(this.text) + end + end) + editBox:SetScript("OnEscapePressed", function(this) + this:ClearFocus() + end) + createDonateFrame = nil +end + +local function fix(char) + return ("%%%02x"):format(char:byte()) +end + +local function urlencode(text) + return text:gsub("[^0-9A-Za-z]", fix) +end + +function AceAddon.prototype:OpenDonationFrame() + if createDonateFrame then + createDonateFrame() + end + local donate = self.donate + if type(donate) ~= "string" then + donate = "Wowace" + end + local style, data = (":"):split(donate, 2) + style = style:lower() + if style ~= "website" and style ~= "paypal" then + style = "wowace" + end + if style == "wowace" then + donateFrame.editBox.text = "http://www.wowace.com/wiki/Donations" + elseif style == "website" then + donateFrame.editBox.text = data + else -- PayPal + local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data)) + local name + if type(self.title) == "string" then + name = self.title + elseif type(self.name) == "string" then + name = self.name + end + if name then + name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "") + text = text .. "&item_name=" .. urlencode(name) + end + donateFrame.editBox.text = text + end + donateFrame.editBox:SetText(donateFrame.editBox.text) + + if aboutFrame and aboutFrame:IsShown() then + aboutFrame:Hide() + end + + donateFrame:Show() + + donateFrame.editBox:SetFocus() +end + +local options +function AceAddon:GetAceOptionsDataTable(target) + return { + about = { + name = ABOUT, + desc = PRINT_ADDON_INFO, + type = "execute", + func = "PrintAddonInfo", + order = -1, + }, + donate = { + name = DONATE, + desc = DONATE_DESC, + type = "execute", + func = "OpenDonationFrame", + order = -1, + hidden = function() + return not target.donate + end + } + } +end + +function AceAddon:PLAYER_LOGIN() + self.playerLoginFired = true + if self.addonsToOnEnable then + while #self.addonsToOnEnable > 0 do + local addon = table.remove(self.addonsToOnEnable, 1) + self.addonsStarted[addon] = true + if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then + AceAddon:ManualEnable(addon) + end + end + self.addonsToOnEnable = nil + end +end + +function AceAddon.prototype:Inject(t) + AceAddon:argCheck(t, 2, "table") + for k,v in pairs(t) do + self[k] = v + end +end + +function AceAddon.prototype:init() + if not AceEvent then + error(MAJOR_VERSION .. " requires AceEvent-2.0", 4) + end + AceAddon.super.prototype.init(self) + + self.super = self.class.prototype + + AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED") + local names = {} + for i = 1, GetNumAddOns() do + if IsAddOnLoaded(i) then names[GetAddOnInfo(i)] = true end + end + self.possibleNames = names + table.insert(AceAddon.nextAddon, self) +end + +function AceAddon.prototype:ToString() + local x + if type(self.title) == "string" then + x = self.title + elseif type(self.name) == "string" then + x = self.name + else + x = "<" .. tostring(self.class) .. " instance>" + end + if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then + x = x .. " " .. STANDBY + end + return x +end + +AceAddon.new = function(self, ...) + local class = AceAddon:pcall(AceOO.Classpool, self, ...) + return class:new() +end + +function AceAddon:ManualEnable(addon) + AceAddon:argCheck(addon, 2, "table") + local first = nil + if AceOO.inherits(addon, "AceAddon-2.0") then + if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[addon] then + first = true + AceAddon.addonsEnabled[addon] = true + end + end + local current = addon.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedEnable) == "function" then + safecall(mixin.OnEmbedEnable, mixin, addon, first) + end + end + end + current = current.super + end + if type(addon.OnEnable) == "function" then + safecall(addon.OnEnable, addon, first) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonEnabled", addon, first) + end +end + +function AceAddon:ManualDisable(addon) + AceAddon:argCheck(addon, 2, "table") + local current = addon.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedDisable) == "function" then + safecall(mixin.OnEmbedDisable, mixin, addon) + end + end + end + current = current.super + end + if type(module.OnDisable) == "function" then + safecall(module.OnDisable, addon) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonDisabled", addon) + end +end + +local function external(self, major, instance) + if major == "AceEvent-2.0" then + AceEvent = instance + + AceEvent:embed(self) + + self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) + elseif major == "AceConsole-2.0" then + AceConsole = instance + + local slashCommands = { "/ace2" } + local _,_,_,enabled,loadable = GetAddOnInfo("Ace") + if not enabled or not loadable then + table.insert(slashCommands, "/ace") + end + local function listAddon(addon, depth) + if not depth then + depth = 0 + end + + local s = (" "):rep(depth) .. " - " .. tostring(addon) + if rawget(addon, 'version') then + s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r" + end + if rawget(addon, 'slashCommand') then + s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r" + end + print(s) + if type(rawget(addon, 'modules')) == "table" then + local i = 0 + for k,v in pairs(addon.modules) do + i = i + 1 + if i == 6 then + print((" "):rep(depth + 1) .. " - more...") + break + else + listAddon(v, depth + 1) + end + end + end + end + local function listNormalAddon(i) + local name,_,_,enabled,loadable = GetAddOnInfo(i) + if not loadable then + enabled = false + end + if self.addons[name] then + listAddon(self.addons[name]) + else + local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name) + local version = GetAddOnMetadata(i, "Version") + if version then + if version:find("%$Revision: (%d+) %$") then + version = version:gsub("%$Revision: (%d+) %$", "%1") + elseif version:find("%$Rev: (%d+) %$") then + version = version:gsub("%$Rev: (%d+) %$", "%1") + elseif version:find("%$LastChangedRevision: (%d+) %$") then + version = version:gsub("%$LastChangedRevision: (%d+) %$", "%1") + end + s = s .. " - |cffffff7f" .. version .. "|r" + end + if not enabled then + s = s .. " |cffff0000(disabled)|r" + end + if IsAddOnLoadOnDemand(i) then + s = s .. " |cff00ff00[LoD]|r" + end + print(s) + end + end + local function mySort(alpha, bravo) + return tostring(alpha) < tostring(bravo) + end + AceConsole.RegisterChatCommand(self, slashCommands, { + desc = "AddOn development framework", + name = "Ace2", + type = "group", + args = { + about = { + desc = "Get information about Ace2", + name = "About", + type = "execute", + func = function() + print("|cffffff7fAce2|r - |cffffff7f2.0." .. MINOR_VERSION:gsub("%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework") + print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team") + print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/") + end + }, + list = { + desc = "List addons", + name = "List", + type = "group", + args = { + ace2 = { + desc = "List addons using Ace2", + name = "Ace2", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + table.sort(self.addons, mySort) + for _,v in ipairs(self.addons) do + listAddon(v) + end + end + }, + all = { + desc = "List all addons", + name = "All", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + listNormalAddon(i) + end + end + }, + enabled = { + desc = "List all enabled addons", + name = "Enabled", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + local _,_,_,enabled,loadable = GetAddOnInfo(i) + if enabled and loadable then + listNormalAddon(i) + end + end + end + }, + disabled = { + desc = "List all disabled addons", + name = "Disabled", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + local _,_,_,enabled,loadable = GetAddOnInfo(i) + if not enabled or not loadable then + listNormalAddon(i) + end + end + end + }, + lod = { + desc = "List all LoadOnDemand addons", + name = "LoadOnDemand", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + if IsAddOnLoadOnDemand(i) then + listNormalAddon(i) + end + end + end + }, + ace1 = { + desc = "List all addons using Ace1", + name = "Ace 1.x", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) + if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then + listNormalAddon(i) + end + end + end + }, + libs = { + desc = "List all libraries using AceLibrary", + name = "Libraries", + type = "execute", + func = function() + if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then + print("|cffffff7fLibrary list:|r") + for name, data in pairs(AceLibrary.libs) do + local s + if data.minor then + s = " - " .. tostring(name) .. "." .. tostring(data.minor) + else + s = " - " .. tostring(name) + end + if rawget(AceLibrary(name), 'slashCommand') then + s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)" + end + print(s) + end + end + end + }, + search = { + desc = "Search by name", + name = "Search", + type = "text", + usage = "<keyword>", + input = true, + get = false, + set = function(...) + local arg = { ... } + for i,v in ipairs(arg) do + arg[i] = v:gsub('%*', '.*'):gsub('%%', '%%%%'):lower() + end + local count = GetNumAddOns() + for i = 1, count do + local name = GetAddOnInfo(i) + local good = true + for _,v in ipairs(arg) do + if not name:lower():find(v) then + good = false + break + end + end + if good then + listNormalAddon(i) + end + end + end + } + }, + }, + enable = { + desc = "Enable addon(s).", + name = "Enable", + type = "text", + usage = "<addon 1> <addon 2> ...", + get = false, + input = true, + set = function(...) + for i = 1, select("#", ...) do + local addon = select(i, ...) + local name, title, _, enabled, _, reason = GetAddOnInfo(addon) + if reason == "MISSING" then + print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) + elseif not enabled then + EnableAddOn(addon) + print(("|cffffff7fAce2:|r %s is now enabled."):format(addon or name)) + else + print(("|cffffff7fAce2:|r %s is already enabled."):format(addon or name)) + end + end + end, + }, + disable = { + desc = "Disable addon(s).", + name = "Disable", + type = "text", + usage = "<addon 1> <addon 2> ...", + get = false, + input = true, + set = function(...) + for i = 1, select("#", ...) do + local addon = select(i, ...) + local name, title, _, enabled, _, reason = GetAddOnInfo(addon) + if reason == "MISSING" then + print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) + elseif enabled then + DisableAddOn(addon) + print(("|cffffff7fAce2:|r %s is now disabled."):format(addon or name)) + else + print(("|cffffff7fAce2:|r %s is already disabled."):format(addon or name)) + end + end + end, + }, + load = { + desc = "Load addon(s).", + name = "Load", + type = "text", + usage = "<addon 1> <addon 2> ...", + get = false, + input = true, + set = function(...) + for i = 1, select("#", ...) do + local addon = select(i, ...) + local name, title, _, _, loadable, reason = GetAddOnInfo(addon) + if reason == "MISSING" then + print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) + elseif not loadable then + print(("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s."):format(addon, reason)) + else + LoadAddOn(addon) + print(("|cffffff7fAce2:|r %s is now loaded."):format(addon or name)) + end + end + end + }, + info = { + desc = "Display information", + name = "Information", + type = "execute", + func = function() + local mem, threshold = gcinfo() + print((" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r"):format(mem / 1024)) + if threshold then + print((" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r"):format(threshold / 1024)) + end + print((" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r"):format(GetFramerate())) + local bandwidthIn, bandwidthOut, latency = GetNetStats() + bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024) + print((" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r"):format(latency)) + print((" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r"):format(bandwidthIn)) + print((" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r"):format(bandwidthOut)) + print((" - |cffffff7fTotal addons [|r%d|cffffff7f]|r"):format(GetNumAddOns())) + print((" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r"):format(#self.addons)) + local ace = 0 + local enabled = 0 + local disabled = 0 + local lod = 0 + for i = 1, GetNumAddOns() do + local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) + if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then + ace = ace + 1 + end + if IsAddOnLoadOnDemand(i) then + lod = lod + 1 + end + local isActive, loadable = select(4, GetAddOnInfo(i)) + if not isActive or not loadable then + disabled = disabled + 1 + else + enabled = enabled + 1 + end + end + print((" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r"):format(ace)) + print((" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r"):format(lod)) + print((" - |cffffff7fenabled addons [|r%d|cffffff7f]|r"):format(enabled)) + print((" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r"):format(disabled)) + local libs = 0 + if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then + for _ in pairs(AceLibrary.libs) do + libs = libs + 1 + end + end + print((" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r"):format(libs)) + end + } + } + }) + elseif major == "AceModuleCore-2.0" then + AceModuleCore = instance + end +end + +local function activate(self, oldLib, oldDeactivate) + AceAddon = self + + self.playerLoginFired = oldLib and oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage + self.addonsToOnEnable = oldLib and oldLib.addonsToOnEnable + self.addons = oldLib and oldLib.addons or {} + self.nextAddon = oldLib and oldLib.nextAddon or {} + self.skipAddon = oldLib and oldLib.skipAddon or {} + self.addonsStarted = oldLib and oldLib.addonsStarted or {} + self.addonsEnabled = oldLib and oldLib.addonsEnabled or {} + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceAddon-2.0/AceAddon-2.0.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,12 @@ +## Interface: 20200 + +## Title: Lib: AceAddon-2.0 +## Notes: AddOn development framework +## Author: Ace Development Team +## LoadOnDemand: 1 +## X-Website: http://www.wowace.com +## X-Category: Library +## X-License: LGPL v2.1 + MIT for AceOO-2.0 +## Dependencies: AceLibrary, AceOO-2.0 + +AceAddon-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,1082 @@ +--[[ +Name: AceEvent-2.0 +Revision: $Rev: 49307 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceEvent-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0 +Description: Mixin to allow for event handling, scheduling, and inter-addon + communication. +Dependencies: AceLibrary, AceOO-2.0 +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceEvent-2.0" +local MINOR_VERSION = "$Revision: 49307 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end + +local AceOO = AceLibrary:GetInstance("AceOO-2.0") +local Mixin = AceOO.Mixin +local AceEvent = Mixin { + "RegisterEvent", + "RegisterAllEvents", + "UnregisterEvent", + "UnregisterAllEvents", + "TriggerEvent", + "ScheduleEvent", + "ScheduleRepeatingEvent", + "CancelScheduledEvent", + "CancelAllScheduledEvents", + "IsEventRegistered", + "IsEventScheduled", + "RegisterBucketEvent", + "UnregisterBucketEvent", + "UnregisterAllBucketEvents", + "IsBucketEventRegistered", + "ScheduleLeaveCombatAction", + "CancelAllCombatSchedules", +} + +local weakKey = {__mode="k"} + +local FAKE_NIL +local RATE + +local eventsWhichHappenOnce = { + PLAYER_LOGIN = true, + AceEvent_FullyInitialized = true, + VARIABLES_LOADED = true, + PLAYER_LOGOUT = true, +} +local next = next +local pairs = pairs +local pcall = pcall +local type = type +local GetTime = GetTime +local gcinfo = gcinfo +local unpack = unpack +local geterrorhandler = geterrorhandler + +local build = GetBuildInfo() +local useTablesAsIDs = build:find("^2%.0%.") or build:find("^2%.1%.") or build:find("^0%.1%.") + +local new, del +do + local cache = setmetatable({}, {__mode='k'}) + function new(...) + local t = next(cache) + if t then + cache[t] = nil + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + return t + else + return { ... } + end + end + function del(t) + for k in pairs(t) do + t[k] = nil + end + cache[t] = true + return nil + end +end + +local registeringFromAceEvent +--[[---------------------------------------------------------------------------------- +Notes: + * Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered. +Arguments: + string - name of the event to register + [optional] string or function - name of the method or function to call. Default: same name as "event". + [optional] boolean - whether to have method called only once. Default: false +------------------------------------------------------------------------------------]] +function AceEvent:RegisterEvent(event, method, once) + AceEvent:argCheck(event, 2, "string") + if self == AceEvent and not registeringFromAceEvent then + AceEvent:argCheck(method, 3, "function") + self = method + else + AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number") + if type(method) == "boolean" or type(method) == "number" then + AceEvent:argCheck(once, 4, "nil") + once, method = method, event + end + end + AceEvent:argCheck(once, 4, "number", "boolean", "nil") + if eventsWhichHappenOnce[event] then + once = true + end + local throttleRate + if type(once) == "number" then + throttleRate, once = once + end + if not method then + method = event + end + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) + else + assert(type(method) == "function" or type(method) == "string") + end + + local AceEvent_registry = AceEvent.registry + if not AceEvent_registry[event] then + AceEvent_registry[event] = new() + AceEvent.frame:RegisterEvent(event) + end + + local remember = true + if AceEvent_registry[event][self] then + remember = false + end + AceEvent_registry[event][self] = method + + local AceEvent_onceRegistry = AceEvent.onceRegistry + if once then + if not AceEvent_onceRegistry then + AceEvent.onceRegistry = {} + AceEvent_onceRegistry = AceEvent.onceRegistry + end + if not AceEvent_onceRegistry[event] then + AceEvent_onceRegistry[event] = new() + end + AceEvent_onceRegistry[event][self] = true + else + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then + AceEvent_onceRegistry[event][self] = nil + if not next(AceEvent_onceRegistry[event]) then + AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) + end + end + end + + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + if throttleRate then + if not AceEvent_throttleRegistry then + AceEvent.throttleRegistry = {} + AceEvent_throttleRegistry = AceEvent.throttleRegistry + end + if not AceEvent_throttleRegistry[event] then + AceEvent_throttleRegistry[event] = new() + end + if AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = nil + end + AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey) + local t = AceEvent_throttleRegistry[event][self] + t[RATE] = throttleRate + else + if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then + if AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = nil + end + if not next(AceEvent_throttleRegistry[event]) then + AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) + end + end + end + + if remember then + AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event) + end +end + +local ALL_EVENTS + +--[[---------------------------------------------------------------------------------- +Notes: + * Registers all events to the given method + * To access the current event, check AceEvent.currentEvent + * To access the current event's unique identifier, check AceEvent.currentEventUID + * This is only for debugging purposes. +Arguments: + [optional] string or function - name of the method or function to call. Default: same name as "event". +------------------------------------------------------------------------------------]] +function AceEvent:RegisterAllEvents(method) + if self == AceEvent then + AceEvent:argCheck(method, 1, "function") + self = method + else + AceEvent:argCheck(method, 1, "string", "function") + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register all events to method %q, it does not exist", method) + end + end + + local AceEvent_registry = AceEvent.registry + if not AceEvent_registry[ALL_EVENTS] then + AceEvent_registry[ALL_EVENTS] = new() + AceEvent.frame:RegisterAllEvents() + end + + local remember = not AceEvent_registry[ALL_EVENTS][self] + AceEvent_registry[ALL_EVENTS][self] = method + if remember then + AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all") + end +end + +--[[---------------------------------------------------------------------------------- +Notes: + * Trigger a custom AceEvent. + * This should never be called to simulate fake Blizzard events. + * Custom events should be in the form of AddonName_SpecificEvent +Arguments: + string - name of the event + tuple - list of arguments to pass along +------------------------------------------------------------------------------------]] +function AceEvent:TriggerEvent(event, ...) + if type(event) ~= "string" then + DEFAULT_CHAT_FRAME:AddMessage(debugstack()) + end + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then + return + end + local lastEvent = AceEvent.currentEvent + AceEvent.currentEvent = event + local lastEventUID = AceEvent.currentEventUID + local uid = AceEvent.UID_NUM + 1 + AceEvent.UID_NUM = uid + AceEvent.currentEventUID = uid + + local tmp = new() + + local AceEvent_onceRegistry = AceEvent.onceRegistry + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then + for obj, method in pairs(AceEvent_onceRegistry[event]) do + tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + AceEvent.UnregisterEvent(obj, event) + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + elseif method then -- function + local success, err = pcall(method, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + tmp[obj] = nil + obj = next(tmp) + end + end + + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] + if AceEvent_registry[event] then + for obj, method in pairs(AceEvent_registry[event]) do + tmp[obj] = method + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + local continue = false + if throttleTable and throttleTable[obj] then + local a1 = ... + if a1 == nil then + a1 = FAKE_NIL + end + if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then + throttleTable[obj][a1] = GetTime() + else + continue = true + end + end + if not continue then + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + elseif method then -- function + local success, err = pcall(method, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + end + tmp[obj] = nil + obj = next(tmp) + end + end + if AceEvent_registry[ALL_EVENTS] then + for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do + tmp[obj] = method + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + elseif method then -- function + local success, err = pcall(method, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + tmp[obj] = nil + obj = next(tmp) + end + end + tmp = del(tmp) + AceEvent.currentEvent = lastEvent + AceEvent.currentEventUID = lastEventUID +end + +local delayRegistry +local OnUpdate +do + local tmp = {} + OnUpdate = function() + local t = GetTime() + for k,v in pairs(delayRegistry) do + tmp[k] = true + end + for k in pairs(tmp) do + local v = delayRegistry[k] + if v then + local v_time = v.time + if not v_time then + delayRegistry[k] = nil + elseif v_time <= t then + local v_repeatDelay = v.repeatDelay + if v_repeatDelay then + -- use the event time, not the current time, else timing inaccuracies add up over time + v.time = v_time + v_repeatDelay + end + local event = v.event + if type(event) == "function" then + local uid = AceEvent.UID_NUM + 1 + AceEvent.UID_NUM = uid + AceEvent.currentEventUID = uid + local success, err = pcall(event, unpack(v, 1, v.n)) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + AceEvent.currentEventUID = nil + else + AceEvent:TriggerEvent(event, unpack(v, 1, v.n)) + end + if not v_repeatDelay then + local x = delayRegistry[k] + if x and x.time == v_time then -- check if it was manually reset + if not useTablesAsIDs or type(k) == "string" then + del(delayRegistry[k]) + end + delayRegistry[k] = nil + end + end + end + end + end + for k in pairs(tmp) do + tmp[k] = nil + end + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + end +end + +local function ScheduleEvent(self, repeating, event, delay, ...) + local id + if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then + if useTablesAsIDs and type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + id, event, delay = event, delay, ... + AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(delay, 4, "number") + self:CancelScheduledEvent(id) + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + if not delayRegistry then + AceEvent.delayRegistry = {} + delayRegistry = AceEvent.delayRegistry + AceEvent.frame:SetScript("OnUpdate", OnUpdate) + end + local t + if useTablesAsIDs and type(id) == "table" then + for k in pairs(id) do + id[k] = nil + end + t = id + for i = 2, select('#', ...) do + t[i-1] = select(i, ...) + end + t.n = select('#', ...) - 1 + elseif id then + t = new(select(2, ...)) + t.n = select('#', ...) - 1 + else + t = new(...) + t.n = select('#', ...) + end + t.event = event + t.time = GetTime() + delay + t.self = self + t.id = id or t + t.repeatDelay = repeating and delay + delayRegistry[t.id] = t + AceEvent.frame:Show() + if useTablesAsIDs then + return t.id + else + return + end +end + +--[[---------------------------------------------------------------------------------- +Notes: + * Schedule an event to fire. + * To fire on the next frame, specify a delay of 0. +Arguments: + string or function - name of the event to fire, or a function to call. + number - the amount of time to wait until calling. + tuple - a list of arguments to pass along. +------------------------------------------------------------------------------------]] +function AceEvent:ScheduleEvent(event, delay, ...) + if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then + if useTablesAsIDs and type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(..., 4, "number") + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + return ScheduleEvent(self, false, event, delay, ...) +end + +function AceEvent:ScheduleRepeatingEvent(event, delay, ...) + if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then + if useTablesAsIDs and type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(..., 4, "number") + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + return ScheduleEvent(self, true, event, delay, ...) +end + +function AceEvent:CancelScheduledEvent(t) + if useTablesAsIDs then + AceEvent:argCheck(t, 2, "string", "table") + else + AceEvent:argCheck(t, 2, "string") + end + if delayRegistry then + local v = delayRegistry[t] + if v then + if not useTablesAsIDs or type(t) == "string" then + del(delayRegistry[t]) + end + delayRegistry[t] = nil + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + return true + end + end + return false +end + +function AceEvent:IsEventScheduled(t) + if useTablesAsIDs then + AceEvent:argCheck(t, 2, "string", "table") + else + AceEvent:argCheck(t, 2, "string") + end + if delayRegistry then + local v = delayRegistry[t] + if v then + return true, v.time - GetTime() + end + end + return false, nil +end + +function AceEvent:UnregisterEvent(event) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if AceEvent_registry[event] and AceEvent_registry[event][self] then + AceEvent_registry[event][self] = nil + local AceEvent_onceRegistry = AceEvent.onceRegistry + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then + AceEvent_onceRegistry[event][self] = nil + if not next(AceEvent_onceRegistry[event]) then + AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) + end + end + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = nil + if not next(AceEvent_throttleRegistry[event]) then + AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) + end + end + if not next(AceEvent_registry[event]) then + AceEvent_registry[event] = del(AceEvent_registry[event]) + if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then + AceEvent.frame:UnregisterEvent(event) + end + end + else + if self == AceEvent then + error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2) + else + AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self) + end + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) +end + +function AceEvent:UnregisterAllEvents() + local AceEvent_registry = AceEvent.registry + if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then + AceEvent_registry[ALL_EVENTS][self] = nil + if not next(AceEvent_registry[ALL_EVENTS]) then + AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS]) + AceEvent.frame:UnregisterAllEvents() + for k,v in pairs(AceEvent_registry) do + AceEvent.frame:RegisterEvent(k) + end + end + end + if AceEvent_registry.AceEvent_EventUnregistered then + local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered + local x = data[self] + data[self] = nil + if x then + if not next(data) then + if not AceEvent_registry[ALL_EVENTS] then + AceEvent.frame:UnregisterEvent(event) + end + AceEvent_registry[event] = del(AceEvent_registry[event]) + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) + end + end + for event, data in pairs(AceEvent_registry) do + local x = data[self] + data[self] = nil + if x and event ~= ALL_EVENTS then + if not next(data) then + if not AceEvent_registry[ALL_EVENTS] then + AceEvent.frame:UnregisterEvent(event) + end + AceEvent_registry[event] = del(AceEvent_registry[event]) + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) + end + end + if AceEvent.onceRegistry then + for event, data in pairs(AceEvent.onceRegistry) do + data[self] = nil + end + end +end + +function AceEvent:CancelAllScheduledEvents() + if delayRegistry then + for k,v in pairs(delayRegistry) do + if v.self == self then + if not useTablesAsIDs or type(k) == "string" then + del(delayRegistry[k]) + end + delayRegistry[k] = nil + end + end + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + end +end + +function AceEvent:IsEventRegistered(event) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if self == AceEvent then + return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false + end + if AceEvent_registry[event] and AceEvent_registry[event][self] then + return true, AceEvent_registry[event][self] + end + if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then + return true, AceEvent_registry[ALL_EVENTS][self] + end + return false, nil +end + +local UnitExists = UnitExists +local bucketfunc +function AceEvent:RegisterBucketEvent(event, delay, method, ...) + AceEvent:argCheck(event, 2, "string", "table") + if type(event) == "table" then + for k,v in pairs(event) do + if type(k) ~= "number" then + AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.") + elseif type(v) ~= "string" then + AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.") + end + end + end + AceEvent:argCheck(delay, 3, "number") + if AceEvent == self then + AceEvent:argCheck(method, 4, "function") + self = method + else + if type(event) == "string" then + AceEvent:argCheck(method, 4, "string", "function", "nil") + if not method then + method = event + end + else + AceEvent:argCheck(method, 4, "string", "function") + end + + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) + end + end + local buckets = AceEvent.buckets + if not buckets[event] then + buckets[event] = new() + end + if not buckets[event][self] then + local t = new() + t.current = new() + t.self = self + buckets[event][self] = t + else + AceEvent.CancelScheduledEvent(self, buckets[event][self].id) + end + local bucket = buckets[event][self] + bucket.method = method + + local n = select('#', ...) + if n > 0 then + for i = 1, n do + bucket[i] = select(i, ...) + end + end + bucket.n = n + + local func = function(arg1) + bucket.run = true + if arg1 then + bucket.current[arg1] = true + end + end + buckets[event][self].func = func + local isUnitBucket = true + if type(event) == "string" then + AceEvent.RegisterEvent(self, event, func) + if not event:find("^UNIT_") then + isUnitBucket = false + end + else + for _,v in ipairs(event) do + AceEvent.RegisterEvent(self, v, func) + if isUnitBucket and not v:find("^UNIT_") then + isUnitBucket = false + end + end + end + bucket.unit = isUnitBucket + if not bucketfunc then + bucketfunc = function(bucket) + local current = bucket.current + local method = bucket.method + local self = bucket.self + if bucket.run then + if bucket.unit then + for unit in pairs(current) do + if not UnitExists(unit) then + current[unit] = nil + end + end + end + if type(method) == "string" then + self[method](self, current, unpack(bucket, 1, bucket.n)) + elseif method then -- function + method(current, unpack(bucket, 1, bucket.n)) + end + for k in pairs(current) do + current[k] = nil + k = nil + end + bucket.run = false + end + end + end + bucket.id = "AceEvent-Bucket-" .. tostring(bucket) + AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket) +end + +function AceEvent:IsBucketEventRegistered(event) + AceEvent:argCheck(event, 2, "string", "table") + return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self] +end + +function AceEvent:UnregisterBucketEvent(event) + AceEvent:argCheck(event, 2, "string", "table") + if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then + AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self) + end + + local bucket = AceEvent.buckets[event][self] + + if type(event) == "string" then + AceEvent.UnregisterEvent(self, event) + else + for _,v in ipairs(event) do + AceEvent.UnregisterEvent(self, v) + end + end + AceEvent:CancelScheduledEvent(bucket.id) + + bucket.current = del(bucket.current) + AceEvent.buckets[event][self] = del(bucket) + if not next(AceEvent.buckets[event]) then + AceEvent.buckets[event] = del(AceEvent.buckets[event]) + end +end + +function AceEvent:UnregisterAllBucketEvents() + if not AceEvent.buckets or not next(AceEvent.buckets) then + return + end + for k,v in pairs(AceEvent.buckets) do + if v == self then + AceEvent.UnregisterBucketEvent(self, k) + k = nil + end + end +end + +local combatSchedules +function AceEvent:CancelAllCombatSchedules() + local i = 0 + while true do + i = i + 1 + if not combatSchedules[i] then + break + end + local v = combatSchedules[i] + if v.self == self then + v = del(v) + table.remove(combatSchedules, i) + i = i - 1 + end + end +end + +local inCombat = false + +function AceEvent:PLAYER_REGEN_DISABLED() + inCombat = true +end + +do + local tmp = {} + function AceEvent:PLAYER_REGEN_ENABLED() + inCombat = false + for i, v in ipairs(combatSchedules) do + tmp[i] = v + combatSchedules[i] = nil + end + for i, v in ipairs(tmp) do + local func = v.func + if func then + local success, err = pcall(func, unpack(v, 1, v.n)) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + else + local obj = v.obj or v.self + local method = v.method + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, unpack(v, 1, v.n)) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + end + tmp[i] = del(v) + end + end +end + +function AceEvent:ScheduleLeaveCombatAction(method, ...) + local style = type(method) + if self == AceEvent then + if style == "table" then + local func = (...) + AceEvent:argCheck(func, 3, "string") + if type(method[func]) ~= "function" then + AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func) + end + else + AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table") + end + self = method + else + AceEvent:argCheck(method, 2, "function", "string", "table") + if style == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method) + elseif style == "table" then + local func = (...) + AceEvent:argCheck(func, 3, "string") + if type(method[func]) ~= "function" then + AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func) + end + end + end + + if not inCombat then + local success, err + if type(method) == "function" then + success, err = pcall(method, ...) + elseif type(method) == "table" then + local func = (...) + success, err = pcall(method[func], method, select(2, ...)) + else + success, err = pcall(self[method], self, ...) + end + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + return + end + local t + local n = select('#', ...) + if style == "table" then + t = new(select(2, ...)) + t.obj = method + t.method = (...) + t.n = n-1 + else + t = new(...) + t.n = n + if style == "function" then + t.func = method + else + t.method = method + end + end + t.self = self + table.insert(combatSchedules, t) +end + +function AceEvent:OnEmbedDisable(target) + self.UnregisterAllEvents(target) + + self.CancelAllScheduledEvents(target) + + self.UnregisterAllBucketEvents(target) + + self.CancelAllCombatSchedules(target) +end + +function AceEvent:IsFullyInitialized() + return self.postInit or false +end + +function AceEvent:IsPostPlayerLogin() + return IsLoggedIn() and true or false +end + +local function activate(self, oldLib, oldDeactivate) + AceEvent = self + + self.onceRegistry = oldLib and oldLib.onceRegistry or {} + self.throttleRegistry = oldLib and oldLib.throttleRegistry or {} + self.delayRegistry = oldLib and oldLib.delayRegistry or {} + self.buckets = oldLib and oldLib.buckets or {} + self.registry = oldLib and oldLib.registry or {} + self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame") + self.playerLogin = IsLoggedIn() and true + self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true + self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy() + self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy() + self.RATE = oldLib and oldLib.RATE or _G.newproxy() + self.combatSchedules = oldLib and oldLib.combatSchedules or {} + self.UID_NUM = oldLib and oldLib.UID_NUM or 0 + + -- Delete this down the road. Makes sure that the addonframes from revisions 33121 - 36174 get their events unregistered. + local addonframes = oldLib and oldLib.addonframes + if addonframes then + for _, v in pairs(addonframes) do + v:UnregisterAllEvents() + end + end + + combatSchedules = self.combatSchedules + ALL_EVENTS = self.ALL_EVENTS + FAKE_NIL = self.FAKE_NIL + RATE = self.RATE + local inPlw = false + local blacklist = { + UNIT_INVENTORY_CHANGED = true, + BAG_UPDATE = true, + ITEM_LOCK_CHANGED = true, + ACTIONBAR_SLOT_CHANGED = true, + } + self.frame:SetScript("OnEvent", function(_, event, ...) + if event == "PLAYER_ENTERING_WORLD" then + inPlw = false + elseif event == "PLAYER_LEAVING_WORLD" then + inPlw = true + end + if event and (not inPlw or not blacklist[event]) then + self:TriggerEvent(event, ...) + end + end) + if self.delayRegistry then + delayRegistry = self.delayRegistry + self.frame:SetScript("OnUpdate", OnUpdate) + end + + self:UnregisterAllEvents() + self:CancelAllScheduledEvents() + + registeringFromAceEvent = true + self:RegisterEvent("LOOT_OPENED", function() + SendAddonMessage("LOOT_OPENED", "", "RAID") + end) + registeringFromAceEvent = nil + + local function handleFullInit() + if not self.postInit then + local function func() + self.postInit = true + self:TriggerEvent("AceEvent_FullyInitialized") + if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then + self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") + end + if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then + self:UnregisterEvent("MEETINGSTONE_CHANGED") + end + if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then + self:UnregisterEvent("MINIMAP_ZONE_CHANGED") + end + if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then + self:UnregisterEvent("LANGUAGE_LIST_CHANGED") + end + collectgarbage('collect') + end + registeringFromAceEvent = true + local f = function() + self.playerLogin = true + self:ScheduleEvent("AceEvent_FullyInitialized", func, 1) + end + self:RegisterEvent("MEETINGSTONE_CHANGED", f, true) + self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function() + self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15) + end) + self:RegisterEvent("LANGUAGE_LIST_CHANGED", function() + if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then + registeringFromAceEvent = true + self:UnregisterEvent("MEETINGSTONE_CHANGED") + self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true) + registeringFromAceEvent = nil + end + end) + self:ScheduleEvent("AceEvent_FullyInitialized", func, 10) + registeringFromAceEvent = nil + end + end + + if not self.playerLogin then + registeringFromAceEvent = true + self:RegisterEvent("PLAYER_LOGIN", function() + self.playerLogin = true + handleFullInit() + handleFullInit = nil + collectgarbage('collect') + end, true) + registeringFromAceEvent = nil + else + handleFullInit() + handleFullInit = nil + end + + if not AceEvent20EditBox then + CreateFrame("Editbox", "AceEvent20EditBox") + end + local editbox = AceEvent20EditBox + function editbox:Execute(line) + local defaulteditbox = DEFAULT_CHAT_FRAME.editBox + self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType")) + self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget")) + self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget")) + self:SetText(line) + ChatEdit_SendText(self) + end + editbox:Hide() + _G["SLASH_IN1"] = "/in" + SlashCmdList["IN"] = function(msg) + local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$") + seconds = tonumber(seconds) + if not seconds then + DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'") + return + end + if IsSecureCmd(command) then + DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command)) + return + end + self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest) + end + registeringFromAceEvent = true + self:RegisterEvent("PLAYER_REGEN_ENABLED") + self:RegisterEvent("PLAYER_REGEN_DISABLED") + inCombat = InCombatLockdown() + registeringFromAceEvent = nil + + -- another hack to make sure that we clean up properly from rev 33121 - 36174 + if self.registry[ALL_EVENTS] then + self.frame:RegisterAllEvents() + else + for event in pairs(self.registry) do + self.frame:RegisterEvent(event) + end + end + + self:activate(oldLib, oldDeactivate) + if oldLib then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,12 @@ +## Interface: 20200 + +## Title: Lib: AceEvent-2.0 +## Notes: AddOn development framework +## Author: Ace Development Team +## LoadOnDemand: 1 +## X-Website: http://www.wowace.com +## X-Category: Library +## X-License: LGPL v2.1 + MIT for AceOO-2.0 +## Dependencies: AceLibrary, AceOO-2.0 + +AceEvent-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,856 @@ +--[[ +Name: AceLibrary +Revision: $Rev: 49421 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Iriel (iriel@vigilance-committee.org) + Tekkub (tekkub@gmail.com) + Revision: $Rev: 49421 $ +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceLibrary +SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary +Description: Versioning library to handle other library instances, upgrading, + and proper access. + It also provides a base for libraries to work off of, providing + proper error tools. It is handy because all the errors occur in the + file that called it, not in the library file itself. +Dependencies: None +License: LGPL v2.1 +]] + +local ACELIBRARY_MAJOR = "AceLibrary" +local ACELIBRARY_MINOR = "$Revision: 49421 $" + +local _G = getfenv(0) +local previous = _G[ACELIBRARY_MAJOR] +if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end + +do + -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info + -- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke + local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! + local LibStub = _G[LIBSTUB_MAJOR] + + if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) + end +end +local LibStub = _G.LibStub + +-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but +-- disabled in the addon screen, set this to true. +local DONT_ENABLE_LIBRARIES = nil + +local function safecall(func,...) + local success, err = pcall(func,...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end +end + +local WoW22 = false +if type(GetBuildInfo) == "function" then + local success, buildinfo = pcall(GetBuildInfo) + if success and type(buildinfo) == "string" then + local num = tonumber(buildinfo:match("^(%d+%.%d+)")) + if num and num >= 2.2 then + WoW22 = true + end + end +end + +-- @table AceLibrary +-- @brief System to handle all versioning of libraries. +local AceLibrary = {} +local AceLibrary_mt = {} +setmetatable(AceLibrary, AceLibrary_mt) + +local function error(self, message, ...) + if type(self) ~= "table" then + return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2) + end + + local stack = debugstack() + if not message then + local second = stack:match("\n(.-)\n") + message = "error raised! " .. second + else + local arg = { ... } -- not worried about table creation, as errors don't happen often + + for i = 1, #arg do + arg[i] = tostring(arg[i]) + end + for i = 1, 10 do + table.insert(arg, "nil") + end + message = message:format(unpack(arg)) + end + + if getmetatable(self) and getmetatable(self).__tostring then + message = ("%s: %s"):format(tostring(self), message) + elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then + message = ("%s: %s"):format(self:GetLibraryVersion(), message) + elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then + message = ("%s: %s"):format(self.class:GetLibraryVersion(), message) + end + + local first = stack:gsub("\n.*", "") + local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1") + file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + + + local i = 0 + for s in stack:gmatch("\n([^\n]*)") do + i = i + 1 + if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then + file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1") + file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + break + end + end + local j = 0 + for s in stack:gmatch("\n([^\n]*)") do + j = j + 1 + if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then + return _G.error(message, j+1) + end + end + return _G.error(message, 2) +end + +local assert +if not WoW22 then + function assert(self, condition, message, ...) + if not condition then + if not message then + local stack = debugstack() + local second = stack:match("\n(.-)\n") + message = "assertion failed! " .. second + end + return error(self, message, ...) + end + return condition + end +end + +local type = type +local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5) + if type(num) ~= "number" then + return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num)) + elseif type(kind) ~= "string" then + return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) + end + arg = type(arg) + if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then + local stack = debugstack() + local func = stack:match("`argCheck'.-([`<].-['>])") + if not func then + func = stack:match("([`<].-['>])") + end + if kind5 then + return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg) + elseif kind4 then + return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg) + elseif kind3 then + return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg) + elseif kind2 then + return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg) + else + return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg) + end + end +end + +local pcall +do + local function check(self, ret, ...) + if not ret then + local s = ... + return error(self, (s:gsub(".-%.lua:%d-: ", ""))) + else + return ... + end + end + + function pcall(self, func, ...) + return check(self, _G.pcall(func, ...)) + end +end + +local recurse = {} +local function addToPositions(t, major) + if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then + rawset(t, recurse, true) + AceLibrary.positions[t] = major + for k,v in pairs(t) do + if type(v) == "table" and not rawget(v, recurse) then + addToPositions(v, major) + end + if type(k) == "table" and not rawget(k, recurse) then + addToPositions(k, major) + end + end + local mt = getmetatable(t) + if mt and not rawget(mt, recurse) then + addToPositions(mt, major) + end + rawset(t, recurse, nil) + end +end + +local function svnRevisionToNumber(text) + local kind = type(text) + if kind == "number" or tonumber(text) then + return tonumber(text) + elseif kind == "string" then + if text:find("^%$Revision: (%d+) %$$") then + return tonumber((text:match("^%$Revision: (%d+) %$$"))) + elseif text:find("^%$Rev: (%d+) %$$") then + return tonumber((text:match("^%$Rev: (%d+) %$$"))) + elseif text:find("^%$LastChangedRevision: (%d+) %$$") then + return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$"))) + end + end + return nil +end + +local crawlReplace +do + local recurse = {} + local function func(t, to, from) + if recurse[t] then + return + end + recurse[t] = true + local mt = getmetatable(t) + setmetatable(t, nil) + rawset(t, to, rawget(t, from)) + rawset(t, from, nil) + for k,v in pairs(t) do + if v == from then + t[k] = to + elseif type(v) == "table" then + if not recurse[v] then + func(v, to, from) + end + end + + if type(k) == "table" then + if not recurse[k] then + func(k, to, from) + end + end + end + setmetatable(t, mt) + if mt then + if mt == from then + setmetatable(t, to) + elseif not recurse[mt] then + func(mt, to, from) + end + end + end + function crawlReplace(t, to, from) + func(t, to, from) + for k in pairs(recurse) do + recurse[k] = nil + end + end +end + +-- @function destroyTable +-- @brief remove all the contents of a table +-- @param t table to destroy +local function destroyTable(t) + setmetatable(t, nil) + for k,v in pairs(t) do + t[k] = nil + end +end + +local function isFrame(frame) + return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function" +end + +-- @function copyTable +-- @brief Create a shallow copy of a table and return it. +-- @param from The table to copy from +-- @return A shallow copy of the table +local function copyTable(from, to) + if not to then + to = {} + end + for k,v in pairs(from) do + to[k] = v + end + setmetatable(to, getmetatable(from)) + return to +end + +-- @function deepTransfer +-- @brief Fully transfer all data, keeping proper previous table +-- backreferences stable. +-- @param to The table with which data is to be injected into +-- @param from The table whose data will be injected into the first +-- @param saveFields If available, a shallow copy of the basic data is saved +-- in here. +-- @param list The account of table references +-- @param list2 The current status on which tables have been traversed. +local deepTransfer +do + -- @function examine + -- @brief Take account of all the table references to be shared + -- between the to and from tables. + -- @param to The table with which data is to be injected into + -- @param from The table whose data will be injected into the first + -- @param list An account of the table references + local function examine(to, from, list, major) + list[from] = to + for k,v in pairs(from) do + if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then + if from[k] == to[k] then + list[from[k]] = to[k] + elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then + list[from[k]] = from[k] + elseif not list[from[k]] then + examine(to[k], from[k], list, major) + end + end + end + return list + end + + function deepTransfer(to, from, saveFields, major, list, list2) + setmetatable(to, nil) + if not list then + list = {} + list2 = {} + examine(to, from, list, major) + end + list2[to] = to + for k,v in pairs(to) do + if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then + if saveFields then + saveFields[k] = v + end + to[k] = nil + elseif v ~= _G then + if saveFields then + saveFields[k] = copyTable(v) + end + end + end + for k in pairs(from) do + if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then + if not list2[to[k]] then + deepTransfer(to[k], from[k], nil, major, list, list2) + end + to[k] = list[to[k]] or list2[to[k]] + else + rawset(to, k, from[k]) + end + end + setmetatable(to, getmetatable(from)) + local mt = getmetatable(to) + if mt then + if list[mt] then + setmetatable(to, list[mt]) + elseif mt.__index and list[mt.__index] then + mt.__index = list[mt.__index] + end + end + destroyTable(from) + end +end + +local function TryToEnable(addon) + if DONT_ENABLE_LIBRARIES then return end + local isondemand = IsAddOnLoadOnDemand(addon) + if isondemand then + local _, _, _, enabled = GetAddOnInfo(addon) + EnableAddOn(addon) + local _, _, _, _, loadable = GetAddOnInfo(addon) + if not loadable and not enabled then + DisableAddOn(addon) + end + + return loadable + end +end + +-- @method TryToLoadStandalone +-- @brief Attempt to find and load a standalone version of the requested library +-- @param major A string representing the major version +-- @return If library is found and loaded, true is return. If not loadable, false is returned. +-- If the library has been requested previously, nil is returned. +local function TryToLoadStandalone(major) + if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end + if AceLibrary.scannedlibs[major] then return end + + AceLibrary.scannedlibs[major] = true + + local name, _, _, enabled, loadable = GetAddOnInfo(major) + + loadable = (enabled and loadable) or TryToEnable(name) + + local loaded = false + if loadable then + loaded = true + LoadAddOn(name) + end + + local field = "X-AceLibrary-" .. major + for i = 1, GetNumAddOns() do + if GetAddOnMetadata(i, field) then + name, _, _, enabled, loadable = GetAddOnInfo(i) + + loadable = (enabled and loadable) or TryToEnable(name) + if loadable then + loaded = true + LoadAddOn(name) + end + end + end + return loaded +end + +-- @method IsNewVersion +-- @brief Obtain whether the supplied version would be an upgrade to the +-- current version. This allows for bypass code in library +-- declaration. +-- @param major A string representing the major version +-- @param minor An integer or an svn revision string representing the minor version +-- @return whether the supplied version would be newer than what is +-- currently available. +function AceLibrary:IsNewVersion(major, minor) + argCheck(self, major, 2, "string") + TryToLoadStandalone(major) + + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 3, "number") + local lib, oldMinor = LibStub:GetLibrary(major, true) + if lib then + return oldMinor < minor + end + local data = self.libs[major] + if not data then + return true + end + return data.minor < minor +end + +-- @method HasInstance +-- @brief Returns whether an instance exists. This allows for optional support of a library. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return Whether an instance exists. +function AceLibrary:HasInstance(major, minor) + argCheck(self, major, 2, "string") + if minor ~= false then + TryToLoadStandalone(major) + end + + local lib, ver = LibStub:GetLibrary(major, true) + if not lib and self.libs[major] then + lib, ver = self.libs[major].instance, self.libs[major].minor + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 3, "number") + if not lib then + return false + end + return ver == minor + end + return not not lib +end + +-- @method GetInstance +-- @brief Returns the library with the given major/minor version. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return The library with the given major/minor version. +function AceLibrary:GetInstance(major, minor) + argCheck(self, major, 2, "string") + if minor ~= false then + TryToLoadStandalone(major) + end + + local data, ver = LibStub:GetLibrary(major, true) + if not data then + if self.libs[major] then + data, ver = self.libs[major].instance, self.libs[major].minor + else + _G.error(("Cannot find a library instance of %s."):format(major), 2) + return + end + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 2, "number") + if ver ~= minor then + _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2) + end + end + return data +end + +-- Syntax sugar. AceLibrary("FooBar-1.0") +AceLibrary_mt.__call = AceLibrary.GetInstance + +local donothing = function() end + +local AceEvent + +local tmp = {} + +-- @method Register +-- @brief Registers a new version of a given library. +-- @param newInstance the library to register +-- @param major the major version of the library +-- @param minor the minor version of the library +-- @param activateFunc (optional) A function to be called when the library is +-- fully activated. Takes the arguments +-- (newInstance [, oldInstance, oldDeactivateFunc]). If +-- oldInstance is given, you should probably call +-- oldDeactivateFunc(oldInstance). +-- @param deactivateFunc (optional) A function to be called by a newer library's +-- activateFunc. +-- @param externalFunc (optional) A function to be called whenever a new +-- library is registered. +function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc) + argCheck(self, newInstance, 2, "table") + argCheck(self, major, 3, "string") + if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == newInstance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end + if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then + _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) + end + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 4, "number") + if math.floor(minor) ~= minor or minor < 0 then + error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) + end + argCheck(self, activateFunc, 5, "function", "nil") + argCheck(self, deactivateFunc, 6, "function", "nil") + argCheck(self, externalFunc, 7, "function", "nil") + if not deactivateFunc then + deactivateFunc = donothing + end + local data = self.libs[major] + if not data then + -- This is new + if LibStub:GetLibrary(major, true) then + error(self, "Cannot register library %q. It is already registered with LibStub.", major) + end + local instance = LibStub:NewLibrary(major, minor) + copyTable(newInstance, instance) + crawlReplace(instance, instance, newInstance) + destroyTable(newInstance) + if AceLibrary == newInstance then + self = instance + AceLibrary = instance + end + self.libs[major] = { + instance = instance, + minor = minor, + deactivateFunc = deactivateFunc, + externalFunc = externalFunc, + } + rawset(instance, 'GetLibraryVersion', function(self) + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not WoW22 and not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + addToPositions(instance, major) + if activateFunc then + safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil + +--[[ if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == instance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end]] + end + + if externalFunc then + for k, data_instance in LibStub:IterateLibraries() do -- all libraries + tmp[k] = data_instance + end + for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub + tmp[k] = data.instance + end + for k, data_instance in pairs(tmp) do + if k ~= major then + safecall(externalFunc, instance, k, data_instance) + end + tmp[k] = nil + end + end + + for k,data in pairs(self.libs) do -- only Ace libraries + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end + if major == "AceEvent-2.0" then + AceEvent = instance + end + if AceEvent then + AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance) + end + + return instance + end + if minor <= data.minor then + -- This one is already obsolete, raise an error. + _G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2) + return + end + local instance = data.instance + -- This is an update + local oldInstance = {} + + local libStubInstance = LibStub:GetLibrary(major, true) + if not libStubInstance then -- non-LibStub AceLibrary registered the library + -- pass + elseif libStubInstance ~= instance then + error(self, "Cannot register library %q. It is already registered with LibStub.", major) + else + LibStub:NewLibrary(major, minor) -- upgrade the minor version + end + + addToPositions(newInstance, major) + local isAceLibrary = (AceLibrary == newInstance) + local old_error, old_assert, old_argCheck, old_pcall + if isAceLibrary then + self = instance + AceLibrary = instance + + old_error = instance.error + if not WoW22 then + old_assert = instance.assert + end + old_argCheck = instance.argCheck + old_pcall = instance.pcall + + self.error = error + if not WoW22 then + self.assert = assert + end + self.argCheck = argCheck + self.pcall = pcall + end + deepTransfer(instance, newInstance, oldInstance, major) + crawlReplace(instance, instance, newInstance) + local oldDeactivateFunc = data.deactivateFunc + data.minor = minor + data.deactivateFunc = deactivateFunc + data.externalFunc = externalFunc + rawset(instance, 'GetLibraryVersion', function() + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not WoW22 and not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + if isAceLibrary then + for _,v in pairs(self.libs) do + local i = type(v) == "table" and v.instance + if type(i) == "table" then + if not rawget(i, 'error') or i.error == old_error then + rawset(i, 'error', error) + end + if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then + rawset(i, 'assert', assert) + end + if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then + rawset(i, 'argCheck', argCheck) + end + if not rawget(i, 'pcall') or i.pcall == old_pcall then + rawset(i, 'pcall', pcall) + end + end + end + end + if activateFunc then + safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) + +--[[ if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == instance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end]] + else + safecall(oldDeactivateFunc, oldInstance) + end + oldInstance = nil + + if externalFunc then + for k, data_instance in LibStub:IterateLibraries() do -- all libraries + tmp[k] = data_instance + end + for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub + tmp[k] = data.instance + end + for k, data_instance in pairs(tmp) do + if k ~= major then + safecall(externalFunc, instance, k, data_instance) + end + tmp[k] = nil + end + end + + return instance +end + +function AceLibrary:IterateLibraries() + local t = {} + for major, instance in LibStub:IterateLibraries() do + t[major] = instance + end + for major, data in pairs(self.libs) do + t[major] = data.instance + end + return pairs(t) +end + +local function manuallyFinalize(major, instance) + if AceLibrary.libs[major] then + -- don't work on Ace libraries + return + end + local finalizedExternalLibs = AceLibrary.finalizedExternalLibs + if finalizedExternalLibs[major] then + return + end + finalizedExternalLibs[major] = true + + for k,data in pairs(AceLibrary.libs) do -- only Ace libraries + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end +end + +-- @function Activate +-- @brief The activateFunc for AceLibrary itself. Called when +-- AceLibrary properly registers. +-- @param self Reference to AceLibrary +-- @param oldLib (optional) Reference to an old version of AceLibrary +-- @param oldDeactivate (optional) Function to deactivate the old lib +local function activate(self, oldLib, oldDeactivate) + AceLibrary = self + if not self.libs then + self.libs = oldLib and oldLib.libs or {} + self.scannedlibs = oldLib and oldLib.scannedlibs or {} + end + if not self.positions then + self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" }) + end + self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {} + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("ADDON_LOADED") + self.frame:SetScript("OnEvent", function() + for major, instance in LibStub:IterateLibraries() do + manuallyFinalize(major, instance) + end + end) + for major, instance in LibStub:IterateLibraries() do + manuallyFinalize(major, instance) + end + + -- Expose the library in the global environment + _G[ACELIBRARY_MAJOR] = self + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +if not previous then + previous = AceLibrary +end +if not previous.libs then + previous.libs = {} +end +AceLibrary.libs = previous.libs +if not previous.positions then + previous.positions = setmetatable({}, { __mode = "k" }) +end +AceLibrary.positions = previous.positions +AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceLibrary/AceLibrary.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,10 @@ +## Interface: 20200 + +## Title: Lib: AceLibrary +## Notes: AddOn development framework +## Author: Ace Development Team +## X-Website: http://www.wowace.com +## X-Category: Library +## X-License: LGPL v2.1 + MIT for AceOO-2.0 + +AceLibrary.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceOO-2.0/AceOO-2.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,980 @@ +--[[ +Name: AceOO-2.0 +Revision: $Rev: 38641 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceOO-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0 +Description: Library to provide an object-orientation framework. +Dependencies: AceLibrary +License: MIT +]] + +local MAJOR_VERSION = "AceOO-2.0" +local MINOR_VERSION = "$Revision: 38641 $" + +-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local AceOO = { + error = AceLibrary.error, + argCheck = AceLibrary.argCheck +} + +-- @function getuid +-- @brief Obtain a unique string identifier for the object in question. +-- @param t The object to obtain the uid for. +-- @return The uid string. +local function getuid(t) + local mt = getmetatable(t) + setmetatable(t, nil) + local str = tostring(t) + setmetatable(t, mt) + local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$") + if cap then + return ("0"):rep(8 - #cap) .. cap + end +end + +local function getlibrary(o) + if type(o) == "table" then + return o + elseif type(o) == "string" then + if not AceLibrary:HasInstance(o) then + AceOO:error("Library %q does not exist.", o) + end + return AceLibrary(o) + end +end + +local function deeprawget(self, k) + while true do + local v = rawget(self, k) + if v ~= nil then + return v + end + local mt = getmetatable(self) + if not mt or type(mt.__index) ~= "table" then + return nil + end + self = mt.__index + end +end + +-- @function Factory +-- @brief Construct a factory for the creation of objects. +-- @param obj The object whose init method will be called on the new factory +-- object. +-- @param newobj The object whose init method will be called on the new +-- objects that the Factory creates, to initialize them. +-- @param (...) Arguments which will be passed to obj.init() in addition +-- to the Factory object. +-- @return The new factory which creates a newobj when its new method is called, +-- or when it is called directly (__call metamethod). +local Factory +do + local function getlibraries(...) + if select('#', ...) == 0 then + return + end + return getlibrary((select(1, ...))), getlibraries(select(2, ...)) + end + local arg = {} + local function new(obj, ...) + local t = {} + local uid = getuid(t) + obj:init(t, getlibraries(...)) + t.uid = uid + return t + end + + local function createnew(self, ...) + local o = self.prototype + local x = new(o, getlibraries(...)) + return x + end + + function Factory(obj, newobj, ...) + local t = new(obj, ...) + t.prototype = newobj + t.new = createnew + getmetatable(t).__call = t.new + return t + end +end + + +local function objtostring(self) + if self.ToString then + return self:ToString() + elseif self.GetLibraryVersion then + return (self:GetLibraryVersion()) + elseif self.super then + local s = "Sub-" .. tostring(self.super) + local first = true + if self.interfaces then + for interface in pairs(self.interfaces) do + if first then + s = s .. "(" .. tostring(interface) + first = false + else + s = s .. ", " .. tostring(interface) + end + end + end + if self.mixins then + for mixin in pairs(self.mixins) do + if first then + s = s .. tostring(mixin) + first = false + else + s = s .. ", " .. tostring(mixin) + end + end + end + if first then + if self.uid then + return s .. ":" .. self.uid + else + return s + end + else + return s .. ")" + end + else + return self.uid and 'Subclass:' .. self.uid or 'Subclass' + end +end + +-- @table Object +-- @brief Base of all objects, including Class. +-- +-- @method init +-- @brief Initialize a new object. +-- @param newobject The object to initialize +-- @param class The class to make newobject inherit from +local Object +do + Object = {} + function Object:init(newobject, class) + local parent = class or self + if not rawget(newobject, 'uid') then + newobject.uid = getuid(newobject) + end + local mt = { + __index = parent, + __tostring = objtostring, + } + setmetatable(newobject, mt) + end + Object.uid = getuid(Object) + setmetatable(Object, { __tostring = function() return 'Object' end }) +end + +local Interface + +local function validateInterface(object, interface) + if not object.class and object.prototype then + object = object.prototype + end + for k,v in pairs(interface.interface) do + if tostring(type(object[k])) ~= v then + return false + end + end + if interface.superinterfaces then + for superinterface in pairs(interface.superinterfaces) do + if not validateInterface(object, superinterface) then + return false + end + end + end + if type(object.class) == "table" and rawequal(object.class.prototype, object) then + if not object.class.interfaces then + rawset(object.class, 'interfaces', {}) + end + object.class.interfaces[interface] = true + elseif type(object.class) == "table" and type(object.class.prototype) == "table" then + validateInterface(object.class.prototype, interface) + -- check if class is proper, thus preventing future checks. + end + return true +end + +-- @function inherits +-- @brief Return whether an Object or Class inherits from a given +-- parent. +-- @param object Object or Class to check +-- @param parent Parent to test inheritance from +-- @return whether an Object or Class inherits from a given +-- parent. +local function inherits(object, parent) + object = getlibrary(object) + if type(parent) == "string" then + if not AceLibrary:HasInstance(parent) then + return false + else + parent = AceLibrary(parent) + end + end + AceOO:argCheck(parent, 2, "table") + if type(object) ~= "table" then + return false + end + local current + local class = deeprawget(object, 'class') + if class then + current = class + else + current = object + end + if type(current) ~= "table" then + return false + end + if rawequal(current, parent) then + return true + end + if parent.class then + while true do + if rawequal(current, Object) then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if rawequal(mixin, parent) then + return true + end + end + end + if current.interfaces then + for interface in pairs(current.interfaces) do + if rawequal(interface, parent) then + return true + end + end + end + current = deeprawget(current, 'super') + if type(current) ~= "table" then + break + end + end + + local isInterface = false + local curr = parent.class + while true do + if rawequal(curr, Object) then + break + elseif rawequal(curr, Interface) then + isInterface = true + break + end + curr = deeprawget(curr, 'super') + if type(curr) ~= "table" then + break + end + end + return isInterface and validateInterface(object, parent) + else + while true do + if rawequal(current, parent) then + return true + elseif rawequal(current, Object) then + return false + end + current = deeprawget(current, 'super') + if type(current) ~= "table" then + return false + end + end + end +end + +-- @table Class +-- @brief An object factory which sets up inheritence and supports +-- 'mixins'. +-- +-- @metamethod Class call +-- @brief Call ClassFactory:new() to create a new class. +-- +-- @method Class new +-- @brief Construct a new object. +-- @param (...) Arguments to pass to the object init function. +-- @return The new object. +-- +-- @method Class init +-- @brief Initialize a new class. +-- @param parent Superclass. +-- @param (...) Mixins. +-- +-- @method Class ToString +-- @return A string representing the object, in this case 'Class'. +local initStatus +local Class +local Mixin +local autoEmbed = false +local function traverseInterfaces(bit, total) + if bit.superinterfaces then + for interface in pairs(bit.superinterfaces) do + if not total[interface] then + total[interface] = true + traverseInterfaces(interface, total) + end + end + end +end +local class_new +do + Class = Factory(Object, setmetatable({}, {__index = Object}), Object) + Class.super = Object + + local function protostring(t) + return '<' .. tostring(t.class) .. ' prototype>' + end + local function classobjectstring(t) + if t.ToString then + return t:ToString() + elseif t.GetLibraryVersion then + return (t:GetLibraryVersion()) + else + return '<' .. tostring(t.class) .. ' instance>' + end + end + local function classobjectequal(self, other) + if type(self) == "table" and self.Equals then + return self:Equals(other) + elseif type(other) == "table" and other.Equals then + return other:Equals(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) == 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) == 0 + else + return rawequal(self, other) + end + end + local function classobjectlessthan(self, other) + if type(self) == "table" and self.IsLessThan then + return self:IsLessThan(other) + elseif type(other) == "table" and other.IsLessThanOrEqualTo then + return not other:IsLessThanOrEqualTo(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) < 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) > 0 + elseif type(other) == "table" and other.IsLessThan and other.Equals then + return other:Equals(self) or other:IsLessThan(self) + else + AceOO:error("cannot compare two objects") + end + end + local function classobjectlessthanequal(self, other) + if type(self) == "table" and self.IsLessThanOrEqualTo then + return self:IsLessThanOrEqualTo(other) + elseif type(other) == "table" and other.IsLessThan then + return not other:IsLessThan(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) <= 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) >= 0 + elseif type(self) == "table" and self.IsLessThan and self.Equals then + return self:Equals(other) or self:IsLessThan(other) + else + AceOO:error("cannot compare two incompatible objects") + end + end + local function classobjectadd(self, other) + if type(self) == "table" and self.Add then + return self:Add(other) + else + AceOO:error("cannot add two incompatible objects") + end + end + local function classobjectsub(self, other) + if type(self) == "table" and self.Subtract then + return self:Subtract(other) + else + AceOO:error("cannot subtract two incompatible objects") + end + end + local function classobjectunm(self, other) + if type(self) == "table" and self.UnaryNegation then + return self:UnaryNegation(other) + else + AceOO:error("attempt to negate an incompatible object") + end + end + local function classobjectmul(self, other) + if type(self) == "table" and self.Multiply then + return self:Multiply(other) + else + AceOO:error("cannot multiply two incompatible objects") + end + end + local function classobjectdiv(self, other) + if type(self) == "table" and self.Divide then + return self:Divide(other) + else + AceOO:error("cannot divide two incompatible objects") + end + end + local function classobjectpow(self, other) + if type(self) == "table" and self.Exponent then + return self:Exponent(other) + else + AceOO:error("cannot exponentiate two incompatible objects") + end + end + local function classobjectconcat(self, other) + if type(self) == "table" and self.Concatenate then + return self:Concatenate(other) + else + AceOO:error("cannot concatenate two incompatible objects") + end + end + function class_new(self, ...) + if self.virtual then + AceOO:error("Cannot instantiate a virtual class.") + end + + local o = self.prototype + local newobj = {} + if o.class and o.class.instancemeta then + setmetatable(newobj, o.class.instancemeta) + else + Object:init(newobj, o) + end + + if self.interfaces and not self.interfacesVerified then + -- Verify the interfaces + + for interface in pairs(self.interfaces) do + for field,kind in pairs(interface.interface) do + if tostring(type(newobj[field])) ~= kind then + AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field]))) + end + end + end + self.interfacesVerified = true + end + local tmp = initStatus + initStatus = newobj + newobj:init(...) + if initStatus then + initStatus = tmp + AceOO:error("Initialization not completed, be sure to call the superclass's init method.") + return + end + initStatus = tmp + return newobj + end + local classmeta = { + __tostring = objtostring, + __call = function(self, ...) + return self:new(...) + end, + } + function Class:init(newclass, parent, ...) + parent = parent or self + + local total + + if parent.class then + total = { parent, ... } + parent = self + else + total = { ... } + end + if not inherits(parent, Class) then + AceOO:error("Classes must inherit from a proper class") + end + if parent.sealed then + AceOO:error("Cannot inherit from a sealed class") + end + for i,v in ipairs(total) do + if inherits(v, Mixin) and v.class then + if v.__deprecated then + AceOO:error(v.__deprecated) + end + if not newclass.mixins then + newclass.mixins = {} + end + if newclass.mixins[v] then + AceOO:error("Cannot explicitly inherit from the same mixin twice") + end + newclass.mixins[v] = true + elseif inherits(v, Interface) and v.class then + if not newclass.interfaces then + newclass.interfaces = {} + end + if newclass.interfaces[v] then + AceOO:error("Cannot explicitly inherit from the same interface twice") + end + newclass.interfaces[v] = true + else + AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces") + end + end + if parent.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(parent.interfaces) do + newclass.interfaces[interface] = true + end + end + for k in pairs(total) do + total[k] = nil + end + + newclass.super = parent + + newclass.prototype = setmetatable(total, { + __index = parent.prototype, + __tostring = protostring, + }) + total = nil + + newclass.instancemeta = { + __index = newclass.prototype, + __tostring = classobjectstring, + __eq = classobjectequal, + __lt = classobjectlessthan, + __le = classobjectlessthanequal, + __add = classobjectadd, + __sub = classobjectsub, + __unm = classobjectunm, + __mul = classobjectmul, + __div = classobjectdiv, + __pow = classobjectpow, + __concat = classobjectconcat, + } + + setmetatable(newclass, classmeta) + + newclass.new = class_new + + if newclass.mixins then + -- Fold in the mixins + local err, msg + for mixin in pairs(newclass.mixins) do + local ret + autoEmbed = true + ret, msg = pcall(mixin.embed, mixin, newclass.prototype) + autoEmbed = false + if not ret then + err = true + break + end + end + + if err then + local pt = newclass.prototype + for k,v in pairs(pt) do + pt[k] = nil + end + + -- method conflict + AceOO:error(msg) + end + end + + newclass.prototype.class = newclass + + if newclass.interfaces then + for interface in pairs(newclass.interfaces) do + traverseInterfaces(interface, newclass.interfaces) + end + end + if newclass.mixins then + for mixin in pairs(newclass.mixins) do + if mixin.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(mixin.interfaces) do + newclass.interfaces[interface] = true + end + end + end + end + end + function Class:ToString() + if type(self.GetLibraryVersion) == "function" then + return (self:GetLibraryVersion()) + else + return "Class" + end + end + + local tmp + function Class.prototype:init() + if rawequal(self, initStatus) then + initStatus = nil + else + AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2) + end + self.uid = getuid(self) + local current = self.class + while true do + if current == Class then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnInstanceInit) == "function" then + mixin:OnInstanceInit(self) + end + end + end + current = current.super + end + end +end + + +-- @object ClassFactory +-- @brief A factory for creating classes. Rarely used directly. +local ClassFactory = Factory(Object, Class, Object) + +function Class:new(...) + local x = ClassFactory:new(...) + if AceOO.classes then + AceOO.classes[x] = true + end + return x +end +getmetatable(Class).__call = Class.new + +-- @class Mixin +-- @brief A class to create mixin objects, which contain methods that get +-- "mixed in" to class prototypes. +-- +-- @object Mixin prototype +-- @brief The prototype that mixin objects inherit their methods from. +-- +-- @method Mixin prototype embed +-- @brief Mix in the methods of our object which are listed in our interface +-- to the supplied target table. +-- +-- @method Mixin prototype init +-- @brief Initialize the mixin object. +-- @param newobj The new object we're initializing. +-- @param interface The interface we implement (the list of methods our +-- prototype provides which should be mixed into the target +-- table by embed). +do + Mixin = Class() + function Mixin:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Mixin' + end + end + local function _Embed(state, field, target) + field = next(state.export, field) + if field == nil then + return + end + + if rawget(target, field) or (target[field] and target[field] ~= state[field]) then + AceOO:error("Method conflict in attempt to mixin. Field %q", field) + end + + target[field] = state[field] + + local ret,msg = pcall(_Embed, state, field, target) + if not ret then + -- Mix in the next method according to the defined interface. If that + -- fails due to a conflict, re-raise to back out the previous mixed + -- methods. + + target[field] = nil + AceOO:error(msg) + end + end + function Mixin.prototype:embed(target) + if self.__deprecated then + AceOO:error(self.__deprecated) + end + local mt = getmetatable(target) + setmetatable(target, nil) + local err, msg = pcall(_Embed, self, nil, target) + if not err then + setmetatable(target, mt) + AceOO:error(msg) + return + end + if type(self.embedList) == "table" then + self.embedList[target] = true + end + if type(target.class) ~= "table" then + target[self] = true + end + if not autoEmbed and type(self.OnManualEmbed) == "function" then + self:OnManualEmbed(target) + end + setmetatable(target, mt) + end + + function Mixin.prototype:activate(oldLib, oldDeactivate) + if oldLib and oldLib.embedList then + for target in pairs(oldLib.embedList) do + local mt = getmetatable(target) + setmetatable(target, nil) + for field in pairs(oldLib.export) do + target[field] = nil + end + setmetatable(target, mt) + end + self.embedList = oldLib.embedList + for target in pairs(self.embedList) do + self:embed(target) + end + else + self.embedList = setmetatable({}, {__mode="k"}) + end + end + + function Mixin.prototype:init(export, ...) + AceOO:argCheck(export, 2, "table") + for k,v in pairs(export) do + if type(k) ~= "number" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + end + end + local num = #export + for i = 1, num do + local v = export[i] + export[i] = nil + export[v] = true + end + + local interfaces + if select('#', ...) >= 1 then + interfaces = { ... } + for i,v in ipairs(interfaces) do + v = getlibrary(v) + interfaces[i] = v + if not v.class or not inherits(v, Interface) then + AceOO:error("Mixins can inherit only from interfaces") + end + end + local num = #interfaces + for i = 1, num do + local v = interfaces[i] + interfaces[i] = nil + interfaces[v] = true + end + for interface in pairs(interfaces) do + traverseInterfaces(interface, interfaces) + end + for interface in pairs(interfaces) do + for field,kind in pairs(interface.interface) do + if kind ~= "nil" then + local good = false + for bit in pairs(export) do + if bit == field then + good = true + break + end + end + if not good then + AceOO:error("Mixin does not fully accommodate field %q", field) + end + end + end + end + end + self.super = Mixin.prototype + Mixin.super.prototype.init(self) + self.export = export + self.interfaces = interfaces + end +end + +-- @class Interface +-- @brief A class to create interfaces, which contain contracts that classes +-- which inherit from this must comply with. +-- +-- @object Interface prototype +-- @brief The prototype that interface objects must adhere to. +-- +-- @method Interface prototype init +-- @brief Initialize the mixin object. +-- @param interface The interface we contract (the hash of fields forced). +-- @param (...) Superinterfaces +do + Interface = Class() + function Interface:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Instance' + end + end + function Interface.prototype:init(interface, ...) + Interface.super.prototype.init(self) + AceOO:argCheck(interface, 2, "table") + for k,v in pairs(interface) do + if type(k) ~= "string" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then + AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".') + end + end + if select('#', ...) >= 1 then + self.superinterfaces = { ... } + for i,v in ipairs(self.superinterfaces) do + v = getlibrary(v) + self.superinterfaces[i] = v + if not inherits(v, Interface) or not v.class then + AceOO:error('Cannot provide a non-Interface to inherit from') + end + end + local num = #self.superinterfaces + for i = 1, num do + local v = self.superinterfaces[i] + self.superinterfaces[i] = nil + self.superinterfaces[v] = true + end + end + self.interface = interface + end +end + +-- @function Classpool +-- @brief Obtain a read only class from our pool of classes, indexed by the +-- superclass and mixins. +-- @param sc The superclass of the class we want. +-- @param (m1..m20) Mixins of the class we want's objects. +-- @return A read only class from the class pool. +local Classpool +do + local pool = setmetatable({}, {__mode = 'v'}) + local function newindex(k, v) + AceOO:error('Attempt to modify a read-only class.') + end + local function protonewindex(k, v) + AceOO:error('Attempt to modify a read-only class prototype.') + end + local function ts(bit) + if type(bit) ~= "table" then + return tostring(bit) + elseif getmetatable(bit) and bit.__tostring then + return tostring(bit) + elseif type(bit.GetLibraryVersion) == "function" then + return bit:GetLibraryVersion() + else + return tostring(bit) + end + end + local t = {} + local function getcomplexuid(sc, ...) + if sc then + if sc.uid then + table.insert(t, sc.uid) + else + AceOO:error("%s is not an appropriate class/mixin", ts(sc)) + end + end + for i = 1, select('#', ...) do + local m = select(i, ...) + if m.uid then + table.insert(t, m.uid) + else + AceOO:error("%s is not an appropriate mixin", ts(m)) + end + end + table.sort(t) + local uid = table.concat(t, '') + local num = #t + for i = 1, num do + t[i] = nil + end + return uid + end + local classmeta + local arg = {} + function Classpool(superclass, ...) + local l = getlibrary + superclass = getlibrary(superclass) + arg = { ... } + for i, v in ipairs(arg) do + arg[i] = getlibrary(v) + end + if superclass then + if superclass.class then -- mixin + table.insert(arg, 1, superclass) + superclass = Class + end + else + superclass = Class + end + local key = getcomplexuid(superclass, unpack(arg)) + if not pool[key] then + local class = Class(superclass, unpack(arg)) + if not classmeta then + classmeta = {} + local mt = getmetatable(class) + for k,v in pairs(mt) do + classmeta[k] = v + end + classmeta.__newindex = newindex + end + -- Prevent the user from adding methods to this class. + -- NOTE: I'm not preventing modifications of existing class members, + -- but it's likely that only a truly malicious user will be doing so. + class.sealed = true + setmetatable(class, classmeta) + getmetatable(class.prototype).__newindex = protonewindex + pool[key] = class + end + return pool[key] + end +end + +AceOO.Factory = Factory +AceOO.Object = Object +AceOO.Class = Class +AceOO.Mixin = Mixin +AceOO.Interface = Interface +AceOO.Classpool = Classpool +AceOO.inherits = inherits + +-- Library handling bits + +local function activate(self, oldLib, oldDeactivate) + AceOO = self + Factory = self.Factory + Object = self.Object + Class = self.Class + ClassFactory.prototype = Class + Mixin = self.Mixin + Interface = self.Interface + Classpool = self.Classpool + + if oldLib then + self.classes = oldLib.classes + end + if not self.classes then + self.classes = setmetatable({}, {__mode="k"}) + else + for class in pairs(self.classes) do + class.new = class_new + end + end + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate) +AceOO = AceLibrary(MAJOR_VERSION)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/AceOO-2.0/AceOO-2.0.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,12 @@ +## Interface: 20200 + +## Title: Lib: AceOO-2.0 +## Notes: AddOn development framework +## Author: Ace Development Team +## LoadOnDemand: 1 +## X-Website: http://www.wowace.com +## X-Category: Library +## X-License: LGPL v2.1 + MIT for AceOO-2.0 +## Dependencies: AceLibrary + +AceOO-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/FuBar_ReActionFu/lib/Dewdrop-2.0/Dewdrop-2.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,3487 @@ +--[[ +Name: Dewdrop-2.0 +Revision: $Rev: 48630 $ +Author(s): ckknight (ckknight@gmail.com) +Website: http://ckknight.wowinterface.com/ +Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0 +SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0 +Description: A library to provide a clean dropdown menu interface. +Dependencies: AceLibrary +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "Dewdrop-2.0" +local MINOR_VERSION = "$Revision: 48630 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local Dewdrop = {} + +local SharedMedia + +local CLOSE = "Close" +local CLOSE_DESC = "Close the menu." +local VALIDATION_ERROR = "Validation error." +local USAGE_TOOLTIP = "Usage: %s." +local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one." +local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." +local KEY_BUTTON1 = "Left Mouse" +local KEY_BUTTON2 = "Right Mouse" +local DISABLED = "Disabled" +local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" + +if GetLocale() == "deDE" then + CLOSE = "Schlie\195\159en" + CLOSE_DESC = "Men\195\188 schlie\195\159en." + VALIDATION_ERROR = "Validierungsfehler." + USAGE_TOOLTIP = "Benutzung: %s." + RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen." + RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen." + KEY_BUTTON1 = "Linke Maustaste" + KEY_BUTTON2 = "Rechte Maustaste" + DISABLED = "Deaktiviert" + DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?" +elseif GetLocale() == "koKR" then + CLOSE = "닫기" + CLOSE_DESC = "메뉴를 닫습니다." + VALIDATION_ERROR = "오류 확인." + USAGE_TOOLTIP = "사용법: %s." + RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다." + RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요." + KEY_BUTTON1 = "왼쪽 마우스" + KEY_BUTTON2 = "오른쪽 마우스" + DISABLED = "비활성화됨" + DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?" +elseif GetLocale() == "frFR" then + CLOSE = "Fermer" + CLOSE_DESC = "Ferme le menu." + VALIDATION_ERROR = "Erreur de validation." + USAGE_TOOLTIP = "Utilisation : %s." + RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement." + RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci." + KEY_BUTTON1 = "Clic gauche" + KEY_BUTTON2 = "Clic droit" + DISABLED = "D\195\169sactiv\195\169" + DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?" +elseif GetLocale() == "esES" then + CLOSE = "Cerrar" + CLOSE_DESC = "Cierra el menú." + VALIDATION_ERROR = "Error de validación." + USAGE_TOOLTIP = "Uso: %s." + RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador." + RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla." + KEY_BUTTON1 = "Clic Izquierdo" + KEY_BUTTON2 = "Clic Derecho" + DISABLED = "Desactivado" + DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?" +elseif GetLocale() == "zhTW" then + CLOSE = "關閉" + CLOSE_DESC = "關閉選單。" + VALIDATION_ERROR = "驗證錯誤。" + USAGE_TOOLTIP = "用法: %s。" + RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。" + RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。" + KEY_BUTTON1 = "滑鼠左鍵" + KEY_BUTTON2 = "滑鼠右鍵" + DISABLED = "停用" + DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" +elseif GetLocale() == "zhCN" then + CLOSE = "关闭" + CLOSE_DESC = "关闭菜单" + VALIDATION_ERROR = "验证错误." + USAGE_TOOLTIP = "用法: %s." + RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页." + RESET_KEYBINDING_DESC = "按ESC键清除按键绑定" + KEY_BUTTON1 = "鼠标左键" + KEY_BUTTON2 = "鼠标右键" + DISABLED = "禁用" + DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?" +end + +Dewdrop.KEY_BUTTON1 = KEY_BUTTON1 +Dewdrop.KEY_BUTTON2 = KEY_BUTTON2 + +local function new(...) + local t = {} + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t +end + +local tmp +do + local t = {} + function tmp(...) + for k in pairs(t) do + t[k] = nil + end + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t + end +end +local tmp2 +do + local t = {} + function tmp2(...) + for k in pairs(t) do + t[k] = nil + end + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t + end +end +local levels +local buttons + + +-- Secure frame handling: +-- Rather than using secure buttons in the menu (has problems), we have one +-- master secureframe that we pop onto menu items on mouseover. This requires +-- some dark magic with OnLeave etc, but it's not too bad. + +local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate") +secureFrame:Hide() + +local function secureFrame_Show(self) + local owner = self.owner + + if self.secure then -- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..) + for k,v in pairs(self.secure) do + self:SetAttribute(k, nil) + end + end + self.secure = owner.secure; -- Grab hold of new secure data + + local scale = owner:GetEffectiveScale() + + self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale) + self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale) + self:EnableMouse(true) + for k,v in pairs(self.secure) do + self:SetAttribute(k, v) + end + + secureFrame:SetFrameStrata(owner:GetFrameStrata()) + secureFrame:SetFrameLevel(owner:GetFrameLevel()+1) + + self:Show() +end + +local function secureFrame_Hide(self) + self:Hide() + if self.secure then + for k,v in pairs(self.secure) do + self:SetAttribute(k, nil) + end + end + self.secure = nil +end + +secureFrame:SetScript("OnEvent", + function() + if event=="PLAYER_REGEN_ENABLED" then + this.combat = false + if not this:IsShown() and this.owner then + secureFrame_Show(this) + end + elseif event=="PLAYER_REGEN_DISABLED" then + this.combat = true + if this:IsShown() then + secureFrame_Hide(this) + end + end + end +) +secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED") +secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED") + +secureFrame:SetScript("OnLeave", + function() + local owner=this.owner + this:Deactivate() + owner:GetScript("OnLeave")() + end +) + +secureFrame:HookScript("OnClick", + function() + local realthis = this + this = this.owner + this:GetScript("OnClick")() + end +) + +function secureFrame:IsOwnedBy(frame) + return self.owner == frame +end + +function secureFrame:Activate(owner) + if self.owner then -- "Shouldn't" happen but apparently it does and I cba to troubleshoot... + if not self.combat then + secureFrame_Hide(self) + end + end + self.owner = owner + if not self.combat then + secureFrame_Show(self) + end +end + +function secureFrame:Deactivate() + if not self.combat then + secureFrame_Hide(self) + end + self.owner = nil +end + +-- END secure frame utilities + + +-- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies +local underlineFrame = CreateFrame("Frame", nil) +underlineFrame.tx = underlineFrame:CreateTexture() +underlineFrame.tx:SetTexture(1,1,0.5,0.75) +underlineFrame:SetScript("OnHide", function(this) this:Hide(); end) +underlineFrame:SetScript("OnShow", function(this) -- change sizing on the fly to catch runtime uiscale changes + underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale()) + underlineFrame.tx:SetPoint("RIGHT", 1,0) + underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale()); +end) +underlineFrame:SetHeight(1) + +-- END underline on mouseover + + +local function GetScaledCursorPosition() + local x, y = GetCursorPosition() + local scale = UIParent:GetEffectiveScale() + return x / scale, y / scale +end + +local function StartCounting(self, level) + for i = level, 1, -1 do + if levels[i] then + levels[i].count = 3 + end + end +end + +local function StopCounting(self, level) + for i = level, 1, -1 do + if levels[i] then + levels[i].count = nil + end + end +end + +local function OnUpdate(self, elapsed) + for _,level in ipairs(levels) do + local count = level.count + if count then + count = count - elapsed + if count < 0 then + level.count = nil + self:Close(level.num) + else + level.count = count + end + end + end +end + +local function CheckDualMonitor(self, frame) + local ratio = GetScreenWidth() / GetScreenHeight() + if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then + local offsetx + if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then + offsetx = GetScreenWidth() / 2 - frame:GetRight() + else + offsetx = GetScreenWidth() / 2 - frame:GetLeft() + end + local point, parent, relativePoint, x, y = frame:GetPoint(1) + frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0) + end +end + +local function CheckSize(self, level) + if not level.buttons then + return + end + local height = 20 + for _, button in ipairs(level.buttons) do + height = height + button:GetHeight() + end + level:SetHeight(height) + local width = 160 + for _, button in ipairs(level.buttons) do + local extra = 1 + if button.hasArrow or button.hasColorSwatch then + extra = extra + 16 + end + if not button.notCheckable then + extra = extra + 24 + end + button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight) + if button.text:GetWidth() + extra > width then + width = button.text:GetWidth() + extra + end + end + level:SetWidth(width + 20) + if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then + level:ClearAllPoints() + local parent = level.parent or level:GetParent() + if type(parent) ~= "table" then + parent = UIParent + end + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local dirty = false + if not level:GetRight() then + self:Close() + return + end + if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then + level.lastDirection = "LEFT" + dirty = true + elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then + level.lastDirection = "RIGHT" + dirty = true + end + if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then + level.lastVDirection = "DOWN" + dirty = true + elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then + level.lastVDirection = "UP" + dirty = true + end + if dirty then + level:ClearAllPoints() + local parent = level.parent or level:GetParent() + if type(parent) ~= "table" then + parent = UIParent + end + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + if level:GetTop() > GetScreenHeight() then + local top = level:GetTop() + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:ClearAllPoints() + level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top) + elseif level:GetBottom() < 0 then + local bottom = level:GetBottom() + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:ClearAllPoints() + level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom) + end + CheckDualMonitor(self, level) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end +end + +local Open +local OpenSlider +local OpenEditBox +local Refresh +local Clear +local function ReleaseButton(self, level, index) + if not level.buttons then + return + end + if not level.buttons[index] then + return + end + local button = level.buttons[index] + button:Hide() + if button.highlight then + button.highlight:Hide() + end +-- button.arrow:SetVertexColor(1, 1, 1) +-- button.arrow:SetHeight(16) +-- button.arrow:SetWidth(16) + table.remove(level.buttons, index) + table.insert(buttons, button) + for k in pairs(button) do + if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then + button[k] = nil + end + end + return true +end + +local function Scroll(self, level, down) + if down then + if level:GetBottom() < 0 then + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:SetPoint(point, parent, relativePoint, x, y + 50) + if level:GetBottom() > 0 then + level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom()) + end + end + else + if level:GetTop() > GetScreenHeight() then + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:SetPoint(point, parent, relativePoint, x, y - 50) + if level:GetTop() < GetScreenHeight() then + level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop()) + end + end + end +end + +local function getArgs(t, str, num, ...) + local x = t[str .. num] + if x == nil then + return ... + else + return x, getArgs(t, str, num + 1, ...) + end +end + +local sliderFrame +local editBoxFrame + +local normalFont +local lastSetFont +local justSetFont = false +local regionTmp = {} +local function fillRegionTmp(...) + for i = 1, select('#', ...) do + regionTmp[i] = select(i, ...) + end +end + +local function showGameTooltip(this) + if this.tooltipTitle or this.tooltipText then + GameTooltip_SetDefaultAnchor(GameTooltip, this) + local disabled = not this.isTitle and this.disabled + local font + if this.tooltipTitle then + if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then + font = SharedMedia:Fetch("font", this.tooltipTitle) + end + if disabled then + GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1) + else + GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1) + end + if this.tooltipText then + if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then + font = SharedMedia:Fetch("font", this.tooltipText) + end + if disabled then + GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1) + else + GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) + end + end + else + if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then + font = SharedMedia:Fetch("font", this.tooltipText) + end + if disabled then + GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1) + else + GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1) + end + end + if font then + fillRegionTmp(GameTooltip:GetRegions()) + lastSetFont = font + justSetFont = true + for i,v in ipairs(regionTmp) do + if v.SetFont then + local norm,size,outline = v:GetFont() + v:SetFont(font, size, outline) + if not normalFont then + normalFont = norm + end + end + regionTmp[i] = nil + end + elseif not normalFont then + fillRegionTmp(GameTooltip:GetRegions()) + for i,v in ipairs(regionTmp) do + if v.GetFont and not normalFont then + normalFont = v:GetFont() + end + regionTmp[i] = nil + end + end + GameTooltip:Show() + end + if this.tooltipFunc then + GameTooltip:SetOwner(this, "ANCHOR_NONE") + GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) + this.tooltipFunc(getArgs(this, 'tooltipArg', 1)) + GameTooltip:Show() + end +end + +local tmpt = setmetatable({}, {mode='v'}) +local numButtons = 0 +local function AcquireButton(self, level) + if not levels[level] then + return + end + level = levels[level] + if not level.buttons then + level.buttons = {} + end + local button + if #buttons == 0 then + numButtons = numButtons + 1 + button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) + button:SetFrameStrata("FULLSCREEN_DIALOG") + button:SetHeight(16) + local highlight = button:CreateTexture(nil, "BACKGROUND") + highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") + button.highlight = highlight + highlight:SetBlendMode("ADD") + highlight:SetAllPoints(button) + highlight:Hide() + local check = button:CreateTexture(nil, "ARTWORK") + button.check = check + check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") + check:SetPoint("CENTER", button, "LEFT", 12, 0) + check:SetWidth(24) + check:SetHeight(24) + local radioHighlight = button:CreateTexture(nil, "ARTWORK") + button.radioHighlight = radioHighlight + radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton") + radioHighlight:SetAllPoints(check) + radioHighlight:SetBlendMode("ADD") + radioHighlight:SetTexCoord(0.5, 0.75, 0, 1) + radioHighlight:Hide() + button:SetScript("OnEnter", function() + if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then + for i = 1, this.level.num do + Refresh(self, levels[i]) + end + return + end + self:Close(this.level.num + 1) + if not this.disabled then + if this.secure then + secureFrame:Activate(this) + elseif this.hasSlider then + OpenSlider(self, this) + elseif this.hasEditBox then + OpenEditBox(self, this) + elseif this.hasArrow then + Open(self, this, nil, this.level.num + 1, this.value) + end + end + if not this.level then -- button reclaimed + return + end + StopCounting(self, this.level.num + 1) + if not this.disabled then + highlight:Show() + if this.isRadio then + button.radioHighlight:Show() + end + if this.mouseoverUnderline then + underlineFrame:SetParent(this) + underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0) + underlineFrame:SetWidth(this.text:GetWidth()) + underlineFrame:Show() + end + end + showGameTooltip(this) + end) + button:SetScript("OnHide", function() + if this.secure and secureFrame:IsOwnedBy(this) then + secureFrame:Deactivate() + end + end) + button:SetScript("OnLeave", function() + if this.secure and secureFrame:IsShown() then + return; -- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it + end + underlineFrame:Hide() + if not this.selected then + highlight:Hide() + end + button.radioHighlight:Hide() + if this.level then + StartCounting(self, this.level.num) + end + GameTooltip:Hide() + end) + local first = true + button:SetScript("OnClick", function() + if not this.disabled then + if this.hasColorSwatch then + local func = button.colorFunc + local hasOpacity = this.hasOpacity + local this = this + for k in pairs(tmpt) do + tmpt[k] = nil + end + for i = 1, 1000 do + local x = this['colorArg'..i] + if x == nil then + break + else + tmpt[i] = x + end + end + ColorPickerFrame.func = function() + if func then + local r,g,b = ColorPickerFrame:GetColorRGB() + local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil + local n = #tmpt + tmpt[n+1] = r + tmpt[n+2] = g + tmpt[n+3] = b + tmpt[n+4] = a + func(unpack(tmpt)) + tmpt[n+1] = nil + tmpt[n+2] = nil + tmpt[n+3] = nil + tmpt[n+4] = nil + end + end + ColorPickerFrame.hasOpacity = this.hasOpacity + ColorPickerFrame.opacityFunc = ColorPickerFrame.func + ColorPickerFrame.opacity = 1 - this.opacity + ColorPickerFrame:SetColorRGB(this.r, this.g, this.b) + local r, g, b, a = this.r, this.g, this.b, this.opacity + ColorPickerFrame.cancelFunc = function() + if func then + local n = #tmpt + tmpt[n+1] = r + tmpt[n+2] = g + tmpt[n+3] = b + tmpt[n+4] = a + func(unpack(tmpt)) + for i = 1, n+4 do + tmpt[i] = nil + end + end + end + self:Close(1) + ShowUIPanel(ColorPickerFrame) + elseif this.func then + local level = this.level + if type(this.func) == "string" then + if type(this.arg1[this.func]) ~= "function" then + self:error("Cannot call method %q", this.func) + end + this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2)) + else + this.func(getArgs(this, 'arg', 1)) + end + if this.closeWhenClicked then + self:Close() + elseif level:IsShown() then + for i = 1, level.num do + Refresh(self, levels[i]) + end + local value = levels[level.num].value + for i = level.num-1, 1, -1 do + local level = levels[i] + local good = false + for _,button in ipairs(level.buttons) do + if button.value == value then + good = true + break + end + end + if not good then + Dewdrop:Close(i+1) + end + value = levels[i].value + end + end + elseif this.closeWhenClicked then + self:Close() + end + end + end) + local text = button:CreateFontString(nil, "ARTWORK") + button.text = text + text:SetFontObject(GameFontHighlightSmall) + button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) + button:SetScript("OnMouseDown", function() + if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then + text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1) + end + end) + button:SetScript("OnMouseUp", function() + if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then + text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0) + end + end) + local arrow = button:CreateTexture(nil, "ARTWORK") + button.arrow = arrow + arrow:SetPoint("LEFT", button, "RIGHT", -16, 0) + arrow:SetWidth(16) + arrow:SetHeight(16) + arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") + local colorSwatch = button:CreateTexture(nil, "ARTWORK") + button.colorSwatch = colorSwatch + colorSwatch:SetWidth(20) + colorSwatch:SetHeight(20) + colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") + local texture = button:CreateTexture(nil, "OVERLAY") + colorSwatch.texture = texture + texture:SetTexture("Interface\\Buttons\\WHITE8X8") + texture:SetWidth(11.5) + texture:SetHeight(11.5) + texture:Show() + texture:SetPoint("CENTER", colorSwatch, "CENTER") + colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) + else + button = table.remove(buttons) + end + button:ClearAllPoints() + button:SetParent(level) + button:SetFrameStrata(level:GetFrameStrata()) + button:SetFrameLevel(level:GetFrameLevel() + 1) + button:SetPoint("LEFT", level, "LEFT", 10, 0) + button:SetPoint("RIGHT", level, "RIGHT", -10, 0) + if #level.buttons == 0 then + button:SetPoint("TOP", level, "TOP", 0, -10) + else + button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0) + end + button.text:SetPoint("LEFT", button, "LEFT", 24, 0) + button:Show() + button.level = level + table.insert(level.buttons, button) + if not level.parented then + level.parented = true + level:ClearAllPoints() + if level.num == 1 then + if level.parent ~= UIParent and type(level.parent) == "table" then + level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") + else + level:SetPoint("CENTER", UIParent, "CENTER") + end + else + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10) + end + end + end + level:SetFrameStrata("FULLSCREEN_DIALOG") + end + button:SetAlpha(1) + return button +end + +local numLevels = 0 +local function AcquireLevel(self, level) + if not levels[level] then + for i = #levels + 1, level, -1 do + local i = i + numLevels = numLevels + 1 + local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) + if i == 1 then + local old_CloseSpecialWindows = CloseSpecialWindows + function CloseSpecialWindows() + local found = old_CloseSpecialWindows() + if levels[1]:IsShown() then + self:Close() + return 1 + end + return found + end + end + levels[i] = frame + frame.num = i + frame:SetParent(UIParent) + frame:SetFrameStrata("FULLSCREEN_DIALOG") + frame:Hide() + frame:SetWidth(180) + frame:SetHeight(10) + frame:SetFrameLevel(i * 3) + frame:SetScript("OnHide", function() + self:Close(level + 1) + end) + if frame.SetTopLevel then + frame:SetTopLevel(true) + end + frame:EnableMouse(true) + frame:EnableMouseWheel(true) + local backdrop = CreateFrame("Frame", nil, frame) + backdrop:SetAllPoints(frame) + backdrop:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + frame:SetScript("OnClick", function() + self:Close(i) + end) + frame:SetScript("OnEnter", function() + StopCounting(self, i) + end) + frame:SetScript("OnLeave", function() + StartCounting(self, i) + end) + frame:SetScript("OnMouseWheel", function() + Scroll(self, frame, arg1 < 0) + end) + if i == 1 then + frame:SetScript("OnUpdate", function(this, arg1) + OnUpdate(self, arg1) + end) + levels[1].lastDirection = "RIGHT" + levels[1].lastVDirection = "DOWN" + else + levels[i].lastDirection = levels[i - 1].lastDirection + levels[i].lastVDirection = levels[i - 1].lastVDirection + end + end + end + local fullscreenFrame = GetUIPanel("fullscreen") + local l = levels[level] + local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() + if fullscreenFrame then + l:SetParent(fullscreenFrame) + else + l:SetParent(UIParent) + end + l:SetFrameStrata(strata) + l:SetFrameLevel(framelevel) + l:SetAlpha(1) + return l +end + +local function validateOptions(options, position, baseOptions, fromPass) + if not baseOptions then + baseOptions = options + end + if type(options) ~= "table" then + return "Options must be a table.", position + end + local kind = options.type + if type(kind) ~= "string" then + return '"type" must be a string.', position + elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then + return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position + end + if options.aliases then + if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then + return '"alias" must be a table or string', position + end + end + if not fromPass then + if kind == "execute" then + if type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + elseif kind == "range" or kind == "text" or kind == "toggle" then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if kind == "text" and options.get == false then + elseif type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif kind == "group" and options.pass then + if options.pass ~= true then + return '"pass" must be either nil, true, or false', position + end + if not options.func then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + end + end + if options ~= baseOptions then + if kind == "header" then + elseif type(options.desc) ~= "string" then + return '"desc" must be a string', position + elseif options.desc:len() == 0 then + return '"desc" cannot be a 0-length string', position + end + end + if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then + if options.type == "header" and not options.cmdName and not options.name then + elseif options.cmdName then + if type(options.cmdName) ~= "string" then + return '"cmdName" must be a string or nil', position + elseif options.cmdName:len() == 0 then + return '"cmdName" cannot be a 0-length string', position + end + if type(options.guiName) ~= "string" then + if not options.guiNameIsMap then + return '"guiName" must be a string or nil', position + end + elseif options.guiName:len() == 0 then + return '"guiName" cannot be a 0-length string', position + end + else + if type(options.name) ~= "string" then + return '"name" must be a string', position + elseif options.name:len() == 0 then + return '"name" cannot be a 0-length string', position + end + end + end + if options.guiNameIsMap then + if type(options.guiNameIsMap) ~= "boolean" then + return '"guiNameIsMap" must be a boolean or nil', position + elseif options.type ~= "toggle" then + return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position + elseif type(options.map) ~= "table" then + return '"map" must be a table', position + end + end + if options.message and type(options.message) ~= "string" then + return '"message" must be a string or nil', position + end + if options.error and type(options.error) ~= "string" then + return '"error" must be a string or nil', position + end + if options.current and type(options.current) ~= "string" then + return '"current" must be a string or nil', position + end + if options.order then + if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then + return '"order" must be a non-zero number or nil', position + end + end + if options.disabled then + if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then + return '"disabled" must be a function, string, or boolean', position + end + end + if options.cmdHidden then + if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then + return '"cmdHidden" must be a function, string, or boolean', position + end + end + if options.guiHidden then + if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then + return '"guiHidden" must be a function, string, or boolean', position + end + end + if options.hidden then + if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then + return '"hidden" must be a function, string, or boolean', position + end + end + if kind == "text" then + if type(options.validate) == "table" then + local t = options.validate + local iTable = nil + for k,v in pairs(t) do + if type(k) == "number" then + if iTable == nil then + iTable = true + elseif not iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + elseif k < 1 or k > #t then + return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position + end + else + if iTable == nil then + iTable = false + elseif iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + end + end + if type(v) ~= "string" then + return '"validate" values must all be strings', position + end + end + if options.multiToggle and options.multiToggle ~= true then + return '"multiToggle" must be a boolean or nil if "validate" is a table', position + end + elseif options.validate == "keybinding" then + -- no other checks + else + if type(options.usage) ~= "string" then + return '"usage" must be a string', position + elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return '"validate" must be a string, function, or table', position + end + end + if options.multiToggle and type(options.validate) ~= "table" then + return '"validate" must be a table if "multiToggle" is true', position + end + elseif kind == "range" then + if options.min or options.max then + if type(options.min) ~= "number" then + return '"min" must be a number', position + elseif type(options.max) ~= "number" then + return '"max" must be a number', position + elseif options.min >= options.max then + return '"min" must be less than "max"', position + end + end + if options.step then + if type(options.step) ~= "number" then + return '"step" must be a number', position + elseif options.step < 0 then + return '"step" must be nonnegative', position + end + end + if options.bigStep then + if type(options.bigStep) ~= "number" then + return '"bigStep" must be a number', position + elseif options.bigStep < 0 then + return '"bigStep" must be nonnegative', position + end + end + if options.isPercent and options.isPercent ~= true then + return '"isPercent" must either be nil, true, or false', position + end + elseif kind == "toggle" then + if options.map then + if type(options.map) ~= "table" then + return '"map" must be a table', position + elseif type(options.map[true]) ~= "string" then + return '"map[true]" must be a string', position + elseif type(options.map[false]) ~= "string" then + return '"map[false]" must be a string', position + end + end + elseif kind == "color" then + if options.hasAlpha and options.hasAlpha ~= true then + return '"hasAlpha" must be nil, true, or false', position + end + elseif kind == "group" then + if options.pass and options.pass ~= true then + return '"pass" must be nil, true, or false', position + end + if type(options.args) ~= "table" then + return '"args" must be a table', position + end + for k,v in pairs(options.args) do + if type(k) ~= "number" then + if type(k) ~= "string" then + return '"args" keys must be strings or numbers', position + elseif k:len() == 0 then + return '"args" keys must not be 0-length strings.', position + end + end + if type(v) ~= "table" then + return '"args" values must be tables', position and position .. "." .. k or k + end + local newposition + if position then + newposition = position .. ".args." .. k + else + newposition = "args." .. k + end + local err, pos = validateOptions(v, newposition, baseOptions, options.pass) + if err then + return err, pos + end + end + elseif kind == "execute" then + if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then + return '"confirm" must be a string, boolean, or nil', position + end + end + if options.icon and type(options.icon) ~= "string" then + return'"icon" must be a string', position + end + if options.iconWidth or options.iconHeight then + if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then + return '"iconHeight" and "iconWidth" must be numbers', position + end + end + if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then + if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then + return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position + end + end +end + +local validatedOptions + +local values +local mysort_args +local mysort +local othersort +local othersort_validate + +local baseFunc, currentLevel + +local function confirmPopup(message, func, ...) + if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then + StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {} + end + local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] + for k in pairs(t) do + t[k] = nil + end + t.text = message + t.button1 = ACCEPT or "Accept" + t.button2 = CANCEL or "Cancel" + t.OnAccept = function() + func(unpack(t)) + end + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + t.timeout = 0 + t.whileDead = 1 + t.hideOnEscape = 1 + + Dewdrop:Close() + StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG") +end + + +local function getMethod(settingname, handler, v, methodName, ...) -- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222" + assert(v and type(v)=="table") + assert(methodName and type(methodName)=="string") + + local method = v[methodName] + if type(method)=="function" then + return method, ... + elseif type(method)=="string" then + if not handler then + Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) + elseif not handler[method] then + Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method) + end + return handler[method], handler, ... + end + + Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName) +end + +local function callMethod(settingname, handler, v, methodName, ...) + assert(v and type(v)=="table") + assert(methodName and type(methodName)=="string") + + local method = v[methodName] + if type(method)=="function" then + local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...) + if not success then + geterrorhandler()(ret) + return nil + end + return ret,ret2,ret3,ret4 + + elseif type(method)=="string" then + + local neg = method:match("^~(.-)$") + if neg then + method = neg + end + if not handler then + Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) + elseif not handler[method] then + Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method) + end + local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...) + if not success then + geterrorhandler()(ret) + return nil + end + if neg then + return not ret + end + return ret,ret2,ret3,ret4 + elseif method == false then + return nil + end + + Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)") +end + +local function skip1Nil(...) + if select(1,...)==nil then + return select(2,...) + end + return ... +end + +function Dewdrop:FeedAceOptionsTable(options, difference) + self:argCheck(options, 2, "table") + self:argCheck(difference, 3, "nil", "number") + if not currentLevel then + self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") + end + if not difference then + difference = 0 + end + if not validatedOptions then + validatedOptions = {} + end + if not validatedOptions[options] then + local err, position = validateOptions(options) + + if err then + if position then + Dewdrop:error(position .. ": " .. err) + else + Dewdrop:error(err) + end + end + + validatedOptions[options] = true + end + local level = levels[currentLevel] + if not level then + self:error("Improper level given") + end + if not values then + values = {} + else + for k,v in pairs(values) do + values[k] = nil + end + end + + local current = level + while current do -- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later + if current.num == difference + 1 then + break + end + table.insert(values, current.value) + current = levels[current.num - 1] + end + + local realOptions = options + local handler = options.handler + local passTable + local passValue + while #values > 0 do -- This loop traverses values from the END (trunk nodes first, then onto leaf nodes) + if options.pass then + if options.get and options.set then + passTable = options + elseif not passTable then + passTable = options + end + else + passTable = nil + end + local value = table.remove(values) + options = options.args and options.args[value] + if not options then + return + end + handler = options.handler or handler + passValue = passTable and value or nil + end + + if options.type == "group" then + local hidden = options.hidden + if type(hidden) == "function" or type(hidden) == "string" then + hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false + end + if hidden then + return + end + local disabled = options.disabled + if type(disabled) == "function" or type(disabled) == "string" then + disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false + end + if disabled then + self:AddLine( + 'text', DISABLED, + 'disabled', true + ) + return + end + for k in pairs(options.args) do + table.insert(values, k) + end + if options.pass then + if options.get and options.set then + passTable = options + elseif not passTable then + passTable = options + end + else + passTable = nil + end + if not mysort then + mysort = function(a, b) + local alpha, bravo = mysort_args[a], mysort_args[b] + local alpha_order = alpha.order or 100 + local bravo_order = bravo.order or 100 + local alpha_name = alpha.guiName or alpha.name + local bravo_name = bravo.guiName or bravo.name + if alpha_order == bravo_order then + if not alpha_name then + return bravo_name + elseif not bravo_name then + return false + else + return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() + end + else + if alpha_order < 0 then + if bravo_order > 0 then + return false + end + else + if bravo_order < 0 then + return true + end + end + return alpha_order < bravo_order + end + end + end + mysort_args = options.args + table.sort(values, mysort) + mysort_args = nil + local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0 + local last_order = 1 + for _,k in ipairs(values) do + local v = options.args[k] + local handler = v.handler or handler + if hasBoth and last_order > 0 and (v.order or 100) < 0 then + hasBoth = false + self:AddLine() + end + local hidden, disabled = v.guiHidden or v.hidden, v.disabled + + if type(hidden) == "function" or type(hidden) == "string" then + hidden = callMethod(k, handler, v, "hidden", v.passValue) or false + end + if not hidden then + if type(disabled) == "function" or type(disabled) == "string" then + disabled = callMethod(k, handler, v, "disabled", v.passValue) or false + end + local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) + local desc = v.guiDesc or v.desc + local iconHeight = v.iconHeight or 16 + local iconWidth = v.iconWidth or 16 + local iconCoordLeft = v.iconCoordLeft + local iconCoordRight = v.iconCoordRight + local iconCoordBottom = v.iconCoordBottom + local iconCoordTop = v.iconCoordTop + local tooltipTitle, tooltipText + tooltipTitle = name + if name ~= desc then + tooltipText = desc + end + if type(v.usage) == "string" and v.usage:trim():len() > 0 then + if tooltipText then + tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage) + else + tooltipText = USAGE_TOOLTIP:format(v.usage) + end + end + local v_p = passTable + if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then + v_p = v + end + local passValue = v.passValue or (v_p~=v and k) or nil + if v.type == "toggle" then + local checked = callMethod(name, handler, v_p, "get", passValue) or false + local checked_arg = checked + if type(v_p.get)=="string" and v_p.get:match("^~") then + checked_arg = not checked + end + local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set", skip1Nil(passValue, not checked_arg)) + if v.guiNameIsMap then + checked = checked and true or false + name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") + tooltipTitle = name + checked = true--nil + end + self:AddLine( + 'text', name, + 'checked', checked, + 'isRadio', v.isRadio, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + elseif v.type == "execute" then + local func, arg1, arg2, arg3, arg4 + local confirm = v.confirm + if confirm == true then + confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle) + func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) + elseif type(confirm) == "string" then + func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) + else + func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue) + end + self:AddLine( + 'text', name, + 'checked', checked, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'arg4', arg4, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "range" then + local sliderValue + sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0 + local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set", passValue) + if tooltipText then + tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP) + else + tooltipText = RANGE_TOOLTIP + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'hasSlider', true, + 'sliderMin', v.min or 0, + 'sliderMax', v.max or 1, + 'sliderStep', v.step or 0, + 'sliderBigStep', v.bigStep or nil, + 'sliderIsPercent', v.isPercent or false, + 'sliderValue', sliderValue, + 'sliderFunc', sliderFunc, + 'sliderArg1', sliderArg1, + 'sliderArg2', sliderArg2, + 'fromAceOptions', true, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "color" then + local r,g,b,a = callMethod(name, handler, v_p, "get", passValue) + if not r then + r,g,b,a = 0,0,0,0 + end + local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set", passValue) + self:AddLine( + 'text', name, + 'hasArrow', true, + 'hasColorSwatch', true, + 'r', r, + 'g', g, + 'b', b, + 'opacity', v.hasAlpha and a or nil, + 'hasOpacity', v.hasAlpha, + 'colorFunc', colorFunc, + 'colorArg1', colorArg1, + 'colorArg2', colorArg2, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + elseif v.type == "text" then + if type(v.validate) == "table" then + local func,arg1,arg2 + if v.onClick then + func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) + end + local checked + if v.isChecked then + checked = callMethod(name, handler, v, "isChecked", passValue) or false + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'value', k, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'mouseoverUnderline', func and true or nil, + 'disabled', disabled, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + else + local editBoxText + editBoxText = callMethod(name, handler, v_p, "get", passValue) or "" + local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set", passValue) + + local editBoxValidateFunc, editBoxValidateArg1 + + if v.validate and v.validate ~= "keybinding" then + if v.validate == "keybinding" then + if tooltipText then + tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC) + else + tooltipText = RESET_KEYBINDING_DESC + end + else + editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue! + end + end + + self:AddLine( + 'text', name, + 'hasArrow', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom, + 'hasEditBox', true, + 'editBoxText', editBoxText, + 'editBoxFunc', editBoxFunc, + 'editBoxArg1', editBoxArg1, + 'editBoxArg2', editBoxArg2, + 'editBoxValidateFunc', editBoxValidateFunc, + 'editBoxValidateArg1', editBoxValidateArg1, + 'editBoxIsKeybinding', v.validate == "keybinding", + 'editBoxKeybindingOnly', v.keybindingOnly, + 'editBoxKeybindingExcept', v.keybindingExcept, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + end + elseif v.type == "group" then + local func,arg1,arg2 + if v.onClick then + func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) + end + local checked + if v.isChecked then + checked = callMethod(name, handler, v, "isChecked", passValue) or false + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'value', k, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'mouseoverUnderline', func and true or nil, + 'disabled', disabled, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "header" then + if name == "" or not name then + self:AddLine( + 'isTitle', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + else + self:AddLine( + 'text', name, + 'isTitle', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + end + end + end + last_order = v.order or 100 + end + elseif options.type == "text" and type(options.validate) == "table" then + local current + local options_p = passTable + if not options_p or (options.get and options.set) then + options_p = options + passTable = nil + passValue = nil + end + local multiToggle = options.multiToggle + local passValue = options.passValue or passValue + if not multiToggle then + current = callMethod(k, handler, options_p, "get", passValue) + end + local indexed = true + for k,v in pairs(options.validate) do + if type(k) ~= "number" then + indexed = false + end + table.insert(values, k) + end + if not indexed then + if not othersort then + othersort = function(alpha, bravo) + return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() + end + end + othersort_validate = options.validate + table.sort(values, othersort) + othersort_validate = nil + end + for _,k in ipairs(values) do + local v = options.validate[k] + if type(k) == "number" then + k = v + end + local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set", skip1Nil(passValue, k)) + local checked + if multiToggle then + checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false + if arg2 == nil then + arg2 = not checked + elseif arg3 == nil then + arg3 = not checked + else + arg4 = not checked + end + else + checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) + if checked then + func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil + end + end + local tooltipTitle + local tooltipText + if options.validateDesc then + tooltipTitle = v + tooltipText = options.validateDesc[k] + else + tooltipTitle = options.guiName or options.name + tooltipText = v + end + self:AddLine( + 'text', v, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'arg4', arg4, + 'isRadio', not multiToggle, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + end + for k in pairs(values) do + values[k] = nil + end + else + return false + end + return true +end + +function Dewdrop:FeedTable(s, difference) + self:argCheck(s, 2, "table") + self:argCheck(difference, 3, "nil", "number") + if not currentLevel then + self:error("Cannot call `FeedTable' outside of a Dewdrop declaration") + end + if not difference then + difference = 0 + end + local level = levels[currentLevel] + if not level then + self:error("Improper level given") + end + if not values then + values = {} + else + for k,v in pairs(values) do + values[k] = nil + end + end + local t = s.subMenu and s or {subMenu = s} + local current = level + while current do + if current.num == difference + 1 then + break + end + table.insert(values, current.value) + current = levels[current.num - 1] + end + + while #values > 0 do + local value = table.remove(values) + t = t.subMenu and t.subMenu[value] + if not t then + return + end + end + + if t.subMenu or current.num == 1 then + for k in pairs(t.subMenu) do + table.insert(values, k) + end + table.sort(values) + for _,k in ipairs(values) do + local argTable = {"value", k} + for key, val in pairs(t.subMenu[k]) do + table.insert(argTable, key) + table.insert(argTable, val) + end + self:AddLine(unpack(argTable)) + end + for k in pairs(values) do + values[k] = nil + end + return false + end + return true +end + +function Refresh(self, level) + if type(level) == "number" then + level = levels[level] + end + if not level then + return + end + if baseFunc then + Clear(self, level) + currentLevel = level.num + if type(baseFunc) == "table" then + if currentLevel == 1 then + local handler = baseFunc.handler + if handler then + local name = tostring(handler) + if not name:find('^table:') and not handler.hideMenuTitle then + name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") + self:AddLine( + 'text', name, + 'isTitle', true + ) + end + end +-- elseif level.parentText then +-- self:AddLine( +-- 'text', level.parentText, +-- 'tooltipTitle', level.parentTooltipTitle, +-- 'tooltipText', level.parentTooltipText, +-- 'tooltipFunc', level.parentTooltipFunc, +-- 'isTitle', true +-- ) + end + self:FeedAceOptionsTable(baseFunc) + if currentLevel == 1 then + self:AddLine( + 'text', CLOSE, + 'tooltipTitle', CLOSE, + 'tooltipText', CLOSE_DESC, + 'closeWhenClicked', true + ) + end + else +-- if level.parentText then +-- self:AddLine( +-- 'text', level.parentText, +-- 'tooltipTitle', level.parentTooltipTitle, +-- 'tooltipText', level.parentTooltipText, +-- 'tooltipFunc', level.parentTooltipFunc, +-- 'isTitle', true +-- ) +-- end + baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value) + end + currentLevel = nil + CheckSize(self, level) + end +end + +function Dewdrop:Refresh(level) + self:argCheck(level, 2, "number", "nil") + if not level then + for k,v in pairs(levels) do + Refresh(self, v) + end + else + Refresh(self, levels[level]) + end +end + +function OpenSlider(self, parent) + if not sliderFrame then + sliderFrame = CreateFrame("Frame", nil, nil) + sliderFrame:SetWidth(100) + sliderFrame:SetHeight(170) + sliderFrame:SetScale(UIParent:GetScale()) + sliderFrame:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG") + if sliderFrame.SetTopLevel then + sliderFrame:SetTopLevel(true) + end + sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + sliderFrame:EnableMouse(true) + sliderFrame:EnableMouseWheel(true) + sliderFrame:Hide() + sliderFrame:SetPoint("CENTER", UIParent, "CENTER") + local slider = CreateFrame("Slider", nil, sliderFrame) + sliderFrame.slider = slider + slider:SetOrientation("VERTICAL") + slider:SetMinMaxValues(0, 1) + slider:SetValueStep(0.000000001) + slider:SetValue(0.5) + slider:SetWidth(16) + slider:SetHeight(128) + slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0) + slider:SetBackdrop(tmp( + 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", + 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", + 'tile', true, + 'edgeSize', 8, + 'tileSize', 8, + 'insets', tmp2( + 'left', 3, + 'right', 3, + 'top', 3, + 'bottom', 3 + ) + )) + local texture = slider:CreateTexture() + slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") + local text = slider:CreateFontString(nil, "ARTWORK") + sliderFrame.topText = text + text:SetFontObject(GameFontGreenSmall) + text:SetText("100%") + text:SetPoint("BOTTOM", slider, "TOP") + local text = slider:CreateFontString(nil, "ARTWORK") + sliderFrame.bottomText = text + text:SetFontObject(GameFontGreenSmall) + text:SetText("0%") + text:SetPoint("TOP", slider, "BOTTOM") + local editBox = CreateFrame("EditBox", nil, sliderFrame) + sliderFrame.currentText = editBox + editBox:SetFontObject(ChatFontNormal) + editBox:SetHeight(13) + editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0) + editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0) + editBox:SetText("50%") + editBox:SetJustifyH("CENTER") + + local width = editBox:GetWidth()/2 + 10 + local left = editBox:CreateTexture(nil, "BACKGROUND") + left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") + left:SetTexCoord(0, width / 256, 0, 1) + left:SetWidth(width) + left:SetHeight(32) + left:SetPoint("LEFT", editBox, "LEFT", -10, 0) + local right = editBox:CreateTexture(nil, "BACKGROUND") + right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") + right:SetTexCoord(1 - width / 256, 1, 0, 1) + right:SetWidth(width) + right:SetHeight(32) + right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) + + local changed = false + local inside = false + slider:SetScript("OnValueChanged", function() + if sliderFrame.changing then + return + end + changed = true + local done = false + if sliderFrame.parent and sliderFrame.parent.sliderFunc then + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step + if sliderFrame.fineStep then + step = sliderFrame.parent.sliderStep or (max - min) / 100 + else + step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 + end + local value = (1 - slider:GetValue()) * (max - min) + min + if step > 0 then + value = math.floor((value - min) / step + 0.5) * step + min + if value > max then + value = max + elseif value < min then + value = min + end + end + if value == sliderFrame.lastValue then + return + end + sliderFrame.lastValue = value + local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value)) + if sliderFrame.parent.fromAceOptions then + text = nil + elseif type(text) == "string" or type(text) == "number" then + sliderFrame.currentText:SetText(text) + done = true + end + end + if not done then + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step + if sliderFrame.fineStep then + step = sliderFrame.parent.sliderStep or (max - min) / 100 + else + step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 + end + local value = (1 - slider:GetValue()) * (max - min) + min + if step > 0 then + value = math.floor((value - min) / step + 0.5) * step + min + if value > max then + value = max + elseif value < min then + value = min + end + end + if sliderFrame.parent.sliderIsPercent then + sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100)) + else + if step < 0.1 then + sliderFrame.currentText:SetText(string.format("%.2f", value)) + elseif step < 1 then + sliderFrame.currentText:SetText(string.format("%.1f", value)) + else + sliderFrame.currentText:SetText(string.format("%.0f", value)) + end + end + end + end) + local function onEnter() + StopCounting(self, sliderFrame.level) + showGameTooltip(sliderFrame.parent) + end + local function onLeave() + GameTooltip:Hide() + end + sliderFrame:SetScript("OnEnter", onEnter) + sliderFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + if changed then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + end + end) + editBox:SetScript("OnEnter", onEnter) + editBox:SetScript("OnLeave", onLeave) + slider:SetScript("OnMouseDown", function() + sliderFrame.mouseDown = true + GameTooltip:Hide() + end) + slider:SetScript("OnMouseUp", function() + sliderFrame.mouseDown = false + if changed--[[ and not inside]] then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + end + if inside then + showGameTooltip(sliderFrame.parent) + end + end) + slider:SetScript("OnEnter", function() + inside = true + StopCounting(self, sliderFrame.level) + showGameTooltip(sliderFrame.parent) + end) + slider:SetScript("OnLeave", function() + inside = false + GameTooltip:Hide() + if changed and not sliderFrame.mouseDown then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + + changed = false + end + end) + sliderFrame:SetScript("OnMouseWheel", function(t, a1) + local arg1 = a1 or arg1 + local up = arg1 > 0 + + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step = sliderFrame.parent.sliderStep or (max - min) / 100 + if step <= 0 then + step = (max - min) / 100 + end + + local value = (1 - slider:GetValue()) * (max - min) + min + if up then + value = value + step + else + value = value - step + end + if value > max then + value = max + elseif value < min then + value = min + end + sliderFrame.fineStep = true + if max<=min then + slider:SetValue(0) + else + slider:SetValue(1 - (value - min) / (max - min)) + end + sliderFrame.fineStep = nil + end) + slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel")) + editBox:SetScript("OnEnterPressed", function(t, a1) + local value = editBox:GetNumber() + + if sliderFrame.parent.sliderIsPercent then + value = value / 100 + end + + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + + if value > max then + value = max + elseif value < min then + value = min + end + sliderFrame.fineStep = true + if max <= min then + slider:SetValue(0) + else + slider:SetValue(1 - (value - min) / (max - min)) + end + sliderFrame.fineStep = nil + + StartCounting(self, sliderFrame.level) + end) + editBox:SetScript("OnEscapePressed", function() + self:Close(sliderFrame.level) + StartCounting(self, sliderFrame.level) + end) + editBox:SetAutoFocus(false) + end + sliderFrame.parent = parent + sliderFrame.level = parent.level.num + 1 + sliderFrame.parentValue = parent.level.value + sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) + sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) + sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) + sliderFrame.currentText:ClearFocus() + sliderFrame.changing = true + if not parent.sliderMin or not parent.sliderMax then + return + end + + if parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + + sliderFrame:SetClampedToScreen(false) + if not parent.sliderValue then + parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 + end + if parent.sliderMax <= parent.sliderMin then + sliderFrame.slider:SetValue(0) + else + sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) + end + sliderFrame.changing = false + sliderFrame.bottomText:SetText(parent.sliderMinText or "0") + sliderFrame.topText:SetText(parent.sliderMaxText or "1") + local text + if parent.sliderFunc and not parent.fromAceOptions then + text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue)) + end + if type(text) == "number" or type(text) == "string" then + sliderFrame.currentText:SetText(text) + elseif parent.sliderIsPercent then + sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) + else + if parent.sliderStep < 0.1 then + sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue)) + elseif parent.sliderStep < 1 then + sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue)) + else + sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue)) + end + end + + + sliderFrame.lastValue = parent.sliderValue + + local level = parent.level + sliderFrame:Show() + sliderFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + local dirty + if level.lastDirection == "RIGHT" then + if sliderFrame:GetRight() > GetScreenWidth() then + level.lastDirection = "LEFT" + dirty = true + end + elseif sliderFrame:GetLeft() < 0 then + level.lastDirection = "RIGHT" + dirty = true + end + if level.lastVDirection == "DOWN" then + if sliderFrame:GetBottom() < 0 then + level.lastVDirection = "UP" + dirty = true + end + elseif sliderFrame:GetTop() > GetScreenWidth() then + level.lastVDirection = "DOWN" + dirty = true + end + if dirty then + sliderFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom() + sliderFrame:ClearAllPoints() + sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end + sliderFrame:SetClampedToScreen(true) +end + +function OpenEditBox(self, parent) + if not editBoxFrame then + editBoxFrame = CreateFrame("Frame", nil, nil) + editBoxFrame:SetWidth(200) + editBoxFrame:SetHeight(40) + editBoxFrame:SetScale(UIParent:GetScale()) + editBoxFrame:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG") + if editBoxFrame.SetTopLevel then + editBoxFrame:SetTopLevel(true) + end + editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + editBoxFrame:EnableMouse(true) + editBoxFrame:EnableMouseWheel(true) + editBoxFrame:Hide() + editBoxFrame:SetPoint("CENTER", UIParent, "CENTER") + + local editBox = CreateFrame("EditBox", nil, editBoxFrame) + editBoxFrame.editBox = editBox + editBox:SetFontObject(ChatFontNormal) + editBox:SetWidth(160) + editBox:SetHeight(13) + editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0) + + local left = editBox:CreateTexture(nil, "BACKGROUND") + left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") + left:SetTexCoord(0, 100 / 256, 0, 1) + left:SetWidth(100) + left:SetHeight(32) + left:SetPoint("LEFT", editBox, "LEFT", -10, 0) + local right = editBox:CreateTexture(nil, "BACKGROUND") + right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") + right:SetTexCoord(156/256, 1, 0, 1) + right:SetWidth(100) + right:SetHeight(32) + right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) + + editBox:SetScript("OnEnterPressed", function() + if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then + local t = editBox.realText or editBox:GetText() or "" + local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t)) + if not result then + UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) + return + end + end + if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then + local t + if editBox.realText ~= "NONE" then + t = editBox.realText or editBox:GetText() or "" + end + editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t)) + end + self:Close(editBoxFrame.level) + for i = 1, editBoxFrame.level - 1 do + Refresh(self, levels[i]) + end + StartCounting(self, editBoxFrame.level-1) + end) + editBox:SetScript("OnEscapePressed", function() + self:Close(editBoxFrame.level) + StartCounting(self, editBoxFrame.level-1) + end) + editBox:SetScript("OnReceiveDrag", function(this) + if GetCursorInfo then + local type, alpha, bravo = GetCursorInfo() + local text + if type == "spell" then + text = GetSpellName(alpha, bravo) + elseif type == "item" then + text = bravo + end + if not text then + return + end + ClearCursor() + editBox:SetText(text) + end + end) + local changing = false + local skipNext = false + + function editBox:SpecialSetText(text) + local oldText = editBox:GetText() or "" + if not text then + text = "" + end + if text ~= oldText then + changing = true + self:SetText(tostring(text)) + changing = false + skipNext = true + end + end + + editBox:SetScript("OnTextChanged", function() + if skipNext then + skipNext = false + elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then + local t + if editBox.realText ~= "NONE" then + t = editBox.realText or editBox:GetText() or "" + end + local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t)) + if text then + editBox:SpecialSetText(text) + end + end + end) + editBoxFrame:SetScript("OnEnter", function() + StopCounting(self, editBoxFrame.level) + showGameTooltip(editBoxFrame.parent) + end) + editBoxFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + editBox:SetScript("OnEnter", function() + StopCounting(self, editBoxFrame.level) + showGameTooltip(editBoxFrame.parent) + end) + editBox:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + editBoxFrame:SetScript("OnKeyDown", function(this, a1) + if not editBox.keybinding then + return + end + local arg1 = a1 or arg1 + local screenshotKey = GetBindingKey("SCREENSHOT") + if screenshotKey and arg1 == screenshotKey then + Screenshot() + return + end + + if arg1 == "LeftButton" then + arg1 = "BUTTON1" + elseif arg1 == "RightButton" then + arg1 = "BUTTON2" + elseif arg1 == "MiddleButton" then + arg1 = "BUTTON3" + elseif arg1 == "Button4" then + arg1 = "BUTTON4" + elseif arg1 == "Button5" then + arg1 = "BUTTON5" + end + if arg1 == "UNKNOWN" then + return + elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then + return + elseif arg1 == "ENTER" then + if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then + return editBox:GetScript("OnEscapePressed")() + elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then + return editBox:GetScript("OnEscapePressed")() + else + return editBox:GetScript("OnEnterPressed")() + end + elseif arg1 == "ESCAPE" then + if editBox.realText == "NONE" then + return editBox:GetScript("OnEscapePressed")() + else + editBox:SpecialSetText(NONE or "NONE") + editBox.realText = "NONE" + return + end + elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then + return + elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then + return + end + local s = GetBindingText(arg1, "KEY_") + if s == "BUTTON1" then + s = KEY_BUTTON1 + elseif s == "BUTTON2" then + s = KEY_BUTTON2 + end + local real = arg1 + if IsShiftKeyDown() then + s = "Shift-" .. s + real = "SHIFT-" .. real + end + if IsControlKeyDown() then + s = "Ctrl-" .. s + real = "CTRL-" .. real + end + if IsAltKeyDown() then + s = "Alt-" .. s + real = "ALT-" .. real + end + if editBox:GetText() ~= s then + editBox:SpecialSetText("-") + editBox:SpecialSetText(s) + editBox.realText = real + return editBox:GetScript("OnTextChanged")() + end + end) + editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) + editBox:SetScript("OnMouseDown", function(this, ...) + if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then + return editBox:GetScript("OnReceiveDrag")(this, ...) + end + return editBoxFrame:GetScript("OnKeyDown")(this, ...) + end) + editBoxFrame:SetScript("OnMouseWheel", function(t, a1) + local arg1 = a1 or arg1 + local up = arg1 > 0 + arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" + return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1) + end) + editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel")) + end + editBoxFrame.parent = parent + editBoxFrame.level = parent.level.num + 1 + editBoxFrame.parentValue = parent.level.value + editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) + editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1) + editBoxFrame.editBox.realText = nil + editBoxFrame:SetClampedToScreen(false) + + editBoxFrame.editBox:SpecialSetText("") + if parent.editBoxIsKeybinding then + local s = parent.editBoxText + if s == "" then + s = "NONE" + end + editBoxFrame.editBox.realText = s + if s and s ~= "NONE" then + local alpha,bravo = s:match("^(.+)%-(.+)$") + if not bravo then + alpha = nil + bravo = s + end + bravo = GetBindingText(bravo, "KEY_") + if alpha then + editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) + else + editBoxFrame.editBox:SpecialSetText(bravo) + end + else + editBoxFrame.editBox:SpecialSetText(NONE or "NONE") + end + else + editBoxFrame.editBox:SpecialSetText(parent.editBoxText) + end + + editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding + editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly + editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept + editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) + editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) + + if parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + + local level = parent.level + editBoxFrame:Show() + editBoxFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + local dirty + if level.lastDirection == "RIGHT" then + if editBoxFrame:GetRight() > GetScreenWidth() then + level.lastDirection = "LEFT" + dirty = true + end + elseif editBoxFrame:GetLeft() < 0 then + level.lastDirection = "RIGHT" + dirty = true + end + if level.lastVDirection == "DOWN" then + if editBoxFrame:GetBottom() < 0 then + level.lastVDirection = "UP" + dirty = true + end + elseif editBoxFrame:GetTop() > GetScreenWidth() then + level.lastVDirection = "DOWN" + dirty = true + end + if dirty then + editBoxFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom() + editBoxFrame:ClearAllPoints() + editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end + editBoxFrame:SetClampedToScreen(true) +end + +function Dewdrop:EncodeKeybinding(text) + if text == nil or text == "NONE" then + return nil + end + text = tostring(text):upper() + local shift, ctrl, alt + local modifier + while true do + if text == "-" then + break + end + modifier, text = strsplit('-', text, 2) + if text then + if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then + return false + end + if modifier == "SHIFT" then + if shift then + return false + end + shift = true + end + if modifier == "CTRL" then + if ctrl then + return false + end + ctrl = true + end + if modifier == "ALT" then + if alt then + return false + end + alt = true + end + else + text = modifier + break + end + end + if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then + return false + end + local s = GetBindingText(text, "KEY_") + if s == "BUTTON1" then + s = KEY_BUTTON1 + elseif s == "BUTTON2" then + s = KEY_BUTTON2 + end + if shift then + s = "Shift-" .. s + end + if ctrl then + s = "Ctrl-" .. s + end + if alt then + s = "Alt-" .. s + end + return s +end + +function Dewdrop:IsOpen(parent) + self:argCheck(parent, 2, "table", "string", "nil") + return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent()) +end + +function Dewdrop:GetOpenedParent() + return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent()) +end + +function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY) + self:Close(level) + if DewdropLib then + local d = DewdropLib:GetInstance('1.0') + local ret, val = pcall(d, IsOpen, d) + if ret and val then + DewdropLib:GetInstance('1.0'):Close() + end + end + if type(parent) == "table" then + parent:GetCenter() + end + local frame = AcquireLevel(self, level) + if level == 1 then + frame.lastDirection = "RIGHT" + frame.lastVDirection = "DOWN" + else + frame.lastDirection = levels[level - 1].lastDirection + frame.lastVDirection = levels[level - 1].lastVDirection + end + frame:SetFrameStrata("FULLSCREEN_DIALOG") + frame:ClearAllPoints() + frame.parent = parent + frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0) + frame:Show() + if level == 1 then + baseFunc = func + end + levels[level].value = value +-- levels[level].parentText = parent.text and parent.text:GetText() or nil +-- levels[level].parentTooltipTitle = parent.tooltipTitle +-- levels[level].parentTooltipText = parent.tooltipText +-- levels[level].parentTooltipFunc = parent.tooltipFunc + if type(parent) == "table" and parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + relativePoint = relativePoint or point + Refresh(self, levels[level]) + if point or (cursorX and cursorY) then + frame:ClearAllPoints() + if cursorX and cursorY then + local curX, curY = GetScaledCursorPosition() + if curY < GetScreenHeight() / 2 then + point, relativePoint = "BOTTOM", "BOTTOM" + else + point, relativePoint = "TOP", "TOP" + end + if curX < GetScreenWidth() / 2 then + point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT" + else + point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint) + if cursorX and cursorY then + local left = frame:GetLeft() + local width = frame:GetWidth() + local bottom = frame:GetBottom() + local height = frame:GetHeight() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "BOTTOM" or point == "TOP" then + if curX < GetScreenWidth() / 2 then + point = point .. "LEFT" + else + point = point .. "RIGHT" + end + elseif point == "CENTER" then + if curX < GetScreenWidth() / 2 then + point = "LEFT" + else + point = "RIGHT" + end + end + local xOffset, yOffset = 0, 0 + if curY > GetScreenHeight() / 2 then + yOffset = -height + end + if curX > GetScreenWidth() / 2 then + xOffset = -width + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset) + if level == 1 then + frame.lastDirection = "RIGHT" + end + elseif cursorX then + local left = frame:GetLeft() + local width = frame:GetWidth() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "BOTTOM" or point == "TOP" then + if curX < GetScreenWidth() / 2 then + point = point .. "LEFT" + else + point = point .. "RIGHT" + end + elseif point == "CENTER" then + if curX < GetScreenWidth() / 2 then + point = "LEFT" + else + point = "RIGHT" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0) + if level == 1 then + frame.lastDirection = "RIGHT" + end + elseif cursorY then + local bottom = frame:GetBottom() + local height = frame:GetHeight() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "LEFT" or point == "RIGHT" then + if curX < GetScreenHeight() / 2 then + point = point .. "BOTTOM" + else + point = point .. "TOP" + end + elseif point == "CENTER" then + if curX < GetScreenHeight() / 2 then + point = "BOTTOM" + else + point = "TOP" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2) + if level == 1 then + frame.lastDirection = "DOWN" + end + end + if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then + if frame:GetBottom() < 0 then + local point, parent, relativePoint, x, y = frame:GetPoint(1) + local change = GetScreenHeight() - frame:GetTop() + local otherChange = -frame:GetBottom() + if otherChange < change then + change = otherChange + end + frame:SetPoint(point, parent, relativePoint, x, y + change) + elseif frame:GetTop() > GetScreenHeight() then + local point, parent, relativePoint, x, y = frame:GetPoint(1) + local change = GetScreenHeight() - frame:GetTop() + local otherChange = -frame:GetBottom() + if otherChange < change then + change = otherChange + end + frame:SetPoint(point, parent, relativePoint, x, y + change) + end + end + end + CheckDualMonitor(self, frame) + frame:SetClampedToScreen(true) + frame:SetClampedToScreen(false) + StartCounting(self, level) +end + +function Dewdrop:IsRegistered(parent) + self:argCheck(parent, 2, "table", "string") + return not not self.registry[parent] +end + +function Dewdrop:Register(parent, ...) + self:argCheck(parent, 2, "table", "string") + if self.registry[parent] then + self:Unregister(parent) + end + local info = new(...) + if type(info.children) == "table" then + local err, position = validateOptions(info.children) + + if err then + if position then + Dewdrop:error(position .. ": " .. err) + else + Dewdrop:error(err) + end + end + end + self.registry[parent] = info + if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then + if parent:HasScript("OnMouseUp") then + local script = parent:GetScript("OnMouseUp") + parent:SetScript("OnMouseUp", function(this, ...) + if script then + script(this, ...) + end + if arg1 == "RightButton" and self.registry[parent] then + if self:IsOpen(parent) then + self:Close() + else + self:Open(parent) + end + end + end) + end + if parent:HasScript("OnMouseDown") then + local script = parent:GetScript("OnMouseDown") + parent:SetScript("OnMouseDown", function(this, ...) + if script then + script(this, ...) + end + if self.registry[parent] then + self:Close() + end + end) + end + end + self.onceRegistered[parent] = true +end + +function Dewdrop:Unregister(parent) + self:argCheck(parent, 2, "table", "string") + self.registry[parent] = nil +end + +function Dewdrop:Open(parent, ...) + self:argCheck(parent, 2, "table", "string") + local info + local k1 = ... + if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then + info = tmp(select(2, ...)) + for k,v in pairs(self.registry[k1]) do + if info[k] == nil then + info[k] = v + end + end + else + info = tmp(...) + if self.registry[parent] then + for k,v in pairs(self.registry[parent]) do + if info[k] == nil then + info[k] = v + end + end + end + end + local point = info.point + local relativePoint = info.relativePoint + local cursorX = info.cursorX + local cursorY = info.cursorY + if type(point) == "function" then + local b + point, b = point(parent) + if b then + relativePoint = b + end + end + if type(relativePoint) == "function" then + relativePoint = relativePoint(parent) + end + Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY) +end + +function Clear(self, level) + if level then + if level.buttons then + for i = #level.buttons, 1, -1 do + ReleaseButton(self, level, i) + end + end + end +end + +function Dewdrop:Close(level) + if DropDownList1:IsShown() then + DropDownList1:Hide() + end + if DewdropLib then + local d = DewdropLib:GetInstance('1.0') + local ret, val = pcall(d, IsOpen, d) + if ret and val then + DewdropLib:GetInstance('1.0'):Close() + end + end + self:argCheck(level, 2, "number", "nil") + if not level then + level = 1 + end + if level == 1 and levels[level] then + levels[level].parented = false + end + if level > 1 and levels[level-1].buttons then + local buttons = levels[level-1].buttons + for _,button in ipairs(buttons) do +-- button.arrow:SetWidth(16) +-- button.arrow:SetHeight(16) + button.selected = nil + button.highlight:Hide() +-- button.arrow:SetVertexColor(1, 1, 1) + end + end + if sliderFrame and sliderFrame.level >= level then + sliderFrame:Hide() + end + if editBoxFrame and editBoxFrame.level >= level then + editBoxFrame:Hide() + end + for i = level, #levels do + Clear(self, levels[level]) + levels[i]:Hide() + levels[i]:ClearAllPoints() + levels[i]:SetPoint("CENTER", UIParent, "CENTER") + levels[i].value = nil + end +end + +function Dewdrop:AddSeparator(level) + level = levels[level or currentLevel] + if not level or not level.buttons then return; end + + local prevbutton = level.buttons[#level.buttons] + if not prevbutton then return; end + + if prevbutton.disabled and prevbutton.text:GetText() == "" then + return + end + self:AddLine("text", "", "disabled", true) +end + +function Dewdrop:AddLine(...) + local info = tmp(...) + local level = info.level or currentLevel + info.level = nil + local button = AcquireButton(self, level) + if not next(info) then + info.disabled = true + end + button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure) + button.isTitle = info.isTitle + button.notClickable = info.notClickable + if button.isTitle then + button.text:SetFontObject(GameFontNormalSmall) + elseif button.notClickable then + button.text:SetFontObject(GameFontHighlightSmall) + elseif button.disabled then + button.text:SetFontObject(GameFontDisableSmall) + else + button.text:SetFontObject(GameFontHighlightSmall) + end + if info.disabled then + button.arrow:SetDesaturated(true) + button.check:SetDesaturated(true) + else + button.arrow:SetDesaturated(false) + button.check:SetDesaturated(false) + end + if info.textR and info.textG and info.textB then + button.textR = info.textR + button.textG = info.textG + button.textB = info.textB + button.text:SetTextColor(button.textR, button.textG, button.textB) + else + button.text:SetTextColor(button.text:GetFontObject():GetTextColor()) + end + button.notCheckable = info.notCheckable + button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0) + button.checked = not info.notCheckable and info.checked + button.mouseoverUnderline = info.mouseoverUnderline + button.isRadio = not info.notCheckable and info.isRadio + if info.isRadio then + button.check:Show() + button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") + if button.checked then + button.check:SetTexCoord(0.25, 0.5, 0, 1) + button.check:SetVertexColor(1, 1, 1, 1) + else + button.check:SetTexCoord(0, 0.25, 0, 1) + button.check:SetVertexColor(1, 1, 1, 0.5) + end + button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") + button.check:SetWidth(16) + button.check:SetHeight(16) + elseif info.icon then + button.check:Show() + button.check:SetTexture(info.icon) + if info.iconWidth and info.iconHeight then + button.check:SetWidth(info.iconWidth) + button.check:SetHeight(info.iconHeight) + else + button.check:SetWidth(16) + button.check:SetHeight(16) + end + if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then + button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) + elseif info.icon:find("^Interface\\Icons\\") then + button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) + else + button.check:SetTexCoord(0, 1, 0, 1) + end + button.check:SetVertexColor(1, 1, 1, 1) + else + if button.checked then + if info.checkIcon then + button.check:SetWidth(16) + button.check:SetHeight(16) + button.check:SetTexture(info.checkIcon) + if info.checkIcon:find("^Interface\\Icons\\") then + button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) + else + button.check:SetTexCoord(0, 1, 0, 1) + end + else + button.check:SetWidth(24) + button.check:SetHeight(24) + button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") + button.check:SetTexCoord(0, 1, 0, 1) + end + button.check:SetVertexColor(1, 1, 1, 1) + else + button.check:SetVertexColor(1, 1, 1, 0) + end + end + if not button.disabled then + button.func = info.func + button.secure = info.secure + end + button.hasColorSwatch = info.hasColorSwatch + if button.hasColorSwatch then + button.colorSwatch:Show() + button.colorSwatch.texture:Show() + button.r = info.r or 1 + button.g = info.g or 1 + button.b = info.b or 1 + button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b) + button.checked = false + button.func = nil + button.colorFunc = info.colorFunc + local i = 1 + while true do + local k = "colorArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.hasOpacity = info.hasOpacity + button.opacity = info.opacity or 1 + else + button.colorSwatch:Hide() + button.colorSwatch.texture:Hide() + end + button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow + if button.hasArrow then + button.arrow:SetAlpha(1) + if info.hasSlider then + button.hasSlider = true + button.sliderMin = info.sliderMin or 0 + button.sliderMax = info.sliderMax or 1 + button.sliderStep = info.sliderStep or 0 + button.sliderBigStep = info.sliderBigStep or button.sliderStep + if button.sliderBigStep < button.sliderStep then + button.sliderBigStep = button.sliderStep + end + button.sliderIsPercent = info.sliderIsPercent and true or false + button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin + button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax + button.sliderFunc = info.sliderFunc + button.sliderValue = info.sliderValue + button.fromAceOptions = info.fromAceOptions + local i = 1 + while true do + local k = "sliderArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + elseif info.hasEditBox then + button.hasEditBox = true + button.editBoxText = info.editBoxText or "" + button.editBoxFunc = info.editBoxFunc + local i = 1 + while true do + local k = "editBoxArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxChangeFunc = info.editBoxChangeFunc + local i = 1 + while true do + local k = "editBoxChangeArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxValidateFunc = info.editBoxValidateFunc + local i = 1 + while true do + local k = "editBoxValidateArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxIsKeybinding = info.editBoxIsKeybinding + button.editBoxKeybindingOnly = info.editBoxKeybindingOnly + button.editBoxKeybindingExcept = info.editBoxKeybindingExcept + else + button.value = info.value + local l = levels[level+1] + if l and info.value == l.value then +-- button.arrow:SetWidth(24) +-- button.arrow:SetHeight(24) + button.selected = true + button.highlight:Show() + end + end + else + button.arrow:SetAlpha(0) + end + local i = 1 + while true do + local k = "arg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.closeWhenClicked = info.closeWhenClicked + button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10 + local font,_ = button.text:GetFont() + button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight) + button:SetHeight(button.textHeight + 6) + button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT") + button.text:SetJustifyH(info.justifyH or "LEFT") + button.text:SetText(info.text) + button.tooltipTitle = info.tooltipTitle + button.tooltipText = info.tooltipText + button.tooltipFunc = info.tooltipFunc + local i = 1 + while true do + local k = "tooltipArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then + button.tooltipTitle = info.text + end + if type(button.func) == "string" then + if type(button.arg1) ~= "table" then + self:error("Cannot call method %q on a non-table", button.func) + end + if type(button.arg1[button.func]) ~= "function" then + self:error("Method %q nonexistant.", button.func) + end + end +end + +function Dewdrop:InjectAceOptionsTable(handler, options) + self:argCheck(handler, 2, "table") + self:argCheck(options, 3, "table") + if tostring(options.type):lower() ~= "group" then + self:error('Cannot inject into options table argument #3 if its type is not "group"') + end + if options.handler ~= nil and options.handler ~= handler then + self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") + end + options.handler = handler + local class = handler.class + if not AceLibrary:HasInstance("AceOO-2.0") or not class then + if Rock then + -- possible Rock object + for mixin in Rock:IterateObjectMixins(handler) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + else + -- Ace2 object + while class and class ~= AceLibrary("AceOO-2.0").Class do + if type(class.GetAceOptionsDataTable) == "function" then + local t = class:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + local mixins = class.mixins + if mixins then + for mixin in pairs(mixins) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + class = class.super + end + end + return options +end + +function Dewdrop:OnTooltipHide() + if lastSetFont then + if lastSetFont == normalFont then + lastSetFont = nil + return + end + fillRegionTmp(GameTooltip:GetRegions()) + for i,v in ipairs(regionTmp) do + if v.GetFont then + local font,size,outline = v:GetFont() + if font == lastSetFont then + v:SetFont(normalFont, size, outline) + end + end + regionTmp[i] = nil + end + lastSetFont = nil + end +end + +local function activate(self, oldLib, oldDeactivate) + Dewdrop = self + if oldLib and oldLib.registry then + self.registry = oldLib.registry + self.onceRegistered = oldLib.onceRegistered + else + self.registry = {} + self.onceRegistered = {} + + local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown") + local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp") + local oldX, oldY, clickTime + WorldFrame:SetScript("OnMouseDown", function(this, ...) + oldX,oldY = GetCursorPosition() + clickTime = GetTime() + if WorldFrame_OnMouseDown then + WorldFrame_OnMouseDown(this, ...) + end + end) + + WorldFrame:SetScript("OnMouseUp", function(this, ...) + local x,y = GetCursorPosition() + if not oldX or not oldY or not x or not y or not clickTime then + self:Close() + if WorldFrame_OnMouseUp then + WorldFrame_OnMouseUp(this, ...) + end + return + end + local d = math.abs(x - oldX) + math.abs(y - oldY) + if d <= 5 and GetTime() - clickTime < 0.5 then + self:Close() + end + if WorldFrame_OnMouseUp then + WorldFrame_OnMouseUp(this, ...) + end + end) + + hooksecurefunc(DropDownList1, "Show", function() + if levels[1] and levels[1]:IsVisible() then + self:Close() + end + end) + + hooksecurefunc("HideDropDownMenu", function() + if levels[1] and levels[1]:IsVisible() then + self:Close() + end + end) + + hooksecurefunc("CloseDropDownMenus", function() + if levels[1] and levels[1]:IsVisible() then + local stack = debugstack() + if not stack:find("`TargetFrame_OnHide'") then + self:Close() + end + end + end) + end + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("PLAYER_REGEN_ENABLED") + self.frame:RegisterEvent("PLAYER_REGEN_DISABLED") + self.frame:Hide() + self.frame:SetScript("OnEvent", function(this, event) + this:Show() + if event=="PLAYER_REGEN_ENABLED" then -- track combat state for secure frame operations + self.combat = false + elseif event=="PLAYER_REGEN_DISABLED" then + self.combat = true + end + end) + self.frame:SetScript("OnUpdate", function(this) + this:Hide() + self:Refresh(1) + end) + self.hookedTooltip = true + if not oldLib or not oldLib.hookedTooltip then + local OnTooltipHide = GameTooltip:GetScript("OnHide") + GameTooltip:SetScript("OnHide", function(this, ...) + if OnTooltipHide then + OnTooltipHide(this, ...) + end + if type(self.OnTooltipHide) == "function" then + self:OnTooltipHide() + end + end) + end + levels = {} + buttons = {} + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +local function external(lib, major, instance) + if major == "SharedMedia-1.0" then + SharedMedia = instance + end +end + +AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/modules/ReAction_Action/ReAction_Action.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/ReAction_Action/ReAction_Action.lua Mon Mar 17 18:24:53 2008 +0000 @@ -11,34 +11,22 @@ local ReAction = ReAction local L = ReAction.L local _G = _G -local AceOO = AceLibrary("AceOO-2.0") local CreateFrame = CreateFrame local print = ReAction.print -- module declaration local moduleID = "Action" -local module = ReAction:NewModule( moduleID, - "AceEvent-2.0" -) - --- --- action button class declaration --- -local BtnClass = AceOO.Class() -local Button = BtnClass.prototype -module.BtnClass = BtnClass - - +local module = ReAction:NewModule( moduleID ) -- module methods function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", + self.db = ReAction.db:RegisterNamespace( moduleID, { - buttons = { } + profile = { + buttons = { } + } } ) - self.buttons = { } end @@ -48,9 +36,6 @@ function module:OnDisable() end -function module:OnProfileEnable() -end - function module:ApplyToBar(bar) self:RefreshBar(bar) end @@ -136,7 +121,7 @@ name = L["New Action Bar"], desc = L["Create a new bar of standard action buttons"], func = function() - ReAction:GetModule("Bar"):CreateBar() + ReAction:CreateBar() end, disabled = InCombatLockdown, } @@ -194,9 +179,11 @@ --- button class methods -function Button:init( bar, idx, config ) - BtnClass.super.prototype.init(self) + +------ Button class ------ +local Button = { } + +local function Constructor( self, bar, idx, config ) self.bar, self.idx, self.config = bar, idx, config local barFrame = bar:GetFrame() @@ -225,8 +212,8 @@ f:Hide() f:SetParent(UIParent) f:ClearAllPoints() - if self.config.name then - _G[self.config.name] = nil + if self.name then + _G[self.name] = nil end ActionIDList[self.config.actionID] = nil self.frame = nil @@ -249,3 +236,16 @@ function Button:GetActionID() return self.config.actionID end + + +-- export as a class-factory to module +module.BtnClass = { + new = function(self, ...) + local x = { } + for k,v in pairs(Button) do + x[k] = v + end + Constructor(x, ...) + return x + end +}
--- a/modules/ReAction_ConfigUI/ReAction_ConfigUI.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/ReAction_ConfigUI/ReAction_ConfigUI.lua Mon Mar 17 18:24:53 2008 +0000 @@ -30,13 +30,11 @@ local Dewdrop = AceLibrary("Dewdrop-2.0") local print = ReAction.print local InCombatLockdown = InCombatLockdown -local BarModule = ReAction:GetModule("Bar") -- module declaration local moduleID = "ConfigUI" local module = ReAction:NewModule( moduleID, - "AceConsole-2.0", -- temp - "AceEvent-2.0" + "AceEvent-3.0" -- mixins go here ) @@ -97,17 +95,11 @@ -- module methods function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", + self.db = ReAction.db:RegisterNamespace( moduleID, { - + profile = { } } ) - - -- temp: this will be moved to main ReAction.lua later in a more efficient AceConsole-less implementation - -- that can load the ConfigUI module on demand - -- NOTE: this inserts an 'about' command that we don't want - self:RegisterChatCommand( {L["/reaction"], L["/rxn"]}, self.globalOptions, "REACTION" ) end function module:OnEnable() @@ -136,8 +128,8 @@ end function module:SetConfigMode( mode ) - BarModule:CallMethodOnAllBars("ShowControls",mode) - ReAction:CallMethodOnAllModules("ApplyConfigMode",mode,BarModule.bars) + ReAction:CallMethodOnAllBars("ShowControls",mode) + ReAction:CallMethodOnAllModules("ApplyConfigMode",mode,ReAction.bars) self.configMode = mode end @@ -161,11 +153,17 @@ module:RefreshConfig() end +local function SafeCall(module, method, ...) + if module and type(module[method]) == "function" then + return module[method](...) + end +end + function module:RefreshOptions() local opts = self.configOptions.args - for _, m in ReAction:IterateModulesWithMethod("GetGlobalOptions") do - local o = m:GetGlobalOptions(self) + for _, m in ReAction:IterateModules() do + local o = SafeCall(m,"GetGlobalOptions",self) if o then for k, v in pairs(o) do opts.global.args[k] = v @@ -173,8 +171,8 @@ end end - for _, m in ReAction:IterateModulesWithMethod("GetGlobalBarOptions") do - local o = m:GetGlobalBarOptions(self) + for _, m in ReAction:IterateModules() do + local o = SafeCall(m,"GetGlobalBarOptions",self) if o then for k, v in pairs(o) do opts.bar.args[k] = v @@ -182,8 +180,8 @@ end end - for _, m in ReAction:IterateModulesWithMethod("GetModuleOptions") do - local o = m:GetModuleOptions(self) + for _, m in ReAction:IterateModules() do + local o = SafeCall(m,"GetModuleOptions",self) if o then for k, v in pairs(o) do opts.module.args[k] = v @@ -192,7 +190,7 @@ end local barOpts = opts.bar.args - for name, bar in pairs(BarModule.bars) do + for name, bar in pairs(ReAction.bars) do if bar then if barOpts[name] == nil then barOpts[name] = { @@ -200,14 +198,28 @@ name = name, desc = name, handler = bar, - args = { } + args = { + delete = { + type = "execute", + name = L["Delete Bar"], + desc = L["Remove the bar from the current profile"], + func = function() ReAction:EraseBar(bar); self:RefreshConfig() end + }, + rename = { + type = "text", + name = L["Rename Bar"], + desc = L["Set a name for the bar"], + get = "GetName", + set = function(name) ReAction:RenameBar(bar,name); self:RefreshConfig() end + } + } } end if bar.modConfigOpts == nil then bar.modConfigOpts = { } end - for _, m in ReAction:IterateModulesWithMethod("GetBarConfigOptions") do - local o = m:GetBarConfigOptions(bar,self) + for _, m in ReAction:IterateModules() do + local o = SafeCall(m,"GetBarConfigOptions",bar,self) if o then for k, v in pairs(o) do barOpts[name].args[k] = v @@ -218,7 +230,7 @@ end -- remove obsolete bar tables for name, opt in pairs(barOpts) do - if opt.type == "group" and BarModule.bars[name] == nil then + if opt.type == "group" and ReAction.bars[name] == nil then barOpts[name] = nil end end @@ -262,7 +274,7 @@ -- Bar config overlay -- -- import some of these for small OnUpdate performance boost -local Bar = BarModule.BarClass.prototype +local Bar = ReAction.Bar.prototype local GetSize = Bar.GetSize local GetButtonSize = Bar.GetButtonSize local GetButtonGrid = Bar.GetButtonGrid @@ -280,7 +292,7 @@ local point, relativeTo, relativePoint, x, y = f:GetPoint(1) relativeTo = relativeTo or f:GetParent() local anchorTo - for name, b in pairs(BarModule.bars) do + for name, b in pairs(ReAction.bars) do if b then if b:GetFrame() == relativeTo then anchorTo = name @@ -534,8 +546,8 @@ function() -- add bar type and status information to name local name = bar.name - for _, m in ReAction:IterateModulesWithMethod("GetBarNameModifier") do - local suffix = m:GetBarNameModifier(bar) + for _, m in ReAction:IterateModules() do + local suffix = SafeCall(m,"GetBarNameModifier",bar) if suffix then name = format("%s %s",name,suffix) end @@ -584,16 +596,26 @@ func = function() module:OpenConfig(self) end, disabled = InCombatLockdown, order = 1 - } + }, + delete = { + type = "execute", + name = L["Delete Bar"], + desc = L["Remove the bar from the current profile"], + func = function() ReAction:EraseBar(self) end, + order = 2 + }, } } end if self.modMenuOpts == nil then self.modMenuOpts = { } end - for _, m in ReAction:IterateModulesWithMethod("GetBarMenuOptions") do - for k, v in pairs(m:GetBarMenuOptions(self, module)) do - self.menuOpts.args[k] = v + for _, m in ReAction:IterateModules() do + local opts = SafeCall(m,"GetBarMenuOptions",self,module) + if opts then + for k, v in pairs(opts) do + self.menuOpts.args[k] = v + end end end Dewdrop:Open(self.controlFrame, "children", self.menuOpts, "cursorX", true, "cursorY", true)
--- a/modules/ReAction_ConfigUI/ReAction_ConfigUI.xml Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/ReAction_ConfigUI/ReAction_ConfigUI.xml Mon Mar 17 18:24:53 2008 +0000 @@ -2,7 +2,11 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> + <Script file="lib\AceLibrary\AceLibrary.lua"/> + <Script file="lib\AceOO-2.0\AceOO-2.0.lua"/> <Script file="lib\Waterfall-1.0\Waterfall-1.0.lua"/> + <Script file="lib\Dewdrop-2.0\Dewdrop-2.0.lua"/> + <Script file="ReAction_ConfigUI.lua"/> </Ui> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,856 @@ +--[[ +Name: AceLibrary +Revision: $Rev: 49421 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Iriel (iriel@vigilance-committee.org) + Tekkub (tekkub@gmail.com) + Revision: $Rev: 49421 $ +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceLibrary +SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary +Description: Versioning library to handle other library instances, upgrading, + and proper access. + It also provides a base for libraries to work off of, providing + proper error tools. It is handy because all the errors occur in the + file that called it, not in the library file itself. +Dependencies: None +License: LGPL v2.1 +]] + +local ACELIBRARY_MAJOR = "AceLibrary" +local ACELIBRARY_MINOR = "$Revision: 49421 $" + +local _G = getfenv(0) +local previous = _G[ACELIBRARY_MAJOR] +if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end + +do + -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info + -- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke + local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! + local LibStub = _G[LIBSTUB_MAJOR] + + if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) + end +end +local LibStub = _G.LibStub + +-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but +-- disabled in the addon screen, set this to true. +local DONT_ENABLE_LIBRARIES = nil + +local function safecall(func,...) + local success, err = pcall(func,...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end +end + +local WoW22 = false +if type(GetBuildInfo) == "function" then + local success, buildinfo = pcall(GetBuildInfo) + if success and type(buildinfo) == "string" then + local num = tonumber(buildinfo:match("^(%d+%.%d+)")) + if num and num >= 2.2 then + WoW22 = true + end + end +end + +-- @table AceLibrary +-- @brief System to handle all versioning of libraries. +local AceLibrary = {} +local AceLibrary_mt = {} +setmetatable(AceLibrary, AceLibrary_mt) + +local function error(self, message, ...) + if type(self) ~= "table" then + return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2) + end + + local stack = debugstack() + if not message then + local second = stack:match("\n(.-)\n") + message = "error raised! " .. second + else + local arg = { ... } -- not worried about table creation, as errors don't happen often + + for i = 1, #arg do + arg[i] = tostring(arg[i]) + end + for i = 1, 10 do + table.insert(arg, "nil") + end + message = message:format(unpack(arg)) + end + + if getmetatable(self) and getmetatable(self).__tostring then + message = ("%s: %s"):format(tostring(self), message) + elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then + message = ("%s: %s"):format(self:GetLibraryVersion(), message) + elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then + message = ("%s: %s"):format(self.class:GetLibraryVersion(), message) + end + + local first = stack:gsub("\n.*", "") + local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1") + file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + + + local i = 0 + for s in stack:gmatch("\n([^\n]*)") do + i = i + 1 + if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then + file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1") + file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + break + end + end + local j = 0 + for s in stack:gmatch("\n([^\n]*)") do + j = j + 1 + if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then + return _G.error(message, j+1) + end + end + return _G.error(message, 2) +end + +local assert +if not WoW22 then + function assert(self, condition, message, ...) + if not condition then + if not message then + local stack = debugstack() + local second = stack:match("\n(.-)\n") + message = "assertion failed! " .. second + end + return error(self, message, ...) + end + return condition + end +end + +local type = type +local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5) + if type(num) ~= "number" then + return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num)) + elseif type(kind) ~= "string" then + return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) + end + arg = type(arg) + if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then + local stack = debugstack() + local func = stack:match("`argCheck'.-([`<].-['>])") + if not func then + func = stack:match("([`<].-['>])") + end + if kind5 then + return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg) + elseif kind4 then + return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg) + elseif kind3 then + return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg) + elseif kind2 then + return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg) + else + return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg) + end + end +end + +local pcall +do + local function check(self, ret, ...) + if not ret then + local s = ... + return error(self, (s:gsub(".-%.lua:%d-: ", ""))) + else + return ... + end + end + + function pcall(self, func, ...) + return check(self, _G.pcall(func, ...)) + end +end + +local recurse = {} +local function addToPositions(t, major) + if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then + rawset(t, recurse, true) + AceLibrary.positions[t] = major + for k,v in pairs(t) do + if type(v) == "table" and not rawget(v, recurse) then + addToPositions(v, major) + end + if type(k) == "table" and not rawget(k, recurse) then + addToPositions(k, major) + end + end + local mt = getmetatable(t) + if mt and not rawget(mt, recurse) then + addToPositions(mt, major) + end + rawset(t, recurse, nil) + end +end + +local function svnRevisionToNumber(text) + local kind = type(text) + if kind == "number" or tonumber(text) then + return tonumber(text) + elseif kind == "string" then + if text:find("^%$Revision: (%d+) %$$") then + return tonumber((text:match("^%$Revision: (%d+) %$$"))) + elseif text:find("^%$Rev: (%d+) %$$") then + return tonumber((text:match("^%$Rev: (%d+) %$$"))) + elseif text:find("^%$LastChangedRevision: (%d+) %$$") then + return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$"))) + end + end + return nil +end + +local crawlReplace +do + local recurse = {} + local function func(t, to, from) + if recurse[t] then + return + end + recurse[t] = true + local mt = getmetatable(t) + setmetatable(t, nil) + rawset(t, to, rawget(t, from)) + rawset(t, from, nil) + for k,v in pairs(t) do + if v == from then + t[k] = to + elseif type(v) == "table" then + if not recurse[v] then + func(v, to, from) + end + end + + if type(k) == "table" then + if not recurse[k] then + func(k, to, from) + end + end + end + setmetatable(t, mt) + if mt then + if mt == from then + setmetatable(t, to) + elseif not recurse[mt] then + func(mt, to, from) + end + end + end + function crawlReplace(t, to, from) + func(t, to, from) + for k in pairs(recurse) do + recurse[k] = nil + end + end +end + +-- @function destroyTable +-- @brief remove all the contents of a table +-- @param t table to destroy +local function destroyTable(t) + setmetatable(t, nil) + for k,v in pairs(t) do + t[k] = nil + end +end + +local function isFrame(frame) + return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function" +end + +-- @function copyTable +-- @brief Create a shallow copy of a table and return it. +-- @param from The table to copy from +-- @return A shallow copy of the table +local function copyTable(from, to) + if not to then + to = {} + end + for k,v in pairs(from) do + to[k] = v + end + setmetatable(to, getmetatable(from)) + return to +end + +-- @function deepTransfer +-- @brief Fully transfer all data, keeping proper previous table +-- backreferences stable. +-- @param to The table with which data is to be injected into +-- @param from The table whose data will be injected into the first +-- @param saveFields If available, a shallow copy of the basic data is saved +-- in here. +-- @param list The account of table references +-- @param list2 The current status on which tables have been traversed. +local deepTransfer +do + -- @function examine + -- @brief Take account of all the table references to be shared + -- between the to and from tables. + -- @param to The table with which data is to be injected into + -- @param from The table whose data will be injected into the first + -- @param list An account of the table references + local function examine(to, from, list, major) + list[from] = to + for k,v in pairs(from) do + if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then + if from[k] == to[k] then + list[from[k]] = to[k] + elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then + list[from[k]] = from[k] + elseif not list[from[k]] then + examine(to[k], from[k], list, major) + end + end + end + return list + end + + function deepTransfer(to, from, saveFields, major, list, list2) + setmetatable(to, nil) + if not list then + list = {} + list2 = {} + examine(to, from, list, major) + end + list2[to] = to + for k,v in pairs(to) do + if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then + if saveFields then + saveFields[k] = v + end + to[k] = nil + elseif v ~= _G then + if saveFields then + saveFields[k] = copyTable(v) + end + end + end + for k in pairs(from) do + if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then + if not list2[to[k]] then + deepTransfer(to[k], from[k], nil, major, list, list2) + end + to[k] = list[to[k]] or list2[to[k]] + else + rawset(to, k, from[k]) + end + end + setmetatable(to, getmetatable(from)) + local mt = getmetatable(to) + if mt then + if list[mt] then + setmetatable(to, list[mt]) + elseif mt.__index and list[mt.__index] then + mt.__index = list[mt.__index] + end + end + destroyTable(from) + end +end + +local function TryToEnable(addon) + if DONT_ENABLE_LIBRARIES then return end + local isondemand = IsAddOnLoadOnDemand(addon) + if isondemand then + local _, _, _, enabled = GetAddOnInfo(addon) + EnableAddOn(addon) + local _, _, _, _, loadable = GetAddOnInfo(addon) + if not loadable and not enabled then + DisableAddOn(addon) + end + + return loadable + end +end + +-- @method TryToLoadStandalone +-- @brief Attempt to find and load a standalone version of the requested library +-- @param major A string representing the major version +-- @return If library is found and loaded, true is return. If not loadable, false is returned. +-- If the library has been requested previously, nil is returned. +local function TryToLoadStandalone(major) + if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end + if AceLibrary.scannedlibs[major] then return end + + AceLibrary.scannedlibs[major] = true + + local name, _, _, enabled, loadable = GetAddOnInfo(major) + + loadable = (enabled and loadable) or TryToEnable(name) + + local loaded = false + if loadable then + loaded = true + LoadAddOn(name) + end + + local field = "X-AceLibrary-" .. major + for i = 1, GetNumAddOns() do + if GetAddOnMetadata(i, field) then + name, _, _, enabled, loadable = GetAddOnInfo(i) + + loadable = (enabled and loadable) or TryToEnable(name) + if loadable then + loaded = true + LoadAddOn(name) + end + end + end + return loaded +end + +-- @method IsNewVersion +-- @brief Obtain whether the supplied version would be an upgrade to the +-- current version. This allows for bypass code in library +-- declaration. +-- @param major A string representing the major version +-- @param minor An integer or an svn revision string representing the minor version +-- @return whether the supplied version would be newer than what is +-- currently available. +function AceLibrary:IsNewVersion(major, minor) + argCheck(self, major, 2, "string") + TryToLoadStandalone(major) + + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 3, "number") + local lib, oldMinor = LibStub:GetLibrary(major, true) + if lib then + return oldMinor < minor + end + local data = self.libs[major] + if not data then + return true + end + return data.minor < minor +end + +-- @method HasInstance +-- @brief Returns whether an instance exists. This allows for optional support of a library. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return Whether an instance exists. +function AceLibrary:HasInstance(major, minor) + argCheck(self, major, 2, "string") + if minor ~= false then + TryToLoadStandalone(major) + end + + local lib, ver = LibStub:GetLibrary(major, true) + if not lib and self.libs[major] then + lib, ver = self.libs[major].instance, self.libs[major].minor + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 3, "number") + if not lib then + return false + end + return ver == minor + end + return not not lib +end + +-- @method GetInstance +-- @brief Returns the library with the given major/minor version. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return The library with the given major/minor version. +function AceLibrary:GetInstance(major, minor) + argCheck(self, major, 2, "string") + if minor ~= false then + TryToLoadStandalone(major) + end + + local data, ver = LibStub:GetLibrary(major, true) + if not data then + if self.libs[major] then + data, ver = self.libs[major].instance, self.libs[major].minor + else + _G.error(("Cannot find a library instance of %s."):format(major), 2) + return + end + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 2, "number") + if ver ~= minor then + _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2) + end + end + return data +end + +-- Syntax sugar. AceLibrary("FooBar-1.0") +AceLibrary_mt.__call = AceLibrary.GetInstance + +local donothing = function() end + +local AceEvent + +local tmp = {} + +-- @method Register +-- @brief Registers a new version of a given library. +-- @param newInstance the library to register +-- @param major the major version of the library +-- @param minor the minor version of the library +-- @param activateFunc (optional) A function to be called when the library is +-- fully activated. Takes the arguments +-- (newInstance [, oldInstance, oldDeactivateFunc]). If +-- oldInstance is given, you should probably call +-- oldDeactivateFunc(oldInstance). +-- @param deactivateFunc (optional) A function to be called by a newer library's +-- activateFunc. +-- @param externalFunc (optional) A function to be called whenever a new +-- library is registered. +function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc) + argCheck(self, newInstance, 2, "table") + argCheck(self, major, 3, "string") + if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == newInstance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end + if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then + _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) + end + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 4, "number") + if math.floor(minor) ~= minor or minor < 0 then + error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) + end + argCheck(self, activateFunc, 5, "function", "nil") + argCheck(self, deactivateFunc, 6, "function", "nil") + argCheck(self, externalFunc, 7, "function", "nil") + if not deactivateFunc then + deactivateFunc = donothing + end + local data = self.libs[major] + if not data then + -- This is new + if LibStub:GetLibrary(major, true) then + error(self, "Cannot register library %q. It is already registered with LibStub.", major) + end + local instance = LibStub:NewLibrary(major, minor) + copyTable(newInstance, instance) + crawlReplace(instance, instance, newInstance) + destroyTable(newInstance) + if AceLibrary == newInstance then + self = instance + AceLibrary = instance + end + self.libs[major] = { + instance = instance, + minor = minor, + deactivateFunc = deactivateFunc, + externalFunc = externalFunc, + } + rawset(instance, 'GetLibraryVersion', function(self) + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not WoW22 and not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + addToPositions(instance, major) + if activateFunc then + safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil + +--[[ if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == instance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end]] + end + + if externalFunc then + for k, data_instance in LibStub:IterateLibraries() do -- all libraries + tmp[k] = data_instance + end + for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub + tmp[k] = data.instance + end + for k, data_instance in pairs(tmp) do + if k ~= major then + safecall(externalFunc, instance, k, data_instance) + end + tmp[k] = nil + end + end + + for k,data in pairs(self.libs) do -- only Ace libraries + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end + if major == "AceEvent-2.0" then + AceEvent = instance + end + if AceEvent then + AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance) + end + + return instance + end + if minor <= data.minor then + -- This one is already obsolete, raise an error. + _G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2) + return + end + local instance = data.instance + -- This is an update + local oldInstance = {} + + local libStubInstance = LibStub:GetLibrary(major, true) + if not libStubInstance then -- non-LibStub AceLibrary registered the library + -- pass + elseif libStubInstance ~= instance then + error(self, "Cannot register library %q. It is already registered with LibStub.", major) + else + LibStub:NewLibrary(major, minor) -- upgrade the minor version + end + + addToPositions(newInstance, major) + local isAceLibrary = (AceLibrary == newInstance) + local old_error, old_assert, old_argCheck, old_pcall + if isAceLibrary then + self = instance + AceLibrary = instance + + old_error = instance.error + if not WoW22 then + old_assert = instance.assert + end + old_argCheck = instance.argCheck + old_pcall = instance.pcall + + self.error = error + if not WoW22 then + self.assert = assert + end + self.argCheck = argCheck + self.pcall = pcall + end + deepTransfer(instance, newInstance, oldInstance, major) + crawlReplace(instance, instance, newInstance) + local oldDeactivateFunc = data.deactivateFunc + data.minor = minor + data.deactivateFunc = deactivateFunc + data.externalFunc = externalFunc + rawset(instance, 'GetLibraryVersion', function() + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not WoW22 and not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + if isAceLibrary then + for _,v in pairs(self.libs) do + local i = type(v) == "table" and v.instance + if type(i) == "table" then + if not rawget(i, 'error') or i.error == old_error then + rawset(i, 'error', error) + end + if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then + rawset(i, 'assert', assert) + end + if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then + rawset(i, 'argCheck', argCheck) + end + if not rawget(i, 'pcall') or i.pcall == old_pcall then + rawset(i, 'pcall', pcall) + end + end + end + end + if activateFunc then + safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) + +--[[ if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == instance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end]] + else + safecall(oldDeactivateFunc, oldInstance) + end + oldInstance = nil + + if externalFunc then + for k, data_instance in LibStub:IterateLibraries() do -- all libraries + tmp[k] = data_instance + end + for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub + tmp[k] = data.instance + end + for k, data_instance in pairs(tmp) do + if k ~= major then + safecall(externalFunc, instance, k, data_instance) + end + tmp[k] = nil + end + end + + return instance +end + +function AceLibrary:IterateLibraries() + local t = {} + for major, instance in LibStub:IterateLibraries() do + t[major] = instance + end + for major, data in pairs(self.libs) do + t[major] = data.instance + end + return pairs(t) +end + +local function manuallyFinalize(major, instance) + if AceLibrary.libs[major] then + -- don't work on Ace libraries + return + end + local finalizedExternalLibs = AceLibrary.finalizedExternalLibs + if finalizedExternalLibs[major] then + return + end + finalizedExternalLibs[major] = true + + for k,data in pairs(AceLibrary.libs) do -- only Ace libraries + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end +end + +-- @function Activate +-- @brief The activateFunc for AceLibrary itself. Called when +-- AceLibrary properly registers. +-- @param self Reference to AceLibrary +-- @param oldLib (optional) Reference to an old version of AceLibrary +-- @param oldDeactivate (optional) Function to deactivate the old lib +local function activate(self, oldLib, oldDeactivate) + AceLibrary = self + if not self.libs then + self.libs = oldLib and oldLib.libs or {} + self.scannedlibs = oldLib and oldLib.scannedlibs or {} + end + if not self.positions then + self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" }) + end + self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {} + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("ADDON_LOADED") + self.frame:SetScript("OnEvent", function() + for major, instance in LibStub:IterateLibraries() do + manuallyFinalize(major, instance) + end + end) + for major, instance in LibStub:IterateLibraries() do + manuallyFinalize(major, instance) + end + + -- Expose the library in the global environment + _G[ACELIBRARY_MAJOR] = self + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +if not previous then + previous = AceLibrary +end +if not previous.libs then + previous.libs = {} +end +AceLibrary.libs = previous.libs +if not previous.positions then + previous.positions = setmetatable({}, { __mode = "k" }) +end +AceLibrary.positions = previous.positions +AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_ConfigUI/lib/AceLibrary/AceLibrary.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,10 @@ +## Interface: 20200 + +## Title: Lib: AceLibrary +## Notes: AddOn development framework +## Author: Ace Development Team +## X-Website: http://www.wowace.com +## X-Category: Library +## X-License: LGPL v2.1 + MIT for AceOO-2.0 + +AceLibrary.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,980 @@ +--[[ +Name: AceOO-2.0 +Revision: $Rev: 38641 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceOO-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0 +Description: Library to provide an object-orientation framework. +Dependencies: AceLibrary +License: MIT +]] + +local MAJOR_VERSION = "AceOO-2.0" +local MINOR_VERSION = "$Revision: 38641 $" + +-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local AceOO = { + error = AceLibrary.error, + argCheck = AceLibrary.argCheck +} + +-- @function getuid +-- @brief Obtain a unique string identifier for the object in question. +-- @param t The object to obtain the uid for. +-- @return The uid string. +local function getuid(t) + local mt = getmetatable(t) + setmetatable(t, nil) + local str = tostring(t) + setmetatable(t, mt) + local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$") + if cap then + return ("0"):rep(8 - #cap) .. cap + end +end + +local function getlibrary(o) + if type(o) == "table" then + return o + elseif type(o) == "string" then + if not AceLibrary:HasInstance(o) then + AceOO:error("Library %q does not exist.", o) + end + return AceLibrary(o) + end +end + +local function deeprawget(self, k) + while true do + local v = rawget(self, k) + if v ~= nil then + return v + end + local mt = getmetatable(self) + if not mt or type(mt.__index) ~= "table" then + return nil + end + self = mt.__index + end +end + +-- @function Factory +-- @brief Construct a factory for the creation of objects. +-- @param obj The object whose init method will be called on the new factory +-- object. +-- @param newobj The object whose init method will be called on the new +-- objects that the Factory creates, to initialize them. +-- @param (...) Arguments which will be passed to obj.init() in addition +-- to the Factory object. +-- @return The new factory which creates a newobj when its new method is called, +-- or when it is called directly (__call metamethod). +local Factory +do + local function getlibraries(...) + if select('#', ...) == 0 then + return + end + return getlibrary((select(1, ...))), getlibraries(select(2, ...)) + end + local arg = {} + local function new(obj, ...) + local t = {} + local uid = getuid(t) + obj:init(t, getlibraries(...)) + t.uid = uid + return t + end + + local function createnew(self, ...) + local o = self.prototype + local x = new(o, getlibraries(...)) + return x + end + + function Factory(obj, newobj, ...) + local t = new(obj, ...) + t.prototype = newobj + t.new = createnew + getmetatable(t).__call = t.new + return t + end +end + + +local function objtostring(self) + if self.ToString then + return self:ToString() + elseif self.GetLibraryVersion then + return (self:GetLibraryVersion()) + elseif self.super then + local s = "Sub-" .. tostring(self.super) + local first = true + if self.interfaces then + for interface in pairs(self.interfaces) do + if first then + s = s .. "(" .. tostring(interface) + first = false + else + s = s .. ", " .. tostring(interface) + end + end + end + if self.mixins then + for mixin in pairs(self.mixins) do + if first then + s = s .. tostring(mixin) + first = false + else + s = s .. ", " .. tostring(mixin) + end + end + end + if first then + if self.uid then + return s .. ":" .. self.uid + else + return s + end + else + return s .. ")" + end + else + return self.uid and 'Subclass:' .. self.uid or 'Subclass' + end +end + +-- @table Object +-- @brief Base of all objects, including Class. +-- +-- @method init +-- @brief Initialize a new object. +-- @param newobject The object to initialize +-- @param class The class to make newobject inherit from +local Object +do + Object = {} + function Object:init(newobject, class) + local parent = class or self + if not rawget(newobject, 'uid') then + newobject.uid = getuid(newobject) + end + local mt = { + __index = parent, + __tostring = objtostring, + } + setmetatable(newobject, mt) + end + Object.uid = getuid(Object) + setmetatable(Object, { __tostring = function() return 'Object' end }) +end + +local Interface + +local function validateInterface(object, interface) + if not object.class and object.prototype then + object = object.prototype + end + for k,v in pairs(interface.interface) do + if tostring(type(object[k])) ~= v then + return false + end + end + if interface.superinterfaces then + for superinterface in pairs(interface.superinterfaces) do + if not validateInterface(object, superinterface) then + return false + end + end + end + if type(object.class) == "table" and rawequal(object.class.prototype, object) then + if not object.class.interfaces then + rawset(object.class, 'interfaces', {}) + end + object.class.interfaces[interface] = true + elseif type(object.class) == "table" and type(object.class.prototype) == "table" then + validateInterface(object.class.prototype, interface) + -- check if class is proper, thus preventing future checks. + end + return true +end + +-- @function inherits +-- @brief Return whether an Object or Class inherits from a given +-- parent. +-- @param object Object or Class to check +-- @param parent Parent to test inheritance from +-- @return whether an Object or Class inherits from a given +-- parent. +local function inherits(object, parent) + object = getlibrary(object) + if type(parent) == "string" then + if not AceLibrary:HasInstance(parent) then + return false + else + parent = AceLibrary(parent) + end + end + AceOO:argCheck(parent, 2, "table") + if type(object) ~= "table" then + return false + end + local current + local class = deeprawget(object, 'class') + if class then + current = class + else + current = object + end + if type(current) ~= "table" then + return false + end + if rawequal(current, parent) then + return true + end + if parent.class then + while true do + if rawequal(current, Object) then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if rawequal(mixin, parent) then + return true + end + end + end + if current.interfaces then + for interface in pairs(current.interfaces) do + if rawequal(interface, parent) then + return true + end + end + end + current = deeprawget(current, 'super') + if type(current) ~= "table" then + break + end + end + + local isInterface = false + local curr = parent.class + while true do + if rawequal(curr, Object) then + break + elseif rawequal(curr, Interface) then + isInterface = true + break + end + curr = deeprawget(curr, 'super') + if type(curr) ~= "table" then + break + end + end + return isInterface and validateInterface(object, parent) + else + while true do + if rawequal(current, parent) then + return true + elseif rawequal(current, Object) then + return false + end + current = deeprawget(current, 'super') + if type(current) ~= "table" then + return false + end + end + end +end + +-- @table Class +-- @brief An object factory which sets up inheritence and supports +-- 'mixins'. +-- +-- @metamethod Class call +-- @brief Call ClassFactory:new() to create a new class. +-- +-- @method Class new +-- @brief Construct a new object. +-- @param (...) Arguments to pass to the object init function. +-- @return The new object. +-- +-- @method Class init +-- @brief Initialize a new class. +-- @param parent Superclass. +-- @param (...) Mixins. +-- +-- @method Class ToString +-- @return A string representing the object, in this case 'Class'. +local initStatus +local Class +local Mixin +local autoEmbed = false +local function traverseInterfaces(bit, total) + if bit.superinterfaces then + for interface in pairs(bit.superinterfaces) do + if not total[interface] then + total[interface] = true + traverseInterfaces(interface, total) + end + end + end +end +local class_new +do + Class = Factory(Object, setmetatable({}, {__index = Object}), Object) + Class.super = Object + + local function protostring(t) + return '<' .. tostring(t.class) .. ' prototype>' + end + local function classobjectstring(t) + if t.ToString then + return t:ToString() + elseif t.GetLibraryVersion then + return (t:GetLibraryVersion()) + else + return '<' .. tostring(t.class) .. ' instance>' + end + end + local function classobjectequal(self, other) + if type(self) == "table" and self.Equals then + return self:Equals(other) + elseif type(other) == "table" and other.Equals then + return other:Equals(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) == 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) == 0 + else + return rawequal(self, other) + end + end + local function classobjectlessthan(self, other) + if type(self) == "table" and self.IsLessThan then + return self:IsLessThan(other) + elseif type(other) == "table" and other.IsLessThanOrEqualTo then + return not other:IsLessThanOrEqualTo(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) < 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) > 0 + elseif type(other) == "table" and other.IsLessThan and other.Equals then + return other:Equals(self) or other:IsLessThan(self) + else + AceOO:error("cannot compare two objects") + end + end + local function classobjectlessthanequal(self, other) + if type(self) == "table" and self.IsLessThanOrEqualTo then + return self:IsLessThanOrEqualTo(other) + elseif type(other) == "table" and other.IsLessThan then + return not other:IsLessThan(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) <= 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) >= 0 + elseif type(self) == "table" and self.IsLessThan and self.Equals then + return self:Equals(other) or self:IsLessThan(other) + else + AceOO:error("cannot compare two incompatible objects") + end + end + local function classobjectadd(self, other) + if type(self) == "table" and self.Add then + return self:Add(other) + else + AceOO:error("cannot add two incompatible objects") + end + end + local function classobjectsub(self, other) + if type(self) == "table" and self.Subtract then + return self:Subtract(other) + else + AceOO:error("cannot subtract two incompatible objects") + end + end + local function classobjectunm(self, other) + if type(self) == "table" and self.UnaryNegation then + return self:UnaryNegation(other) + else + AceOO:error("attempt to negate an incompatible object") + end + end + local function classobjectmul(self, other) + if type(self) == "table" and self.Multiply then + return self:Multiply(other) + else + AceOO:error("cannot multiply two incompatible objects") + end + end + local function classobjectdiv(self, other) + if type(self) == "table" and self.Divide then + return self:Divide(other) + else + AceOO:error("cannot divide two incompatible objects") + end + end + local function classobjectpow(self, other) + if type(self) == "table" and self.Exponent then + return self:Exponent(other) + else + AceOO:error("cannot exponentiate two incompatible objects") + end + end + local function classobjectconcat(self, other) + if type(self) == "table" and self.Concatenate then + return self:Concatenate(other) + else + AceOO:error("cannot concatenate two incompatible objects") + end + end + function class_new(self, ...) + if self.virtual then + AceOO:error("Cannot instantiate a virtual class.") + end + + local o = self.prototype + local newobj = {} + if o.class and o.class.instancemeta then + setmetatable(newobj, o.class.instancemeta) + else + Object:init(newobj, o) + end + + if self.interfaces and not self.interfacesVerified then + -- Verify the interfaces + + for interface in pairs(self.interfaces) do + for field,kind in pairs(interface.interface) do + if tostring(type(newobj[field])) ~= kind then + AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field]))) + end + end + end + self.interfacesVerified = true + end + local tmp = initStatus + initStatus = newobj + newobj:init(...) + if initStatus then + initStatus = tmp + AceOO:error("Initialization not completed, be sure to call the superclass's init method.") + return + end + initStatus = tmp + return newobj + end + local classmeta = { + __tostring = objtostring, + __call = function(self, ...) + return self:new(...) + end, + } + function Class:init(newclass, parent, ...) + parent = parent or self + + local total + + if parent.class then + total = { parent, ... } + parent = self + else + total = { ... } + end + if not inherits(parent, Class) then + AceOO:error("Classes must inherit from a proper class") + end + if parent.sealed then + AceOO:error("Cannot inherit from a sealed class") + end + for i,v in ipairs(total) do + if inherits(v, Mixin) and v.class then + if v.__deprecated then + AceOO:error(v.__deprecated) + end + if not newclass.mixins then + newclass.mixins = {} + end + if newclass.mixins[v] then + AceOO:error("Cannot explicitly inherit from the same mixin twice") + end + newclass.mixins[v] = true + elseif inherits(v, Interface) and v.class then + if not newclass.interfaces then + newclass.interfaces = {} + end + if newclass.interfaces[v] then + AceOO:error("Cannot explicitly inherit from the same interface twice") + end + newclass.interfaces[v] = true + else + AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces") + end + end + if parent.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(parent.interfaces) do + newclass.interfaces[interface] = true + end + end + for k in pairs(total) do + total[k] = nil + end + + newclass.super = parent + + newclass.prototype = setmetatable(total, { + __index = parent.prototype, + __tostring = protostring, + }) + total = nil + + newclass.instancemeta = { + __index = newclass.prototype, + __tostring = classobjectstring, + __eq = classobjectequal, + __lt = classobjectlessthan, + __le = classobjectlessthanequal, + __add = classobjectadd, + __sub = classobjectsub, + __unm = classobjectunm, + __mul = classobjectmul, + __div = classobjectdiv, + __pow = classobjectpow, + __concat = classobjectconcat, + } + + setmetatable(newclass, classmeta) + + newclass.new = class_new + + if newclass.mixins then + -- Fold in the mixins + local err, msg + for mixin in pairs(newclass.mixins) do + local ret + autoEmbed = true + ret, msg = pcall(mixin.embed, mixin, newclass.prototype) + autoEmbed = false + if not ret then + err = true + break + end + end + + if err then + local pt = newclass.prototype + for k,v in pairs(pt) do + pt[k] = nil + end + + -- method conflict + AceOO:error(msg) + end + end + + newclass.prototype.class = newclass + + if newclass.interfaces then + for interface in pairs(newclass.interfaces) do + traverseInterfaces(interface, newclass.interfaces) + end + end + if newclass.mixins then + for mixin in pairs(newclass.mixins) do + if mixin.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(mixin.interfaces) do + newclass.interfaces[interface] = true + end + end + end + end + end + function Class:ToString() + if type(self.GetLibraryVersion) == "function" then + return (self:GetLibraryVersion()) + else + return "Class" + end + end + + local tmp + function Class.prototype:init() + if rawequal(self, initStatus) then + initStatus = nil + else + AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2) + end + self.uid = getuid(self) + local current = self.class + while true do + if current == Class then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnInstanceInit) == "function" then + mixin:OnInstanceInit(self) + end + end + end + current = current.super + end + end +end + + +-- @object ClassFactory +-- @brief A factory for creating classes. Rarely used directly. +local ClassFactory = Factory(Object, Class, Object) + +function Class:new(...) + local x = ClassFactory:new(...) + if AceOO.classes then + AceOO.classes[x] = true + end + return x +end +getmetatable(Class).__call = Class.new + +-- @class Mixin +-- @brief A class to create mixin objects, which contain methods that get +-- "mixed in" to class prototypes. +-- +-- @object Mixin prototype +-- @brief The prototype that mixin objects inherit their methods from. +-- +-- @method Mixin prototype embed +-- @brief Mix in the methods of our object which are listed in our interface +-- to the supplied target table. +-- +-- @method Mixin prototype init +-- @brief Initialize the mixin object. +-- @param newobj The new object we're initializing. +-- @param interface The interface we implement (the list of methods our +-- prototype provides which should be mixed into the target +-- table by embed). +do + Mixin = Class() + function Mixin:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Mixin' + end + end + local function _Embed(state, field, target) + field = next(state.export, field) + if field == nil then + return + end + + if rawget(target, field) or (target[field] and target[field] ~= state[field]) then + AceOO:error("Method conflict in attempt to mixin. Field %q", field) + end + + target[field] = state[field] + + local ret,msg = pcall(_Embed, state, field, target) + if not ret then + -- Mix in the next method according to the defined interface. If that + -- fails due to a conflict, re-raise to back out the previous mixed + -- methods. + + target[field] = nil + AceOO:error(msg) + end + end + function Mixin.prototype:embed(target) + if self.__deprecated then + AceOO:error(self.__deprecated) + end + local mt = getmetatable(target) + setmetatable(target, nil) + local err, msg = pcall(_Embed, self, nil, target) + if not err then + setmetatable(target, mt) + AceOO:error(msg) + return + end + if type(self.embedList) == "table" then + self.embedList[target] = true + end + if type(target.class) ~= "table" then + target[self] = true + end + if not autoEmbed and type(self.OnManualEmbed) == "function" then + self:OnManualEmbed(target) + end + setmetatable(target, mt) + end + + function Mixin.prototype:activate(oldLib, oldDeactivate) + if oldLib and oldLib.embedList then + for target in pairs(oldLib.embedList) do + local mt = getmetatable(target) + setmetatable(target, nil) + for field in pairs(oldLib.export) do + target[field] = nil + end + setmetatable(target, mt) + end + self.embedList = oldLib.embedList + for target in pairs(self.embedList) do + self:embed(target) + end + else + self.embedList = setmetatable({}, {__mode="k"}) + end + end + + function Mixin.prototype:init(export, ...) + AceOO:argCheck(export, 2, "table") + for k,v in pairs(export) do + if type(k) ~= "number" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + end + end + local num = #export + for i = 1, num do + local v = export[i] + export[i] = nil + export[v] = true + end + + local interfaces + if select('#', ...) >= 1 then + interfaces = { ... } + for i,v in ipairs(interfaces) do + v = getlibrary(v) + interfaces[i] = v + if not v.class or not inherits(v, Interface) then + AceOO:error("Mixins can inherit only from interfaces") + end + end + local num = #interfaces + for i = 1, num do + local v = interfaces[i] + interfaces[i] = nil + interfaces[v] = true + end + for interface in pairs(interfaces) do + traverseInterfaces(interface, interfaces) + end + for interface in pairs(interfaces) do + for field,kind in pairs(interface.interface) do + if kind ~= "nil" then + local good = false + for bit in pairs(export) do + if bit == field then + good = true + break + end + end + if not good then + AceOO:error("Mixin does not fully accommodate field %q", field) + end + end + end + end + end + self.super = Mixin.prototype + Mixin.super.prototype.init(self) + self.export = export + self.interfaces = interfaces + end +end + +-- @class Interface +-- @brief A class to create interfaces, which contain contracts that classes +-- which inherit from this must comply with. +-- +-- @object Interface prototype +-- @brief The prototype that interface objects must adhere to. +-- +-- @method Interface prototype init +-- @brief Initialize the mixin object. +-- @param interface The interface we contract (the hash of fields forced). +-- @param (...) Superinterfaces +do + Interface = Class() + function Interface:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Instance' + end + end + function Interface.prototype:init(interface, ...) + Interface.super.prototype.init(self) + AceOO:argCheck(interface, 2, "table") + for k,v in pairs(interface) do + if type(k) ~= "string" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then + AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".') + end + end + if select('#', ...) >= 1 then + self.superinterfaces = { ... } + for i,v in ipairs(self.superinterfaces) do + v = getlibrary(v) + self.superinterfaces[i] = v + if not inherits(v, Interface) or not v.class then + AceOO:error('Cannot provide a non-Interface to inherit from') + end + end + local num = #self.superinterfaces + for i = 1, num do + local v = self.superinterfaces[i] + self.superinterfaces[i] = nil + self.superinterfaces[v] = true + end + end + self.interface = interface + end +end + +-- @function Classpool +-- @brief Obtain a read only class from our pool of classes, indexed by the +-- superclass and mixins. +-- @param sc The superclass of the class we want. +-- @param (m1..m20) Mixins of the class we want's objects. +-- @return A read only class from the class pool. +local Classpool +do + local pool = setmetatable({}, {__mode = 'v'}) + local function newindex(k, v) + AceOO:error('Attempt to modify a read-only class.') + end + local function protonewindex(k, v) + AceOO:error('Attempt to modify a read-only class prototype.') + end + local function ts(bit) + if type(bit) ~= "table" then + return tostring(bit) + elseif getmetatable(bit) and bit.__tostring then + return tostring(bit) + elseif type(bit.GetLibraryVersion) == "function" then + return bit:GetLibraryVersion() + else + return tostring(bit) + end + end + local t = {} + local function getcomplexuid(sc, ...) + if sc then + if sc.uid then + table.insert(t, sc.uid) + else + AceOO:error("%s is not an appropriate class/mixin", ts(sc)) + end + end + for i = 1, select('#', ...) do + local m = select(i, ...) + if m.uid then + table.insert(t, m.uid) + else + AceOO:error("%s is not an appropriate mixin", ts(m)) + end + end + table.sort(t) + local uid = table.concat(t, '') + local num = #t + for i = 1, num do + t[i] = nil + end + return uid + end + local classmeta + local arg = {} + function Classpool(superclass, ...) + local l = getlibrary + superclass = getlibrary(superclass) + arg = { ... } + for i, v in ipairs(arg) do + arg[i] = getlibrary(v) + end + if superclass then + if superclass.class then -- mixin + table.insert(arg, 1, superclass) + superclass = Class + end + else + superclass = Class + end + local key = getcomplexuid(superclass, unpack(arg)) + if not pool[key] then + local class = Class(superclass, unpack(arg)) + if not classmeta then + classmeta = {} + local mt = getmetatable(class) + for k,v in pairs(mt) do + classmeta[k] = v + end + classmeta.__newindex = newindex + end + -- Prevent the user from adding methods to this class. + -- NOTE: I'm not preventing modifications of existing class members, + -- but it's likely that only a truly malicious user will be doing so. + class.sealed = true + setmetatable(class, classmeta) + getmetatable(class.prototype).__newindex = protonewindex + pool[key] = class + end + return pool[key] + end +end + +AceOO.Factory = Factory +AceOO.Object = Object +AceOO.Class = Class +AceOO.Mixin = Mixin +AceOO.Interface = Interface +AceOO.Classpool = Classpool +AceOO.inherits = inherits + +-- Library handling bits + +local function activate(self, oldLib, oldDeactivate) + AceOO = self + Factory = self.Factory + Object = self.Object + Class = self.Class + ClassFactory.prototype = Class + Mixin = self.Mixin + Interface = self.Interface + Classpool = self.Classpool + + if oldLib then + self.classes = oldLib.classes + end + if not self.classes then + self.classes = setmetatable({}, {__mode="k"}) + else + for class in pairs(self.classes) do + class.new = class_new + end + end + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate) +AceOO = AceLibrary(MAJOR_VERSION)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_ConfigUI/lib/AceOO-2.0/AceOO-2.0.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,12 @@ +## Interface: 20200 + +## Title: Lib: AceOO-2.0 +## Notes: AddOn development framework +## Author: Ace Development Team +## LoadOnDemand: 1 +## X-Website: http://www.wowace.com +## X-Category: Library +## X-License: LGPL v2.1 + MIT for AceOO-2.0 +## Dependencies: AceLibrary + +AceOO-2.0.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_ConfigUI/lib/Dewdrop-2.0/Dewdrop-2.0.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,3487 @@ +--[[ +Name: Dewdrop-2.0 +Revision: $Rev: 48630 $ +Author(s): ckknight (ckknight@gmail.com) +Website: http://ckknight.wowinterface.com/ +Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0 +SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0 +Description: A library to provide a clean dropdown menu interface. +Dependencies: AceLibrary +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "Dewdrop-2.0" +local MINOR_VERSION = "$Revision: 48630 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local Dewdrop = {} + +local SharedMedia + +local CLOSE = "Close" +local CLOSE_DESC = "Close the menu." +local VALIDATION_ERROR = "Validation error." +local USAGE_TOOLTIP = "Usage: %s." +local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one." +local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." +local KEY_BUTTON1 = "Left Mouse" +local KEY_BUTTON2 = "Right Mouse" +local DISABLED = "Disabled" +local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" + +if GetLocale() == "deDE" then + CLOSE = "Schlie\195\159en" + CLOSE_DESC = "Men\195\188 schlie\195\159en." + VALIDATION_ERROR = "Validierungsfehler." + USAGE_TOOLTIP = "Benutzung: %s." + RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen." + RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen." + KEY_BUTTON1 = "Linke Maustaste" + KEY_BUTTON2 = "Rechte Maustaste" + DISABLED = "Deaktiviert" + DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?" +elseif GetLocale() == "koKR" then + CLOSE = "닫기" + CLOSE_DESC = "메뉴를 닫습니다." + VALIDATION_ERROR = "오류 확인." + USAGE_TOOLTIP = "사용법: %s." + RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다." + RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요." + KEY_BUTTON1 = "왼쪽 마우스" + KEY_BUTTON2 = "오른쪽 마우스" + DISABLED = "비활성화됨" + DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?" +elseif GetLocale() == "frFR" then + CLOSE = "Fermer" + CLOSE_DESC = "Ferme le menu." + VALIDATION_ERROR = "Erreur de validation." + USAGE_TOOLTIP = "Utilisation : %s." + RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement." + RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci." + KEY_BUTTON1 = "Clic gauche" + KEY_BUTTON2 = "Clic droit" + DISABLED = "D\195\169sactiv\195\169" + DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?" +elseif GetLocale() == "esES" then + CLOSE = "Cerrar" + CLOSE_DESC = "Cierra el menú." + VALIDATION_ERROR = "Error de validación." + USAGE_TOOLTIP = "Uso: %s." + RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador." + RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla." + KEY_BUTTON1 = "Clic Izquierdo" + KEY_BUTTON2 = "Clic Derecho" + DISABLED = "Desactivado" + DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?" +elseif GetLocale() == "zhTW" then + CLOSE = "關閉" + CLOSE_DESC = "關閉選單。" + VALIDATION_ERROR = "驗證錯誤。" + USAGE_TOOLTIP = "用法: %s。" + RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。" + RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。" + KEY_BUTTON1 = "滑鼠左鍵" + KEY_BUTTON2 = "滑鼠右鍵" + DISABLED = "停用" + DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" +elseif GetLocale() == "zhCN" then + CLOSE = "关闭" + CLOSE_DESC = "关闭菜单" + VALIDATION_ERROR = "验证错误." + USAGE_TOOLTIP = "用法: %s." + RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页." + RESET_KEYBINDING_DESC = "按ESC键清除按键绑定" + KEY_BUTTON1 = "鼠标左键" + KEY_BUTTON2 = "鼠标右键" + DISABLED = "禁用" + DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?" +end + +Dewdrop.KEY_BUTTON1 = KEY_BUTTON1 +Dewdrop.KEY_BUTTON2 = KEY_BUTTON2 + +local function new(...) + local t = {} + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t +end + +local tmp +do + local t = {} + function tmp(...) + for k in pairs(t) do + t[k] = nil + end + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t + end +end +local tmp2 +do + local t = {} + function tmp2(...) + for k in pairs(t) do + t[k] = nil + end + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t + end +end +local levels +local buttons + + +-- Secure frame handling: +-- Rather than using secure buttons in the menu (has problems), we have one +-- master secureframe that we pop onto menu items on mouseover. This requires +-- some dark magic with OnLeave etc, but it's not too bad. + +local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate") +secureFrame:Hide() + +local function secureFrame_Show(self) + local owner = self.owner + + if self.secure then -- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..) + for k,v in pairs(self.secure) do + self:SetAttribute(k, nil) + end + end + self.secure = owner.secure; -- Grab hold of new secure data + + local scale = owner:GetEffectiveScale() + + self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale) + self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale) + self:EnableMouse(true) + for k,v in pairs(self.secure) do + self:SetAttribute(k, v) + end + + secureFrame:SetFrameStrata(owner:GetFrameStrata()) + secureFrame:SetFrameLevel(owner:GetFrameLevel()+1) + + self:Show() +end + +local function secureFrame_Hide(self) + self:Hide() + if self.secure then + for k,v in pairs(self.secure) do + self:SetAttribute(k, nil) + end + end + self.secure = nil +end + +secureFrame:SetScript("OnEvent", + function() + if event=="PLAYER_REGEN_ENABLED" then + this.combat = false + if not this:IsShown() and this.owner then + secureFrame_Show(this) + end + elseif event=="PLAYER_REGEN_DISABLED" then + this.combat = true + if this:IsShown() then + secureFrame_Hide(this) + end + end + end +) +secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED") +secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED") + +secureFrame:SetScript("OnLeave", + function() + local owner=this.owner + this:Deactivate() + owner:GetScript("OnLeave")() + end +) + +secureFrame:HookScript("OnClick", + function() + local realthis = this + this = this.owner + this:GetScript("OnClick")() + end +) + +function secureFrame:IsOwnedBy(frame) + return self.owner == frame +end + +function secureFrame:Activate(owner) + if self.owner then -- "Shouldn't" happen but apparently it does and I cba to troubleshoot... + if not self.combat then + secureFrame_Hide(self) + end + end + self.owner = owner + if not self.combat then + secureFrame_Show(self) + end +end + +function secureFrame:Deactivate() + if not self.combat then + secureFrame_Hide(self) + end + self.owner = nil +end + +-- END secure frame utilities + + +-- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies +local underlineFrame = CreateFrame("Frame", nil) +underlineFrame.tx = underlineFrame:CreateTexture() +underlineFrame.tx:SetTexture(1,1,0.5,0.75) +underlineFrame:SetScript("OnHide", function(this) this:Hide(); end) +underlineFrame:SetScript("OnShow", function(this) -- change sizing on the fly to catch runtime uiscale changes + underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale()) + underlineFrame.tx:SetPoint("RIGHT", 1,0) + underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale()); +end) +underlineFrame:SetHeight(1) + +-- END underline on mouseover + + +local function GetScaledCursorPosition() + local x, y = GetCursorPosition() + local scale = UIParent:GetEffectiveScale() + return x / scale, y / scale +end + +local function StartCounting(self, level) + for i = level, 1, -1 do + if levels[i] then + levels[i].count = 3 + end + end +end + +local function StopCounting(self, level) + for i = level, 1, -1 do + if levels[i] then + levels[i].count = nil + end + end +end + +local function OnUpdate(self, elapsed) + for _,level in ipairs(levels) do + local count = level.count + if count then + count = count - elapsed + if count < 0 then + level.count = nil + self:Close(level.num) + else + level.count = count + end + end + end +end + +local function CheckDualMonitor(self, frame) + local ratio = GetScreenWidth() / GetScreenHeight() + if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then + local offsetx + if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then + offsetx = GetScreenWidth() / 2 - frame:GetRight() + else + offsetx = GetScreenWidth() / 2 - frame:GetLeft() + end + local point, parent, relativePoint, x, y = frame:GetPoint(1) + frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0) + end +end + +local function CheckSize(self, level) + if not level.buttons then + return + end + local height = 20 + for _, button in ipairs(level.buttons) do + height = height + button:GetHeight() + end + level:SetHeight(height) + local width = 160 + for _, button in ipairs(level.buttons) do + local extra = 1 + if button.hasArrow or button.hasColorSwatch then + extra = extra + 16 + end + if not button.notCheckable then + extra = extra + 24 + end + button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight) + if button.text:GetWidth() + extra > width then + width = button.text:GetWidth() + extra + end + end + level:SetWidth(width + 20) + if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then + level:ClearAllPoints() + local parent = level.parent or level:GetParent() + if type(parent) ~= "table" then + parent = UIParent + end + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local dirty = false + if not level:GetRight() then + self:Close() + return + end + if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then + level.lastDirection = "LEFT" + dirty = true + elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then + level.lastDirection = "RIGHT" + dirty = true + end + if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then + level.lastVDirection = "DOWN" + dirty = true + elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then + level.lastVDirection = "UP" + dirty = true + end + if dirty then + level:ClearAllPoints() + local parent = level.parent or level:GetParent() + if type(parent) ~= "table" then + parent = UIParent + end + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + if level:GetTop() > GetScreenHeight() then + local top = level:GetTop() + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:ClearAllPoints() + level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top) + elseif level:GetBottom() < 0 then + local bottom = level:GetBottom() + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:ClearAllPoints() + level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom) + end + CheckDualMonitor(self, level) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end +end + +local Open +local OpenSlider +local OpenEditBox +local Refresh +local Clear +local function ReleaseButton(self, level, index) + if not level.buttons then + return + end + if not level.buttons[index] then + return + end + local button = level.buttons[index] + button:Hide() + if button.highlight then + button.highlight:Hide() + end +-- button.arrow:SetVertexColor(1, 1, 1) +-- button.arrow:SetHeight(16) +-- button.arrow:SetWidth(16) + table.remove(level.buttons, index) + table.insert(buttons, button) + for k in pairs(button) do + if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then + button[k] = nil + end + end + return true +end + +local function Scroll(self, level, down) + if down then + if level:GetBottom() < 0 then + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:SetPoint(point, parent, relativePoint, x, y + 50) + if level:GetBottom() > 0 then + level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom()) + end + end + else + if level:GetTop() > GetScreenHeight() then + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:SetPoint(point, parent, relativePoint, x, y - 50) + if level:GetTop() < GetScreenHeight() then + level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop()) + end + end + end +end + +local function getArgs(t, str, num, ...) + local x = t[str .. num] + if x == nil then + return ... + else + return x, getArgs(t, str, num + 1, ...) + end +end + +local sliderFrame +local editBoxFrame + +local normalFont +local lastSetFont +local justSetFont = false +local regionTmp = {} +local function fillRegionTmp(...) + for i = 1, select('#', ...) do + regionTmp[i] = select(i, ...) + end +end + +local function showGameTooltip(this) + if this.tooltipTitle or this.tooltipText then + GameTooltip_SetDefaultAnchor(GameTooltip, this) + local disabled = not this.isTitle and this.disabled + local font + if this.tooltipTitle then + if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then + font = SharedMedia:Fetch("font", this.tooltipTitle) + end + if disabled then + GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1) + else + GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1) + end + if this.tooltipText then + if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then + font = SharedMedia:Fetch("font", this.tooltipText) + end + if disabled then + GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1) + else + GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) + end + end + else + if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then + font = SharedMedia:Fetch("font", this.tooltipText) + end + if disabled then + GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1) + else + GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1) + end + end + if font then + fillRegionTmp(GameTooltip:GetRegions()) + lastSetFont = font + justSetFont = true + for i,v in ipairs(regionTmp) do + if v.SetFont then + local norm,size,outline = v:GetFont() + v:SetFont(font, size, outline) + if not normalFont then + normalFont = norm + end + end + regionTmp[i] = nil + end + elseif not normalFont then + fillRegionTmp(GameTooltip:GetRegions()) + for i,v in ipairs(regionTmp) do + if v.GetFont and not normalFont then + normalFont = v:GetFont() + end + regionTmp[i] = nil + end + end + GameTooltip:Show() + end + if this.tooltipFunc then + GameTooltip:SetOwner(this, "ANCHOR_NONE") + GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) + this.tooltipFunc(getArgs(this, 'tooltipArg', 1)) + GameTooltip:Show() + end +end + +local tmpt = setmetatable({}, {mode='v'}) +local numButtons = 0 +local function AcquireButton(self, level) + if not levels[level] then + return + end + level = levels[level] + if not level.buttons then + level.buttons = {} + end + local button + if #buttons == 0 then + numButtons = numButtons + 1 + button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) + button:SetFrameStrata("FULLSCREEN_DIALOG") + button:SetHeight(16) + local highlight = button:CreateTexture(nil, "BACKGROUND") + highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") + button.highlight = highlight + highlight:SetBlendMode("ADD") + highlight:SetAllPoints(button) + highlight:Hide() + local check = button:CreateTexture(nil, "ARTWORK") + button.check = check + check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") + check:SetPoint("CENTER", button, "LEFT", 12, 0) + check:SetWidth(24) + check:SetHeight(24) + local radioHighlight = button:CreateTexture(nil, "ARTWORK") + button.radioHighlight = radioHighlight + radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton") + radioHighlight:SetAllPoints(check) + radioHighlight:SetBlendMode("ADD") + radioHighlight:SetTexCoord(0.5, 0.75, 0, 1) + radioHighlight:Hide() + button:SetScript("OnEnter", function() + if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then + for i = 1, this.level.num do + Refresh(self, levels[i]) + end + return + end + self:Close(this.level.num + 1) + if not this.disabled then + if this.secure then + secureFrame:Activate(this) + elseif this.hasSlider then + OpenSlider(self, this) + elseif this.hasEditBox then + OpenEditBox(self, this) + elseif this.hasArrow then + Open(self, this, nil, this.level.num + 1, this.value) + end + end + if not this.level then -- button reclaimed + return + end + StopCounting(self, this.level.num + 1) + if not this.disabled then + highlight:Show() + if this.isRadio then + button.radioHighlight:Show() + end + if this.mouseoverUnderline then + underlineFrame:SetParent(this) + underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0) + underlineFrame:SetWidth(this.text:GetWidth()) + underlineFrame:Show() + end + end + showGameTooltip(this) + end) + button:SetScript("OnHide", function() + if this.secure and secureFrame:IsOwnedBy(this) then + secureFrame:Deactivate() + end + end) + button:SetScript("OnLeave", function() + if this.secure and secureFrame:IsShown() then + return; -- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it + end + underlineFrame:Hide() + if not this.selected then + highlight:Hide() + end + button.radioHighlight:Hide() + if this.level then + StartCounting(self, this.level.num) + end + GameTooltip:Hide() + end) + local first = true + button:SetScript("OnClick", function() + if not this.disabled then + if this.hasColorSwatch then + local func = button.colorFunc + local hasOpacity = this.hasOpacity + local this = this + for k in pairs(tmpt) do + tmpt[k] = nil + end + for i = 1, 1000 do + local x = this['colorArg'..i] + if x == nil then + break + else + tmpt[i] = x + end + end + ColorPickerFrame.func = function() + if func then + local r,g,b = ColorPickerFrame:GetColorRGB() + local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil + local n = #tmpt + tmpt[n+1] = r + tmpt[n+2] = g + tmpt[n+3] = b + tmpt[n+4] = a + func(unpack(tmpt)) + tmpt[n+1] = nil + tmpt[n+2] = nil + tmpt[n+3] = nil + tmpt[n+4] = nil + end + end + ColorPickerFrame.hasOpacity = this.hasOpacity + ColorPickerFrame.opacityFunc = ColorPickerFrame.func + ColorPickerFrame.opacity = 1 - this.opacity + ColorPickerFrame:SetColorRGB(this.r, this.g, this.b) + local r, g, b, a = this.r, this.g, this.b, this.opacity + ColorPickerFrame.cancelFunc = function() + if func then + local n = #tmpt + tmpt[n+1] = r + tmpt[n+2] = g + tmpt[n+3] = b + tmpt[n+4] = a + func(unpack(tmpt)) + for i = 1, n+4 do + tmpt[i] = nil + end + end + end + self:Close(1) + ShowUIPanel(ColorPickerFrame) + elseif this.func then + local level = this.level + if type(this.func) == "string" then + if type(this.arg1[this.func]) ~= "function" then + self:error("Cannot call method %q", this.func) + end + this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2)) + else + this.func(getArgs(this, 'arg', 1)) + end + if this.closeWhenClicked then + self:Close() + elseif level:IsShown() then + for i = 1, level.num do + Refresh(self, levels[i]) + end + local value = levels[level.num].value + for i = level.num-1, 1, -1 do + local level = levels[i] + local good = false + for _,button in ipairs(level.buttons) do + if button.value == value then + good = true + break + end + end + if not good then + Dewdrop:Close(i+1) + end + value = levels[i].value + end + end + elseif this.closeWhenClicked then + self:Close() + end + end + end) + local text = button:CreateFontString(nil, "ARTWORK") + button.text = text + text:SetFontObject(GameFontHighlightSmall) + button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) + button:SetScript("OnMouseDown", function() + if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then + text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1) + end + end) + button:SetScript("OnMouseUp", function() + if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then + text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0) + end + end) + local arrow = button:CreateTexture(nil, "ARTWORK") + button.arrow = arrow + arrow:SetPoint("LEFT", button, "RIGHT", -16, 0) + arrow:SetWidth(16) + arrow:SetHeight(16) + arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") + local colorSwatch = button:CreateTexture(nil, "ARTWORK") + button.colorSwatch = colorSwatch + colorSwatch:SetWidth(20) + colorSwatch:SetHeight(20) + colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") + local texture = button:CreateTexture(nil, "OVERLAY") + colorSwatch.texture = texture + texture:SetTexture("Interface\\Buttons\\WHITE8X8") + texture:SetWidth(11.5) + texture:SetHeight(11.5) + texture:Show() + texture:SetPoint("CENTER", colorSwatch, "CENTER") + colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) + else + button = table.remove(buttons) + end + button:ClearAllPoints() + button:SetParent(level) + button:SetFrameStrata(level:GetFrameStrata()) + button:SetFrameLevel(level:GetFrameLevel() + 1) + button:SetPoint("LEFT", level, "LEFT", 10, 0) + button:SetPoint("RIGHT", level, "RIGHT", -10, 0) + if #level.buttons == 0 then + button:SetPoint("TOP", level, "TOP", 0, -10) + else + button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0) + end + button.text:SetPoint("LEFT", button, "LEFT", 24, 0) + button:Show() + button.level = level + table.insert(level.buttons, button) + if not level.parented then + level.parented = true + level:ClearAllPoints() + if level.num == 1 then + if level.parent ~= UIParent and type(level.parent) == "table" then + level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") + else + level:SetPoint("CENTER", UIParent, "CENTER") + end + else + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10) + end + end + end + level:SetFrameStrata("FULLSCREEN_DIALOG") + end + button:SetAlpha(1) + return button +end + +local numLevels = 0 +local function AcquireLevel(self, level) + if not levels[level] then + for i = #levels + 1, level, -1 do + local i = i + numLevels = numLevels + 1 + local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) + if i == 1 then + local old_CloseSpecialWindows = CloseSpecialWindows + function CloseSpecialWindows() + local found = old_CloseSpecialWindows() + if levels[1]:IsShown() then + self:Close() + return 1 + end + return found + end + end + levels[i] = frame + frame.num = i + frame:SetParent(UIParent) + frame:SetFrameStrata("FULLSCREEN_DIALOG") + frame:Hide() + frame:SetWidth(180) + frame:SetHeight(10) + frame:SetFrameLevel(i * 3) + frame:SetScript("OnHide", function() + self:Close(level + 1) + end) + if frame.SetTopLevel then + frame:SetTopLevel(true) + end + frame:EnableMouse(true) + frame:EnableMouseWheel(true) + local backdrop = CreateFrame("Frame", nil, frame) + backdrop:SetAllPoints(frame) + backdrop:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + frame:SetScript("OnClick", function() + self:Close(i) + end) + frame:SetScript("OnEnter", function() + StopCounting(self, i) + end) + frame:SetScript("OnLeave", function() + StartCounting(self, i) + end) + frame:SetScript("OnMouseWheel", function() + Scroll(self, frame, arg1 < 0) + end) + if i == 1 then + frame:SetScript("OnUpdate", function(this, arg1) + OnUpdate(self, arg1) + end) + levels[1].lastDirection = "RIGHT" + levels[1].lastVDirection = "DOWN" + else + levels[i].lastDirection = levels[i - 1].lastDirection + levels[i].lastVDirection = levels[i - 1].lastVDirection + end + end + end + local fullscreenFrame = GetUIPanel("fullscreen") + local l = levels[level] + local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() + if fullscreenFrame then + l:SetParent(fullscreenFrame) + else + l:SetParent(UIParent) + end + l:SetFrameStrata(strata) + l:SetFrameLevel(framelevel) + l:SetAlpha(1) + return l +end + +local function validateOptions(options, position, baseOptions, fromPass) + if not baseOptions then + baseOptions = options + end + if type(options) ~= "table" then + return "Options must be a table.", position + end + local kind = options.type + if type(kind) ~= "string" then + return '"type" must be a string.', position + elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then + return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position + end + if options.aliases then + if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then + return '"alias" must be a table or string', position + end + end + if not fromPass then + if kind == "execute" then + if type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + elseif kind == "range" or kind == "text" or kind == "toggle" then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if kind == "text" and options.get == false then + elseif type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif kind == "group" and options.pass then + if options.pass ~= true then + return '"pass" must be either nil, true, or false', position + end + if not options.func then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + end + end + if options ~= baseOptions then + if kind == "header" then + elseif type(options.desc) ~= "string" then + return '"desc" must be a string', position + elseif options.desc:len() == 0 then + return '"desc" cannot be a 0-length string', position + end + end + if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then + if options.type == "header" and not options.cmdName and not options.name then + elseif options.cmdName then + if type(options.cmdName) ~= "string" then + return '"cmdName" must be a string or nil', position + elseif options.cmdName:len() == 0 then + return '"cmdName" cannot be a 0-length string', position + end + if type(options.guiName) ~= "string" then + if not options.guiNameIsMap then + return '"guiName" must be a string or nil', position + end + elseif options.guiName:len() == 0 then + return '"guiName" cannot be a 0-length string', position + end + else + if type(options.name) ~= "string" then + return '"name" must be a string', position + elseif options.name:len() == 0 then + return '"name" cannot be a 0-length string', position + end + end + end + if options.guiNameIsMap then + if type(options.guiNameIsMap) ~= "boolean" then + return '"guiNameIsMap" must be a boolean or nil', position + elseif options.type ~= "toggle" then + return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position + elseif type(options.map) ~= "table" then + return '"map" must be a table', position + end + end + if options.message and type(options.message) ~= "string" then + return '"message" must be a string or nil', position + end + if options.error and type(options.error) ~= "string" then + return '"error" must be a string or nil', position + end + if options.current and type(options.current) ~= "string" then + return '"current" must be a string or nil', position + end + if options.order then + if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then + return '"order" must be a non-zero number or nil', position + end + end + if options.disabled then + if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then + return '"disabled" must be a function, string, or boolean', position + end + end + if options.cmdHidden then + if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then + return '"cmdHidden" must be a function, string, or boolean', position + end + end + if options.guiHidden then + if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then + return '"guiHidden" must be a function, string, or boolean', position + end + end + if options.hidden then + if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then + return '"hidden" must be a function, string, or boolean', position + end + end + if kind == "text" then + if type(options.validate) == "table" then + local t = options.validate + local iTable = nil + for k,v in pairs(t) do + if type(k) == "number" then + if iTable == nil then + iTable = true + elseif not iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + elseif k < 1 or k > #t then + return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position + end + else + if iTable == nil then + iTable = false + elseif iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + end + end + if type(v) ~= "string" then + return '"validate" values must all be strings', position + end + end + if options.multiToggle and options.multiToggle ~= true then + return '"multiToggle" must be a boolean or nil if "validate" is a table', position + end + elseif options.validate == "keybinding" then + -- no other checks + else + if type(options.usage) ~= "string" then + return '"usage" must be a string', position + elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return '"validate" must be a string, function, or table', position + end + end + if options.multiToggle and type(options.validate) ~= "table" then + return '"validate" must be a table if "multiToggle" is true', position + end + elseif kind == "range" then + if options.min or options.max then + if type(options.min) ~= "number" then + return '"min" must be a number', position + elseif type(options.max) ~= "number" then + return '"max" must be a number', position + elseif options.min >= options.max then + return '"min" must be less than "max"', position + end + end + if options.step then + if type(options.step) ~= "number" then + return '"step" must be a number', position + elseif options.step < 0 then + return '"step" must be nonnegative', position + end + end + if options.bigStep then + if type(options.bigStep) ~= "number" then + return '"bigStep" must be a number', position + elseif options.bigStep < 0 then + return '"bigStep" must be nonnegative', position + end + end + if options.isPercent and options.isPercent ~= true then + return '"isPercent" must either be nil, true, or false', position + end + elseif kind == "toggle" then + if options.map then + if type(options.map) ~= "table" then + return '"map" must be a table', position + elseif type(options.map[true]) ~= "string" then + return '"map[true]" must be a string', position + elseif type(options.map[false]) ~= "string" then + return '"map[false]" must be a string', position + end + end + elseif kind == "color" then + if options.hasAlpha and options.hasAlpha ~= true then + return '"hasAlpha" must be nil, true, or false', position + end + elseif kind == "group" then + if options.pass and options.pass ~= true then + return '"pass" must be nil, true, or false', position + end + if type(options.args) ~= "table" then + return '"args" must be a table', position + end + for k,v in pairs(options.args) do + if type(k) ~= "number" then + if type(k) ~= "string" then + return '"args" keys must be strings or numbers', position + elseif k:len() == 0 then + return '"args" keys must not be 0-length strings.', position + end + end + if type(v) ~= "table" then + return '"args" values must be tables', position and position .. "." .. k or k + end + local newposition + if position then + newposition = position .. ".args." .. k + else + newposition = "args." .. k + end + local err, pos = validateOptions(v, newposition, baseOptions, options.pass) + if err then + return err, pos + end + end + elseif kind == "execute" then + if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then + return '"confirm" must be a string, boolean, or nil', position + end + end + if options.icon and type(options.icon) ~= "string" then + return'"icon" must be a string', position + end + if options.iconWidth or options.iconHeight then + if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then + return '"iconHeight" and "iconWidth" must be numbers', position + end + end + if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then + if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then + return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position + end + end +end + +local validatedOptions + +local values +local mysort_args +local mysort +local othersort +local othersort_validate + +local baseFunc, currentLevel + +local function confirmPopup(message, func, ...) + if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then + StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {} + end + local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] + for k in pairs(t) do + t[k] = nil + end + t.text = message + t.button1 = ACCEPT or "Accept" + t.button2 = CANCEL or "Cancel" + t.OnAccept = function() + func(unpack(t)) + end + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + t.timeout = 0 + t.whileDead = 1 + t.hideOnEscape = 1 + + Dewdrop:Close() + StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG") +end + + +local function getMethod(settingname, handler, v, methodName, ...) -- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222" + assert(v and type(v)=="table") + assert(methodName and type(methodName)=="string") + + local method = v[methodName] + if type(method)=="function" then + return method, ... + elseif type(method)=="string" then + if not handler then + Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) + elseif not handler[method] then + Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method) + end + return handler[method], handler, ... + end + + Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName) +end + +local function callMethod(settingname, handler, v, methodName, ...) + assert(v and type(v)=="table") + assert(methodName and type(methodName)=="string") + + local method = v[methodName] + if type(method)=="function" then + local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...) + if not success then + geterrorhandler()(ret) + return nil + end + return ret,ret2,ret3,ret4 + + elseif type(method)=="string" then + + local neg = method:match("^~(.-)$") + if neg then + method = neg + end + if not handler then + Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) + elseif not handler[method] then + Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method) + end + local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...) + if not success then + geterrorhandler()(ret) + return nil + end + if neg then + return not ret + end + return ret,ret2,ret3,ret4 + elseif method == false then + return nil + end + + Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)") +end + +local function skip1Nil(...) + if select(1,...)==nil then + return select(2,...) + end + return ... +end + +function Dewdrop:FeedAceOptionsTable(options, difference) + self:argCheck(options, 2, "table") + self:argCheck(difference, 3, "nil", "number") + if not currentLevel then + self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") + end + if not difference then + difference = 0 + end + if not validatedOptions then + validatedOptions = {} + end + if not validatedOptions[options] then + local err, position = validateOptions(options) + + if err then + if position then + Dewdrop:error(position .. ": " .. err) + else + Dewdrop:error(err) + end + end + + validatedOptions[options] = true + end + local level = levels[currentLevel] + if not level then + self:error("Improper level given") + end + if not values then + values = {} + else + for k,v in pairs(values) do + values[k] = nil + end + end + + local current = level + while current do -- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later + if current.num == difference + 1 then + break + end + table.insert(values, current.value) + current = levels[current.num - 1] + end + + local realOptions = options + local handler = options.handler + local passTable + local passValue + while #values > 0 do -- This loop traverses values from the END (trunk nodes first, then onto leaf nodes) + if options.pass then + if options.get and options.set then + passTable = options + elseif not passTable then + passTable = options + end + else + passTable = nil + end + local value = table.remove(values) + options = options.args and options.args[value] + if not options then + return + end + handler = options.handler or handler + passValue = passTable and value or nil + end + + if options.type == "group" then + local hidden = options.hidden + if type(hidden) == "function" or type(hidden) == "string" then + hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false + end + if hidden then + return + end + local disabled = options.disabled + if type(disabled) == "function" or type(disabled) == "string" then + disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false + end + if disabled then + self:AddLine( + 'text', DISABLED, + 'disabled', true + ) + return + end + for k in pairs(options.args) do + table.insert(values, k) + end + if options.pass then + if options.get and options.set then + passTable = options + elseif not passTable then + passTable = options + end + else + passTable = nil + end + if not mysort then + mysort = function(a, b) + local alpha, bravo = mysort_args[a], mysort_args[b] + local alpha_order = alpha.order or 100 + local bravo_order = bravo.order or 100 + local alpha_name = alpha.guiName or alpha.name + local bravo_name = bravo.guiName or bravo.name + if alpha_order == bravo_order then + if not alpha_name then + return bravo_name + elseif not bravo_name then + return false + else + return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() + end + else + if alpha_order < 0 then + if bravo_order > 0 then + return false + end + else + if bravo_order < 0 then + return true + end + end + return alpha_order < bravo_order + end + end + end + mysort_args = options.args + table.sort(values, mysort) + mysort_args = nil + local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0 + local last_order = 1 + for _,k in ipairs(values) do + local v = options.args[k] + local handler = v.handler or handler + if hasBoth and last_order > 0 and (v.order or 100) < 0 then + hasBoth = false + self:AddLine() + end + local hidden, disabled = v.guiHidden or v.hidden, v.disabled + + if type(hidden) == "function" or type(hidden) == "string" then + hidden = callMethod(k, handler, v, "hidden", v.passValue) or false + end + if not hidden then + if type(disabled) == "function" or type(disabled) == "string" then + disabled = callMethod(k, handler, v, "disabled", v.passValue) or false + end + local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) + local desc = v.guiDesc or v.desc + local iconHeight = v.iconHeight or 16 + local iconWidth = v.iconWidth or 16 + local iconCoordLeft = v.iconCoordLeft + local iconCoordRight = v.iconCoordRight + local iconCoordBottom = v.iconCoordBottom + local iconCoordTop = v.iconCoordTop + local tooltipTitle, tooltipText + tooltipTitle = name + if name ~= desc then + tooltipText = desc + end + if type(v.usage) == "string" and v.usage:trim():len() > 0 then + if tooltipText then + tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage) + else + tooltipText = USAGE_TOOLTIP:format(v.usage) + end + end + local v_p = passTable + if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then + v_p = v + end + local passValue = v.passValue or (v_p~=v and k) or nil + if v.type == "toggle" then + local checked = callMethod(name, handler, v_p, "get", passValue) or false + local checked_arg = checked + if type(v_p.get)=="string" and v_p.get:match("^~") then + checked_arg = not checked + end + local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set", skip1Nil(passValue, not checked_arg)) + if v.guiNameIsMap then + checked = checked and true or false + name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") + tooltipTitle = name + checked = true--nil + end + self:AddLine( + 'text', name, + 'checked', checked, + 'isRadio', v.isRadio, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + elseif v.type == "execute" then + local func, arg1, arg2, arg3, arg4 + local confirm = v.confirm + if confirm == true then + confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle) + func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) + elseif type(confirm) == "string" then + func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) + else + func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue) + end + self:AddLine( + 'text', name, + 'checked', checked, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'arg4', arg4, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "range" then + local sliderValue + sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0 + local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set", passValue) + if tooltipText then + tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP) + else + tooltipText = RANGE_TOOLTIP + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'hasSlider', true, + 'sliderMin', v.min or 0, + 'sliderMax', v.max or 1, + 'sliderStep', v.step or 0, + 'sliderBigStep', v.bigStep or nil, + 'sliderIsPercent', v.isPercent or false, + 'sliderValue', sliderValue, + 'sliderFunc', sliderFunc, + 'sliderArg1', sliderArg1, + 'sliderArg2', sliderArg2, + 'fromAceOptions', true, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "color" then + local r,g,b,a = callMethod(name, handler, v_p, "get", passValue) + if not r then + r,g,b,a = 0,0,0,0 + end + local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set", passValue) + self:AddLine( + 'text', name, + 'hasArrow', true, + 'hasColorSwatch', true, + 'r', r, + 'g', g, + 'b', b, + 'opacity', v.hasAlpha and a or nil, + 'hasOpacity', v.hasAlpha, + 'colorFunc', colorFunc, + 'colorArg1', colorArg1, + 'colorArg2', colorArg2, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + elseif v.type == "text" then + if type(v.validate) == "table" then + local func,arg1,arg2 + if v.onClick then + func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) + end + local checked + if v.isChecked then + checked = callMethod(name, handler, v, "isChecked", passValue) or false + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'value', k, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'mouseoverUnderline', func and true or nil, + 'disabled', disabled, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + else + local editBoxText + editBoxText = callMethod(name, handler, v_p, "get", passValue) or "" + local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set", passValue) + + local editBoxValidateFunc, editBoxValidateArg1 + + if v.validate and v.validate ~= "keybinding" then + if v.validate == "keybinding" then + if tooltipText then + tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC) + else + tooltipText = RESET_KEYBINDING_DESC + end + else + editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue! + end + end + + self:AddLine( + 'text', name, + 'hasArrow', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom, + 'hasEditBox', true, + 'editBoxText', editBoxText, + 'editBoxFunc', editBoxFunc, + 'editBoxArg1', editBoxArg1, + 'editBoxArg2', editBoxArg2, + 'editBoxValidateFunc', editBoxValidateFunc, + 'editBoxValidateArg1', editBoxValidateArg1, + 'editBoxIsKeybinding', v.validate == "keybinding", + 'editBoxKeybindingOnly', v.keybindingOnly, + 'editBoxKeybindingExcept', v.keybindingExcept, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + end + elseif v.type == "group" then + local func,arg1,arg2 + if v.onClick then + func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) + end + local checked + if v.isChecked then + checked = callMethod(name, handler, v, "isChecked", passValue) or false + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'value', k, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'mouseoverUnderline', func and true or nil, + 'disabled', disabled, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "header" then + if name == "" or not name then + self:AddLine( + 'isTitle', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + else + self:AddLine( + 'text', name, + 'isTitle', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + end + end + end + last_order = v.order or 100 + end + elseif options.type == "text" and type(options.validate) == "table" then + local current + local options_p = passTable + if not options_p or (options.get and options.set) then + options_p = options + passTable = nil + passValue = nil + end + local multiToggle = options.multiToggle + local passValue = options.passValue or passValue + if not multiToggle then + current = callMethod(k, handler, options_p, "get", passValue) + end + local indexed = true + for k,v in pairs(options.validate) do + if type(k) ~= "number" then + indexed = false + end + table.insert(values, k) + end + if not indexed then + if not othersort then + othersort = function(alpha, bravo) + return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() + end + end + othersort_validate = options.validate + table.sort(values, othersort) + othersort_validate = nil + end + for _,k in ipairs(values) do + local v = options.validate[k] + if type(k) == "number" then + k = v + end + local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set", skip1Nil(passValue, k)) + local checked + if multiToggle then + checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false + if arg2 == nil then + arg2 = not checked + elseif arg3 == nil then + arg3 = not checked + else + arg4 = not checked + end + else + checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) + if checked then + func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil + end + end + local tooltipTitle + local tooltipText + if options.validateDesc then + tooltipTitle = v + tooltipText = options.validateDesc[k] + else + tooltipTitle = options.guiName or options.name + tooltipText = v + end + self:AddLine( + 'text', v, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'arg4', arg4, + 'isRadio', not multiToggle, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + end + for k in pairs(values) do + values[k] = nil + end + else + return false + end + return true +end + +function Dewdrop:FeedTable(s, difference) + self:argCheck(s, 2, "table") + self:argCheck(difference, 3, "nil", "number") + if not currentLevel then + self:error("Cannot call `FeedTable' outside of a Dewdrop declaration") + end + if not difference then + difference = 0 + end + local level = levels[currentLevel] + if not level then + self:error("Improper level given") + end + if not values then + values = {} + else + for k,v in pairs(values) do + values[k] = nil + end + end + local t = s.subMenu and s or {subMenu = s} + local current = level + while current do + if current.num == difference + 1 then + break + end + table.insert(values, current.value) + current = levels[current.num - 1] + end + + while #values > 0 do + local value = table.remove(values) + t = t.subMenu and t.subMenu[value] + if not t then + return + end + end + + if t.subMenu or current.num == 1 then + for k in pairs(t.subMenu) do + table.insert(values, k) + end + table.sort(values) + for _,k in ipairs(values) do + local argTable = {"value", k} + for key, val in pairs(t.subMenu[k]) do + table.insert(argTable, key) + table.insert(argTable, val) + end + self:AddLine(unpack(argTable)) + end + for k in pairs(values) do + values[k] = nil + end + return false + end + return true +end + +function Refresh(self, level) + if type(level) == "number" then + level = levels[level] + end + if not level then + return + end + if baseFunc then + Clear(self, level) + currentLevel = level.num + if type(baseFunc) == "table" then + if currentLevel == 1 then + local handler = baseFunc.handler + if handler then + local name = tostring(handler) + if not name:find('^table:') and not handler.hideMenuTitle then + name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") + self:AddLine( + 'text', name, + 'isTitle', true + ) + end + end +-- elseif level.parentText then +-- self:AddLine( +-- 'text', level.parentText, +-- 'tooltipTitle', level.parentTooltipTitle, +-- 'tooltipText', level.parentTooltipText, +-- 'tooltipFunc', level.parentTooltipFunc, +-- 'isTitle', true +-- ) + end + self:FeedAceOptionsTable(baseFunc) + if currentLevel == 1 then + self:AddLine( + 'text', CLOSE, + 'tooltipTitle', CLOSE, + 'tooltipText', CLOSE_DESC, + 'closeWhenClicked', true + ) + end + else +-- if level.parentText then +-- self:AddLine( +-- 'text', level.parentText, +-- 'tooltipTitle', level.parentTooltipTitle, +-- 'tooltipText', level.parentTooltipText, +-- 'tooltipFunc', level.parentTooltipFunc, +-- 'isTitle', true +-- ) +-- end + baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value) + end + currentLevel = nil + CheckSize(self, level) + end +end + +function Dewdrop:Refresh(level) + self:argCheck(level, 2, "number", "nil") + if not level then + for k,v in pairs(levels) do + Refresh(self, v) + end + else + Refresh(self, levels[level]) + end +end + +function OpenSlider(self, parent) + if not sliderFrame then + sliderFrame = CreateFrame("Frame", nil, nil) + sliderFrame:SetWidth(100) + sliderFrame:SetHeight(170) + sliderFrame:SetScale(UIParent:GetScale()) + sliderFrame:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG") + if sliderFrame.SetTopLevel then + sliderFrame:SetTopLevel(true) + end + sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + sliderFrame:EnableMouse(true) + sliderFrame:EnableMouseWheel(true) + sliderFrame:Hide() + sliderFrame:SetPoint("CENTER", UIParent, "CENTER") + local slider = CreateFrame("Slider", nil, sliderFrame) + sliderFrame.slider = slider + slider:SetOrientation("VERTICAL") + slider:SetMinMaxValues(0, 1) + slider:SetValueStep(0.000000001) + slider:SetValue(0.5) + slider:SetWidth(16) + slider:SetHeight(128) + slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0) + slider:SetBackdrop(tmp( + 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", + 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", + 'tile', true, + 'edgeSize', 8, + 'tileSize', 8, + 'insets', tmp2( + 'left', 3, + 'right', 3, + 'top', 3, + 'bottom', 3 + ) + )) + local texture = slider:CreateTexture() + slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") + local text = slider:CreateFontString(nil, "ARTWORK") + sliderFrame.topText = text + text:SetFontObject(GameFontGreenSmall) + text:SetText("100%") + text:SetPoint("BOTTOM", slider, "TOP") + local text = slider:CreateFontString(nil, "ARTWORK") + sliderFrame.bottomText = text + text:SetFontObject(GameFontGreenSmall) + text:SetText("0%") + text:SetPoint("TOP", slider, "BOTTOM") + local editBox = CreateFrame("EditBox", nil, sliderFrame) + sliderFrame.currentText = editBox + editBox:SetFontObject(ChatFontNormal) + editBox:SetHeight(13) + editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0) + editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0) + editBox:SetText("50%") + editBox:SetJustifyH("CENTER") + + local width = editBox:GetWidth()/2 + 10 + local left = editBox:CreateTexture(nil, "BACKGROUND") + left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") + left:SetTexCoord(0, width / 256, 0, 1) + left:SetWidth(width) + left:SetHeight(32) + left:SetPoint("LEFT", editBox, "LEFT", -10, 0) + local right = editBox:CreateTexture(nil, "BACKGROUND") + right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") + right:SetTexCoord(1 - width / 256, 1, 0, 1) + right:SetWidth(width) + right:SetHeight(32) + right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) + + local changed = false + local inside = false + slider:SetScript("OnValueChanged", function() + if sliderFrame.changing then + return + end + changed = true + local done = false + if sliderFrame.parent and sliderFrame.parent.sliderFunc then + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step + if sliderFrame.fineStep then + step = sliderFrame.parent.sliderStep or (max - min) / 100 + else + step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 + end + local value = (1 - slider:GetValue()) * (max - min) + min + if step > 0 then + value = math.floor((value - min) / step + 0.5) * step + min + if value > max then + value = max + elseif value < min then + value = min + end + end + if value == sliderFrame.lastValue then + return + end + sliderFrame.lastValue = value + local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value)) + if sliderFrame.parent.fromAceOptions then + text = nil + elseif type(text) == "string" or type(text) == "number" then + sliderFrame.currentText:SetText(text) + done = true + end + end + if not done then + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step + if sliderFrame.fineStep then + step = sliderFrame.parent.sliderStep or (max - min) / 100 + else + step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 + end + local value = (1 - slider:GetValue()) * (max - min) + min + if step > 0 then + value = math.floor((value - min) / step + 0.5) * step + min + if value > max then + value = max + elseif value < min then + value = min + end + end + if sliderFrame.parent.sliderIsPercent then + sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100)) + else + if step < 0.1 then + sliderFrame.currentText:SetText(string.format("%.2f", value)) + elseif step < 1 then + sliderFrame.currentText:SetText(string.format("%.1f", value)) + else + sliderFrame.currentText:SetText(string.format("%.0f", value)) + end + end + end + end) + local function onEnter() + StopCounting(self, sliderFrame.level) + showGameTooltip(sliderFrame.parent) + end + local function onLeave() + GameTooltip:Hide() + end + sliderFrame:SetScript("OnEnter", onEnter) + sliderFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + if changed then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + end + end) + editBox:SetScript("OnEnter", onEnter) + editBox:SetScript("OnLeave", onLeave) + slider:SetScript("OnMouseDown", function() + sliderFrame.mouseDown = true + GameTooltip:Hide() + end) + slider:SetScript("OnMouseUp", function() + sliderFrame.mouseDown = false + if changed--[[ and not inside]] then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + end + if inside then + showGameTooltip(sliderFrame.parent) + end + end) + slider:SetScript("OnEnter", function() + inside = true + StopCounting(self, sliderFrame.level) + showGameTooltip(sliderFrame.parent) + end) + slider:SetScript("OnLeave", function() + inside = false + GameTooltip:Hide() + if changed and not sliderFrame.mouseDown then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + + changed = false + end + end) + sliderFrame:SetScript("OnMouseWheel", function(t, a1) + local arg1 = a1 or arg1 + local up = arg1 > 0 + + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step = sliderFrame.parent.sliderStep or (max - min) / 100 + if step <= 0 then + step = (max - min) / 100 + end + + local value = (1 - slider:GetValue()) * (max - min) + min + if up then + value = value + step + else + value = value - step + end + if value > max then + value = max + elseif value < min then + value = min + end + sliderFrame.fineStep = true + if max<=min then + slider:SetValue(0) + else + slider:SetValue(1 - (value - min) / (max - min)) + end + sliderFrame.fineStep = nil + end) + slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel")) + editBox:SetScript("OnEnterPressed", function(t, a1) + local value = editBox:GetNumber() + + if sliderFrame.parent.sliderIsPercent then + value = value / 100 + end + + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + + if value > max then + value = max + elseif value < min then + value = min + end + sliderFrame.fineStep = true + if max <= min then + slider:SetValue(0) + else + slider:SetValue(1 - (value - min) / (max - min)) + end + sliderFrame.fineStep = nil + + StartCounting(self, sliderFrame.level) + end) + editBox:SetScript("OnEscapePressed", function() + self:Close(sliderFrame.level) + StartCounting(self, sliderFrame.level) + end) + editBox:SetAutoFocus(false) + end + sliderFrame.parent = parent + sliderFrame.level = parent.level.num + 1 + sliderFrame.parentValue = parent.level.value + sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) + sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) + sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) + sliderFrame.currentText:ClearFocus() + sliderFrame.changing = true + if not parent.sliderMin or not parent.sliderMax then + return + end + + if parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + + sliderFrame:SetClampedToScreen(false) + if not parent.sliderValue then + parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 + end + if parent.sliderMax <= parent.sliderMin then + sliderFrame.slider:SetValue(0) + else + sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) + end + sliderFrame.changing = false + sliderFrame.bottomText:SetText(parent.sliderMinText or "0") + sliderFrame.topText:SetText(parent.sliderMaxText or "1") + local text + if parent.sliderFunc and not parent.fromAceOptions then + text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue)) + end + if type(text) == "number" or type(text) == "string" then + sliderFrame.currentText:SetText(text) + elseif parent.sliderIsPercent then + sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) + else + if parent.sliderStep < 0.1 then + sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue)) + elseif parent.sliderStep < 1 then + sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue)) + else + sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue)) + end + end + + + sliderFrame.lastValue = parent.sliderValue + + local level = parent.level + sliderFrame:Show() + sliderFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + local dirty + if level.lastDirection == "RIGHT" then + if sliderFrame:GetRight() > GetScreenWidth() then + level.lastDirection = "LEFT" + dirty = true + end + elseif sliderFrame:GetLeft() < 0 then + level.lastDirection = "RIGHT" + dirty = true + end + if level.lastVDirection == "DOWN" then + if sliderFrame:GetBottom() < 0 then + level.lastVDirection = "UP" + dirty = true + end + elseif sliderFrame:GetTop() > GetScreenWidth() then + level.lastVDirection = "DOWN" + dirty = true + end + if dirty then + sliderFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom() + sliderFrame:ClearAllPoints() + sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end + sliderFrame:SetClampedToScreen(true) +end + +function OpenEditBox(self, parent) + if not editBoxFrame then + editBoxFrame = CreateFrame("Frame", nil, nil) + editBoxFrame:SetWidth(200) + editBoxFrame:SetHeight(40) + editBoxFrame:SetScale(UIParent:GetScale()) + editBoxFrame:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG") + if editBoxFrame.SetTopLevel then + editBoxFrame:SetTopLevel(true) + end + editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + editBoxFrame:EnableMouse(true) + editBoxFrame:EnableMouseWheel(true) + editBoxFrame:Hide() + editBoxFrame:SetPoint("CENTER", UIParent, "CENTER") + + local editBox = CreateFrame("EditBox", nil, editBoxFrame) + editBoxFrame.editBox = editBox + editBox:SetFontObject(ChatFontNormal) + editBox:SetWidth(160) + editBox:SetHeight(13) + editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0) + + local left = editBox:CreateTexture(nil, "BACKGROUND") + left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") + left:SetTexCoord(0, 100 / 256, 0, 1) + left:SetWidth(100) + left:SetHeight(32) + left:SetPoint("LEFT", editBox, "LEFT", -10, 0) + local right = editBox:CreateTexture(nil, "BACKGROUND") + right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") + right:SetTexCoord(156/256, 1, 0, 1) + right:SetWidth(100) + right:SetHeight(32) + right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) + + editBox:SetScript("OnEnterPressed", function() + if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then + local t = editBox.realText or editBox:GetText() or "" + local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t)) + if not result then + UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) + return + end + end + if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then + local t + if editBox.realText ~= "NONE" then + t = editBox.realText or editBox:GetText() or "" + end + editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t)) + end + self:Close(editBoxFrame.level) + for i = 1, editBoxFrame.level - 1 do + Refresh(self, levels[i]) + end + StartCounting(self, editBoxFrame.level-1) + end) + editBox:SetScript("OnEscapePressed", function() + self:Close(editBoxFrame.level) + StartCounting(self, editBoxFrame.level-1) + end) + editBox:SetScript("OnReceiveDrag", function(this) + if GetCursorInfo then + local type, alpha, bravo = GetCursorInfo() + local text + if type == "spell" then + text = GetSpellName(alpha, bravo) + elseif type == "item" then + text = bravo + end + if not text then + return + end + ClearCursor() + editBox:SetText(text) + end + end) + local changing = false + local skipNext = false + + function editBox:SpecialSetText(text) + local oldText = editBox:GetText() or "" + if not text then + text = "" + end + if text ~= oldText then + changing = true + self:SetText(tostring(text)) + changing = false + skipNext = true + end + end + + editBox:SetScript("OnTextChanged", function() + if skipNext then + skipNext = false + elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then + local t + if editBox.realText ~= "NONE" then + t = editBox.realText or editBox:GetText() or "" + end + local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t)) + if text then + editBox:SpecialSetText(text) + end + end + end) + editBoxFrame:SetScript("OnEnter", function() + StopCounting(self, editBoxFrame.level) + showGameTooltip(editBoxFrame.parent) + end) + editBoxFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + editBox:SetScript("OnEnter", function() + StopCounting(self, editBoxFrame.level) + showGameTooltip(editBoxFrame.parent) + end) + editBox:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + editBoxFrame:SetScript("OnKeyDown", function(this, a1) + if not editBox.keybinding then + return + end + local arg1 = a1 or arg1 + local screenshotKey = GetBindingKey("SCREENSHOT") + if screenshotKey and arg1 == screenshotKey then + Screenshot() + return + end + + if arg1 == "LeftButton" then + arg1 = "BUTTON1" + elseif arg1 == "RightButton" then + arg1 = "BUTTON2" + elseif arg1 == "MiddleButton" then + arg1 = "BUTTON3" + elseif arg1 == "Button4" then + arg1 = "BUTTON4" + elseif arg1 == "Button5" then + arg1 = "BUTTON5" + end + if arg1 == "UNKNOWN" then + return + elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then + return + elseif arg1 == "ENTER" then + if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then + return editBox:GetScript("OnEscapePressed")() + elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then + return editBox:GetScript("OnEscapePressed")() + else + return editBox:GetScript("OnEnterPressed")() + end + elseif arg1 == "ESCAPE" then + if editBox.realText == "NONE" then + return editBox:GetScript("OnEscapePressed")() + else + editBox:SpecialSetText(NONE or "NONE") + editBox.realText = "NONE" + return + end + elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then + return + elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then + return + end + local s = GetBindingText(arg1, "KEY_") + if s == "BUTTON1" then + s = KEY_BUTTON1 + elseif s == "BUTTON2" then + s = KEY_BUTTON2 + end + local real = arg1 + if IsShiftKeyDown() then + s = "Shift-" .. s + real = "SHIFT-" .. real + end + if IsControlKeyDown() then + s = "Ctrl-" .. s + real = "CTRL-" .. real + end + if IsAltKeyDown() then + s = "Alt-" .. s + real = "ALT-" .. real + end + if editBox:GetText() ~= s then + editBox:SpecialSetText("-") + editBox:SpecialSetText(s) + editBox.realText = real + return editBox:GetScript("OnTextChanged")() + end + end) + editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) + editBox:SetScript("OnMouseDown", function(this, ...) + if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then + return editBox:GetScript("OnReceiveDrag")(this, ...) + end + return editBoxFrame:GetScript("OnKeyDown")(this, ...) + end) + editBoxFrame:SetScript("OnMouseWheel", function(t, a1) + local arg1 = a1 or arg1 + local up = arg1 > 0 + arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" + return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1) + end) + editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel")) + end + editBoxFrame.parent = parent + editBoxFrame.level = parent.level.num + 1 + editBoxFrame.parentValue = parent.level.value + editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) + editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1) + editBoxFrame.editBox.realText = nil + editBoxFrame:SetClampedToScreen(false) + + editBoxFrame.editBox:SpecialSetText("") + if parent.editBoxIsKeybinding then + local s = parent.editBoxText + if s == "" then + s = "NONE" + end + editBoxFrame.editBox.realText = s + if s and s ~= "NONE" then + local alpha,bravo = s:match("^(.+)%-(.+)$") + if not bravo then + alpha = nil + bravo = s + end + bravo = GetBindingText(bravo, "KEY_") + if alpha then + editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) + else + editBoxFrame.editBox:SpecialSetText(bravo) + end + else + editBoxFrame.editBox:SpecialSetText(NONE or "NONE") + end + else + editBoxFrame.editBox:SpecialSetText(parent.editBoxText) + end + + editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding + editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly + editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept + editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) + editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) + + if parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + + local level = parent.level + editBoxFrame:Show() + editBoxFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + local dirty + if level.lastDirection == "RIGHT" then + if editBoxFrame:GetRight() > GetScreenWidth() then + level.lastDirection = "LEFT" + dirty = true + end + elseif editBoxFrame:GetLeft() < 0 then + level.lastDirection = "RIGHT" + dirty = true + end + if level.lastVDirection == "DOWN" then + if editBoxFrame:GetBottom() < 0 then + level.lastVDirection = "UP" + dirty = true + end + elseif editBoxFrame:GetTop() > GetScreenWidth() then + level.lastVDirection = "DOWN" + dirty = true + end + if dirty then + editBoxFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom() + editBoxFrame:ClearAllPoints() + editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end + editBoxFrame:SetClampedToScreen(true) +end + +function Dewdrop:EncodeKeybinding(text) + if text == nil or text == "NONE" then + return nil + end + text = tostring(text):upper() + local shift, ctrl, alt + local modifier + while true do + if text == "-" then + break + end + modifier, text = strsplit('-', text, 2) + if text then + if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then + return false + end + if modifier == "SHIFT" then + if shift then + return false + end + shift = true + end + if modifier == "CTRL" then + if ctrl then + return false + end + ctrl = true + end + if modifier == "ALT" then + if alt then + return false + end + alt = true + end + else + text = modifier + break + end + end + if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then + return false + end + local s = GetBindingText(text, "KEY_") + if s == "BUTTON1" then + s = KEY_BUTTON1 + elseif s == "BUTTON2" then + s = KEY_BUTTON2 + end + if shift then + s = "Shift-" .. s + end + if ctrl then + s = "Ctrl-" .. s + end + if alt then + s = "Alt-" .. s + end + return s +end + +function Dewdrop:IsOpen(parent) + self:argCheck(parent, 2, "table", "string", "nil") + return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent()) +end + +function Dewdrop:GetOpenedParent() + return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent()) +end + +function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY) + self:Close(level) + if DewdropLib then + local d = DewdropLib:GetInstance('1.0') + local ret, val = pcall(d, IsOpen, d) + if ret and val then + DewdropLib:GetInstance('1.0'):Close() + end + end + if type(parent) == "table" then + parent:GetCenter() + end + local frame = AcquireLevel(self, level) + if level == 1 then + frame.lastDirection = "RIGHT" + frame.lastVDirection = "DOWN" + else + frame.lastDirection = levels[level - 1].lastDirection + frame.lastVDirection = levels[level - 1].lastVDirection + end + frame:SetFrameStrata("FULLSCREEN_DIALOG") + frame:ClearAllPoints() + frame.parent = parent + frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0) + frame:Show() + if level == 1 then + baseFunc = func + end + levels[level].value = value +-- levels[level].parentText = parent.text and parent.text:GetText() or nil +-- levels[level].parentTooltipTitle = parent.tooltipTitle +-- levels[level].parentTooltipText = parent.tooltipText +-- levels[level].parentTooltipFunc = parent.tooltipFunc + if type(parent) == "table" and parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + relativePoint = relativePoint or point + Refresh(self, levels[level]) + if point or (cursorX and cursorY) then + frame:ClearAllPoints() + if cursorX and cursorY then + local curX, curY = GetScaledCursorPosition() + if curY < GetScreenHeight() / 2 then + point, relativePoint = "BOTTOM", "BOTTOM" + else + point, relativePoint = "TOP", "TOP" + end + if curX < GetScreenWidth() / 2 then + point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT" + else + point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint) + if cursorX and cursorY then + local left = frame:GetLeft() + local width = frame:GetWidth() + local bottom = frame:GetBottom() + local height = frame:GetHeight() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "BOTTOM" or point == "TOP" then + if curX < GetScreenWidth() / 2 then + point = point .. "LEFT" + else + point = point .. "RIGHT" + end + elseif point == "CENTER" then + if curX < GetScreenWidth() / 2 then + point = "LEFT" + else + point = "RIGHT" + end + end + local xOffset, yOffset = 0, 0 + if curY > GetScreenHeight() / 2 then + yOffset = -height + end + if curX > GetScreenWidth() / 2 then + xOffset = -width + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset) + if level == 1 then + frame.lastDirection = "RIGHT" + end + elseif cursorX then + local left = frame:GetLeft() + local width = frame:GetWidth() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "BOTTOM" or point == "TOP" then + if curX < GetScreenWidth() / 2 then + point = point .. "LEFT" + else + point = point .. "RIGHT" + end + elseif point == "CENTER" then + if curX < GetScreenWidth() / 2 then + point = "LEFT" + else + point = "RIGHT" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0) + if level == 1 then + frame.lastDirection = "RIGHT" + end + elseif cursorY then + local bottom = frame:GetBottom() + local height = frame:GetHeight() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "LEFT" or point == "RIGHT" then + if curX < GetScreenHeight() / 2 then + point = point .. "BOTTOM" + else + point = point .. "TOP" + end + elseif point == "CENTER" then + if curX < GetScreenHeight() / 2 then + point = "BOTTOM" + else + point = "TOP" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2) + if level == 1 then + frame.lastDirection = "DOWN" + end + end + if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then + if frame:GetBottom() < 0 then + local point, parent, relativePoint, x, y = frame:GetPoint(1) + local change = GetScreenHeight() - frame:GetTop() + local otherChange = -frame:GetBottom() + if otherChange < change then + change = otherChange + end + frame:SetPoint(point, parent, relativePoint, x, y + change) + elseif frame:GetTop() > GetScreenHeight() then + local point, parent, relativePoint, x, y = frame:GetPoint(1) + local change = GetScreenHeight() - frame:GetTop() + local otherChange = -frame:GetBottom() + if otherChange < change then + change = otherChange + end + frame:SetPoint(point, parent, relativePoint, x, y + change) + end + end + end + CheckDualMonitor(self, frame) + frame:SetClampedToScreen(true) + frame:SetClampedToScreen(false) + StartCounting(self, level) +end + +function Dewdrop:IsRegistered(parent) + self:argCheck(parent, 2, "table", "string") + return not not self.registry[parent] +end + +function Dewdrop:Register(parent, ...) + self:argCheck(parent, 2, "table", "string") + if self.registry[parent] then + self:Unregister(parent) + end + local info = new(...) + if type(info.children) == "table" then + local err, position = validateOptions(info.children) + + if err then + if position then + Dewdrop:error(position .. ": " .. err) + else + Dewdrop:error(err) + end + end + end + self.registry[parent] = info + if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then + if parent:HasScript("OnMouseUp") then + local script = parent:GetScript("OnMouseUp") + parent:SetScript("OnMouseUp", function(this, ...) + if script then + script(this, ...) + end + if arg1 == "RightButton" and self.registry[parent] then + if self:IsOpen(parent) then + self:Close() + else + self:Open(parent) + end + end + end) + end + if parent:HasScript("OnMouseDown") then + local script = parent:GetScript("OnMouseDown") + parent:SetScript("OnMouseDown", function(this, ...) + if script then + script(this, ...) + end + if self.registry[parent] then + self:Close() + end + end) + end + end + self.onceRegistered[parent] = true +end + +function Dewdrop:Unregister(parent) + self:argCheck(parent, 2, "table", "string") + self.registry[parent] = nil +end + +function Dewdrop:Open(parent, ...) + self:argCheck(parent, 2, "table", "string") + local info + local k1 = ... + if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then + info = tmp(select(2, ...)) + for k,v in pairs(self.registry[k1]) do + if info[k] == nil then + info[k] = v + end + end + else + info = tmp(...) + if self.registry[parent] then + for k,v in pairs(self.registry[parent]) do + if info[k] == nil then + info[k] = v + end + end + end + end + local point = info.point + local relativePoint = info.relativePoint + local cursorX = info.cursorX + local cursorY = info.cursorY + if type(point) == "function" then + local b + point, b = point(parent) + if b then + relativePoint = b + end + end + if type(relativePoint) == "function" then + relativePoint = relativePoint(parent) + end + Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY) +end + +function Clear(self, level) + if level then + if level.buttons then + for i = #level.buttons, 1, -1 do + ReleaseButton(self, level, i) + end + end + end +end + +function Dewdrop:Close(level) + if DropDownList1:IsShown() then + DropDownList1:Hide() + end + if DewdropLib then + local d = DewdropLib:GetInstance('1.0') + local ret, val = pcall(d, IsOpen, d) + if ret and val then + DewdropLib:GetInstance('1.0'):Close() + end + end + self:argCheck(level, 2, "number", "nil") + if not level then + level = 1 + end + if level == 1 and levels[level] then + levels[level].parented = false + end + if level > 1 and levels[level-1].buttons then + local buttons = levels[level-1].buttons + for _,button in ipairs(buttons) do +-- button.arrow:SetWidth(16) +-- button.arrow:SetHeight(16) + button.selected = nil + button.highlight:Hide() +-- button.arrow:SetVertexColor(1, 1, 1) + end + end + if sliderFrame and sliderFrame.level >= level then + sliderFrame:Hide() + end + if editBoxFrame and editBoxFrame.level >= level then + editBoxFrame:Hide() + end + for i = level, #levels do + Clear(self, levels[level]) + levels[i]:Hide() + levels[i]:ClearAllPoints() + levels[i]:SetPoint("CENTER", UIParent, "CENTER") + levels[i].value = nil + end +end + +function Dewdrop:AddSeparator(level) + level = levels[level or currentLevel] + if not level or not level.buttons then return; end + + local prevbutton = level.buttons[#level.buttons] + if not prevbutton then return; end + + if prevbutton.disabled and prevbutton.text:GetText() == "" then + return + end + self:AddLine("text", "", "disabled", true) +end + +function Dewdrop:AddLine(...) + local info = tmp(...) + local level = info.level or currentLevel + info.level = nil + local button = AcquireButton(self, level) + if not next(info) then + info.disabled = true + end + button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure) + button.isTitle = info.isTitle + button.notClickable = info.notClickable + if button.isTitle then + button.text:SetFontObject(GameFontNormalSmall) + elseif button.notClickable then + button.text:SetFontObject(GameFontHighlightSmall) + elseif button.disabled then + button.text:SetFontObject(GameFontDisableSmall) + else + button.text:SetFontObject(GameFontHighlightSmall) + end + if info.disabled then + button.arrow:SetDesaturated(true) + button.check:SetDesaturated(true) + else + button.arrow:SetDesaturated(false) + button.check:SetDesaturated(false) + end + if info.textR and info.textG and info.textB then + button.textR = info.textR + button.textG = info.textG + button.textB = info.textB + button.text:SetTextColor(button.textR, button.textG, button.textB) + else + button.text:SetTextColor(button.text:GetFontObject():GetTextColor()) + end + button.notCheckable = info.notCheckable + button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0) + button.checked = not info.notCheckable and info.checked + button.mouseoverUnderline = info.mouseoverUnderline + button.isRadio = not info.notCheckable and info.isRadio + if info.isRadio then + button.check:Show() + button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") + if button.checked then + button.check:SetTexCoord(0.25, 0.5, 0, 1) + button.check:SetVertexColor(1, 1, 1, 1) + else + button.check:SetTexCoord(0, 0.25, 0, 1) + button.check:SetVertexColor(1, 1, 1, 0.5) + end + button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") + button.check:SetWidth(16) + button.check:SetHeight(16) + elseif info.icon then + button.check:Show() + button.check:SetTexture(info.icon) + if info.iconWidth and info.iconHeight then + button.check:SetWidth(info.iconWidth) + button.check:SetHeight(info.iconHeight) + else + button.check:SetWidth(16) + button.check:SetHeight(16) + end + if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then + button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) + elseif info.icon:find("^Interface\\Icons\\") then + button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) + else + button.check:SetTexCoord(0, 1, 0, 1) + end + button.check:SetVertexColor(1, 1, 1, 1) + else + if button.checked then + if info.checkIcon then + button.check:SetWidth(16) + button.check:SetHeight(16) + button.check:SetTexture(info.checkIcon) + if info.checkIcon:find("^Interface\\Icons\\") then + button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) + else + button.check:SetTexCoord(0, 1, 0, 1) + end + else + button.check:SetWidth(24) + button.check:SetHeight(24) + button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") + button.check:SetTexCoord(0, 1, 0, 1) + end + button.check:SetVertexColor(1, 1, 1, 1) + else + button.check:SetVertexColor(1, 1, 1, 0) + end + end + if not button.disabled then + button.func = info.func + button.secure = info.secure + end + button.hasColorSwatch = info.hasColorSwatch + if button.hasColorSwatch then + button.colorSwatch:Show() + button.colorSwatch.texture:Show() + button.r = info.r or 1 + button.g = info.g or 1 + button.b = info.b or 1 + button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b) + button.checked = false + button.func = nil + button.colorFunc = info.colorFunc + local i = 1 + while true do + local k = "colorArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.hasOpacity = info.hasOpacity + button.opacity = info.opacity or 1 + else + button.colorSwatch:Hide() + button.colorSwatch.texture:Hide() + end + button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow + if button.hasArrow then + button.arrow:SetAlpha(1) + if info.hasSlider then + button.hasSlider = true + button.sliderMin = info.sliderMin or 0 + button.sliderMax = info.sliderMax or 1 + button.sliderStep = info.sliderStep or 0 + button.sliderBigStep = info.sliderBigStep or button.sliderStep + if button.sliderBigStep < button.sliderStep then + button.sliderBigStep = button.sliderStep + end + button.sliderIsPercent = info.sliderIsPercent and true or false + button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin + button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax + button.sliderFunc = info.sliderFunc + button.sliderValue = info.sliderValue + button.fromAceOptions = info.fromAceOptions + local i = 1 + while true do + local k = "sliderArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + elseif info.hasEditBox then + button.hasEditBox = true + button.editBoxText = info.editBoxText or "" + button.editBoxFunc = info.editBoxFunc + local i = 1 + while true do + local k = "editBoxArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxChangeFunc = info.editBoxChangeFunc + local i = 1 + while true do + local k = "editBoxChangeArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxValidateFunc = info.editBoxValidateFunc + local i = 1 + while true do + local k = "editBoxValidateArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxIsKeybinding = info.editBoxIsKeybinding + button.editBoxKeybindingOnly = info.editBoxKeybindingOnly + button.editBoxKeybindingExcept = info.editBoxKeybindingExcept + else + button.value = info.value + local l = levels[level+1] + if l and info.value == l.value then +-- button.arrow:SetWidth(24) +-- button.arrow:SetHeight(24) + button.selected = true + button.highlight:Show() + end + end + else + button.arrow:SetAlpha(0) + end + local i = 1 + while true do + local k = "arg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.closeWhenClicked = info.closeWhenClicked + button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10 + local font,_ = button.text:GetFont() + button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight) + button:SetHeight(button.textHeight + 6) + button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT") + button.text:SetJustifyH(info.justifyH or "LEFT") + button.text:SetText(info.text) + button.tooltipTitle = info.tooltipTitle + button.tooltipText = info.tooltipText + button.tooltipFunc = info.tooltipFunc + local i = 1 + while true do + local k = "tooltipArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then + button.tooltipTitle = info.text + end + if type(button.func) == "string" then + if type(button.arg1) ~= "table" then + self:error("Cannot call method %q on a non-table", button.func) + end + if type(button.arg1[button.func]) ~= "function" then + self:error("Method %q nonexistant.", button.func) + end + end +end + +function Dewdrop:InjectAceOptionsTable(handler, options) + self:argCheck(handler, 2, "table") + self:argCheck(options, 3, "table") + if tostring(options.type):lower() ~= "group" then + self:error('Cannot inject into options table argument #3 if its type is not "group"') + end + if options.handler ~= nil and options.handler ~= handler then + self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") + end + options.handler = handler + local class = handler.class + if not AceLibrary:HasInstance("AceOO-2.0") or not class then + if Rock then + -- possible Rock object + for mixin in Rock:IterateObjectMixins(handler) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + else + -- Ace2 object + while class and class ~= AceLibrary("AceOO-2.0").Class do + if type(class.GetAceOptionsDataTable) == "function" then + local t = class:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + local mixins = class.mixins + if mixins then + for mixin in pairs(mixins) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + class = class.super + end + end + return options +end + +function Dewdrop:OnTooltipHide() + if lastSetFont then + if lastSetFont == normalFont then + lastSetFont = nil + return + end + fillRegionTmp(GameTooltip:GetRegions()) + for i,v in ipairs(regionTmp) do + if v.GetFont then + local font,size,outline = v:GetFont() + if font == lastSetFont then + v:SetFont(normalFont, size, outline) + end + end + regionTmp[i] = nil + end + lastSetFont = nil + end +end + +local function activate(self, oldLib, oldDeactivate) + Dewdrop = self + if oldLib and oldLib.registry then + self.registry = oldLib.registry + self.onceRegistered = oldLib.onceRegistered + else + self.registry = {} + self.onceRegistered = {} + + local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown") + local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp") + local oldX, oldY, clickTime + WorldFrame:SetScript("OnMouseDown", function(this, ...) + oldX,oldY = GetCursorPosition() + clickTime = GetTime() + if WorldFrame_OnMouseDown then + WorldFrame_OnMouseDown(this, ...) + end + end) + + WorldFrame:SetScript("OnMouseUp", function(this, ...) + local x,y = GetCursorPosition() + if not oldX or not oldY or not x or not y or not clickTime then + self:Close() + if WorldFrame_OnMouseUp then + WorldFrame_OnMouseUp(this, ...) + end + return + end + local d = math.abs(x - oldX) + math.abs(y - oldY) + if d <= 5 and GetTime() - clickTime < 0.5 then + self:Close() + end + if WorldFrame_OnMouseUp then + WorldFrame_OnMouseUp(this, ...) + end + end) + + hooksecurefunc(DropDownList1, "Show", function() + if levels[1] and levels[1]:IsVisible() then + self:Close() + end + end) + + hooksecurefunc("HideDropDownMenu", function() + if levels[1] and levels[1]:IsVisible() then + self:Close() + end + end) + + hooksecurefunc("CloseDropDownMenus", function() + if levels[1] and levels[1]:IsVisible() then + local stack = debugstack() + if not stack:find("`TargetFrame_OnHide'") then + self:Close() + end + end + end) + end + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("PLAYER_REGEN_ENABLED") + self.frame:RegisterEvent("PLAYER_REGEN_DISABLED") + self.frame:Hide() + self.frame:SetScript("OnEvent", function(this, event) + this:Show() + if event=="PLAYER_REGEN_ENABLED" then -- track combat state for secure frame operations + self.combat = false + elseif event=="PLAYER_REGEN_DISABLED" then + self.combat = true + end + end) + self.frame:SetScript("OnUpdate", function(this) + this:Hide() + self:Refresh(1) + end) + self.hookedTooltip = true + if not oldLib or not oldLib.hookedTooltip then + local OnTooltipHide = GameTooltip:GetScript("OnHide") + GameTooltip:SetScript("OnHide", function(this, ...) + if OnTooltipHide then + OnTooltipHide(this, ...) + end + if type(self.OnTooltipHide) == "function" then + self:OnTooltipHide() + end + end) + end + levels = {} + buttons = {} + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +local function external(lib, major, instance) + if major == "SharedMedia-1.0" then + SharedMedia = instance + end +end + +AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/modules/ReAction_HideBlizzard/ReAction_HideBlizzard.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/ReAction_HideBlizzard/ReAction_HideBlizzard.lua Mon Mar 17 18:24:53 2008 +0000 @@ -18,12 +18,14 @@ -- module methods function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", + self.db = ReAction.db:RegisterNamespace( moduleID, { - hide = false + profile = { + hide = false + } } ) + self.db.RegisterCallback(self,"OnProfileChanged") self.hiddenFrame = CreateFrame("Frame") self.hiddenFrame:Hide() @@ -60,15 +62,14 @@ self:ShowAll(true) end -function module:OnProfileEnable() +function module:OnProfileChanged() if self.db.profile.hide then - self:HideAll(true) + module:HideAll(true) else - self:ShowAll(true) + module:ShowAll(true) end end - local frames = { MainMenuBar, PetActionButton1,
--- a/modules/ReAction_ModuleTemplate/ReAction_ModuleName.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/ReAction_ModuleTemplate/ReAction_ModuleName.lua Mon Mar 17 18:24:53 2008 +0000 @@ -16,12 +16,15 @@ -- module methods function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", + self.db = ReAction.db:RegisterNamespace( moduleID { - + profile = { + -- default profile goes here + } } ) + + end end function module:OnEnable() @@ -32,11 +35,40 @@ end -function module:OnProfileEnable() + +---- ReAction module API ---- + +-- apply module features and settings to a bar object (see Bar.lua for Bar API) +function module:ApplyToBar(bar) end -function module:OnProfileDisable() +-- remove module features and settings from a bar object +function module:RemoveFromBar(bar) end +-- refresh module features and settings on a bar object +function module:RefreshBar(bar) + +end + +-- notification of config mode (true/false) on the list of bars +function module:ApplyConfigMode(mode,listOfBars) + +end + +-- return a name-modifier (suffix) for the bar name display. This can reflect a dynamic state. +function module:GetBarNameModifier(bar) + return nil +end + +-- erase any local configuration entries for the supplied bar name +function module:EraseBarConfig(barName) + +end + +-- update any local configuration entries with the new bar name index +function module:RenameBarConfig(oldName, newName) + +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_PetAction/ReAction_PetAction.lua Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,133 @@ +--[[ + ReAction Pet Action Bar module + +--]] + +-- local imports +local ReAction = ReAction +local L = ReAction.L +local _G = _G + +-- module declaration +local moduleID = "PetAction" +local module = ReAction:NewModule( moduleID ) + + +-- module methods +function module:OnInitialize() + self.db = ReAction.db:RegisterNamespace( moduleID, + { + profile = { + buttons = { } + } + } + ) + + self.buttons = { } +end + +function module:OnEnable() +end + +function module:OnDisable() +end + +function module:GetGlobalBarOptions(opts) + if self.globalBarOpts == nil then + self.globalBarOpts = { + newActionBar = { + type = "execute", + name = L["New Pet Action Bar"], + desc = L["Create a new bar of pet action buttons"], + func = function() + ReAction:CreateBar() + end, + disabled = InCombatLockdown, + } + } + end + return self.globalBarOpts +end + + +-- use-count of action IDs +local ActionIDList = setmetatable( {}, { + __index = function(self, idx) + if idx == nil then + for i = 1, 10 do + if rawget(self,i) == nil then + rawset(self,i,1) + return i + end + end + else + local c = rawget(self,idx) or 0 + rawset(self,idx,c+1) + return idx + end + end, + __newindex = function(self,idx,value) + if value == nil then + value = rawget(self,idx) + if value == 1 then + value = nil + elseif value then + value = value - 1 + end + end + rawset(self,idx,value) + end +}) + + +-- button class methods +local Button = { } + +local function Constructor( self, bar, idx, config ) + self.bar, self.idx, self.config = bar, idx, config + + local barFrame = bar:GetFrame() + + self.name = config.name or "ReAction_"..bar:GetName().."_Pet_"..idx + config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured + + local f = CreateFrame("CheckButton", self.name, barFrame, "PetActionButtonTemplate") + f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton (question: is this protected? does it cause taint?) + self.frame = f + barFrame:SetAttribute("addchild",f) + + -- auto show/hide when pet exists + -- this gets called once per button, which is inefficient but otherwise harmless + barFrame:SetAttribute("unit","pet") + RegisterUnitWatch(barFrame) + + self:Refresh(bar,idx) +end + +function Button:Destroy() + local f = self.frame + f:UnregisterAllEvents() + f:Hide() + f:SetParent(UIParent) + f:ClearAllPoints() + if self.name then + _G[self.name] = nil + end + ActionIDList[self.config.actionID] = nil + self.frame = nil + self.config = nil + self.bar = nil +end + + +-- export as a class-factory to module +module.BtnClass = { + new = function(self, ...) + local x = { } + for k,v in pairs(Button) do + x[k] = v + end + Constructor(x, ...) + return x + end +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_PetAction/ReAction_PetAction.toc Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,11 @@ +## Interface: 20300 +## Title: ReAction: Pet Actions +## Notes: Pet Action Bar support for ReAction +## DefaultState: enabled +## LoadOnDemand: 1 +## Author: Flick +## Version: 1.0 +## X-Category: Action Bars +## Dependencies: ReAction + +ReAction_PetAction.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/ReAction_PetAction/ReAction_PetAction.xml Mon Mar 17 18:24:53 2008 +0000 @@ -0,0 +1,7 @@ +<Ui xmlns="http://www.blizzard.com/wow/ui/" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> + +<Script file="ReAction_PetAction.lua"/> + +</Ui> \ No newline at end of file
--- a/modules/ReAction_State/ReAction_State.lua Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/ReAction_State/ReAction_State.lua Mon Mar 17 18:24:53 2008 +0000 @@ -15,10 +15,9 @@ -- module methods function module:OnInitialize() - self.db = ReAction:AcquireDBNamespace(moduleID) - ReAction:RegisterDefaults(moduleID,"profile", + self.db = ReAction:RegisterNamespace( moduleID, { - + profile = { } } ) end @@ -31,14 +30,6 @@ end -function module:OnProfileEnable() - -end - -function module:OnProfileDisable() - -end - --function module:GetGlobalOptions( configModule ) -- return {} --end
--- a/modules/modules.xml Tue Mar 11 21:39:34 2008 +0000 +++ b/modules/modules.xml Mon Mar 17 18:24:53 2008 +0000 @@ -7,9 +7,9 @@ <Include file="ReAction_HideBlizzard\ReAction_HideBlizzard.xml"/> <Include file="FuBar_ReActionFu\FuBar_ReActionFu.xml"/> -<!-- in progress --> +<!-- in progress <Include file="ReAction_PetAction\ReAction_PetAction.xml"/> - +--> <!-- not yet implemented <Include file="ReAction_State\ReAction_State.xml"/>