comparison classes/ActionButton.lua @ 122:a2d2f23137c8

- Rearranged and consolidated some files in modules directory - Added 'classes' directory, moved Bar and Overlay there - Added Button, ActionButton, and GridProxy classes, not in use yet
author Flick <flickerstreak@gmail.com>
date Mon, 23 Feb 2009 18:56:57 +0000
parents
children 943eed2c7def
comparison
equal deleted inserted replaced
121:fb6c3a642ae3 122:a2d2f23137c8
1 local ReAction = ReAction
2 local L = ReAction.L
3 local _G = _G
4 local CreateFrame = CreateFrame
5 local GetBindingKey = GetBindingKey
6 local format = string.format
7 local IsUsableAction = IsUsableAction
8 local IsEquippedAction = IsEquippedAction
9 local IsConsumableAction = IsConsumableAction
10 local IsStackableAction = IsStackableAction
11 local GetActionText = GetActionText
12 local GetCVar = GetCVar
13 local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
14 local IsCurrentAction = IsCurrentAction
15 local IsAutoRepeatAction = IsAutoRepeatAction
16 local IsUsableAction = IsUsableAction
17 local IsAttackAction = IsAttackAction
18 local CooldownFrame_SetTimer = CooldownFrame_SetTimer
19 local GetActionCooldown = GetActionCooldown
20 local GetActionTexture = GetActionTexture
21 local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
22 local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
23 local IsActionInRange = IsActionInRange
24 local InCombatLockdown = InCombatLockdown
25 local HasAction = HasAction
26
27 ReAction:UpdateRevision("$Revision: 154 $")
28
29 --
30 -- Secure snippets
31 -- These are run within the context of the bar's sandbox, as the
32 -- buttons themselves do not have their own sandbox.
33 --
34 local _onstate_mc = -- function(self, stateid, newstate)
35 [[
36 local oldMcVehicleState = mcVehicleState
37 mcVehicleState = newstate
38 control:ChildUpdate()
39 if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
40 control:ChildUpdate("vehicle")
41 end
42 ]]
43
44 local _childupdate = -- function(self, snippetid, message)
45 [[
46 local action = nil
47 if (doVehicle and mcVehicleState == "vehicle") or
48 (doMindControl and mcVehicleState == "mc") then
49 local idx = self:GetAttribute("bar-idx")
50 if idx and idx <= 12 then
51 action = 120 + idx
52 else
53 action = 0
54 end
55 elseif page and state and page[state] then
56 action = self:GetAttribute("action-page"..page[state])
57 else
58 action = self:GetAttribute("default-action")
59 end
60
61 self:SetAttribute("action",action)
62 local hasaction = (action > 120) or self:GetAttribute("hasaction-"..action)
63
64 if (self:GetAttribute("showgrid") + self:GetAttribute("showgrid-temp") == 0) and not hasaction then
65 self:Hide()
66 else
67 self:Show()
68 end
69 ]]
70
71 local _childupdate_vehicleExit = -- function(self, snippetid, message)
72 [[
73 local show = (mcVehicleState == "vehicle")
74 if show then
75 self:SetAttribute("type","macro")
76 self:SetAttribute("macrotext","/run VehicleExit()")
77 self:Show()
78 else
79 self:SetAttribute("type","action")
80 end
81 control:CallMethod("ShowVehicleExit",show)
82 ]]
83
84 local _childupdate_showgrid = -- function(self, snippetid, message)
85 [[
86 self:SetAttribute("showgrid-temp",message or 0)
87 local count = (message or 0) + (self:GetAttribute("showgrid") or 0)
88 if count == 0 then
89 local action = self:GetAttribute("action")
90 local hasaction = (action > 120) or self:GetAttribute("hasaction-"..action)
91 if hasaction then
92 self:Show()
93 else
94 self:Hide()
95 end
96 else
97 self:Show()
98 end
99 ]]
100
101 local _onDragStart = -- function(self, button, kind, value, ...)
102 [[
103 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
104 return kind, value, ...
105 else
106 -- don't make any assumptions about hiding on grid show here, as we don't know if the
107 -- drag gets cancelled later.
108 return "action", self:GetAttribute("action")
109 end
110 ]]
111
112 local _onReceiveDrag = -- function(self, button, kind, value, ...)
113 [[
114 if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
115 return kind, value, ...
116 else
117 if kind == "spell" or kind == "item" or kind == "macro" then
118 -- assume it's a valid action
119 self:SetAttribute("hasaction-"..self:GetAttribute("action"),true)
120 end
121 return "action", self:GetAttribute("action")
122 end
123 ]]
124
125 --
126 -- private
127 --
128 local eventList = {
129 "PLAYER_REGEN_ENABLED",
130 "PLAYER_ENTERING_WORLD",
131 "ACTIONBAR_PAGE_CHANGED",
132 "ACTIONBAR_SLOT_CHANGED",
133 "UPDATE_BINDINGS",
134 "ACTIONBAR_UPDATE_STATE",
135 "ACTIONBAR_UPDATE_USABLE",
136 "ACTIONBAR_UPDATE_COOLDOWN",
137 "UPDATE_INVENTORY_ALERTS",
138 "PLAYER_TARGET_CHANGED",
139 "TRADE_SKILL_SHOW",
140 "TRADE_SKILL_CLOSE",
141 "PLAYER_ENTER_COMBAT",
142 "PLAYER_LEAVE_COMBAT",
143 "START_AUTOREPEAT_SPELL",
144 "STOP_AUTOREPEAT_SPELL",
145 "UNIT_ENTERED_VEHICLE",
146 "UNIT_EXITED_VEHICLE",
147 "COMPANION_UPDATE",
148 }
149
150 --
151 -- Action Button class
152 --
153 local Super = ReAction.Button
154 local Action = setmetatable( { }, { __index = Super } )
155 ReAction.Button.Action = Action
156
157 function Action:New( idx, config, bar, idHint )
158 self = Super.New(
159 self,
160 format("ReAction_%s_Action_%d",bar:GetName(),idx),
161 config,
162 bar,
163 idx,
164 "ActionButtonTemplate, SecureActionButtonTemplate" )
165
166 local f = self:GetFrame()
167 local barFrame = bar:GetFrame()
168
169 local frames = { }
170 self.frames = frames
171 frames.icon = _G[name.."Icon"]
172 frames.flash = _G[name.."Flash"]
173 frames.hotkey = _G[name.."HotKey"]
174 frames.count = _G[name.."Count"]
175 frames.name = _G[name.."Name"]
176 frames.border = _G[name.."Border"]
177 frames.cooldown = _G[name.."Cooldown"]
178 frames.normalTexture = _G[name.."NormalTexture"]
179
180 self.hotkey = frames.hotkey -- alias for Button methods
181 self.border = frames.border -- alias for Button methods
182
183 self.rangeTimer = TOOLTIP_UPDATE_TIME
184
185 -- set up the base action ID
186 self:SetActionIDPool("action",120)
187 config.actionID = self:AcquireActionID(config.actionID, idHint)
188 self.actionID = config.actionID
189 self.nPages = 1
190
191 -- attribute setup
192 f:SetAttribute("type","action")
193 f:SetAttribute("checkselfcast", true)
194 f:SetAttribute("checkfocuscast", true)
195 f:SetAttribute("useparent-unit", true)
196 f:SetAttribute("action", config.actionID)
197 f:SetAttribute("default-action", config.actionID)
198 f:SetAttribute("showgrid",0)
199 f:SetAttribute("showgrid-temp",0)
200 f:SetAttribute("bar-idx",idx)
201
202 -- non secure scripts
203 f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
204 f:SetScript("OnEnter", function(frame) self:OnEnter() end)
205 f:SetScript("OnLeave", function(frame) self:OnLeave() end)
206 f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
207 f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
208 f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
209 f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
210 f:SetScript("OnReceiveDrag", function(frame), self:OnReceiveDrag() end)
211
212 -- secure handlers
213 f:SetAttribute("_childupate", _childupdate)
214 f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
215 barFrame:WrapScript(f, "OnDragStart", _onDragStart)
216 barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
217 if idx == 7 then
218 -- install vehicle-exit button on 7th button (only)
219 f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
220 local button = self
221 function barFrame:ShowVehicleExit(show)
222 button:ShowVehicleExit(show)
223 end
224 end
225
226 -- event registration
227 f:RegisterForDrag("LeftButton", "RightButton")
228 f:RegisterForClicks("AnyUp")
229 for _, evt in pairs(eventList) do
230 f:RegisterEvent(evt)
231 end
232
233 -- attach to skinner
234 bar:SkinButton(self)
235
236 -- initial display
237 self:ShowGrid(not barFrame:GetConfig().hideEmpty)
238 if ReAction:GetConfigMode() then
239 self:ShowGrid(true)
240 end
241
242 self:Refresh()
243 end
244
245 function Action:Destroy()
246 local f = self:GetFrame()
247
248 f:UnregisterAllEvents()
249
250 f:SetAttribute("_childupdate-vehicle",nil)
251
252 self:ReleaseActionID(config.actionID)
253 if self.config.pageactions then
254 for _, id in ipairs(self.config.pageactions) do
255 self:ReleaseActionID(id)
256 end
257 end
258
259 Super:Destroy()
260 end
261
262 function Action:Refresh()
263 self.bar:PlaceButton(self, 36, 36)
264 self:RefreshPages()
265 self:UpdateAction()
266 end
267
268 function Action:UpdateAll()
269 self:UpdateActionIDLabel(ReAction:GetConfigMode())
270 self:UpdateHotkey()
271 self:UpdateShowGrid()
272 self:UpdateIcon()
273 self:UpdateBorder()
274 self:UpdateMacroText()
275 self:UpdateCount()
276 self:UpdateTooltip()
277 self:UpdateCheckedState()
278 self:UpdateUsable()
279 self:UpdateCooldown()
280 self:UpdateFlash()
281 end
282
283 function Action:UpdateAction()
284 local action = self:GetActionID()
285 if action ~= self.actionID then
286 self.actionID = action
287 self:UpdateAll()
288 end
289 end
290
291 function Action:UpdateShowGrid()
292 -- this is a little bit complicated because there's no
293 -- secure driver to handle show/hide grid events.
294 if InCombatLockdown() then
295 self.showgridPending = true -- handle after combat
296 else
297 self.showgridPending = false
298 -- check if each action has an action or not, and flag an attribute
299 -- so that the showgrid secure handler can make decisions accordingly
300 local f = self:GetFrame()
301 f:SetAttribute("hasaction-"..self.config.actionID, HasAction(self.config.actionID))
302 for i = 1, self.nPages do
303 f:SetAttribute("hasaction-"..self.config.pageactions[i], HasAction(self.config.pageactions[i])
304 end
305 -- the following is an out-of-combat show/hide to supplement the secure
306 -- handling and clean up after it when it guesses
307 if HasAction(self.actionID) then
308 f:Show()
309 else
310 f:Hide()
311 end
312 end
313 end
314
315 function Action:UpdateIcon()
316 local action = self.actionID
317 local texture = GetActionTexture(action)
318 local icon = self.frames.icon
319 local hotkey = self.frames.hotkey
320 local f = self:GetFrame()
321 if texture then
322 icon:SetTexture(texture)
323 icon:Show()
324 self.rangeTimer = -1
325 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
326 hotkey:SetVertexColor(1.0, 1.0, 1.0)
327 else
328 icon:Hide()
329 self.frames.cooldown:Hide()
330 self.rangeTimer = nil
331 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
332 hotkey:SetVertexColor(0.6, 0.6, 0.6)
333 end
334 end
335 end
336
337 function Action:UpdateBorder()
338 local action = self.actionID
339 if ReAction:GetKeybindMode() then
340 self:UpdateKeybindModeDisplay(true)
341 elseif IsEquippedAction(action) then
342 self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
343 self.frames.border:Show()
344 else
345 self.frames.border:Hide()
346 end
347 end
348
349 function Action:UpdateMacroText()
350 local action = self.actionID
351 if not IsConsumableAction(action) and not IsStackableAction(action) then
352 self.frames.name:SetText(GetActionText(action))
353 else
354 self.frames.name:SetText("")
355 end
356 end
357
358 function Action:UpdateCount()
359 local action = self.actionID
360 if IsConsumableAction(action) or IsStackableAction(action) then
361 self.frames.count:SetText(GetActionCount(action))
362 else
363 self.frames.count:SetText("")
364 end
365 end
366
367 function Action:UpdateTooltip()
368 local f = self:GetFrame()
369 if GameTooltip:GetOwner() == f then
370 self:SetTooltip()
371 end
372 end
373
374 function Action:SetTooltip()
375 local f = self:GetFrame()
376 if GetCVar("UberTooltips") == "1" then
377 GameTooltip_SetDefaultAnchor(GameTooltip, f)
378 else
379 GameTooltip:SetOwner(f)
380 end
381 GameTooltip:SetAction(self.actionID)
382 end
383
384 function Action:UpdateCheckedState()
385 local action = self.actionID
386 if IsCurrentAction(action) or IsAutoRepeatAction(action) then
387 self:GetFrame():SetChecked(1)
388 else
389 self:GetFrame():SetChecked(0)
390 end
391 end
392
393 function Action:UpdateUsable()
394 local isUsable, notEnoughMana = IsUsableAction(self.actionID)
395 if isUsable then
396 self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
397 self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
398 elseif notEnoughMana then
399 self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
400 self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
401 else
402 self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
403 self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
404 end
405 end
406
407 function Action:UpdateCooldown()
408 CooldownFrame_SetTimer(self.frames.cooldown, GetActionCooldown(self.actionID))
409 end
410
411 function Action:UpdateFlash()
412 local action = self.actionID
413 self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
414 end
415
416 function Action:SetFlash(flash)
417 if self.flashing ~= flash then
418 self.flashing = flash
419 self.flashtime = 0
420 if not flash then
421 self.frames.flash:Hide()
422 end
423 self:UpdateCheckedState()
424 end
425 end
426
427 function Action:RunFlash(elapsed)
428 if self.flashing then
429 local flashtime = self.flashtime - elapsed
430 self.flashtime = flashtime
431 if flashtime <= 0 then
432 local overtime = -flashtime
433 if overtime >= ATTACK_BUTTON_FLASH_TIME then
434 overtime = 0
435 end
436 flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
437 local flash = self.frames.flash
438 if flash:IsShown() then
439 flash:Hide()
440 else
441 flash:Show()
442 end
443 end
444 end
445 end
446
447 function Action:RunRangeFinder(elapsed)
448 local rangeTimer = self.rangeTimer
449 if rangeTimer then
450 rangeTimer = rangeTimer - elapsed
451 self.rangeTimer = rangeTimer
452 if rangeTimer <= 0 then
453 if IsActionInRange(self.actionID) == 0 then
454 self.frames.icon:SetVertexColor(1.0,0.1,0.1)
455 else
456 self:UpdateUsable()
457 end
458 frame.rangeTimer = TOOLTIP_UPDATE_TIME
459 end
460 end
461 end
462
463 function Action:GetActionID(page)
464 if page == nil then
465 -- get the effective ID
466 return self:GetFrame():GetAttribute("action")
467 else
468 if page == 1 then
469 return self.config.actionID
470 else
471 return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
472 end
473 end
474 end
475
476 function Action:SetActionID( id, page )
477 id = tonumber(id)
478 page = tonumber(page)
479 if id == nil or id < 1 or id > 120 then
480 error("Action:SetActionID - invalid action ID")
481 end
482 if page and page ~= 1 then
483 if not self.config.pageactions then
484 self.config.pageactions = { }
485 end
486 self:ReleaseActionID(self.config.pageactions[page])
487 self.config.pageactions[page] = id
488 self:AcquireActionID(self.config.pageactions[page])
489 self.frame:SetAttribute("action-page"..page,id)
490 else
491 self:ReleaseActionID(self.config.actionID)
492 self.config.actionID = id
493 self:AcquireActionID(self.config.actionID)
494 self.frame:SetAttribute("action",id)
495 self.frame:SetAttribute("default-action",id)
496 if self.config.pageactions then
497 self.config.pageactions[1] = id
498 self.frame:SetAttribute("action-page1",id)
499 end
500 end
501 end
502
503 function Action:RefreshPages( force )
504 local nPages = self.bar:GetConfig().nPages
505 if nPages and (nPages ~= self.nPages or force) then
506 local f = self:GetFrame()
507 local c = self.config.pageactions
508 if nPages > 1 and not c then
509 c = { }
510 self.config.pageactions = c
511 end
512 for i = 1, nPages do
513 if i > 1 then
514 c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
515 else
516 c[i] = self.config.actionID -- page 1 is the same as the base actionID
517 end
518 f:SetAttribute(("action-page%d"):format(i),c[i])
519 end
520 for i = nPages+1, #c do
521 self:ReleaseActionID(c[i])
522 c[i] = nil
523 f:SetAttribute(("action-page%d"):format(i),nil)
524 end
525 self.nPages = nPages
526 end
527 end
528
529 function Action:SetupBarHeader( bar ) -- call this as a static method
530 local f = bar:GetFrame()
531 local c = bar:GetConfig()
532 f:SetAttribute("mindcontrol",c.mindcontrol)
533 f:SetAttribute("vehicle",c.vehicle)
534 f:Execute(
535 [[
536 doMindControl = self:GetAttribute("mindcontrol")
537 doVehicle = self:GetAttribute("vehicle")
538 control:ChildUpdate()
539 ]])
540
541 f:SetAttribute("_onstate-mc", _onstate_mc)
542 RegisterStateDriver(f, "mc", "[target=vehicle,exists] vehicle; [bonusbar:5] mc; none")
543
544 f:SetAttribute("lockbuttons",c.lockButtons)
545 f:SetAttribute("lockbuttonscombat",c.lockButtonsCombat)
546 f:Execute(
547 [[
548 lockButtons = self:GetAttribute("lockbuttons")
549 lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
550 ]])
551 end
552
553
554 function Action:ShowVehicleExit(show)
555 local f = self:GetFrame()
556 local tx = f.vehicleExitTexture
557 if show then
558 if not tx then
559 tx = f:CreateTexture(nil,"ARTWORK")
560 tx:SetAllPoints()
561 -- copied from Blizzard/VehicleMenuBar.lua SkinsData
562 tx:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up")
563 tx:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
564 f.vehicleExitTexture = tx
565 end
566 tx:Show()
567 f.vehicleExitMode = true
568 elseif tx then
569 tx:SetTexCoord(0,1,0,1)
570 tx:Hide()
571 f.vehicleExitMode = false
572 end
573 end
574
575 function Action:OnEnter( )
576 self:SetTooltip()
577 end
578
579 function Action:OnLeave( )
580 GameTooltip:Hide()
581 end
582
583 function Action:OnAttributeChanged( attr, value )
584 self:UpdateAction()
585 end
586
587 function Action:PostClick( )
588 self:UpdateCheckedState()
589 end
590
591 function Action:OnUpdate( elapsed )
592 self:RunFlash(elapsed)
593 self:RunRangeFinder(elapsed)
594 end
595
596 function Action:OnDragStart()
597 self:UpdateCheckedState()
598 self:UpdateFlash()
599 end
600
601 function Action:OnReceiveDrag()
602 self:UpdateCheckedState()
603 self:UpdateFlash()
604 end
605
606 function Action:OnEvent(event, ...)
607 if self[event] then
608 self[event](self, event, ...)
609 end
610 end
611
612 function Action:ACTIONBAR_SLOT_CHANGED(event, action)
613 if action == 0 or action == self.actionID then
614 self:UpdateAction()
615 end
616 end
617
618 function Action:PLAYER_ENTERING_WORLD()
619 self:UpdateAction()
620 end
621
622 function Action:ACTIONBAR_PAGE_CHANGED()
623 self:UpdateAction()
624 end
625
626 function Action:UPDATE_BONUS_ACTIONBAR()
627 self:UpdateAction()
628 end
629
630 function Action:UPDATE_BINDINGS()
631 self:UpdateHotkey()
632 end
633
634 function Action:PLAYER_TARGET_CHANGED()
635 self.rangeTimer = -1
636 end
637
638 function Action:ACTIONBAR_UPDATE_STATE()
639 self:UpdateCheckedState()
640 end
641 Action.TRADE_SKILL_SHOW = Action.ACTIONBAR_UPDATE_STATE
642 Action.TRADE_SKILL_CLOSE = Action.ACTIONBAR_UPDATE_STATE
643
644 function Action:UNIT_ENTERED_VEHICLE(event,unit)
645 if unit == "player" then
646 self:UpdateCheckedState()
647 end
648 end
649 Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE
650
651 function Action:COMPANION_UPDATE(event,unit)
652 if unit == "mount" then
653 self:UpdateCheckedState()
654 end
655 end
656
657 function Action:ACTIONBAR_UPDATE_USABLE()
658 self:UpdateUsable()
659 end
660
661 function Action:ACTIONBAR_UPDATE_COOLDOWN()
662 self:UpdateCooldown()
663 end
664
665 function Action:PLAYER_ENTER_COMBAT()
666 if IsAttackAction(self.actionID) then
667 self:SetFlash(true)
668 end
669 end
670
671 function Action:PLAYER_LEAVE_COMBAT()
672 if IsAttackAction(self.actionID) then
673 self:SetFlash(false)
674 end
675 end
676
677 function Action:START_AUTOREPEAT_SPELL()
678 if IsAutoRepeatAction(self.actionID) then
679 self:SetFlash(true)
680 end
681 end
682
683 function Action:STOP_AUTOREPEAT_SPELL()
684 if not IsAttackAction(self.actionID) then
685 self:SetFlash(false)
686 end
687 end
688
689 function Action:PLAYER_REGEN_ENABLED()
690 if self.showgridPending then
691 self:UpdateShowGrid()
692 end
693 end