annotate Bar.lua @ 296:08a1fbc9ee9b

Added tag 1.1 alpha 11 (5.04 bandaid) for changeset 0cb6a9944497
author Flick
date Tue, 11 Sep 2012 16:51:29 -0700
parents 0cb6a9944497
children 6fbb55e5c624
rev   line source
Flick@276 1 local _, ns = ...
Flick@276 2 local ReAction = ns.ReAction
flickerstreak@122 3 local L = ReAction.L
flickerstreak@183 4 local LKB = ReAction.LKB
flickerstreak@122 5 local _G = _G
flickerstreak@122 6 local CreateFrame = CreateFrame
flickerstreak@122 7 local floor = math.floor
flickerstreak@122 8 local fmod = math.fmod
flickerstreak@122 9 local format = string.format
Flick@276 10 local tfetch = ns.tfetch
Flick@276 11 local tbuild = ns.tbuild
Flick@276 12 local fieldsort = ns.fieldsort
flickerstreak@122 13
flickerstreak@193 14 local LSG = LibStub("ReAction-LibShowActionGrid-1.0")
flickerstreak@147 15
flickerstreak@155 16 ---- Secure snippets ----
flickerstreak@155 17 local _reaction_init =
flickerstreak@155 18 [[
flickerstreak@155 19 anchorKeys = newtable("point","relPoint","x","y")
flickerstreak@155 20
flickerstreak@155 21 state = nil
flickerstreak@155 22 set_state = nil
flickerstreak@155 23 state_override = nil
flickerstreak@156 24 unit_exists = nil
flickerstreak@155 25
flickerstreak@155 26 showAll = false
flickerstreak@155 27 hidden = false
flickerstreak@155 28
flickerstreak@155 29 defaultAlpha = 1.0
flickerstreak@155 30 defaultScale = 1.0
flickerstreak@155 31 defaultAnchor = newtable()
flickerstreak@155 32
flickerstreak@155 33 activeStates = newtable()
flickerstreak@155 34 settings = newtable()
flickerstreak@155 35 extensions = newtable()
flickerstreak@155 36 ]]
flickerstreak@155 37
flickerstreak@155 38 local _reaction_refresh =
flickerstreak@155 39 [[
flickerstreak@155 40 local oldState = state
flickerstreak@155 41 state = state_override or set_state or state
flickerstreak@155 42
flickerstreak@156 43 local hide = nil
flickerstreak@155 44 if state then
flickerstreak@155 45 local settings = settings[state]
flickerstreak@155 46 if settings then
flickerstreak@155 47 -- show/hide
flickerstreak@156 48 hide = settings.hide
flickerstreak@155 49 -- re-anchor
flickerstreak@155 50 local old_anchor = activeStates.anchor
flickerstreak@155 51 activeStates.anchor = settings.anchorEnable and state
flickerstreak@155 52 if old_anchor ~= activeStates.anchor or not set_state then
flickerstreak@155 53 if activeStates.anchor then
flickerstreak@155 54 if settings.anchorPoint then
flickerstreak@155 55 self:ClearAllPoints()
flickerstreak@155 56 local f = self:GetAttribute("frameref-anchor-"..state)
flickerstreak@155 57 if f then
flickerstreak@155 58 self:SetPoint(settings.anchorPoint, f, settings.anchorRelPoint, settings.anchorX, settings.anchorY)
flickerstreak@155 59 end
flickerstreak@155 60 end
flickerstreak@155 61 elseif defaultAnchor.point then
flickerstreak@155 62 self:ClearAllPoints()
flickerstreak@155 63 self:SetPoint(defaultAnchor.point, defaultAnchor.frame,
flickerstreak@155 64 defaultAnchor.relPoint, defaultAnchor.x, defaultAnchor.y)
flickerstreak@155 65 end
flickerstreak@155 66 end
flickerstreak@155 67 -- re-scale
flickerstreak@155 68 local old_scale = activeStates.scale
flickerstreak@155 69 activeStates.scale = settings.enableScale and state
flickerstreak@155 70 if old_scale ~= activeStates.scale or not set_state then
flickerstreak@155 71 self:SetScale(activeStates.scale and settings.scale or defaultScale)
flickerstreak@155 72 end
flickerstreak@155 73 -- alpha
flickerstreak@155 74 local old_alpha = activeStates.alpha
flickerstreak@155 75 activeStates.alpha = settings.enableAlpha and state
flickerstreak@155 76 if old_alpha ~= activeStates.alpha or not set_state then
flickerstreak@155 77 self:SetAlpha(activeStates.alpha and settings.alpha or defaultAlpha)
flickerstreak@155 78 end
flickerstreak@155 79 end
flickerstreak@155 80 end
flickerstreak@155 81
flickerstreak@156 82 -- hide if state or unit_exists says to
flickerstreak@156 83 hide = not showAll and (hide or unithide)
flickerstreak@156 84 if hide ~= hidden then
flickerstreak@156 85 hidden = hide
flickerstreak@156 86 if hide then
flickerstreak@156 87 self:Hide()
flickerstreak@156 88 else
flickerstreak@156 89 self:Show()
flickerstreak@156 90 end
flickerstreak@156 91 end
flickerstreak@156 92
flickerstreak@155 93 for _, attr in pairs(extensions) do
flickerstreak@155 94 control:RunAttribute(attr)
flickerstreak@155 95 end
flickerstreak@155 96
flickerstreak@155 97 control:ChildUpdate()
flickerstreak@155 98
flickerstreak@155 99 if showAll then
flickerstreak@155 100 control:CallMethod("UpdateHiddenLabel", state and settings[state] and settings[state].hide)
flickerstreak@155 101 end
flickerstreak@155 102
flickerstreak@155 103 if oldState ~= state then
flickerstreak@155 104 control:CallMethod("StateRefresh", state)
flickerstreak@155 105 end
flickerstreak@155 106 ]]
flickerstreak@155 107
flickerstreak@155 108 local _onstate_reaction = -- function( self, stateid, newstate )
flickerstreak@155 109 [[
flickerstreak@155 110 set_state = newstate
flickerstreak@155 111 ]] .. _reaction_refresh
flickerstreak@155 112
flickerstreak@155 113 local _onstate_showgrid = -- function( self, stateid, newstate )
flickerstreak@155 114 [[
flickerstreak@155 115 control:ChildUpdate(stateid,newstate)
flickerstreak@155 116 control:CallMethod("UpdateShowGrid")
flickerstreak@155 117 ]]
flickerstreak@155 118
flickerstreak@155 119 local _onstate_unitexists = -- function( self, stateid, newstate )
flickerstreak@155 120 [[
flickerstreak@159 121 unithide = not newstate or newstate == "hide"
flickerstreak@155 122 ]] .. _reaction_refresh
flickerstreak@155 123
flickerstreak@155 124 local _onclick = -- function( self, button, down )
flickerstreak@155 125 [[
flickerstreak@155 126 if state_override == button then
flickerstreak@155 127 state_override = nil -- toggle
flickerstreak@155 128 else
flickerstreak@155 129 state_override = button
flickerstreak@155 130 end
flickerstreak@155 131 ]] .. _reaction_refresh
flickerstreak@155 132
flickerstreak@157 133 -- For reference
flickerstreak@157 134 -- the option field names must match the field names of the options table, below
flickerstreak@157 135 local stateProperties = {
flickerstreak@157 136 hide = true,
flickerstreak@157 137 --keybindState = true, TODO: broken
flickerstreak@157 138 anchorEnable = true,
flickerstreak@157 139 anchorFrame = true,
flickerstreak@157 140 anchorPoint = true,
flickerstreak@157 141 anchorRelPoint = true,
flickerstreak@157 142 anchorX = true,
flickerstreak@157 143 anchorY = true,
flickerstreak@157 144 enableScale = true,
flickerstreak@157 145 scale = true,
flickerstreak@157 146 enableAlpha = true,
flickerstreak@157 147 alpha = true,
flickerstreak@157 148 }
flickerstreak@157 149
flickerstreak@157 150
flickerstreak@155 151
flickerstreak@147 152 ---- Bar class ----
flickerstreak@122 153 local Bar = { }
flickerstreak@147 154 local frameList = { }
flickerstreak@122 155
flickerstreak@122 156 ReAction.Bar = Bar -- export to ReAction
flickerstreak@122 157
Flick@234 158 function Bar:New( name, config, buttonClass )
flickerstreak@122 159 if type(config) ~= "table" then
flickerstreak@122 160 error("ReAction.Bar: config table required")
flickerstreak@122 161 end
flickerstreak@122 162
flickerstreak@122 163 -- create new self
flickerstreak@122 164 self = setmetatable(
flickerstreak@122 165 {
Flick@234 166 config = config,
Flick@234 167 name = name,
Flick@234 168 buttons = { },
Flick@234 169 buttonClass = buttonClass,
Flick@234 170 width = config.width or 480,
Flick@234 171 height = config.height or 40,
flickerstreak@122 172 },
flickerstreak@147 173 {__index = self} )
flickerstreak@122 174
flickerstreak@122 175 -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is
flickerstreak@122 176 -- not mouse-clickable by the user.
flickerstreak@122 177 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
flickerstreak@147 178 name = name and "ReAction-"..name
flickerstreak@147 179 local f = name and frameList[name]
flickerstreak@147 180 if not f then
flickerstreak@147 181 f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate")
flickerstreak@147 182 if name then
flickerstreak@147 183 frameList[name] = f
flickerstreak@147 184 end
flickerstreak@147 185 end
flickerstreak@122 186 f:SetFrameStrata("MEDIUM")
flickerstreak@122 187 f:SetWidth(self.width)
flickerstreak@146 188 f:SetHeight(self.height)
flickerstreak@122 189 f:SetAlpha(config.alpha or 1.0)
flickerstreak@122 190 f:Show()
flickerstreak@122 191 f:EnableMouse(false)
flickerstreak@122 192 f:SetClampedToScreen(true)
flickerstreak@171 193 LSG:AddFrame(f)
flickerstreak@122 194
Flick@287 195 if ReAction.LBF then
Flick@287 196 local g = ReAction.LBF:Group(L["ReAction"], self.name)
Flick@287 197 self.config.ButtonFacade = self.config.ButtonFacade or {
Flick@287 198 skinID = "Blizzard",
Flick@287 199 backdrop = true,
Flick@287 200 gloss = 0,
Flick@287 201 colors = {},
Flick@287 202 }
Flick@287 203 local c = self.config.ButtonFacade
Flick@287 204 g:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
Flick@287 205 self.LBFGroup = g
Flick@287 206 end
Flick@287 207
flickerstreak@155 208 -- secure handlers
flickerstreak@155 209 f:Execute(_reaction_init)
flickerstreak@155 210 f:SetAttribute("_onstate-reaction", _onstate_reaction)
flickerstreak@155 211 f:SetAttribute("_onstate-showgrid", _onstate_showgrid)
flickerstreak@155 212 f:SetAttribute("_onstate-unitexists", _onstate_unitexists)
flickerstreak@155 213 f:SetAttribute("_onclick", _onclick)
flickerstreak@155 214
flickerstreak@155 215 -- secure handler CallMethod()s
flickerstreak@155 216 f.UpdateShowGrid = function() self:UpdateShowGrid() end
flickerstreak@155 217 f.StateRefresh = function() self:RefreshControls() end
flickerstreak@155 218 f.UpdateHiddenLabel = function(f,hidden) self:SetLabelSubtext(hidden and L["Hidden"]) end
flickerstreak@122 219
flickerstreak@122 220 -- Override the default frame accessor to provide strict read-only access
flickerstreak@122 221 function self:GetFrame()
flickerstreak@122 222 return f
flickerstreak@122 223 end
flickerstreak@122 224
flickerstreak@122 225 self:ApplyAnchor()
Flick@287 226 if ReAction:GetConfigMode() then
Flick@287 227 self:SetConfigMode(true)
flickerstreak@213 228 end
flickerstreak@122 229 ReAction.RegisterCallback(self, "OnConfigModeChanged")
Flick@287 230 if ReAction:GetKeybindMode() then
Flick@287 231 self:SetKeybindMode(true)
Flick@287 232 end
flickerstreak@122 233
Flick@234 234 buttonClass:SetupBar(self)
Flick@242 235 self:ApplyStates()
Flick@234 236
flickerstreak@122 237 return self
flickerstreak@122 238 end
flickerstreak@122 239
flickerstreak@122 240 function Bar:Destroy()
flickerstreak@122 241 local f = self:GetFrame()
Flick@242 242 self:CleanupStates()
Flick@234 243 for idx, b in self:IterateButtons() do
Flick@234 244 b:Destroy()
Flick@234 245 end
flickerstreak@122 246 f:UnregisterAllEvents()
flickerstreak@125 247 self:ShowControls(false)
flickerstreak@122 248 ReAction.UnregisterAllCallbacks(self)
flickerstreak@171 249 LKB.UnregisterAllCallbacks(self)
flickerstreak@213 250 if self.LBFGroup then
flickerstreak@213 251 self.LBFGroup:Delete(true)
flickerstreak@213 252 end
flickerstreak@171 253 LSG:RemoveFrame(f)
flickerstreak@122 254 f:SetParent(UIParent)
flickerstreak@122 255 f:ClearAllPoints()
flickerstreak@147 256 f:Hide()
flickerstreak@122 257 end
flickerstreak@122 258
flickerstreak@147 259 --
flickerstreak@147 260 -- Events
flickerstreak@147 261 --
flickerstreak@147 262
flickerstreak@147 263 function Bar:OnConfigModeChanged(event, mode)
flickerstreak@147 264 self:SetConfigMode(mode)
flickerstreak@123 265 end
flickerstreak@123 266
flickerstreak@153 267 --
flickerstreak@153 268 -- Accessors
flickerstreak@153 269 --
flickerstreak@153 270
flickerstreak@153 271 function Bar:GetName()
flickerstreak@153 272 return self.name
flickerstreak@153 273 end
flickerstreak@153 274
flickerstreak@153 275 -- only ReAction:RenameBar() should call this function. Calling from any other
flickerstreak@153 276 -- context will desync the bar list in the ReAction class.
flickerstreak@153 277 function Bar:SetName(name)
flickerstreak@213 278 if self.LBFGroup then
flickerstreak@213 279 -- LBF doesn't offer a method of renaming a group, so delete and remake the group.
flickerstreak@213 280 local c = self.config.ButtonFacade
flickerstreak@213 281 local g = ReAction.LBF:Group(L["ReAction"], name)
Flick@234 282 for idx, b in self:IterateButtons() do
flickerstreak@213 283 self.LBFGroup:RemoveButton(b:GetFrame(), true)
flickerstreak@213 284 g:AddButton(b:GetFrame())
flickerstreak@213 285 end
flickerstreak@213 286 self.LBFGroup:Delete(true)
flickerstreak@213 287 self.LBFGroup = g
flickerstreak@213 288 self.LBFGroup:Skin(c.skinID, c.gloss, c.backdrop, c.colors)
flickerstreak@213 289 end
flickerstreak@153 290 self.name = name
flickerstreak@154 291 if self.overlay then
flickerstreak@154 292 self.overlay:SetLabel(self.name)
flickerstreak@154 293 end
flickerstreak@153 294 end
flickerstreak@153 295
flickerstreak@153 296 function Bar:GetFrame()
flickerstreak@153 297 -- this method is included for documentation purposes. It is overridden
flickerstreak@153 298 -- for each object in the :New() method.
flickerstreak@153 299 error("Invalid Bar object: used without initialization")
flickerstreak@153 300 end
flickerstreak@153 301
Flick@234 302 function Bar:GetButton(idx)
Flick@234 303 return self.buttons[idx]
Flick@234 304 end
Flick@234 305
Flick@237 306 function Bar:GetButtonClass()
Flick@237 307 return self.buttonClass
Flick@237 308 end
Flick@237 309
flickerstreak@153 310 function Bar:GetConfig()
flickerstreak@153 311 return self.config
flickerstreak@153 312 end
flickerstreak@153 313
flickerstreak@153 314 function Bar:GetAnchor()
flickerstreak@122 315 local c = self.config
flickerstreak@153 316 return (c.point or "CENTER"),
flickerstreak@153 317 (c.anchor or self:GetFrame():GetParent():GetName()),
flickerstreak@153 318 (c.relpoint or c.point or "CENTER"),
flickerstreak@153 319 (c.x or 0),
flickerstreak@153 320 (c.y or 0)
flickerstreak@122 321 end
flickerstreak@122 322
flickerstreak@122 323 function Bar:SetAnchor(point, frame, relativePoint, x, y)
flickerstreak@122 324 local c = self.config
flickerstreak@122 325 c.point = point or c.point
flickerstreak@122 326 c.anchor = frame or c.anchor
flickerstreak@122 327 c.relpoint = relativePoint or c.relpoint
flickerstreak@122 328 c.x = x or c.x
flickerstreak@122 329 c.y = y or c.y
flickerstreak@122 330 self:ApplyAnchor()
flickerstreak@122 331 end
flickerstreak@122 332
flickerstreak@122 333 function Bar:GetSize()
flickerstreak@122 334 local f = self:GetFrame()
flickerstreak@122 335 return f:GetWidth(), f:GetHeight()
flickerstreak@122 336 end
flickerstreak@122 337
flickerstreak@122 338 function Bar:SetSize(w,h)
flickerstreak@122 339 local f = self:GetFrame()
flickerstreak@122 340 self.config.width = w
flickerstreak@122 341 self.config.height = h
flickerstreak@122 342 f:SetWidth(w)
flickerstreak@122 343 f:SetHeight(h)
flickerstreak@122 344 end
flickerstreak@122 345
flickerstreak@122 346 function Bar:GetButtonSize()
flickerstreak@122 347 local w = self.config.btnWidth or 32
flickerstreak@122 348 local h = self.config.btnHeight or 32
flickerstreak@122 349 -- TODO: get from modules?
flickerstreak@122 350 return w,h
flickerstreak@122 351 end
flickerstreak@122 352
flickerstreak@122 353 function Bar:SetButtonSize(w,h)
flickerstreak@122 354 if w > 0 and h > 0 then
flickerstreak@122 355 self.config.btnWidth = w
flickerstreak@122 356 self.config.btnHeight = h
Flick@279 357 for _, b in pairs(self.buttons) do
Flick@279 358 b:Refresh()
Flick@279 359 end
flickerstreak@122 360 end
flickerstreak@122 361 end
flickerstreak@122 362
flickerstreak@153 363 function Bar:GetNumButtons()
flickerstreak@153 364 local r,c = self:GetButtonGrid()
flickerstreak@153 365 return r*c
flickerstreak@153 366 end
flickerstreak@153 367
flickerstreak@122 368 function Bar:GetButtonGrid()
flickerstreak@122 369 local cfg = self.config
flickerstreak@122 370 local r = cfg.btnRows or 1
flickerstreak@122 371 local c = cfg.btnColumns or 1
flickerstreak@122 372 local s = cfg.spacing or 4
flickerstreak@122 373 return r,c,s
flickerstreak@122 374 end
flickerstreak@122 375
flickerstreak@122 376 function Bar:SetButtonGrid(r,c,s)
Flick@283 377 local cfg = self.config
Flick@283 378 r = r or cfg.btnRows
Flick@283 379 c = c or cfg.btnColumns
Flick@283 380 s = s or cfg.spacing
flickerstreak@122 381 if r > 0 and c > 0 and s > 0 then
flickerstreak@122 382 cfg.btnRows = r
flickerstreak@122 383 cfg.btnColumns = c
flickerstreak@122 384 cfg.spacing = s
flickerstreak@122 385 end
Flick@234 386 self.buttonClass:SetupBar(self)
flickerstreak@122 387 end
flickerstreak@122 388
flickerstreak@122 389 function Bar:GetAlpha()
flickerstreak@122 390 return self.config.alpha or 1.0
flickerstreak@122 391 end
flickerstreak@122 392
flickerstreak@122 393 function Bar:SetAlpha(value)
flickerstreak@122 394 self.config.alpha = value
flickerstreak@122 395 self:GetFrame():SetAlpha(value or 1.0)
flickerstreak@155 396 self:UpdateDefaultStateAlpha()
flickerstreak@122 397 end
flickerstreak@122 398
flickerstreak@122 399 function Bar:IterateButtons()
Flick@234 400 -- iterator returns idx, button, but does NOT iterate in index order
flickerstreak@122 401 return pairs(self.buttons)
flickerstreak@122 402 end
flickerstreak@122 403
flickerstreak@153 404 --
flickerstreak@153 405 -- Methods
flickerstreak@153 406 --
flickerstreak@153 407
flickerstreak@147 408 function Bar:SetConfigMode(mode)
flickerstreak@155 409 self:SetSecureData("showAll",mode)
flickerstreak@147 410 self:ShowControls(mode)
Flick@234 411 for idx, b in self:IterateButtons() do
flickerstreak@147 412 b:ShowGridTemp(mode)
flickerstreak@147 413 b:UpdateActionIDLabel(mode)
flickerstreak@147 414 end
Flick@279 415 self.buttonClass:SetupBar(self) -- force a full refresh
flickerstreak@147 416 end
flickerstreak@147 417
flickerstreak@147 418 function Bar:SetKeybindMode(mode)
flickerstreak@155 419 self:SetSecureData("showAll",mode)
Flick@234 420 for idx, b in self:IterateButtons() do
flickerstreak@147 421 b:SetKeybindMode(mode)
flickerstreak@147 422 end
flickerstreak@147 423 end
flickerstreak@147 424
flickerstreak@153 425 function Bar:ApplyAnchor()
flickerstreak@153 426 local f = self:GetFrame()
flickerstreak@153 427 local c = self.config
flickerstreak@153 428 local p = c.point
flickerstreak@153 429
flickerstreak@153 430 f:SetWidth(c.width)
flickerstreak@153 431 f:SetHeight(c.height)
flickerstreak@153 432 f:ClearAllPoints()
flickerstreak@153 433
flickerstreak@153 434 if p then
flickerstreak@153 435 local a = f:GetParent()
flickerstreak@153 436 if c.anchor then
flickerstreak@153 437 local bar = ReAction:GetBar(c.anchor)
flickerstreak@153 438 if bar then
flickerstreak@153 439 a = bar:GetFrame()
flickerstreak@153 440 else
flickerstreak@153 441 a = _G[c.anchor]
flickerstreak@153 442 end
flickerstreak@153 443 end
flickerstreak@153 444 local fr = a or f:GetParent()
flickerstreak@153 445 f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0)
flickerstreak@153 446 else
flickerstreak@153 447 f:SetPoint("CENTER")
flickerstreak@153 448 end
flickerstreak@155 449
flickerstreak@155 450 self:UpdateDefaultStateAnchor()
flickerstreak@153 451 end
flickerstreak@153 452
flickerstreak@153 453 function Bar:ClipNButtons( n )
flickerstreak@153 454 local cfg = self.config
flickerstreak@153 455 local r = cfg.btnRows or 1
flickerstreak@153 456 local c = cfg.btnColumns or 1
flickerstreak@153 457
flickerstreak@153 458 cfg.btnRows = ceil(n/c)
flickerstreak@153 459 cfg.btnColumns = min(n,c)
flickerstreak@153 460 end
flickerstreak@153 461
flickerstreak@153 462 function Bar:AddButton(idx, button)
flickerstreak@153 463 local f = self:GetFrame()
flickerstreak@153 464
Flick@234 465 self.buttons[idx] = button
flickerstreak@153 466
flickerstreak@153 467 -- Store a properly wrapped reference to the child frame as an attribute
flickerstreak@153 468 -- (accessible via "frameref-btn#")
flickerstreak@153 469 f:SetFrameRef(format("btn%d",idx), button:GetFrame())
flickerstreak@213 470
flickerstreak@213 471 -- button constructors are responsible for calling SkinButton
flickerstreak@153 472 end
flickerstreak@153 473
flickerstreak@153 474 function Bar:RemoveButton(button)
Flick@234 475 local idx = button:GetIndex()
flickerstreak@153 476 if idx then
flickerstreak@153 477 self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil)
Flick@234 478 self.buttons[idx] = nil
flickerstreak@153 479 end
flickerstreak@213 480 if self.LBFGroup then
flickerstreak@213 481 self.LBFGroup:RemoveButton(button:GetFrame(),true)
flickerstreak@213 482 end
flickerstreak@153 483 end
flickerstreak@153 484
flickerstreak@122 485 function Bar:PlaceButton(button, baseW, baseH)
Flick@234 486 local idx = button:GetIndex()
flickerstreak@122 487 if idx then
flickerstreak@122 488 local r, c, s = self:GetButtonGrid()
flickerstreak@122 489 local bh, bw = self:GetButtonSize()
flickerstreak@122 490 local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
flickerstreak@122 491 local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s)
flickerstreak@122 492 local scale = bw/baseW
flickerstreak@122 493 local b = button:GetFrame()
flickerstreak@122 494
flickerstreak@122 495 b:ClearAllPoints()
flickerstreak@122 496 b:SetPoint("TOPLEFT",x/scale,y/scale)
flickerstreak@122 497 b:SetScale(scale)
flickerstreak@122 498 end
flickerstreak@122 499 end
flickerstreak@122 500
flickerstreak@213 501 function Bar:SkinButton( button, data )
flickerstreak@213 502 if self.LBFGroup then
flickerstreak@213 503 self.LBFGroup:AddButton(button:GetFrame(), data)
flickerstreak@213 504 end
flickerstreak@147 505 end
flickerstreak@148 506
flickerstreak@155 507 function Bar:UpdateShowGrid()
Flick@234 508 for idx, button in self:IterateButtons() do
flickerstreak@155 509 button:UpdateShowGrid()
flickerstreak@155 510 end
flickerstreak@155 511 end
flickerstreak@155 512
flickerstreak@154 513 function Bar:ShowControls(show)
flickerstreak@154 514 if show then
flickerstreak@155 515 if not self.overlay then
flickerstreak@155 516 self.overlay = Bar.Overlay:New(self) -- see Overlay.lua
flickerstreak@154 517 end
flickerstreak@155 518 self.overlay:Show()
flickerstreak@155 519 self:RefreshSecureState()
flickerstreak@155 520 elseif self.overlay then
flickerstreak@155 521 self.overlay:Hide()
flickerstreak@154 522 end
flickerstreak@154 523 end
flickerstreak@154 524
flickerstreak@154 525 function Bar:RefreshControls()
flickerstreak@154 526 if self.overlay and self.overlay:IsShown() then
flickerstreak@154 527 self.overlay:RefreshControls()
flickerstreak@154 528 end
flickerstreak@154 529 end
flickerstreak@154 530
flickerstreak@154 531 function Bar:SetLabelSubtext(text)
flickerstreak@154 532 if self.overlay then
flickerstreak@154 533 self.overlay:SetLabelSubtext(text)
flickerstreak@154 534 end
flickerstreak@154 535 end
flickerstreak@154 536
flickerstreak@154 537 --
flickerstreak@154 538 -- Secure state functions
flickerstreak@154 539 --
flickerstreak@154 540
flickerstreak@155 541 function Bar:GetSecureState()
flickerstreak@155 542 local env = GetManagedEnvironment(self:GetFrame())
flickerstreak@155 543 return env and env.state
flickerstreak@155 544 end
flickerstreak@155 545
flickerstreak@155 546 function Bar:GetStateProperty(state, propname)
Flick@242 547 return tfetch(self:GetConfig(), "states", state, propname)
flickerstreak@155 548 end
flickerstreak@155 549
flickerstreak@155 550 function Bar:SetStateProperty(state, propname, value)
Flick@242 551 local s = tbuild(self:GetConfig(), "states", state)
Flick@242 552 s[propname] = value
Flick@242 553 self:SetSecureStateData(state, propname, value)
Flick@242 554 end
Flick@242 555
Flick@242 556 function Bar:ApplyStates()
Flick@242 557 local states = tfetch(self:GetConfig(), "states")
Flick@242 558 if states then
Flick@242 559 self:SetStateDriver(states)
Flick@242 560 end
Flick@242 561 end
Flick@242 562
Flick@242 563 function Bar:CleanupStates()
Flick@242 564 self:SetStateDriver(nil)
flickerstreak@155 565 end
flickerstreak@155 566
flickerstreak@155 567 function Bar:RefreshSecureState()
flickerstreak@155 568 self:GetFrame():Execute(_reaction_refresh)
flickerstreak@155 569 end
flickerstreak@155 570
flickerstreak@155 571 -- usage: SetSecureData(globalname, [tblkey1, tblkey2, ...], value)
flickerstreak@155 572 function Bar:SetSecureData( ... )
flickerstreak@155 573 local n = select('#',...)
flickerstreak@155 574 if n < 2 then
flickerstreak@155 575 error("ReAction.Bar:SetSecureData() requires at least 2 arguments")
flickerstreak@155 576 end
flickerstreak@155 577 local f = self:GetFrame()
flickerstreak@155 578 f:SetAttribute("data-depth",n-1)
flickerstreak@155 579 f:SetAttribute("data-value",select(n,...))
flickerstreak@155 580 for i = 1, n-1 do
flickerstreak@155 581 local key = select(i,...)
flickerstreak@155 582 if key == nil then
flickerstreak@155 583 error("ReAction.Bar:SetSecureData() - nil table key in argument list (#"..i..")")
flickerstreak@155 584 end
flickerstreak@155 585 f:SetAttribute("data-key-"..i, key)
flickerstreak@155 586 end
flickerstreak@155 587 f:Execute(
flickerstreak@155 588 [[
flickerstreak@155 589 local n = self:GetAttribute("data-depth")
flickerstreak@155 590 if n > 0 then
flickerstreak@155 591 local value = self:GetAttribute("data-value")
flickerstreak@155 592 local t = _G
flickerstreak@155 593 for i = 1, n do
flickerstreak@155 594 local key = self:GetAttribute("data-key-"..i)
flickerstreak@155 595 if not key then return end
flickerstreak@155 596 if not t[key] then
flickerstreak@155 597 t[key] = newtable()
flickerstreak@155 598 end
flickerstreak@155 599 if i == n then
flickerstreak@155 600 t[key] = value
flickerstreak@155 601 else
flickerstreak@155 602 t = t[key]
flickerstreak@155 603 end
flickerstreak@155 604 end
flickerstreak@155 605 end
flickerstreak@155 606 ]])
flickerstreak@155 607 self:RefreshSecureState()
flickerstreak@155 608 end
flickerstreak@155 609
flickerstreak@155 610 function Bar:SetSecureStateData( state, key, value )
flickerstreak@155 611 self:SetSecureData("settings",state,key,value)
flickerstreak@155 612 end
flickerstreak@155 613
flickerstreak@155 614 -- sets a snippet to be run as an extension to _onstate-reaction
flickerstreak@155 615 function Bar:SetSecureStateExtension( id, snippet )
flickerstreak@155 616 if id == nil then
flickerstreak@155 617 error("ReAction.Bar:SetSecureStateExtension() requires an id")
flickerstreak@155 618 end
flickerstreak@155 619 local f = self:GetFrame()
flickerstreak@155 620 f:SetAttribute("input-secure-ext-id",id)
flickerstreak@155 621 f:SetAttribute("secure-ext-"..id,snippet)
flickerstreak@155 622 f:Execute(
flickerstreak@155 623 [[
flickerstreak@155 624 local id = self:GetAttribute("input-secure-ext-id")
flickerstreak@155 625 if id then
flickerstreak@155 626 extensions[id] = self:GetAttribute("secure-ext-"..id) or nil
flickerstreak@155 627 end
flickerstreak@155 628 ]])
flickerstreak@155 629 self:RefreshSecureState()
flickerstreak@155 630 end
flickerstreak@155 631
flickerstreak@155 632 function Bar:SetFrameRef( name, refFrame )
flickerstreak@155 633 if refFrame then
flickerstreak@155 634 local _, explicit = refFrame:IsProtected()
flickerstreak@155 635 if not explicit then
flickerstreak@155 636 refFrame = nil
flickerstreak@155 637 end
flickerstreak@155 638 end
flickerstreak@155 639 if refFrame then
flickerstreak@155 640 self:GetFrame():SetFrameRef(name,refFrame)
flickerstreak@155 641 else
flickerstreak@155 642 self:GetFrame():SetAttribute("frameref-"..name,nil)
flickerstreak@155 643 end
flickerstreak@155 644 end
flickerstreak@155 645
flickerstreak@157 646 function Bar:SetStateDriver( states )
flickerstreak@157 647 if states then
flickerstreak@157 648 for state, props in pairs(states) do
flickerstreak@157 649 self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state
flickerstreak@157 650 for propname, value in pairs(props) do
flickerstreak@157 651 if propname == "anchorFrame" then
flickerstreak@157 652 self:SetFrameRef("anchor-"..state, _G[value])
flickerstreak@157 653 elseif propname == "rule" then
flickerstreak@157 654 -- do nothing
flickerstreak@157 655 else
flickerstreak@157 656 self:SetSecureStateData(state, propname, value)
flickerstreak@157 657 end
flickerstreak@157 658 end
flickerstreak@157 659 end
flickerstreak@157 660 end
flickerstreak@157 661 local rule = states and self:BuildStateRule(states)
flickerstreak@155 662 if rule then
flickerstreak@155 663 RegisterStateDriver(self:GetFrame(),"reaction",rule)
flickerstreak@155 664 elseif self.statedriver then
flickerstreak@155 665 UnregisterStateDriver(self:GetFrame(),"reaction")
flickerstreak@155 666 end
flickerstreak@155 667 self.statedriver = rule
flickerstreak@157 668 self:BuildStateKeybinds(states)
flickerstreak@155 669 self:RefreshSecureState()
flickerstreak@155 670 end
flickerstreak@155 671
flickerstreak@148 672 -- pass unit=nil to set up the unit elsewhere, if you want something more complex
flickerstreak@148 673 function Bar:RegisterUnitWatch( unit, enable )
flickerstreak@148 674 local f = self:GetFrame()
flickerstreak@148 675 if unit then
flickerstreak@148 676 f:SetAttribute("unit",unit)
flickerstreak@148 677 end
flickerstreak@156 678 if enable then
Flick@234 679 if not self.unitwatch then
Flick@279 680 RegisterUnitWatch(f,true)
Flick@234 681 end
flickerstreak@156 682 elseif self.unitwatch then
Flick@279 683 UnregisterUnitWatch(f)
flickerstreak@156 684 end
flickerstreak@148 685 self.unitwatch = enable
flickerstreak@156 686 self:RefreshSecureState()
flickerstreak@148 687 end
flickerstreak@148 688
flickerstreak@155 689 function Bar:SetStateKeybind( key, state )
flickerstreak@155 690 local f = self:GetFrame()
flickerstreak@155 691 local binds = self.statebinds
flickerstreak@155 692 if not binds then
flickerstreak@155 693 binds = { }
flickerstreak@155 694 self.statebinds = binds
flickerstreak@155 695 end
flickerstreak@155 696
flickerstreak@155 697 -- clear the old binding, if any
flickerstreak@155 698 if binds[state] then
flickerstreak@155 699 SetOverrideBinding(f, false, binds[state], nil)
flickerstreak@155 700 end
flickerstreak@155 701
flickerstreak@155 702 if key then
flickerstreak@157 703 SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button
flickerstreak@155 704 end
flickerstreak@155 705 binds[state] = key
flickerstreak@155 706 end
flickerstreak@155 707
flickerstreak@155 708 function Bar:GetStateKeybind( state )
flickerstreak@155 709 if self.statebinds and state then
flickerstreak@155 710 return self.statebinds[state]
flickerstreak@155 711 end
flickerstreak@155 712 end
flickerstreak@155 713
flickerstreak@155 714 function Bar:UpdateDefaultStateAnchor()
flickerstreak@155 715 local point, frame, relPoint, x, y = self:GetAnchor()
flickerstreak@155 716 local f = self:GetFrame()
flickerstreak@155 717 f:SetAttribute("defaultAnchor-point",point)
flickerstreak@155 718 f:SetAttribute("defaultAnchor-relPoint",relPoint)
flickerstreak@155 719 f:SetAttribute("defaultAnchor-x",x)
flickerstreak@155 720 f:SetAttribute("defaultAnchor-y",y)
flickerstreak@155 721 self:SetFrameRef("defaultAnchor",_G[frame or "UIParent"])
flickerstreak@155 722 f:Execute([[
flickerstreak@155 723 for _, k in pairs(anchorKeys) do
flickerstreak@155 724 defaultAnchor[k] = self:GetAttribute("defaultAnchor-"..k)
flickerstreak@155 725 end
flickerstreak@155 726 defaultAnchor.frame = self:GetAttribute("frameref-defaultAnchor")
flickerstreak@155 727 ]])
flickerstreak@155 728 end
flickerstreak@155 729
flickerstreak@155 730 function Bar:UpdateDefaultStateAlpha()
flickerstreak@155 731 local f = self:GetFrame()
flickerstreak@155 732 f:SetAttribute("defaultAlpha",self:GetAlpha())
flickerstreak@155 733 f:Execute([[
flickerstreak@155 734 defaultAlpha = self:GetAttribute("defaultAlpha")
flickerstreak@155 735 ]])
flickerstreak@155 736 end
flickerstreak@157 737
flickerstreak@157 738 ---- secure state driver rules ----
flickerstreak@157 739
flickerstreak@157 740 local playerClass = select(2, UnitClass("player"))
flickerstreak@157 741 local function ClassFilter(...)
flickerstreak@157 742 for i = 1, select('#',...) do
flickerstreak@157 743 if playerClass == select(i,...) then
flickerstreak@157 744 return false
flickerstreak@157 745 end
flickerstreak@157 746 end
flickerstreak@157 747 return true
flickerstreak@157 748 end
flickerstreak@157 749
flickerstreak@157 750 local ruleformats = {
flickerstreak@157 751 stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") },
flickerstreak@157 752 nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") },
Flick@295 753 shadowdance = { format = "stance:2", filter = ClassFilter("ROGUE") },
flickerstreak@157 754 shadowform = { format = "form:1", filter = ClassFilter("PRIEST") },
flickerstreak@157 755 noshadowform = { format = "noform", filter = ClassFilter("PRIEST") },
flickerstreak@157 756 battle = { format = "stance:1", filter = ClassFilter("WARRIOR") },
flickerstreak@157 757 defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") },
flickerstreak@157 758 berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") },
flickerstreak@157 759 caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") },
flickerstreak@157 760 bear = { format = "form:1", filter = ClassFilter("DRUID") },
flickerstreak@157 761 cat = { format = "form:3", filter = ClassFilter("DRUID") },
flickerstreak@157 762 tree = { format = "form:5", filter = ClassFilter("DRUID") },
flickerstreak@157 763 moonkin = { format = "form:5", filter = ClassFilter("DRUID") },
Flick@295 764 demon = { format = "form:1", filter = ClassFilter("WARLOCK") },
flickerstreak@178 765 nodemon = { format = "noform", filter = ClassFilter("WARLOCK") },
flickerstreak@157 766 pet = { format = "pet" },
flickerstreak@157 767 nopet = { format = "nopet" },
flickerstreak@176 768 harm = { format = "@target,harm" },
flickerstreak@176 769 help = { format = "@target,help" },
flickerstreak@176 770 notarget = { format = "@target,noexists" },
flickerstreak@176 771 focusharm = { format = "@focus,harm" },
flickerstreak@176 772 focushelp = { format = "@focus,help" },
flickerstreak@176 773 nofocus = { format = "@focus,noexists" },
flickerstreak@157 774 raid = { format = "group:raid" },
flickerstreak@157 775 party = { format = "group:party" },
flickerstreak@157 776 solo = { format = "nogroup" },
flickerstreak@157 777 combat = { format = "combat" },
flickerstreak@157 778 nocombat = { format = "nocombat" },
Flick@295 779 possess = { format = "overridebar" },
Flick@295 780 vehicle = { format = "vehicleui" },
flickerstreak@157 781 }
flickerstreak@157 782
flickerstreak@157 783 function Bar.InitRuleFormats()
flickerstreak@157 784 local forms = { }
flickerstreak@157 785 for i = 1, GetNumShapeshiftForms() do
flickerstreak@157 786 local _, name = GetShapeshiftFormInfo(i)
flickerstreak@157 787 forms[name] = i;
flickerstreak@157 788 end
flickerstreak@157 789 -- use 9 if not found since 9 is never a valid stance/form
flickerstreak@157 790 local defensive = forms[GetSpellInfo(71)] or 9
flickerstreak@157 791 local berserker = forms[GetSpellInfo(2458)] or 9
flickerstreak@176 792 local bear = forms[GetSpellInfo(5487)] or 9
flickerstreak@157 793 local aquatic = forms[GetSpellInfo(1066)] or 9
flickerstreak@157 794 local cat = forms[GetSpellInfo(768)] or 9
flickerstreak@157 795 local travel = forms[GetSpellInfo(783)] or 9
flickerstreak@157 796 local tree = forms[GetSpellInfo(33891)] or 9
flickerstreak@157 797 local moonkin = forms[GetSpellInfo(24858)] or 9
flickerstreak@157 798 local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9
flickerstreak@157 799
flickerstreak@157 800 ruleformats.defensive.format = "stance:"..defensive
flickerstreak@157 801 ruleformats.berserker.format = "stance:"..berserker
flickerstreak@157 802 ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight)
flickerstreak@157 803 ruleformats.bear.format = "form:"..bear
flickerstreak@157 804 ruleformats.cat.format = "form:"..cat
flickerstreak@157 805 ruleformats.tree.format = "form:"..tree
flickerstreak@157 806 ruleformats.moonkin.format = "form:"..moonkin
flickerstreak@157 807 end
flickerstreak@157 808
flickerstreak@157 809 function Bar:BuildStateRule(states)
flickerstreak@157 810 -- states is a table :
flickerstreak@157 811 -- states[statename].rule = {
flickerstreak@157 812 -- order = #,
flickerstreak@157 813 -- type = "default"/"custom"/"any"/"all",
flickerstreak@157 814 -- values = { ... }, -- keys of ruleformats[]
flickerstreak@157 815 -- custom = "...",
flickerstreak@157 816 -- }
flickerstreak@157 817 local rules = { }
flickerstreak@157 818 local default
flickerstreak@157 819
flickerstreak@157 820 for idx, state in ipairs(fieldsort(states, "rule", "order")) do
flickerstreak@157 821 local c = states[state].rule
flickerstreak@157 822 local type = c.type
flickerstreak@157 823 if type == "default" then
flickerstreak@157 824 default = default or state
flickerstreak@157 825 elseif type == "custom" then
flickerstreak@157 826 if c.custom then
flickerstreak@157 827 -- strip out all spaces from the custom rule
flickerstreak@157 828 table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state))
flickerstreak@157 829 end
flickerstreak@157 830 elseif type == "any" or type == "all" then
flickerstreak@157 831 if c.values then
flickerstreak@157 832 local clauses = { }
flickerstreak@157 833 for key, value in pairs(c.values) do
flickerstreak@157 834 if ruleformats[key] and not ruleformats[key].filter then
flickerstreak@157 835 table.insert(clauses, ruleformats[key].format)
flickerstreak@157 836 end
flickerstreak@157 837 end
flickerstreak@157 838 if #clauses > 0 then
flickerstreak@157 839 local sep = (type == "any") and "][" or ","
flickerstreak@157 840 table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state))
flickerstreak@157 841 end
flickerstreak@157 842 end
flickerstreak@157 843 end
flickerstreak@157 844 end
flickerstreak@157 845 -- make sure that the default, if any, is last
flickerstreak@157 846 if default then
flickerstreak@157 847 table.insert(rules, default)
flickerstreak@157 848 end
flickerstreak@157 849 return table.concat(rules,";")
flickerstreak@157 850 end
flickerstreak@157 851
flickerstreak@157 852 function Bar:BuildStateKeybinds( states )
flickerstreak@157 853 if states then
flickerstreak@157 854 for name, state in pairs(states) do
flickerstreak@157 855 local rule = tfetch(state, "rule")
flickerstreak@157 856 if rule and rule.type == "keybind" then
flickerstreak@157 857 self:SetStateKeybind(rule.keybind, name)
flickerstreak@157 858 else
flickerstreak@157 859 self:SetStateKeybind(nil, name) -- this clears an existing keybind
flickerstreak@157 860 end
flickerstreak@157 861 end
flickerstreak@157 862 end
flickerstreak@157 863 end
flickerstreak@157 864