annotate modules/Action.lua @ 121:fb6c3a642ae3

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