annotate ReAction.lua @ 291:54d7865baae9 stable

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