annotate modules/ReAction_Action/ReAction_Action.lua @ 91:c2504a8b996c

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