annotate modules/ReAction_Action/ReAction_Action.lua @ 88:fc83b3f5b322

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