annotate modules/ReAction_Action/ReAction_Action.lua @ 108:b2fb8f7dc780

ButtonFacade support
author Flick <flickerstreak@gmail.com>
date Wed, 07 Jan 2009 00:57:02 +0000
parents ad49739d110d
children
rev   line source
flickerstreak@24 1 --[[
flickerstreak@53 2 ReAction Action button module.
flickerstreak@24 3
flickerstreak@24 4 The button module implements standard action button functionality by wrapping Blizzard's
flickerstreak@87 5 ActionBarButtonTemplate frame and associated functions.
flickerstreak@77 6
flickerstreak@87 7 It also provides action remapping support for multiple pages and possessed targets
flickerstreak@90 8 (Mind Control, Eyes of the Beast, Karazhan Chess event, various quests, etc).
flickerstreak@24 9 --]]
flickerstreak@24 10
flickerstreak@24 11 -- local imports
flickerstreak@24 12 local ReAction = ReAction
flickerstreak@24 13 local L = ReAction.L
flickerstreak@24 14 local _G = _G
flickerstreak@24 15 local CreateFrame = CreateFrame
flickerstreak@88 16 local format = string.format
flickerstreak@92 17 local wipe = wipe
flickerstreak@24 18
flickerstreak@87 19 ReAction:UpdateRevision("$Revision$")
flickerstreak@77 20
flickerstreak@88 21 -- libraries
flickerstreak@88 22 local KB = LibStub("LibKeyBound-1.0")
flickerstreak@108 23 local LBF -- initialized later
flickerstreak@88 24
flickerstreak@24 25 -- module declaration
flickerstreak@24 26 local moduleID = "Action"
flickerstreak@28 27 local module = ReAction:NewModule( moduleID )
flickerstreak@24 28
flickerstreak@90 29 -- Class declarations
flickerstreak@77 30 local Button = { }
flickerstreak@90 31 local Handle = { }
flickerstreak@90 32 local PropHandler = { }
flickerstreak@87 33
flickerstreak@77 34 -- Event handlers
flickerstreak@24 35 function module:OnInitialize()
flickerstreak@28 36 self.db = ReAction.db:RegisterNamespace( moduleID,
flickerstreak@24 37 {
flickerstreak@28 38 profile = {
flickerstreak@75 39 bars = { },
flickerstreak@28 40 }
flickerstreak@24 41 }
flickerstreak@24 42 )
flickerstreak@90 43 self.handles = setmetatable({ }, weak)
flickerstreak@49 44
flickerstreak@63 45 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
flickerstreak@63 46
flickerstreak@90 47 ReAction.RegisterCallback(self, "OnCreateBar")
flickerstreak@90 48 ReAction.RegisterCallback(self, "OnRefreshBar")
flickerstreak@63 49 ReAction.RegisterCallback(self, "OnDestroyBar")
flickerstreak@63 50 ReAction.RegisterCallback(self, "OnEraseBar")
flickerstreak@63 51 ReAction.RegisterCallback(self, "OnRenameBar")
flickerstreak@63 52 ReAction.RegisterCallback(self, "OnConfigModeChanged")
flickerstreak@63 53
flickerstreak@108 54 LBF = LibStub("LibButtonFacade",true)
flickerstreak@108 55
flickerstreak@88 56 KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED")
flickerstreak@88 57 KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED")
flickerstreak@88 58 KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
flickerstreak@24 59 end
flickerstreak@24 60
flickerstreak@24 61 function module:OnEnable()
flickerstreak@53 62 ReAction:RegisterBarType(L["Action Bar"],
flickerstreak@53 63 {
flickerstreak@53 64 type = moduleID,
flickerstreak@91 65 defaultButtonSize = 36,
flickerstreak@53 66 defaultBarRows = 1,
flickerstreak@53 67 defaultBarCols = 12,
flickerstreak@53 68 defaultBarSpacing = 3
flickerstreak@53 69 }, true)
flickerstreak@90 70 ReAction:GetModule("State"):RegisterStateProperty("page", nil, PropHandler.GetOptions(), PropHandler)
flickerstreak@24 71 end
flickerstreak@24 72
flickerstreak@24 73 function module:OnDisable()
flickerstreak@53 74 ReAction:UnregisterBarType(L["Action Bar"])
flickerstreak@90 75 ReAction:GetModule("State"):UnregisterStateProperty("page")
flickerstreak@90 76 end
flickerstreak@90 77
flickerstreak@90 78 function module:OnCreateBar(event, bar, name)
flickerstreak@90 79 if bar.config.type == moduleID then
flickerstreak@90 80 local profile = self.db.profile
flickerstreak@90 81 if profile.bars[name] == nil then
flickerstreak@90 82 profile.bars[name] = {
flickerstreak@90 83 buttons = { }
flickerstreak@90 84 }
flickerstreak@90 85 end
flickerstreak@90 86 if self.handles[bar] == nil then
flickerstreak@90 87 self.handles[bar] = Handle:New(bar, profile.bars[name])
flickerstreak@90 88 end
flickerstreak@90 89 end
flickerstreak@24 90 end
flickerstreak@24 91
flickerstreak@63 92 function module:OnRefreshBar(event, bar, name)
flickerstreak@90 93 if self.handles[bar] then
flickerstreak@90 94 self.handles[bar]:Refresh()
flickerstreak@24 95 end
flickerstreak@24 96 end
flickerstreak@24 97
flickerstreak@63 98 function module:OnDestroyBar(event, bar, name)
flickerstreak@90 99 if self.handles[bar] then
flickerstreak@90 100 self.handles[bar]:Destroy()
flickerstreak@90 101 self.handles[bar] = nil
flickerstreak@24 102 end
flickerstreak@24 103 end
flickerstreak@24 104
flickerstreak@63 105 function module:OnEraseBar(event, bar, name)
flickerstreak@75 106 self.db.profile.bars[name] = nil
flickerstreak@24 107 end
flickerstreak@24 108
flickerstreak@63 109 function module:OnRenameBar(event, bar, oldname, newname)
flickerstreak@75 110 b = self.db.profile.bars
flickerstreak@75 111 b[newname], b[oldname] = b[oldname], nil
flickerstreak@48 112 end
flickerstreak@48 113
flickerstreak@63 114 function module:OnConfigModeChanged(event, mode)
flickerstreak@90 115 for _, h in pairs(self.handles) do
flickerstreak@90 116 h:SetConfigMode(mode)
flickerstreak@24 117 end
flickerstreak@24 118 end
flickerstreak@24 119
flickerstreak@88 120 function module:LIBKEYBOUND_ENABLED(evt)
flickerstreak@90 121 for _, h in pairs(self.handles) do
flickerstreak@93 122 h:ShowGrid(true)
flickerstreak@90 123 h:SetKeybindMode(true)
flickerstreak@88 124 end
flickerstreak@88 125 end
flickerstreak@88 126
flickerstreak@88 127 function module:LIBKEYBOUND_DISABLED(evt)
flickerstreak@90 128 for _, h in pairs(self.handles) do
flickerstreak@93 129 h:ShowGrid(false)
flickerstreak@90 130 h:SetKeybindMode(false)
flickerstreak@88 131 end
flickerstreak@88 132 end
flickerstreak@88 133
flickerstreak@50 134
flickerstreak@90 135 ---- Interface ----
flickerstreak@90 136 function module:GetBarOptions(bar)
flickerstreak@90 137 local h = self.handles[bar]
flickerstreak@90 138 if h then
flickerstreak@90 139 return h:GetOptions()
flickerstreak@90 140 end
flickerstreak@90 141 end
flickerstreak@90 142
flickerstreak@90 143
flickerstreak@90 144 ---- Bar Handle ----
flickerstreak@90 145
flickerstreak@87 146 do
flickerstreak@87 147 local options = {
flickerstreak@87 148 hideEmpty = {
flickerstreak@87 149 name = L["Hide Empty Buttons"],
flickerstreak@87 150 order = 1,
flickerstreak@87 151 type = "toggle",
flickerstreak@87 152 width = "double",
flickerstreak@87 153 get = "GetHideEmpty",
flickerstreak@87 154 set = "SetHideEmpty",
flickerstreak@87 155 },
flickerstreak@102 156 lockButtons = {
flickerstreak@102 157 name = L["Lock Buttons"],
flickerstreak@102 158 desc = L["Prevents picking up/dragging actions.|nNOTE: This setting is overridden by the global setting in Blizzard's Action Buttons tab"],
flickerstreak@102 159 order = 2,
flickerstreak@102 160 type = "toggle",
flickerstreak@102 161 disabled = "LockButtonsDisabled",
flickerstreak@102 162 get = "GetLockButtons",
flickerstreak@102 163 set = "SetLockButtons",
flickerstreak@102 164 },
flickerstreak@102 165 lockOnlyCombat = {
flickerstreak@102 166 name = L["Only in Combat"],
flickerstreak@102 167 desc = L["Only lock the buttons when in combat"],
flickerstreak@102 168 order = 3,
flickerstreak@102 169 type = "toggle",
flickerstreak@102 170 disabled = "LockButtonsCombatDisabled",
flickerstreak@102 171 get = "GetLockButtonsCombat",
flickerstreak@102 172 set = "SetLockButtonsCombat",
flickerstreak@102 173 },
flickerstreak@87 174 pages = {
flickerstreak@87 175 name = L["# Pages"],
flickerstreak@87 176 desc = L["Use the Dynamic State tab to specify page transitions"],
flickerstreak@102 177 order = 4,
flickerstreak@87 178 type = "range",
flickerstreak@87 179 min = 1,
flickerstreak@87 180 max = 10,
flickerstreak@87 181 step = 1,
flickerstreak@87 182 get = "GetNumPages",
flickerstreak@87 183 set = "SetNumPages",
flickerstreak@87 184 },
flickerstreak@90 185 mindcontrol = {
flickerstreak@90 186 name = L["Mind Control Support"],
flickerstreak@90 187 desc = L["When possessing a target (e.g. via Mind Control), map the first 12 buttons of this bar to the possessed target's actions."],
flickerstreak@102 188 order = 5,
flickerstreak@90 189 type = "toggle",
flickerstreak@90 190 width = "double",
flickerstreak@90 191 set = "SetMindControl",
flickerstreak@90 192 get = "GetMindControl",
flickerstreak@90 193 },
flickerstreak@87 194 actions = {
flickerstreak@87 195 name = L["Edit Action IDs"],
flickerstreak@102 196 order = 6,
flickerstreak@87 197 type = "group",
flickerstreak@87 198 inline = true,
flickerstreak@87 199 args = {
flickerstreak@87 200 method = {
flickerstreak@87 201 name = L["Assign"],
flickerstreak@87 202 order = 1,
flickerstreak@87 203 type = "select",
flickerstreak@87 204 width = "double",
flickerstreak@87 205 values = { [0] = L["Choose Method..."],
flickerstreak@87 206 [1] = L["Individually"],
flickerstreak@87 207 [2] = L["All at Once"], },
flickerstreak@87 208 get = "GetActionEditMethod",
flickerstreak@87 209 set = "SetActionEditMethod",
flickerstreak@87 210 },
flickerstreak@87 211 rowSelect = {
flickerstreak@87 212 name = L["Row"],
flickerstreak@87 213 desc = L["Rows are numbered top to bottom"],
flickerstreak@87 214 order = 2,
flickerstreak@87 215 type = "select",
flickerstreak@87 216 width = "half",
flickerstreak@87 217 hidden = "IsButtonSelectHidden",
flickerstreak@87 218 values = "GetRowList",
flickerstreak@87 219 get = "GetSelectedRow",
flickerstreak@87 220 set = "SetSelectedRow",
flickerstreak@87 221 },
flickerstreak@87 222 colSelect = {
flickerstreak@87 223 name = L["Col"],
flickerstreak@87 224 desc = L["Columns are numbered left to right"],
flickerstreak@87 225 order = 3,
flickerstreak@87 226 type = "select",
flickerstreak@87 227 width = "half",
flickerstreak@87 228 hidden = "IsButtonSelectHidden",
flickerstreak@87 229 values = "GetColumnList",
flickerstreak@87 230 get = "GetSelectedColumn",
flickerstreak@87 231 set = "SetSelectedColumn",
flickerstreak@87 232 },
flickerstreak@87 233 pageSelect = {
flickerstreak@87 234 name = L["Page"],
flickerstreak@87 235 order = 4,
flickerstreak@87 236 type = "select",
flickerstreak@87 237 width = "half",
flickerstreak@87 238 hidden = "IsPageSelectHidden",
flickerstreak@87 239 values = "GetPageList",
flickerstreak@87 240 get = "GetSelectedPage",
flickerstreak@87 241 set = "SetSelectedPage",
flickerstreak@87 242 },
flickerstreak@87 243 single = {
flickerstreak@87 244 name = L["Action ID"],
flickerstreak@87 245 usage = L["Specify ID 1-120"],
flickerstreak@87 246 order = 5,
flickerstreak@87 247 type = "input",
flickerstreak@87 248 width = "half",
flickerstreak@87 249 hidden = "IsButtonSelectHidden",
flickerstreak@87 250 get = "GetActionID",
flickerstreak@87 251 set = "SetActionID",
flickerstreak@87 252 validate = "ValidateActionID",
flickerstreak@87 253 },
flickerstreak@87 254 multi = {
flickerstreak@87 255 name = L["ID List"],
flickerstreak@87 256 usage = L["Specify a comma-separated list of IDs for each button in the bar (in order). Separate multiple pages with semicolons (;)"],
flickerstreak@87 257 order = 6,
flickerstreak@87 258 type = "input",
flickerstreak@87 259 multiline = true,
flickerstreak@87 260 width = "double",
flickerstreak@87 261 hidden = "IsMultiIDHidden",
flickerstreak@87 262 get = "GetMultiID",
flickerstreak@87 263 set = "SetMultiID",
flickerstreak@87 264 validate = "ValidateMultiID",
flickerstreak@90 265 },
flickerstreak@90 266 },
flickerstreak@87 267 },
flickerstreak@87 268 }
flickerstreak@77 269
flickerstreak@90 270 local weak = { __mode="k" }
flickerstreak@90 271 local meta = { __index = Handle }
flickerstreak@90 272
flickerstreak@90 273 function Handle:New( bar, config )
flickerstreak@90 274 local self = setmetatable(
flickerstreak@90 275 {
flickerstreak@90 276 bar = bar,
flickerstreak@90 277 config = config,
flickerstreak@90 278 btns = { }
flickerstreak@90 279 },
flickerstreak@90 280 meta)
flickerstreak@90 281
flickerstreak@90 282 if self.config.buttons == nil then
flickerstreak@90 283 self.config.buttons = { }
flickerstreak@90 284 end
flickerstreak@90 285 self:Refresh()
flickerstreak@92 286 self:SetKeybindMode(ReAction:GetKeybindMode())
flickerstreak@90 287 return self
flickerstreak@90 288 end
flickerstreak@90 289
flickerstreak@90 290 function Handle:Refresh()
flickerstreak@90 291 local r, c = self.bar:GetButtonGrid()
flickerstreak@90 292 local n = r*c
flickerstreak@90 293 local btnCfg = self.config.buttons
flickerstreak@90 294 if n ~= #self.btns then
flickerstreak@90 295 for i = 1, n do
flickerstreak@90 296 if btnCfg[i] == nil then
flickerstreak@90 297 btnCfg[i] = {}
flickerstreak@90 298 end
flickerstreak@90 299 if self.btns[i] == nil then
flickerstreak@90 300 local b = Button:New(self, i, btnCfg[i], self.config)
flickerstreak@90 301 self.btns[i] = b
flickerstreak@90 302 self.bar:AddButton(i,b)
flickerstreak@90 303 end
flickerstreak@90 304 end
flickerstreak@90 305 for i = n+1, #self.btns do
flickerstreak@90 306 if self.btns[i] then
flickerstreak@90 307 self.bar:RemoveButton(self.btns[i])
flickerstreak@90 308 self.btns[i]:Destroy()
flickerstreak@90 309 self.btns[i] = nil
flickerstreak@90 310 btnCfg[i] = nil
flickerstreak@90 311 end
flickerstreak@90 312 end
flickerstreak@90 313 end
flickerstreak@102 314 local f = self.bar:GetFrame()
flickerstreak@90 315 for _, b in ipairs(self.btns) do
flickerstreak@90 316 b:Refresh()
flickerstreak@90 317 end
flickerstreak@90 318 f:SetAttribute("mindcontrol",self.config.mindcontrol)
flickerstreak@90 319 f:Execute(
flickerstreak@90 320 [[
flickerstreak@90 321 doMindControl = self:GetAttribute("mindcontrol")
flickerstreak@90 322 control:ChildUpdate()
flickerstreak@90 323 ]])
flickerstreak@90 324
flickerstreak@90 325 f:SetAttribute("_onstate-mindcontrol",
flickerstreak@90 326 -- function _onstate-mindcontrol(self, stateid, newstate)
flickerstreak@90 327 [[
flickerstreak@90 328 control:ChildUpdate()
flickerstreak@90 329 ]])
flickerstreak@90 330 RegisterStateDriver(f, "mindcontrol", "[bonusbar:5] mc; none")
flickerstreak@102 331 self:UpdateButtonLock()
flickerstreak@90 332 end
flickerstreak@90 333
flickerstreak@90 334 function Handle:Destroy()
flickerstreak@90 335 for _,b in pairs(self.btns) do
flickerstreak@90 336 if b then
flickerstreak@90 337 b:Destroy()
flickerstreak@90 338 end
flickerstreak@90 339 end
flickerstreak@90 340 end
flickerstreak@90 341
flickerstreak@90 342 function Handle:SetConfigMode(mode)
flickerstreak@90 343 for _, b in pairs(self.btns) do
flickerstreak@90 344 b:ShowGrid(mode)
flickerstreak@90 345 b:ShowActionIDLabel(mode)
flickerstreak@90 346 end
flickerstreak@90 347 end
flickerstreak@90 348
flickerstreak@93 349 function Handle:ShowGrid(show)
flickerstreak@93 350 for _, b in pairs(self.btns) do
flickerstreak@93 351 b:ShowGrid(show)
flickerstreak@93 352 end
flickerstreak@93 353 end
flickerstreak@93 354
flickerstreak@102 355 function Handle:UpdateButtonLock()
flickerstreak@102 356 local f = self.bar:GetFrame()
flickerstreak@102 357 f:SetAttribute("lockbuttons",self.config.lockButtons)
flickerstreak@102 358 f:SetAttribute("lockbuttonscombat",self.config.lockButtonsCombat)
flickerstreak@102 359 f:Execute(
flickerstreak@102 360 [[
flickerstreak@102 361 lockButtons = self:GetAttribute("lockbuttons")
flickerstreak@102 362 lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
flickerstreak@102 363 ]])
flickerstreak@102 364 end
flickerstreak@102 365
flickerstreak@90 366 function Handle:SetKeybindMode(mode)
flickerstreak@90 367 for _, b in pairs(self.btns) do
flickerstreak@90 368 if mode then
flickerstreak@90 369 -- set the border for all buttons to the keybind-enable color
flickerstreak@92 370 b.border:SetVertexColor(KB:GetColorKeyBoundMode())
flickerstreak@90 371 b.border:Show()
flickerstreak@92 372 elseif IsEquippedAction(b:GetActionID()) then
flickerstreak@92 373 b.border:SetVertexColor(0, 1.0, 0, 0.35) -- from ActionButton.lua
flickerstreak@90 374 else
flickerstreak@90 375 b.border:Hide()
flickerstreak@90 376 end
flickerstreak@90 377 end
flickerstreak@90 378 end
flickerstreak@90 379
flickerstreak@90 380 function Handle:GetLastButton()
flickerstreak@90 381 return self.btns[#self.btns]
flickerstreak@90 382 end
flickerstreak@90 383
flickerstreak@90 384 -- options handlers
flickerstreak@90 385 function Handle:GetOptions()
flickerstreak@87 386 return {
flickerstreak@87 387 type = "group",
flickerstreak@87 388 name = L["Action Buttons"],
flickerstreak@90 389 handler = self,
flickerstreak@87 390 args = options
flickerstreak@87 391 }
flickerstreak@77 392 end
flickerstreak@77 393
flickerstreak@90 394 function Handle:SetHideEmpty(info, value)
flickerstreak@90 395 if value ~= self.config.hideEmpty then
flickerstreak@90 396 self.config.hideEmpty = value
flickerstreak@102 397 self:ShowGrid(not value)
flickerstreak@77 398 end
flickerstreak@77 399 end
flickerstreak@77 400
flickerstreak@90 401 function Handle:GetHideEmpty()
flickerstreak@90 402 return self.config.hideEmpty
flickerstreak@77 403 end
flickerstreak@87 404
flickerstreak@102 405 function Handle:GetLockButtons()
flickerstreak@102 406 return LOCK_ACTIONBAR == "1" or self.config.lockButtons
flickerstreak@102 407 end
flickerstreak@102 408
flickerstreak@102 409 function Handle:SetLockButtons(info, value)
flickerstreak@102 410 self.config.lockButtons = value
flickerstreak@102 411 self:UpdateButtonLock()
flickerstreak@102 412 end
flickerstreak@102 413
flickerstreak@102 414 function Handle:LockButtonsDisabled()
flickerstreak@102 415 return LOCK_ACTIONBAR == "1"
flickerstreak@102 416 end
flickerstreak@102 417
flickerstreak@102 418 function Handle:GetLockButtonsCombat()
flickerstreak@102 419 return self.config.lockButtonsCombat
flickerstreak@102 420 end
flickerstreak@102 421
flickerstreak@102 422 function Handle:SetLockButtonsCombat(info, value)
flickerstreak@102 423 self.config.lockButtonsCombat = value
flickerstreak@102 424 self:UpdateButtonLock()
flickerstreak@102 425 end
flickerstreak@102 426
flickerstreak@102 427 function Handle:LockButtonsCombatDisabled()
flickerstreak@102 428 return LOCK_ACTIONBAR == "1" or not self.config.lockButtons
flickerstreak@102 429 end
flickerstreak@102 430
flickerstreak@90 431 function Handle:GetNumPages()
flickerstreak@90 432 return self.config.nPages
flickerstreak@87 433 end
flickerstreak@87 434
flickerstreak@90 435 function Handle:SetNumPages(info, value)
flickerstreak@90 436 self.config.nPages = value
flickerstreak@90 437 self:Refresh()
flickerstreak@87 438 end
flickerstreak@87 439
flickerstreak@90 440 function Handle:GetMindControl()
flickerstreak@90 441 return self.config.mindcontrol
flickerstreak@90 442 end
flickerstreak@90 443
flickerstreak@90 444 function Handle:SetMindControl(info, value)
flickerstreak@90 445 self.config.mindcontrol = value
flickerstreak@90 446 self:Refresh()
flickerstreak@90 447 end
flickerstreak@90 448
flickerstreak@90 449 function Handle:GetActionEditMethod()
flickerstreak@87 450 return self.editMethod or 0
flickerstreak@87 451 end
flickerstreak@87 452
flickerstreak@90 453 function Handle:SetActionEditMethod(info, value)
flickerstreak@87 454 self.editMethod = value
flickerstreak@87 455 end
flickerstreak@87 456
flickerstreak@90 457 function Handle:IsButtonSelectHidden()
flickerstreak@87 458 return self.editMethod ~= 1
flickerstreak@87 459 end
flickerstreak@87 460
flickerstreak@90 461 function Handle:GetRowList()
flickerstreak@87 462 local r,c = self.bar:GetButtonGrid()
flickerstreak@87 463 if self.rowList == nil or #self.rowList ~= r then
flickerstreak@87 464 local list = { }
flickerstreak@87 465 for i = 1, r do
flickerstreak@87 466 table.insert(list,i)
flickerstreak@87 467 end
flickerstreak@87 468 self.rowList = list
flickerstreak@87 469 end
flickerstreak@87 470 return self.rowList
flickerstreak@87 471 end
flickerstreak@87 472
flickerstreak@90 473 function Handle:GetSelectedRow()
flickerstreak@87 474 local r, c = self.bar:GetButtonGrid()
flickerstreak@87 475 local row = self.selectedRow or 1
flickerstreak@87 476 if row > r then
flickerstreak@87 477 row = 1
flickerstreak@87 478 end
flickerstreak@87 479 self.selectedRow = row
flickerstreak@87 480 return row
flickerstreak@87 481 end
flickerstreak@87 482
flickerstreak@90 483 function Handle:SetSelectedRow(info, value)
flickerstreak@87 484 self.selectedRow = value
flickerstreak@87 485 end
flickerstreak@87 486
flickerstreak@90 487 function Handle:GetColumnList()
flickerstreak@87 488 local r,c = self.bar:GetButtonGrid()
flickerstreak@87 489 if self.columnList == nil or #self.columnList ~= c then
flickerstreak@87 490 local list = { }
flickerstreak@87 491 for i = 1, c do
flickerstreak@87 492 table.insert(list,i)
flickerstreak@87 493 end
flickerstreak@87 494 self.columnList = list
flickerstreak@87 495 end
flickerstreak@87 496 return self.columnList
flickerstreak@87 497 end
flickerstreak@87 498
flickerstreak@90 499 function Handle:GetSelectedColumn()
flickerstreak@87 500 local r, c = self.bar:GetButtonGrid()
flickerstreak@87 501 local col = self.selectedColumn or 1
flickerstreak@87 502 if col > c then
flickerstreak@87 503 col = 1
flickerstreak@87 504 end
flickerstreak@87 505 self.selectedColumn = col
flickerstreak@87 506 return col
flickerstreak@87 507 end
flickerstreak@87 508
flickerstreak@90 509 function Handle:SetSelectedColumn(info, value)
flickerstreak@87 510 self.selectedColumn = value
flickerstreak@87 511 end
flickerstreak@87 512
flickerstreak@90 513 function Handle:IsPageSelectHidden()
flickerstreak@90 514 return self.editMethod ~= 1 or (self.config.nPages or 1) < 2
flickerstreak@87 515 end
flickerstreak@87 516
flickerstreak@90 517 function Handle:GetPageList()
flickerstreak@90 518 local n = self.config.nPages or 1
flickerstreak@87 519 if self.pageList == nil or #self.pageList ~= n then
flickerstreak@87 520 local p = { }
flickerstreak@87 521 for i = 1, n do
flickerstreak@87 522 table.insert(p,i)
flickerstreak@87 523 end
flickerstreak@87 524 self.pageList = p
flickerstreak@87 525 end
flickerstreak@87 526 return self.pageList
flickerstreak@87 527 end
flickerstreak@87 528
flickerstreak@90 529 function Handle:GetSelectedPage()
flickerstreak@87 530 local p = self.selectedPage or 1
flickerstreak@90 531 if p > (self.config.nPages or 1) then
flickerstreak@87 532 p = 1
flickerstreak@87 533 end
flickerstreak@87 534 self.selectedPage = p
flickerstreak@87 535 return p
flickerstreak@87 536 end
flickerstreak@87 537
flickerstreak@90 538 function Handle:SetSelectedPage(info, value)
flickerstreak@87 539 self.selectedPage = value
flickerstreak@87 540 end
flickerstreak@87 541
flickerstreak@90 542 function Handle:GetActionID()
flickerstreak@87 543 local row = self.selectedRow or 1
flickerstreak@87 544 local col = self.selectedColumn or 1
flickerstreak@87 545 local r, c = self.bar:GetButtonGrid()
flickerstreak@87 546 local n = (row-1) * c + col
flickerstreak@90 547 local btn = self.btns[n]
flickerstreak@87 548 if btn then
flickerstreak@87 549 return tostring(btn:GetActionID(self.selectedPage or 1))
flickerstreak@87 550 end
flickerstreak@87 551 end
flickerstreak@87 552
flickerstreak@90 553 function Handle:SetActionID(info, value)
flickerstreak@87 554 local row = self.selectedRow or 1
flickerstreak@87 555 local col = self.selectedColumn or 1
flickerstreak@87 556 local r, c = self.bar:GetButtonGrid()
flickerstreak@87 557 local n = (row-1) * c + col
flickerstreak@90 558 local btn = self.btns[n]
flickerstreak@87 559 if btn then
flickerstreak@87 560 btn:SetActionID(tonumber(value), self.selectedPage or 1)
flickerstreak@87 561 end
flickerstreak@87 562 end
flickerstreak@87 563
flickerstreak@90 564 function Handle:ValidateActionID(info, value)
flickerstreak@87 565 value = tonumber(value)
flickerstreak@87 566 if value == nil or value < 1 or value > 120 then
flickerstreak@87 567 return L["Specify ID 1-120"]
flickerstreak@87 568 end
flickerstreak@87 569 return true
flickerstreak@87 570 end
flickerstreak@87 571
flickerstreak@90 572 function Handle:IsMultiIDHidden()
flickerstreak@87 573 return self.editMethod ~= 2
flickerstreak@87 574 end
flickerstreak@87 575
flickerstreak@90 576 function Handle:GetMultiID()
flickerstreak@87 577 local p = { }
flickerstreak@90 578 for i = 1, self.config.nPages or 1 do
flickerstreak@87 579 local b = { }
flickerstreak@90 580 for _, btn in ipairs(self.btns) do
flickerstreak@87 581 table.insert(b, btn:GetActionID(i))
flickerstreak@87 582 end
flickerstreak@87 583 table.insert(p, table.concat(b,","))
flickerstreak@87 584 end
flickerstreak@87 585 return table.concat(p,";\n")
flickerstreak@87 586 end
flickerstreak@87 587
flickerstreak@87 588
flickerstreak@87 589 local function ParseMultiID(nBtns, nPages, s)
flickerstreak@87 590 if s:match("[^%d%s,;]") then
flickerstreak@87 591 ReAction:Print("items other than digits, spaces, commas, and semicolons in string",s)
flickerstreak@87 592 return nil
flickerstreak@87 593 end
flickerstreak@87 594 local p = { }
flickerstreak@87 595 for list in s:gmatch("[^;]+") do
flickerstreak@87 596 local pattern = ("^%s?$"):format(("%s*(%d+)%s*,"):rep(nBtns))
flickerstreak@87 597 local ids = { list:match(pattern) }
flickerstreak@87 598 if #ids ~= nBtns then
flickerstreak@87 599 ReAction:Print("found",#ids,"buttons instead of",nBtns)
flickerstreak@87 600 return nil
flickerstreak@87 601 end
flickerstreak@87 602 table.insert(p,ids)
flickerstreak@87 603 end
flickerstreak@87 604 if #p ~= nPages then
flickerstreak@87 605 ReAction:Print("found",#p,"pages instead of",nPages)
flickerstreak@87 606 return nil
flickerstreak@87 607 end
flickerstreak@87 608 return p
flickerstreak@87 609 end
flickerstreak@87 610
flickerstreak@90 611 function Handle:SetMultiID(info, value)
flickerstreak@91 612 local p = ParseMultiID(#self.btns, self.config.nPages or 1, value)
flickerstreak@87 613 for page, b in ipairs(p) do
flickerstreak@87 614 for button, id in ipairs(b) do
flickerstreak@90 615 self.btns[button]:SetActionID(id, page)
flickerstreak@87 616 end
flickerstreak@87 617 end
flickerstreak@87 618 end
flickerstreak@87 619
flickerstreak@90 620 function Handle:ValidateMultiID(info, value)
flickerstreak@87 621 local bad = L["Invalid action ID list string"]
flickerstreak@90 622 if value == nil or ParseMultiID(#self.btns, self.config.nPages or 1, value) == nil then
flickerstreak@87 623 return bad
flickerstreak@87 624 end
flickerstreak@87 625 return true
flickerstreak@87 626 end
flickerstreak@77 627 end
flickerstreak@77 628
flickerstreak@77 629
flickerstreak@87 630 ------ State property options ------
flickerstreak@87 631 do
flickerstreak@87 632 local pageOptions = {
flickerstreak@87 633 page = {
flickerstreak@92 634 name = L["Show Page #"],
flickerstreak@92 635 order = 11,
flickerstreak@92 636 type = "select",
flickerstreak@92 637 width = "half",
flickerstreak@87 638 disabled = "IsPageDisabled",
flickerstreak@87 639 hidden = "IsPageHidden",
flickerstreak@87 640 values = "GetPageValues",
flickerstreak@87 641 set = "SetProp",
flickerstreak@87 642 get = "GetPage",
flickerstreak@87 643 },
flickerstreak@87 644 }
flickerstreak@50 645
flickerstreak@90 646 local function GetBarConfig(bar)
flickerstreak@90 647 return module.db.profile.bars[bar:GetName()]
flickerstreak@87 648 end
flickerstreak@87 649
flickerstreak@90 650 function PropHandler.GetOptions()
flickerstreak@90 651 return pageOptions
flickerstreak@87 652 end
flickerstreak@87 653
flickerstreak@90 654 function PropHandler:IsPageDisabled()
flickerstreak@90 655 local c = GetBarConfig(self.bar)
flickerstreak@90 656 local n = c and c.nPages or 1
flickerstreak@90 657 return not (n > 1)
flickerstreak@87 658 end
flickerstreak@87 659
flickerstreak@90 660 function PropHandler:IsPageHidden()
flickerstreak@87 661 return not GetBarConfig(self.bar)
flickerstreak@87 662 end
flickerstreak@87 663
flickerstreak@90 664 function PropHandler:GetPageValues()
flickerstreak@92 665 if not self._pagevalues then
flickerstreak@92 666 self._pagevalues = { }
flickerstreak@92 667 end
flickerstreak@87 668 local c = GetBarConfig(self.bar)
flickerstreak@87 669 if c then
flickerstreak@87 670 local n = c.nPages
flickerstreak@92 671 -- cache the results
flickerstreak@87 672 if self._npages ~= n then
flickerstreak@87 673 self._npages = n
flickerstreak@92 674 wipe(self._pagevalues)
flickerstreak@87 675 for i = 1, n do
flickerstreak@90 676 self._pagevalues["page"..i] = i
flickerstreak@87 677 end
flickerstreak@87 678 end
flickerstreak@87 679 end
flickerstreak@92 680 return self._pagevalues
flickerstreak@87 681 end
flickerstreak@87 682
flickerstreak@90 683 function PropHandler:GetPage(info)
flickerstreak@87 684 return self:GetProp(info) or 1
flickerstreak@87 685 end
flickerstreak@90 686
flickerstreak@87 687 end
flickerstreak@87 688
flickerstreak@87 689 ------ ActionID allocation ------
flickerstreak@87 690 -- this needs to be high performance when requesting new IDs,
flickerstreak@87 691 -- or certain controls will become sluggish. However, the new-request
flickerstreak@87 692 -- infrastructure can be built lazily the first time that a new request
flickerstreak@87 693 -- comes in (which will only happen at user config time: at static startup
flickerstreak@87 694 -- config time all actionIDs should already have been assigned and stored
flickerstreak@87 695 -- in the config file)
flickerstreak@87 696
flickerstreak@87 697 local IDAlloc
flickerstreak@87 698 do
flickerstreak@87 699 local n = 120
flickerstreak@87 700
flickerstreak@87 701 IDAlloc = setmetatable({ wrap = 1, freecount = n }, {__index = function() return 0 end})
flickerstreak@87 702
flickerstreak@87 703 function IDAlloc:Acquire(id, hint)
flickerstreak@87 704 id = tonumber(id)
flickerstreak@87 705 hint = tonumber(hint)
flickerstreak@87 706 if id and (id < 1 or id > n) then
flickerstreak@87 707 id = nil
flickerstreak@87 708 end
flickerstreak@87 709 if hint and (hint < 1 or hint > n) then
flickerstreak@87 710 hint = nil
flickerstreak@87 711 end
flickerstreak@87 712 if id == nil then
flickerstreak@87 713 -- get a free ID
flickerstreak@87 714 if hint and self[hint] == 0 then
flickerstreak@87 715 -- use the hint if it's free
flickerstreak@87 716 id = hint
flickerstreak@87 717 elseif self.freecount > 0 then
flickerstreak@87 718 -- if neither the id nor the hint are defined or free, but
flickerstreak@87 719 -- the list is known to have free IDs, then start searching
flickerstreak@87 720 -- at the hint for a free one
flickerstreak@87 721 for i = hint or 1, n do
flickerstreak@87 722 if self[i] == 0 then
flickerstreak@87 723 id = i
flickerstreak@87 724 break
flickerstreak@87 725 end
flickerstreak@87 726 end
flickerstreak@87 727 -- self.wrap the search
flickerstreak@87 728 if id == nil and hint and hint > 1 then
flickerstreak@87 729 for i = 1, hint - 1 do
flickerstreak@87 730 if self[i] == 0 then
flickerstreak@87 731 id = i
flickerstreak@87 732 break
flickerstreak@87 733 end
flickerstreak@87 734 end
flickerstreak@87 735 end
flickerstreak@87 736 end
flickerstreak@87 737 if id == nil then
flickerstreak@87 738 -- if there are no free IDs, start wrapping at 1
flickerstreak@87 739 id = self.wrap
flickerstreak@87 740 self.wrap = id + 1
flickerstreak@87 741 if self.wrap > n then
flickerstreak@87 742 self.wrap = 1
flickerstreak@87 743 end
flickerstreak@24 744 end
flickerstreak@24 745 end
flickerstreak@87 746 if self[id] == 0 then
flickerstreak@87 747 self.freecount = self.freecount - 1
flickerstreak@87 748 end
flickerstreak@87 749 self[id] = self[id] + 1
flickerstreak@87 750 return id
flickerstreak@24 751 end
flickerstreak@24 752
flickerstreak@87 753 function IDAlloc:Release(id)
flickerstreak@87 754 id = tonumber(id)
flickerstreak@87 755 if id and (id >= 1 or id <= n) then
flickerstreak@87 756 self[id] = self[id] - 1
flickerstreak@87 757 if self[id] == 0 then
flickerstreak@87 758 self.freecount = self.freecount + 1
flickerstreak@87 759 self.wrap = 1
flickerstreak@87 760 end
flickerstreak@87 761 end
flickerstreak@87 762 end
flickerstreak@87 763 end
flickerstreak@87 764
flickerstreak@88 765 ------ Button class ------
flickerstreak@88 766
flickerstreak@88 767 do
flickerstreak@90 768 local frameRecycler = { }
flickerstreak@90 769 local trash = CreateFrame("Frame")
flickerstreak@90 770 local OnUpdate, KBAttach, GetActionName, GetHotkey, SetKey, FreeKey, ClearBindings, GetBindings
flickerstreak@90 771 do
flickerstreak@90 772 local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
flickerstreak@90 773 local IsActionInRange = IsActionInRange
flickerstreak@87 774
flickerstreak@90 775 local buttonLookup = setmetatable({},{__mode="kv"})
flickerstreak@88 776
flickerstreak@90 777 function OnUpdate(frame, elapsed)
flickerstreak@90 778 -- note: This function taints frame.flashtime and frame.rangeTimer. Both of these
flickerstreak@90 779 -- are only read by ActionButton_OnUpdate (which this function replaces). In
flickerstreak@90 780 -- all other places they're just written, so it doesn't taint any secure code.
flickerstreak@90 781 if frame.flashing == 1 then
flickerstreak@90 782 frame.flashtime = frame.flashtime - elapsed
flickerstreak@90 783 if frame.flashtime <= 0 then
flickerstreak@90 784 local overtime = -frame.flashtime
flickerstreak@90 785 if overtime >= ATTACK_BUTTON_FLASH_TIME then
flickerstreak@90 786 overtime = 0
flickerstreak@90 787 end
flickerstreak@90 788 frame.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
flickerstreak@90 789
flickerstreak@90 790 local flashTexture = frame.flash
flickerstreak@90 791 if flashTexture:IsShown() then
flickerstreak@90 792 flashTexture:Hide()
flickerstreak@90 793 else
flickerstreak@90 794 flashTexture:Show()
flickerstreak@90 795 end
flickerstreak@88 796 end
flickerstreak@90 797 end
flickerstreak@90 798
flickerstreak@90 799 if frame.rangeTimer then
flickerstreak@90 800 frame.rangeTimer = frame.rangeTimer - elapsed;
flickerstreak@88 801
flickerstreak@90 802 if frame.rangeTimer <= 0 then
flickerstreak@90 803 if IsActionInRange(frame.action) == 0 then
flickerstreak@90 804 frame.icon:SetVertexColor(1.0,0.1,0.1)
flickerstreak@90 805 else
flickerstreak@90 806 ActionButton_UpdateUsable(frame)
flickerstreak@90 807 end
flickerstreak@90 808 frame.rangeTimer = 0.1
flickerstreak@88 809 end
flickerstreak@88 810 end
flickerstreak@88 811 end
flickerstreak@90 812
flickerstreak@90 813 -- Use KeyBound-1.0 for binding, but use Override bindings instead of
flickerstreak@90 814 -- regular bindings to support multiple profile use. This is a little
flickerstreak@90 815 -- weird with the KeyBound dialog box (which has per-char selector as well
flickerstreak@90 816 -- as an OK/Cancel box) but it's the least amount of effort to implement.
flickerstreak@90 817 function GetActionName(f)
flickerstreak@90 818 local b = buttonLookup[f]
flickerstreak@90 819 if b then
flickerstreak@90 820 return format("%s:%s", b.bar:GetName(), b.idx)
flickerstreak@90 821 end
flickerstreak@90 822 end
flickerstreak@90 823
flickerstreak@90 824 function GetHotkey(f)
flickerstreak@90 825 local b = buttonLookup[f]
flickerstreak@90 826 if b then
flickerstreak@90 827 return KB:ToShortKey(b:GetConfig().hotkey)
flickerstreak@90 828 end
flickerstreak@90 829 end
flickerstreak@90 830
flickerstreak@90 831 function SetKey(f, key)
flickerstreak@90 832 local b = buttonLookup[f]
flickerstreak@90 833 if b then
flickerstreak@90 834 local c = b:GetConfig()
flickerstreak@90 835 if c.hotkey then
flickerstreak@90 836 SetOverrideBinding(f, false, c.hotkey, nil)
flickerstreak@90 837 end
flickerstreak@90 838 if key then
flickerstreak@90 839 SetOverrideBindingClick(f, false, key, f:GetName(), nil)
flickerstreak@90 840 end
flickerstreak@90 841 c.hotkey = key
flickerstreak@90 842 b:DisplayHotkey(GetHotkey(f))
flickerstreak@90 843 end
flickerstreak@90 844 end
flickerstreak@90 845
flickerstreak@90 846 function FreeKey(f, key)
flickerstreak@90 847 local b = buttonLookup[f]
flickerstreak@90 848 if b then
flickerstreak@90 849 local c = b:GetConfig()
flickerstreak@90 850 if c.hotkey == key then
flickerstreak@90 851 local action = f:GetActionName()
flickerstreak@90 852 SetOverrideBinding(f, false, c.hotkey, nil)
flickerstreak@90 853 c.hotkey = nil
flickerstreak@90 854 b:DisplayHotkey(nil)
flickerstreak@90 855 return action
flickerstreak@90 856 end
flickerstreak@90 857 end
flickerstreak@90 858 return ReAction:FreeOverrideHotkey(key)
flickerstreak@90 859 end
flickerstreak@90 860
flickerstreak@90 861 function ClearBindings(f)
flickerstreak@90 862 SetKey(f, nil)
flickerstreak@90 863 end
flickerstreak@90 864
flickerstreak@90 865 function GetBindings(f)
flickerstreak@90 866 local b = buttonLookup[f]
flickerstreak@90 867 if b then
flickerstreak@90 868 return b:GetConfig().hotkey
flickerstreak@90 869 end
flickerstreak@90 870 end
flickerstreak@90 871
flickerstreak@90 872 function KBAttach( button )
flickerstreak@90 873 local f = button:GetFrame()
flickerstreak@90 874 f.GetActionName = GetActionName
flickerstreak@90 875 f.GetHotkey = GetHotkey
flickerstreak@90 876 f.SetKey = SetKey
flickerstreak@90 877 f.FreeKey = FreeKey
flickerstreak@90 878 f.ClearBindings = ClearBindings
flickerstreak@90 879 f.GetBindings = GetBindings
flickerstreak@90 880 buttonLookup[f] = button
flickerstreak@90 881 f:SetKey(button:GetConfig().hotkey)
flickerstreak@90 882 ReAction:RegisterKeybindFrame(f)
flickerstreak@92 883 if ReAction:GetKeybindMode() then
flickerstreak@92 884 button.border:SetVertexColor(KB:GetColorKeyBoundMode())
flickerstreak@92 885 button.border:Show()
flickerstreak@92 886 end
flickerstreak@90 887 end
flickerstreak@90 888 end
flickerstreak@90 889
flickerstreak@90 890 local meta = {__index = Button}
flickerstreak@90 891
flickerstreak@90 892 function Button:New( handle, idx, config, barConfig )
flickerstreak@90 893 local bar = handle.bar
flickerstreak@90 894
flickerstreak@90 895 -- create new self
flickerstreak@90 896 self = setmetatable(
flickerstreak@90 897 {
flickerstreak@90 898 bar = bar,
flickerstreak@90 899 idx = idx,
flickerstreak@90 900 config = config,
flickerstreak@90 901 barConfig = barConfig,
flickerstreak@90 902 }, meta )
flickerstreak@90 903
flickerstreak@90 904 local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx)
flickerstreak@90 905 self.name = name
flickerstreak@90 906 config.name = name
flickerstreak@90 907 local lastButton = handle:GetLastButton()
flickerstreak@90 908 config.actionID = IDAlloc:Acquire(config.actionID, lastButton and lastButton.config.actionID) -- gets a free one if none configured
flickerstreak@90 909 self.nPages = 1
flickerstreak@88 910
flickerstreak@90 911 -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
flickerstreak@90 912 -- existing globals. Can't set to nil in the global because it's then tainted.
flickerstreak@90 913 local parent = bar:GetFrame()
flickerstreak@90 914 local f = frameRecycler[name]
flickerstreak@90 915 if f then
flickerstreak@90 916 f:SetParent(parent)
flickerstreak@90 917 else
flickerstreak@90 918 f = CreateFrame("CheckButton", name, parent, "ActionBarButtonTemplate")
flickerstreak@90 919 -- ditch the old hotkey text because it's tied in ActionButton_Update() to the
flickerstreak@90 920 -- standard binding. We use override bindings.
flickerstreak@90 921 local hotkey = _G[name.."HotKey"]
flickerstreak@90 922 hotkey:SetParent(trash)
flickerstreak@90 923 hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray")
flickerstreak@90 924 hotkey:SetWidth(36)
flickerstreak@90 925 hotkey:SetHeight(18)
flickerstreak@90 926 hotkey:SetJustifyH("RIGHT")
flickerstreak@90 927 hotkey:SetJustifyV("TOP")
flickerstreak@90 928 hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
flickerstreak@90 929 f.hotkey = hotkey
flickerstreak@90 930 f.icon = _G[name.."Icon"]
flickerstreak@90 931 f.flash = _G[name.."Flash"]
flickerstreak@90 932 f:SetScript("OnUpdate",OnUpdate)
flickerstreak@90 933 end
flickerstreak@88 934
flickerstreak@90 935 self.hotkey = f.hotkey
flickerstreak@90 936 self.border = _G[name.."Border"]
flickerstreak@90 937
flickerstreak@90 938 f:SetAttribute("action", config.actionID)
flickerstreak@90 939 -- install mind control actions for all buttons just for simplicity
flickerstreak@90 940 if self.idx <= 12 then
flickerstreak@90 941 f:SetAttribute("*action-mc", 120 + self.idx)
flickerstreak@90 942 end
flickerstreak@90 943
flickerstreak@90 944 -- set a _childupdate handler, called within the header's context
flickerstreak@90 945 f:SetAttribute("_childupdate",
flickerstreak@90 946 -- function _childupdate(self, snippetid, message)
flickerstreak@90 947 [[
flickerstreak@90 948 local action = "action"
flickerstreak@90 949 if doMindControl and GetBonusBarOffset() == 5 then
flickerstreak@90 950 action = "*action-mc"
flickerstreak@90 951 elseif page and state and page[state] then
flickerstreak@90 952 action = "*action-"..page[state]
flickerstreak@90 953 end
flickerstreak@90 954 local value = self:GetAttribute(action)
flickerstreak@92 955 self:SetAttribute("action",value)
flickerstreak@90 956 ]])
flickerstreak@90 957
flickerstreak@102 958 -- install drag wrappers to lock buttons
flickerstreak@102 959 bar:GetFrame():WrapScript(f, "OnDragStart",
flickerstreak@102 960 -- OnDragStart(self, button, kind, value, ...)
flickerstreak@102 961 [[
flickerstreak@102 962 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
flickerstreak@102 963 return "clear"
flickerstreak@102 964 end
flickerstreak@102 965 ]])
flickerstreak@102 966
flickerstreak@90 967 self.frame = f
flickerstreak@108 968
flickerstreak@90 969
flickerstreak@90 970 -- initialize the hide state
flickerstreak@90 971 f:SetAttribute("showgrid",0)
flickerstreak@90 972 self:ShowGrid(not barConfig.hideEmpty)
flickerstreak@90 973 if ReAction:GetConfigMode() then
flickerstreak@90 974 self:ShowGrid(true)
flickerstreak@90 975 end
flickerstreak@90 976
flickerstreak@90 977 -- show the ID label if applicable
flickerstreak@90 978 self:ShowActionIDLabel(ReAction:GetConfigMode())
flickerstreak@90 979
flickerstreak@90 980 -- attach the keybinder
flickerstreak@90 981 KBAttach(self)
flickerstreak@90 982
flickerstreak@108 983 -- attach to skinner
flickerstreak@108 984 bar:SkinButton(self,
flickerstreak@108 985 {
flickerstreak@108 986 HotKey = self.hotkey,
flickerstreak@108 987 }
flickerstreak@108 988 )
flickerstreak@108 989
flickerstreak@90 990 self:Refresh()
flickerstreak@90 991 return self
flickerstreak@90 992 end
flickerstreak@90 993
flickerstreak@90 994 function Button:Destroy()
flickerstreak@90 995 local f = self.frame
flickerstreak@90 996 f:UnregisterAllEvents()
flickerstreak@90 997 f:Hide()
flickerstreak@90 998 f:SetParent(UIParent)
flickerstreak@90 999 f:ClearAllPoints()
flickerstreak@90 1000 if self.name then
flickerstreak@90 1001 frameRecycler[self.name] = f
flickerstreak@90 1002 end
flickerstreak@90 1003 if self.config.actionID then
flickerstreak@90 1004 IDAlloc:Release(self.config.actionID)
flickerstreak@90 1005 end
flickerstreak@90 1006 if self.config.pageactions then
flickerstreak@90 1007 for _, id in ipairs(self.config.pageactions) do
flickerstreak@90 1008 IDAlloc:Release(id)
flickerstreak@90 1009 end
flickerstreak@90 1010 end
flickerstreak@90 1011 self.frame = nil
flickerstreak@90 1012 self.config = nil
flickerstreak@90 1013 self.bar = nil
flickerstreak@90 1014 end
flickerstreak@90 1015
flickerstreak@90 1016 function Button:Refresh()
flickerstreak@90 1017 local f = self.frame
flickerstreak@90 1018 self.bar:PlaceButton(self, 36, 36)
flickerstreak@90 1019 self:RefreshPages()
flickerstreak@90 1020 end
flickerstreak@90 1021
flickerstreak@90 1022 function Button:GetFrame()
flickerstreak@90 1023 return self.frame
flickerstreak@90 1024 end
flickerstreak@90 1025
flickerstreak@90 1026 function Button:GetName()
flickerstreak@90 1027 return self.name
flickerstreak@90 1028 end
flickerstreak@90 1029
flickerstreak@90 1030 function Button:GetConfig()
flickerstreak@90 1031 return self.config
flickerstreak@90 1032 end
flickerstreak@90 1033
flickerstreak@90 1034 function Button:GetActionID(page)
flickerstreak@90 1035 if page == nil then
flickerstreak@90 1036 -- get the effective ID
flickerstreak@90 1037 return self.frame.action -- kept up-to-date by Blizzard's ActionButton_CalculateAction()
flickerstreak@90 1038 else
flickerstreak@90 1039 if page == 1 then
flickerstreak@90 1040 return self.config.actionID
flickerstreak@90 1041 else
flickerstreak@90 1042 return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
flickerstreak@88 1043 end
flickerstreak@88 1044 end
flickerstreak@88 1045 end
flickerstreak@88 1046
flickerstreak@90 1047 function Button:SetActionID( id, page )
flickerstreak@90 1048 id = tonumber(id)
flickerstreak@90 1049 page = tonumber(page)
flickerstreak@90 1050 if id == nil or id < 1 or id > 120 then
flickerstreak@90 1051 error("Button:SetActionID - invalid action ID")
flickerstreak@90 1052 end
flickerstreak@90 1053 if page and page ~= 1 then
flickerstreak@90 1054 if not self.config.pageactions then
flickerstreak@90 1055 self.config.pageactions = { }
flickerstreak@90 1056 end
flickerstreak@90 1057 if self.config.pageactions[page] then
flickerstreak@90 1058 IDAlloc:Release(self.config.pageactions[page])
flickerstreak@90 1059 end
flickerstreak@90 1060 self.config.pageactions[page] = id
flickerstreak@90 1061 IDAlloc:Acquire(self.config.pageactions[page])
flickerstreak@90 1062 self.frame:SetAttribute(("*action-page%d"):format(page),id)
flickerstreak@90 1063 else
flickerstreak@90 1064 IDAlloc:Release(self.config.actionID)
flickerstreak@90 1065 self.config.actionID = id
flickerstreak@90 1066 IDAlloc:Acquire(self.config.actionID)
flickerstreak@90 1067 self.frame:SetAttribute("action",id)
flickerstreak@90 1068 if self.config.pageactions then
flickerstreak@90 1069 self.config.pageactions[1] = id
flickerstreak@90 1070 self.frame:SetAttribute("*action-page1",id)
flickerstreak@90 1071 end
flickerstreak@88 1072 end
flickerstreak@88 1073 end
flickerstreak@88 1074
flickerstreak@90 1075 function Button:RefreshPages( force )
flickerstreak@90 1076 local nPages = self.barConfig.nPages
flickerstreak@90 1077 if nPages and (nPages ~= self.nPages or force) then
flickerstreak@90 1078 local f = self:GetFrame()
flickerstreak@90 1079 local c = self.config.pageactions
flickerstreak@90 1080 if nPages > 1 and not c then
flickerstreak@90 1081 c = { }
flickerstreak@90 1082 self.config.pageactions = c
flickerstreak@90 1083 end
flickerstreak@90 1084 for i = 1, nPages do
flickerstreak@90 1085 if i > 1 then
flickerstreak@90 1086 c[i] = IDAlloc:Acquire(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
flickerstreak@90 1087 else
flickerstreak@90 1088 c[i] = self.config.actionID -- page 1 is the same as the base actionID
flickerstreak@90 1089 end
flickerstreak@90 1090 f:SetAttribute(("*action-page%d"):format(i),c[i])
flickerstreak@90 1091 end
flickerstreak@90 1092 for i = nPages+1, #c do
flickerstreak@90 1093 IDAlloc:Release(c[i])
flickerstreak@90 1094 c[i] = nil
flickerstreak@90 1095 f:SetAttribute(("*action-page%d"):format(i),nil)
flickerstreak@90 1096 end
flickerstreak@90 1097 self.nPages = nPages
flickerstreak@88 1098 end
flickerstreak@88 1099 end
flickerstreak@88 1100
flickerstreak@90 1101 function Button:ShowGrid( show )
flickerstreak@90 1102 if not InCombatLockdown() then
flickerstreak@90 1103 local f = self.frame
flickerstreak@90 1104 local count = f:GetAttribute("showgrid")
flickerstreak@90 1105 if show then
flickerstreak@90 1106 count = count + 1
flickerstreak@90 1107 else
flickerstreak@90 1108 count = count - 1
flickerstreak@88 1109 end
flickerstreak@90 1110 if count < 0 then
flickerstreak@90 1111 count = 0
flickerstreak@88 1112 end
flickerstreak@90 1113 f:SetAttribute("showgrid",count)
flickerstreak@90 1114
flickerstreak@90 1115 if count >= 1 and not f:GetAttribute("statehidden") then
flickerstreak@108 1116 if LBF then
flickerstreak@108 1117 LBF:SetNormalVertexColor(self.frame, 1.0, 1.0, 1.0, 0.5)
flickerstreak@108 1118 else
flickerstreak@108 1119 self.frame:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5);
flickerstreak@108 1120 end
flickerstreak@90 1121 f:Show()
flickerstreak@90 1122 elseif count < 1 and not HasAction(self:GetActionID()) then
flickerstreak@90 1123 f:Hide()
flickerstreak@90 1124 end
flickerstreak@88 1125 end
flickerstreak@88 1126 end
flickerstreak@88 1127
flickerstreak@90 1128 function Button:ShowActionIDLabel( show )
flickerstreak@90 1129 local f = self:GetFrame()
flickerstreak@90 1130 if show then
flickerstreak@90 1131 local id = self:GetActionID()
flickerstreak@90 1132 if not f.actionIDLabel then
flickerstreak@90 1133 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
flickerstreak@90 1134 label:SetAllPoints()
flickerstreak@90 1135 label:SetJustifyH("CENTER")
flickerstreak@90 1136 label:SetShadowColor(0,0,0,1)
flickerstreak@90 1137 label:SetShadowOffset(2,-2)
flickerstreak@90 1138 f.actionIDLabel = label -- store the label with the frame for recycling
flickerstreak@90 1139
flickerstreak@90 1140 f:HookScript("OnAttributeChanged",
flickerstreak@90 1141 function(frame, attr, value)
flickerstreak@90 1142 if label:IsVisible() and attr:match("action") then
flickerstreak@90 1143 label:SetText(tostring(frame.action))
flickerstreak@90 1144 end
flickerstreak@90 1145 end)
flickerstreak@88 1146 end
flickerstreak@90 1147 f.actionIDLabel:SetText(tostring(id))
flickerstreak@90 1148 f.actionIDLabel:Show()
flickerstreak@90 1149 elseif f.actionIDLabel then
flickerstreak@90 1150 f.actionIDLabel:Hide()
flickerstreak@88 1151 end
flickerstreak@88 1152 end
flickerstreak@88 1153
flickerstreak@90 1154 function Button:DisplayHotkey( key )
flickerstreak@90 1155 self.hotkey:SetText(key or "")
flickerstreak@88 1156 end
flickerstreak@88 1157 end