Mercurial > wow > reaction
view ReAction.lua @ 252:7c62b9b7a70f
Added tag 1.1 beta 5 for changeset 455ef506f969
author | Flick |
---|---|
date | Mon, 28 Mar 2011 16:25:32 -0700 |
parents | 9e708a155ab9 |
children | 36a29870bf34 |
line wrap: on
line source
local addonName, addonTable = ... local pcall = pcall local pairs = pairs local type = type local geterrorhandler = geterrorhandler local L = LibStub("AceLocale-3.0"):GetLocale("ReAction") local LKB = LibStub("LibKeyBound-1.0",true) if not LKB then LoadAddOn("LibKeyBound-1.0") LKB = LibStub("LibKeyBound-1.0") end ------ Utility ------ -- make a deep copy of a table local function tcopy(x) if type(x) ~= "table" then return x end local r = {} for k,v in pairs(x) do r[k] = tcopy(v) end return r end -- traverse a table tree by key list and fetch the result or first nil local function tfetch(t, ...) for i = 1, select('#', ...) do t = t and t[select(i, ...)] end return t end -- traverse a table tree by key list and build tree as necessary local function tbuild(t, ...) for i = 1, select('#', ...) do local key = select(i, ...) if not t[key] then t[key] = { } end t = t[key] end return t end -- return a new array of keys of table 't', sorted by comparing -- sub-fields (obtained via tfetch) of the table values local function fieldsort( t, ... ) local r = { } for k in pairs(t) do table.insert(r,k) end local path = { ... } table.sort(r, function(lhs, rhs) local olhs = tfetch(t[lhs], unpack(path)) or 0 local orhs = tfetch(t[rhs], unpack(path)) or 0 return olhs < orhs end) return r end -- store in the addon table addonTable.tcopy = tcopy addonTable.tfetch = tfetch addonTable.tbuild = tbuild addonTable.fieldsort = fieldsort ------ Core ------ local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction", "AceEvent-3.0" ) addonTable.ReAction = ReAction ReAction.version = GetAddOnMetadata("ReAction","Version") ReAction.L = L ReAction.LKB = LKB ReAction.barTypes = { } ------ Handlers ------ function ReAction:OnInitialize() self.db = LibStub("AceDB-3.0"):New("ReAction_DB", self.defaultProfile, true -- use global 'Default' (locale-specific) ) self:UpgradeProfile() self.bars = { } self.LBF = LibStub("LibButtonFacade",true) if self.LBF then self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self) end -- It's fairly normal to use the Blizzard vehicle bar, and to have -- your regular buttons in the same location. If you do this, and don't -- bother to hide your buttons, they'll obscure some parts of the vehicle bar. VehicleMenuBar:SetFrameLevel(VehicleMenuBar:GetFrameLevel()+3) self.callbacks = LibStub("CallbackHandler-1.0"):New(self) LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED") LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED") LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") -- see Profile.lua for these callback implementations self.db.RegisterCallback(self,"OnProfileChanged") self.db.RegisterCallback(self,"OnProfileCopied","OnProfileChanged") self.db.RegisterCallback(self,"OnNewProfile") self.db.RegisterCallback(self,"OnProfileReset", "OnNewProfile") self:RegisterEvent("PLAYER_REGEN_DISABLED") self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS") self:InitializeOptions() end function ReAction:OnEnable() self:InitializeBars() self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui end function ReAction:OnDisable() self:TearDownBars() end function ReAction:PLAYER_REGEN_DISABLED() if self.configMode == true then self:UserError(L["ReAction config mode disabled during combat."]) self:SetConfigMode(false) self:SetKeybindMode(false) self:CloseEditor() end end function ReAction:UPDATE_SHAPESHIFT_FORMS() -- Re-parse the rules table according to the new form list. -- This happens both at initial login (after PLAYER_ENTERING_WORLD) -- as well as when gaining new abilities. self.Bar:InitRuleFormats() for _, bar in self:IterateBars() do bar:ApplyStates() end end function ReAction:LIBKEYBOUND_ENABLED( evt ) self:SetKeybindMode(true) end function ReAction:LIBKEYBOUND_DISABLED( evt ) return self:SetKeybindMode(false) end function ReAction:OnSkinChanged( skinID, gloss, backdrop, group, button, colors ) if group == nil then -- don't store global else -- 'group' is the bar-name local bar = self:GetBar(group) if bar then local c = bar:GetConfig().ButtonFacade if c then c.skinID = skinID c.gloss = gloss c.backdrop = backdrop c.colors = colors end end end end ------ Methods ------ function ReAction:UserError(msg) UIErrorsFrame:AddMessage(msg) end function ReAction:GetBar(arg) if type(arg) == "string" then return self.bars[arg], arg elseif type(arg) == "table" then -- reverse lookup for name, bar in pairs(self.bars) do if arg == bar then return bar, name end end else error("ReAction:GetBar() requires either a name or a bar table arg") end end function ReAction:IterateBars() return pairs(self.bars) end -- usage: -- (1) ReAction:CreateBar(name, [cfgTable]) -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing]) function ReAction:CreateBar(name, config, ...) local profile = self.db.profile name = tostring(name) if not name or name == "" then error("ReAction:CreateBar() - bar name string required") elseif self.bars[name] then self:UserError(format(L["ReAction: name '%s' already in use"],name)) return nil end local class if type(config) == "string" then class = self.barTypes[config] if not class then error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config)) end config = tcopy(class:GetDefaultBarConfig()) config.btnRows = select(1,...) or config.btnRows config.btnColumns = select(2,...) or config.btnColumns config.btnWidth = select(3,...) or config.btnWidth config.btnHeight = select(3,...) or config.btnHeight config.spacing = select(4,...) or config.spacing config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1 config.anchor = config.anchor or "UIParent" config.point = config.point or "BOTTOM" config.relpoint = config.relpoint or "BOTTOM" config.y = config.y or 200 config.x = config.x or 0 else config = config or profile.bars[name] or { } if not config then error(("ReAction: Unable to fetch config table for bar '%s'"):format(name)) elseif not config.type or not self.barTypes[config.type] then error(("ReAction: Unrecognized bar type '%s' for bar '%s'"):format(tostring(config.type), name)) end class = self.barTypes[config.type] end profile.bars[name] = config local bar = self.Bar:New( name, config, class ) -- ReAction.Bar defined in Bar.lua self.bars[name] = bar self.callbacks:Fire("OnCreateBar", bar, name) if self.configMode then bar:ShowControls(true) end return bar end function ReAction:DestroyBar(x) local bar, name = self:GetBar(x) if bar and name then self.bars[name] = nil self.callbacks:Fire("OnDestroyBar", bar, name) bar:Destroy() end end function ReAction:InitializeBars() if not self.barsInitialized then self:ManageBlizzardBars() for name, config in pairs(self.db.profile.bars) do if config then self:CreateBar(name, config) end end -- re-anchor in case anchor order does not match init order for name, bar in pairs(self.bars) do bar:ApplyAnchor() end self.barsInitialized = true end end function ReAction:TearDownBars() for name, bar in pairs(self.bars) do if bar then self.bars[name] = self:DestroyBar(bar) end end self.barsInitialized = false end function ReAction:RebuildAll() self:TearDownBars() self:InitializeBars() end function ReAction:RenameBar(x, newname) local bar, name = self:GetBar(x) if type(newname) ~= "string" then error("ReAction:RenameBar() - second argument must be a string") end if bar and name and #newname > 0 then if newname == name then return end if self.bars[newname] then self:UserError(format(L["ReAction: name '%s' already in use"],newname)) else self.bars[newname], self.bars[name] = self.bars[name], nil bar:SetName(newname or "") local cfg = self.db.profile.bars cfg[newname], cfg[name] = cfg[name], nil self.callbacks:Fire("OnRenameBar", bar, name, newname) end end end function ReAction:EraseBar(x) local bar, name = self:GetBar(x) if bar and name then self:DestroyBar(bar) self.db.profile.bars[name] = nil end end local blizzFrames = { MainMenuBar, MultiBarLeft, MultiBarRight, MultiBarBottomLeft, MultiBarBottomRight, } local hideFrame = CreateFrame("Frame") hideFrame:Hide() local hiddenParents = { } local function ManageBlizzFrame(f, hide) if hide and not hiddenParents[f] then hiddenParents[f] = f:GetParent() f:SetParent(hideFrame) elseif not hide and hiddenParents[f] then f:SetParent(hiddenParents[f]) hiddenParents[f] = nil if f:IsShown() then f:Show() -- refresh end end end function ReAction:ManageBlizzardBars() for _, f in pairs(blizzFrames) do ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars) end ManageBlizzFrame(VehicleMenuBar, self.db.profile.options.hideBlizzardVehicleBar) end function ReAction:RegisterBarType( class, isDefault ) local name = class:GetButtonTypeID() self.barTypes[name] = class if isDefault then self.defaultBarType = name end end function ReAction:IterateBarTypes() return pairs(self.barTypes) end function ReAction:GetDefaultBarConfig(barType) if barType and self.barTypes[barType] then return self.barTypes[barType]:GetDefaultBarConfig() end end function ReAction:GetBarTypeOptions( fill ) fill = fill or { } for k in self:IterateBarTypes() do fill[k] = k end return fill end function ReAction:GetDefaultBarType() return self.defaultBarType end function ReAction:SetConfigMode( mode ) if mode ~= self.configMode then if mode then self:SetKeybindMode(false) end self.configMode = mode self.callbacks:Fire("OnConfigModeChanged", mode) end end function ReAction:GetConfigMode() return self.configMode end function ReAction:SetKeybindMode( mode ) if mode ~= self.kbMode then if mode then self:SetConfigMode(false) LKB:Activate() else LKB:Deactivate() end for _, bar in self:IterateBars() do bar:SetKeybindMode(mode) end self.kbMode = LKB:IsShown() or false end end function ReAction:GetKeybindMode( mode ) return self.kbMode end -- ConfigMode support CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {} function CONFIGMODE_CALLBACKS.ReAction( action, mode ) if action == "ON" then ReAction:SetConfigMode(true) elseif action == "OFF" then ReAction:SetConfigMode(false) elseif action == "LISTMODES" then -- no modes end end