annotate ReAction.lua @ 278:3dcfc0aad875

Pet action button needs name for auxiliary frames
author Flick
date Wed, 11 May 2011 15:13:38 -0700
parents 36a29870bf34
children 5b9c0164a491
rev   line source
Flick@276 1 local _, ns = ...
flickerstreak@205 2 local pcall = pcall
flickerstreak@205 3 local pairs = pairs
flickerstreak@205 4 local type = type
flickerstreak@205 5 local geterrorhandler = geterrorhandler
flickerstreak@33 6 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
Flick@230 7 local LKB = LibStub("LibKeyBound-1.0",true)
Flick@230 8 if not LKB then
Flick@230 9 LoadAddOn("LibKeyBound-1.0")
Flick@230 10 LKB = LibStub("LibKeyBound-1.0")
Flick@230 11 end
flickerstreak@33 12
flickerstreak@205 13 ------ Utility ------
Flick@241 14 -- make a deep copy of a table
Flick@241 15 local function tcopy(x)
Flick@241 16 if type(x) ~= "table" then
Flick@241 17 return x
flickerstreak@28 18 end
Flick@241 19 local r = {}
Flick@241 20 for k,v in pairs(x) do
Flick@241 21 r[k] = tcopy(v)
Flick@241 22 end
Flick@241 23 return r
flickerstreak@28 24 end
flickerstreak@28 25
Flick@241 26 -- traverse a table tree by key list and fetch the result or first nil
Flick@241 27 local function tfetch(t, ...)
Flick@241 28 for i = 1, select('#', ...) do
Flick@241 29 t = t and t[select(i, ...)]
Flick@241 30 end
Flick@241 31 return t
Flick@241 32 end
Flick@241 33
Flick@241 34 -- traverse a table tree by key list and build tree as necessary
Flick@241 35 local function tbuild(t, ...)
Flick@241 36 for i = 1, select('#', ...) do
Flick@241 37 local key = select(i, ...)
Flick@241 38 if not t[key] then t[key] = { } end
Flick@241 39 t = t[key]
Flick@241 40 end
Flick@241 41 return t
Flick@241 42 end
Flick@241 43
Flick@241 44 -- return a new array of keys of table 't', sorted by comparing
Flick@241 45 -- sub-fields (obtained via tfetch) of the table values
Flick@241 46 local function fieldsort( t, ... )
Flick@241 47 local r = { }
Flick@241 48 for k in pairs(t) do
Flick@241 49 table.insert(r,k)
Flick@241 50 end
Flick@241 51 local path = { ... }
Flick@241 52 table.sort(r, function(lhs, rhs)
Flick@241 53 local olhs = tfetch(t[lhs], unpack(path)) or 0
Flick@241 54 local orhs = tfetch(t[rhs], unpack(path)) or 0
Flick@241 55 return olhs < orhs
Flick@241 56 end)
Flick@241 57 return r
Flick@241 58 end
Flick@241 59
Flick@241 60 -- store in the addon table
Flick@276 61 ns.tcopy = tcopy
Flick@276 62 ns.tfetch = tfetch
Flick@276 63 ns.tbuild = tbuild
Flick@276 64 ns.fieldsort = fieldsort
Flick@241 65
flickerstreak@205 66 ------ Core ------
flickerstreak@205 67 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
flickerstreak@205 68 "AceEvent-3.0"
flickerstreak@205 69 )
Flick@276 70 ns.ReAction = ReAction
Flick@246 71 ReAction.version = GetAddOnMetadata("ReAction","Version")
flickerstreak@205 72 ReAction.L = L
flickerstreak@205 73 ReAction.LKB = LKB
flickerstreak@28 74
flickerstreak@205 75
flickerstreak@223 76 ReAction.barTypes = { }
flickerstreak@223 77
flickerstreak@205 78 ------ Handlers ------
flickerstreak@28 79 function ReAction:OnInitialize()
flickerstreak@28 80 self.db = LibStub("AceDB-3.0"):New("ReAction_DB",
flickerstreak@213 81 self.defaultProfile,
flickerstreak@182 82 true -- use global 'Default' (locale-specific)
flickerstreak@28 83 )
flickerstreak@205 84
flickerstreak@213 85 self:UpgradeProfile()
flickerstreak@211 86
flickerstreak@205 87 self.bars = { }
flickerstreak@205 88
flickerstreak@213 89 self.LBF = LibStub("LibButtonFacade",true)
flickerstreak@213 90 if self.LBF then
flickerstreak@213 91 self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self)
flickerstreak@213 92 end
flickerstreak@213 93
flickerstreak@211 94 -- It's fairly normal to use the Blizzard vehicle bar, and to have
flickerstreak@211 95 -- your regular buttons in the same location. If you do this, and don't
flickerstreak@211 96 -- bother to hide your buttons, they'll obscure some parts of the vehicle bar.
flickerstreak@211 97 VehicleMenuBar:SetFrameLevel(VehicleMenuBar:GetFrameLevel()+3)
flickerstreak@211 98
flickerstreak@205 99 self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
Flick@227 100
flickerstreak@184 101 LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED")
flickerstreak@184 102 LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED")
flickerstreak@207 103 LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
Flick@227 104
Flick@227 105 -- see Profile.lua for these callback implementations
Flick@227 106 self.db.RegisterCallback(self,"OnProfileChanged")
Flick@227 107 self.db.RegisterCallback(self,"OnProfileCopied","OnProfileChanged")
Flick@227 108 self.db.RegisterCallback(self,"OnNewProfile")
Flick@227 109 self.db.RegisterCallback(self,"OnProfileReset", "OnNewProfile")
Flick@227 110
flickerstreak@182 111 self:RegisterEvent("PLAYER_REGEN_DISABLED")
Flick@242 112 self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
Flick@227 113
flickerstreak@182 114 self:InitializeOptions()
flickerstreak@28 115 end
flickerstreak@28 116
flickerstreak@28 117 function ReAction:OnEnable()
flickerstreak@205 118 self:InitializeBars()
Flick@242 119 self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui
flickerstreak@28 120 end
flickerstreak@28 121
flickerstreak@28 122 function ReAction:OnDisable()
flickerstreak@205 123 self:TearDownBars()
flickerstreak@28 124 end
flickerstreak@28 125
flickerstreak@33 126 function ReAction:PLAYER_REGEN_DISABLED()
flickerstreak@205 127 if self.configMode == true then
flickerstreak@63 128 self:UserError(L["ReAction config mode disabled during combat."])
flickerstreak@33 129 self:SetConfigMode(false)
flickerstreak@88 130 self:SetKeybindMode(false)
flickerstreak@185 131 self:CloseEditor()
flickerstreak@33 132 end
flickerstreak@33 133 end
flickerstreak@33 134
Flick@243 135 function ReAction:UPDATE_SHAPESHIFT_FORMS()
Flick@242 136 -- Re-parse the rules table according to the new form list.
Flick@242 137 -- This happens both at initial login (after PLAYER_ENTERING_WORLD)
Flick@242 138 -- as well as when gaining new abilities.
Flick@243 139 self.Bar:InitRuleFormats()
Flick@242 140 for _, bar in self:IterateBars() do
Flick@242 141 bar:ApplyStates()
Flick@242 142 end
Flick@242 143 end
Flick@242 144
flickerstreak@88 145 function ReAction:LIBKEYBOUND_ENABLED( evt )
flickerstreak@88 146 self:SetKeybindMode(true)
flickerstreak@88 147 end
flickerstreak@88 148
flickerstreak@88 149 function ReAction:LIBKEYBOUND_DISABLED( evt )
flickerstreak@88 150 return self:SetKeybindMode(false)
flickerstreak@88 151 end
flickerstreak@88 152
flickerstreak@213 153 function ReAction:OnSkinChanged( skinID, gloss, backdrop, group, button, colors )
flickerstreak@213 154 if group == nil then
flickerstreak@213 155 -- don't store global
flickerstreak@213 156 else
flickerstreak@213 157 -- 'group' is the bar-name
flickerstreak@213 158 local bar = self:GetBar(group)
flickerstreak@213 159 if bar then
flickerstreak@213 160 local c = bar:GetConfig().ButtonFacade
flickerstreak@213 161 if c then
flickerstreak@213 162 c.skinID = skinID
flickerstreak@213 163 c.gloss = gloss
flickerstreak@213 164 c.backdrop = backdrop
flickerstreak@213 165 c.colors = colors
flickerstreak@213 166 end
flickerstreak@213 167 end
flickerstreak@213 168 end
flickerstreak@213 169 end
flickerstreak@213 170
flickerstreak@33 171
flickerstreak@205 172 ------ Methods ------
flickerstreak@77 173
flickerstreak@61 174 function ReAction:UserError(msg)
flickerstreak@61 175 UIErrorsFrame:AddMessage(msg)
flickerstreak@61 176 end
flickerstreak@61 177
flickerstreak@205 178 function ReAction:GetBar(arg)
flickerstreak@205 179 if type(arg) == "string" then
flickerstreak@205 180 return self.bars[arg], arg
flickerstreak@205 181 elseif type(arg) == "table" then -- reverse lookup
flickerstreak@205 182 for name, bar in pairs(self.bars) do
flickerstreak@205 183 if arg == bar then
flickerstreak@205 184 return bar, name
flickerstreak@205 185 end
flickerstreak@205 186 end
flickerstreak@205 187 else
flickerstreak@205 188 error("ReAction:GetBar() requires either a name or a bar table arg")
flickerstreak@205 189 end
flickerstreak@184 190 end
flickerstreak@184 191
flickerstreak@205 192 function ReAction:IterateBars()
flickerstreak@205 193 return pairs(self.bars)
flickerstreak@205 194 end
flickerstreak@184 195
flickerstreak@63 196 -- usage:
flickerstreak@91 197 -- (1) ReAction:CreateBar(name, [cfgTable])
flickerstreak@63 198 -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing])
flickerstreak@91 199 function ReAction:CreateBar(name, config, ...)
flickerstreak@91 200 local profile = self.db.profile
flickerstreak@91 201
flickerstreak@217 202 name = tostring(name)
flickerstreak@217 203 if not name or name == "" then
flickerstreak@217 204 error("ReAction:CreateBar() - bar name string required")
flickerstreak@217 205 elseif self.bars[name] then
flickerstreak@217 206 self:UserError(format(L["ReAction: name '%s' already in use"],name))
flickerstreak@217 207 return nil
flickerstreak@91 208 end
flickerstreak@91 209
flickerstreak@223 210 local class
flickerstreak@91 211 if type(config) == "string" then
flickerstreak@223 212 class = self.barTypes[config]
flickerstreak@218 213 if not class then
flickerstreak@218 214 error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config))
flickerstreak@48 215 end
flickerstreak@218 216 config = tcopy(class:GetDefaultBarConfig())
flickerstreak@218 217 config.btnRows = select(1,...) or config.btnRows
flickerstreak@218 218 config.btnColumns = select(2,...) or config.btnColumns
flickerstreak@218 219 config.btnWidth = select(3,...) or config.btnWidth
flickerstreak@218 220 config.btnHeight = select(3,...) or config.btnHeight
flickerstreak@218 221 config.spacing = select(4,...) or config.spacing
flickerstreak@48 222 config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1
flickerstreak@48 223 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1
flickerstreak@81 224 config.anchor = config.anchor or "UIParent"
flickerstreak@81 225 config.point = config.point or "BOTTOM"
flickerstreak@81 226 config.relpoint = config.relpoint or "BOTTOM"
flickerstreak@48 227 config.y = config.y or 200
flickerstreak@48 228 config.x = config.x or 0
flickerstreak@223 229 else
flickerstreak@223 230 config = config or profile.bars[name] or { }
Flick@248 231 if not config then
Flick@248 232 error(("ReAction: Unable to fetch config table for bar '%s'"):format(name))
Flick@248 233 elseif not config.type or not self.barTypes[config.type] then
Flick@248 234 error(("ReAction: Unrecognized bar type '%s' for bar '%s'"):format(tostring(config.type), name))
flickerstreak@223 235 end
flickerstreak@223 236 class = self.barTypes[config.type]
flickerstreak@48 237 end
flickerstreak@91 238
flickerstreak@91 239 profile.bars[name] = config
Flick@234 240 local bar = self.Bar:New( name, config, class ) -- ReAction.Bar defined in Bar.lua
flickerstreak@205 241 self.bars[name] = bar
flickerstreak@205 242 self.callbacks:Fire("OnCreateBar", bar, name)
flickerstreak@205 243 if self.configMode then
flickerstreak@33 244 bar:ShowControls(true)
flickerstreak@33 245 end
flickerstreak@33 246
flickerstreak@28 247 return bar
flickerstreak@28 248 end
flickerstreak@28 249
flickerstreak@205 250 function ReAction:DestroyBar(x)
flickerstreak@205 251 local bar, name = self:GetBar(x)
flickerstreak@63 252 if bar and name then
flickerstreak@205 253 self.bars[name] = nil
flickerstreak@205 254 self.callbacks:Fire("OnDestroyBar", bar, name)
flickerstreak@205 255 bar:Destroy()
flickerstreak@28 256 end
flickerstreak@28 257 end
flickerstreak@28 258
flickerstreak@205 259 function ReAction:InitializeBars()
flickerstreak@205 260 if not self.barsInitialized then
flickerstreak@211 261 self:ManageBlizzardBars()
flickerstreak@211 262
flickerstreak@205 263 for name, config in pairs(self.db.profile.bars) do
flickerstreak@205 264 if config then
flickerstreak@205 265 self:CreateBar(name, config)
flickerstreak@205 266 end
flickerstreak@205 267 end
Flick@242 268 -- re-anchor in case anchor order does not match init order
flickerstreak@205 269 for name, bar in pairs(self.bars) do
flickerstreak@205 270 bar:ApplyAnchor()
flickerstreak@205 271 end
flickerstreak@205 272 self.barsInitialized = true
flickerstreak@205 273 end
flickerstreak@205 274 end
flickerstreak@205 275
flickerstreak@205 276 function ReAction:TearDownBars()
flickerstreak@205 277 for name, bar in pairs(self.bars) do
flickerstreak@205 278 if bar then
flickerstreak@208 279 self.bars[name] = self:DestroyBar(bar)
flickerstreak@205 280 end
flickerstreak@205 281 end
flickerstreak@205 282 self.barsInitialized = false
flickerstreak@205 283 end
flickerstreak@205 284
flickerstreak@205 285 function ReAction:RebuildAll()
flickerstreak@205 286 self:TearDownBars()
flickerstreak@205 287 self:InitializeBars()
flickerstreak@28 288 end
flickerstreak@28 289
flickerstreak@28 290 function ReAction:RenameBar(x, newname)
flickerstreak@205 291 local bar, name = self:GetBar(x)
flickerstreak@63 292 if type(newname) ~= "string" then
flickerstreak@63 293 error("ReAction:RenameBar() - second argument must be a string")
flickerstreak@63 294 end
flickerstreak@63 295 if bar and name and #newname > 0 then
flickerstreak@127 296 if newname == name then
flickerstreak@127 297 return
flickerstreak@127 298 end
flickerstreak@205 299 if self.bars[newname] then
flickerstreak@127 300 self:UserError(format(L["ReAction: name '%s' already in use"],newname))
flickerstreak@47 301 else
flickerstreak@205 302 self.bars[newname], self.bars[name] = self.bars[name], nil
flickerstreak@47 303 bar:SetName(newname or "")
flickerstreak@47 304 local cfg = self.db.profile.bars
flickerstreak@47 305 cfg[newname], cfg[name] = cfg[name], nil
flickerstreak@205 306 self.callbacks:Fire("OnRenameBar", bar, name, newname)
flickerstreak@28 307 end
flickerstreak@28 308 end
flickerstreak@28 309 end
flickerstreak@28 310
flickerstreak@205 311 function ReAction:EraseBar(x)
flickerstreak@205 312 local bar, name = self:GetBar(x)
flickerstreak@63 313 if bar and name then
flickerstreak@208 314 self:DestroyBar(bar)
flickerstreak@205 315 self.db.profile.bars[name] = nil
flickerstreak@63 316 end
flickerstreak@63 317 end
flickerstreak@63 318
flickerstreak@211 319 local blizzFrames = {
flickerstreak@211 320 MainMenuBar,
flickerstreak@211 321 MultiBarLeft,
flickerstreak@211 322 MultiBarRight,
flickerstreak@211 323 MultiBarBottomLeft,
flickerstreak@211 324 MultiBarBottomRight,
flickerstreak@211 325 }
flickerstreak@211 326
flickerstreak@211 327 local hideFrame = CreateFrame("Frame")
flickerstreak@211 328 hideFrame:Hide()
flickerstreak@211 329 local hiddenParents = { }
flickerstreak@211 330 local function ManageBlizzFrame(f, hide)
flickerstreak@211 331 if hide and not hiddenParents[f] then
flickerstreak@211 332 hiddenParents[f] = f:GetParent()
flickerstreak@211 333 f:SetParent(hideFrame)
flickerstreak@211 334 elseif not hide and hiddenParents[f] then
flickerstreak@211 335 f:SetParent(hiddenParents[f])
flickerstreak@211 336 hiddenParents[f] = nil
flickerstreak@211 337 if f:IsShown() then
flickerstreak@211 338 f:Show() -- refresh
flickerstreak@211 339 end
flickerstreak@211 340 end
flickerstreak@211 341 end
flickerstreak@211 342
flickerstreak@211 343 function ReAction:ManageBlizzardBars()
flickerstreak@211 344 for _, f in pairs(blizzFrames) do
flickerstreak@211 345 ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars)
flickerstreak@211 346 end
flickerstreak@211 347 ManageBlizzFrame(VehicleMenuBar, self.db.profile.options.hideBlizzardVehicleBar)
flickerstreak@211 348 end
flickerstreak@211 349
flickerstreak@218 350 function ReAction:RegisterBarType( class, isDefault )
Flick@231 351 local name = class:GetButtonTypeID()
flickerstreak@218 352 self.barTypes[name] = class
flickerstreak@218 353 if isDefault then
flickerstreak@218 354 self.defaultBarType = name
flickerstreak@48 355 end
flickerstreak@48 356 end
flickerstreak@48 357
flickerstreak@63 358 function ReAction:IterateBarTypes()
flickerstreak@218 359 return pairs(self.barTypes)
flickerstreak@63 360 end
flickerstreak@63 361
flickerstreak@218 362 function ReAction:GetDefaultBarConfig(barType)
flickerstreak@218 363 if barType and self.barTypes[barType] then
flickerstreak@218 364 return self.barTypes[barType]:GetDefaultBarConfig()
flickerstreak@63 365 end
flickerstreak@63 366 end
flickerstreak@63 367
flickerstreak@63 368 function ReAction:GetBarTypeOptions( fill )
flickerstreak@63 369 fill = fill or { }
flickerstreak@63 370 for k in self:IterateBarTypes() do
flickerstreak@63 371 fill[k] = k
flickerstreak@63 372 end
flickerstreak@63 373 return fill
flickerstreak@63 374 end
flickerstreak@63 375
flickerstreak@63 376 function ReAction:GetDefaultBarType()
flickerstreak@218 377 return self.defaultBarType
flickerstreak@63 378 end
flickerstreak@63 379
flickerstreak@33 380 function ReAction:SetConfigMode( mode )
flickerstreak@205 381 if mode ~= self.configMode then
flickerstreak@207 382 if mode then
flickerstreak@207 383 self:SetKeybindMode(false)
flickerstreak@207 384 end
flickerstreak@205 385 self.configMode = mode
flickerstreak@205 386 self.callbacks:Fire("OnConfigModeChanged", mode)
flickerstreak@77 387 end
flickerstreak@63 388 end
flickerstreak@63 389
flickerstreak@63 390 function ReAction:GetConfigMode()
flickerstreak@205 391 return self.configMode
flickerstreak@33 392 end
flickerstreak@38 393
flickerstreak@88 394 function ReAction:SetKeybindMode( mode )
flickerstreak@205 395 if mode ~= self.kbMode then
flickerstreak@88 396 if mode then
flickerstreak@207 397 self:SetConfigMode(false)
flickerstreak@184 398 LKB:Activate()
flickerstreak@88 399 else
flickerstreak@184 400 LKB:Deactivate()
flickerstreak@88 401 end
flickerstreak@207 402 for _, bar in self:IterateBars() do
flickerstreak@207 403 bar:SetKeybindMode(mode)
flickerstreak@207 404 end
flickerstreak@205 405 self.kbMode = LKB:IsShown() or false
flickerstreak@88 406 end
flickerstreak@88 407 end
flickerstreak@88 408
flickerstreak@88 409 function ReAction:GetKeybindMode( mode )
flickerstreak@205 410 return self.kbMode
flickerstreak@88 411 end
Flick@225 412
Flick@225 413
Flick@225 414 -- ConfigMode support
Flick@225 415 CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {}
Flick@225 416
Flick@225 417 function CONFIGMODE_CALLBACKS.ReAction( action, mode )
Flick@225 418 if action == "ON" then
Flick@225 419 ReAction:SetConfigMode(true)
Flick@225 420 elseif action == "OFF" then
Flick@225 421 ReAction:SetConfigMode(false)
Flick@225 422 elseif action == "LISTMODES" then
Flick@225 423 -- no modes
Flick@225 424 end
Flick@225 425 end
Flick@225 426