diff ActionButton.lua @ 257:920d17851a93 stable

Merge 1.1 beta 4 to stable
author Flick
date Tue, 12 Apr 2011 16:06:31 -0700
parents 65f2805957a0
children c918ff9ac787
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ActionButton.lua	Tue Apr 12 16:06:31 2011 -0700
@@ -0,0 +1,806 @@
+local addonName, addonTable = ...
+local ReAction = addonTable.ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local IsUsableAction = IsUsableAction
+local IsEquippedAction = IsEquippedAction
+local IsConsumableAction = IsConsumableAction
+local IsStackableAction = IsStackableAction
+local GetActionText = GetActionText
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local IsCurrentAction = IsCurrentAction
+local IsAutoRepeatAction = IsAutoRepeatAction
+local IsUsableAction = IsUsableAction
+local IsAttackAction = IsAttackAction
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local GetActionCooldown = GetActionCooldown
+local GetActionTexture = GetActionTexture
+local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
+local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
+local IsActionInRange = IsActionInRange
+local InCombatLockdown = InCombatLockdown
+local HasAction = HasAction
+
+--
+-- Secure snippets
+-- These are run within the context of the bar's sandbox, as the
+-- buttons themselves do not have their own sandbox.
+--
+local _onstate_mc = -- function(self, stateid, newstate)
+[[
+  local oldMcVehicleState = mcVehicleState
+  mcVehicleState = newstate
+  control:ChildUpdate()
+  if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
+    control:ChildUpdate("vehicle")
+  end
+]]
+
+local _childupdate = -- function(self, snippetid, message)
+[[
+  local action = nil
+  if (doVehicle and mcVehicleState == "vehicle") or
+     (doMindControl and mcVehicleState == "mc") then
+    local idx = self:GetAttribute("bar-idx")
+    local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12
+    if idx and idx <= maxN then
+      action = 120 + idx
+    else
+      action = 0
+    end
+  elseif state and settings[state] and settings[state].page then
+    action = self:GetAttribute("action-"..settings[state].page) 
+  end
+  if action == nil then
+    action = self:GetAttribute("default-action")
+  end
+
+  self:SetAttribute("action",action)
+
+  if not self:GetAttribute("showgrid") then
+    local tempShow = self:GetAttribute("showgrid-temp")
+    local evtShow = self:GetAttribute("showgrid-event")
+    if tempShow then tempShow = (tempShow > 0) end
+    if evtShow then evtShow = (evtShow > 0) end
+
+    if tempShow or evtShow or HasAction(action) then
+      self:Show()
+    else
+      self:Hide()
+    end
+  end
+]]
+
+local _childupdate_vehicleExit =  -- function(self, snippetid, message)
+[[
+  local show = (mcVehicleState == "vehicle")
+  if show and doVehicle then
+    self:SetAttribute("type","macro")
+    self:Show()
+  else
+    self:SetAttribute("type","action")
+  end
+  control:CallMethod("ShowVehicleExit",show)
+]]
+
+local _childupdate_showgrid = -- function(self, snippetid, message)
+[[
+  showgrid_event = message
+  self:SetAttribute("showgrid-event",message)
+  if not self:GetAttribute("showgrid") then
+    local count = message + (self:GetAttribute("showgrid-temp") or 0)
+    if count <= 0 then
+      local action = self:GetAttribute("action")
+        -- note that HasAction is not updated on the target of a drag until after ACTIONBAR_HIDEGRID
+        -- so, we set a flag for this button in pre-click/receive-drag and check for it here
+      if HasAction(action) or self:GetAttribute("showgrid-clicked") then
+        if not self:IsShown() then
+          self:Show()
+        end
+        self:SetAttribute("showgrid-clicked",false)
+      else 
+        if self:IsShown() then
+          self:Hide()
+        end
+      end
+    else
+      self:Show()
+    end
+  end
+]]
+
+local _onDragStart = -- function(self, button, kind, value, ...)
+[[
+  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
+    return kind, value, ...
+  else
+    return "action", self:GetAttribute("action")
+  end
+]]
+
+local _onReceiveDrag = -- function(self, button, kind, value, ...)
+[[
+  if kind ~= "spell" and kind ~= "item" and kind ~= "macro" and kind ~= "flyout" then
+    return kind, value, ...
+  else
+    if showgrid_event and showgrid_event > 0 then
+      self:SetAttribute("showgrid-clicked",true)
+    end
+    return "action", self:GetAttribute("action")
+  end
+]]
+
+local _onClick = -- function(self, button, down)
+[[
+  if showgrid_event and showgrid_event > 0 then
+    self:SetAttribute("showgrid-clicked",true)
+  end
+  return button
+]]
+
+--
+-- private
+--
+local eventList = {
+  "PLAYER_ENTERING_WORLD",
+  "ACTIONBAR_PAGE_CHANGED",
+  "ACTIONBAR_SLOT_CHANGED",
+  "UPDATE_BINDINGS",
+  "ACTIONBAR_UPDATE_STATE",
+  "ACTIONBAR_UPDATE_USABLE",
+  "ACTIONBAR_UPDATE_COOLDOWN",
+  "UNIT_INVENTORY_CHANGED",
+  "LEARNED_SPELL_IN_TAB",
+  "UPDATE_INVENTORY_ALERTS",
+  "PLAYER_TARGET_CHANGED",
+  "TRADE_SKILL_SHOW",
+  "TRADE_SKILL_CLOSE",
+  "PLAYER_ENTER_COMBAT",
+  "PLAYER_LEAVE_COMBAT",
+  "START_AUTOREPEAT_SPELL",
+  "STOP_AUTOREPEAT_SPELL",
+  "UNIT_ENTERED_VEHICLE",
+  "UNIT_EXITED_VEHICLE",
+  "COMPANION_UPDATE",
+}
+
+--
+-- Action Button class
+--
+local buttonTypeID = "Action"
+local Super = ReAction.Button
+local Action = setmetatable( 
+  { 
+    defaultBarConfig = { 
+      type = buttonTypeID,
+      btnWidth = 36,
+      btnHeight = 36,
+      btnRows = 1,
+      btnColumns = 12,
+      spacing = 3,
+      buttons = { },
+    },
+
+    barType = L["Action Bar"],
+    buttonTypeID = buttonTypeID
+  },
+  { __index = Super } )
+
+ReAction.Button.Action = Action
+ReAction:RegisterBarType(Action, true)
+
+function Action:New( config, bar, idx, idHint )
+  local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+  self.barConfig = bar:GetConfig()
+
+  local f = self:GetFrame()
+  local barFrame = bar:GetFrame()
+
+  self.rangeTimer = TOOLTIP_UPDATE_TIME
+
+  -- set up the base action ID
+  self:SetActionIDPool("action",120)
+  config.actionID = self:AcquireActionID(config.actionID, idHint)
+  self.nPages = 1
+
+  -- attribute setup
+  f:SetAttribute("type","action")
+  f:SetAttribute("checkselfcast", true)
+  f:SetAttribute("checkfocuscast", true)
+  f:SetAttribute("action", config.actionID)
+  f:SetAttribute("default-action", config.actionID)
+  f:SetAttribute("bar-idx",idx)
+  f:SetAttribute("showgrid-temp",0)
+  f:SetAttribute("showgrid-event",0)
+  f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty)
+
+  -- non secure scripts
+  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
+  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
+  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
+  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
+  f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
+  f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
+  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
+  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForDrag("LeftButton", "RightButton")
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  f.action = config.actionID -- need this to support silly ActionButton_UpdateFlyout. Should not taint anything anymore.
+
+  -- secure handlers
+  f:SetAttribute("_childupdate", _childupdate)
+  f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
+  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
+  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)
+  barFrame:WrapScript(f, "OnClick", _onClick)
+
+  -- attach to skinner
+  bar:SkinButton(self)
+
+  -- initial display
+  if ReAction:GetConfigMode() then
+    self:ShowGridTemp(true)
+  end
+
+  self:Refresh()
+
+  return self
+end
+
+function Action:Destroy()
+  local f = self:GetFrame()
+  local c = self:GetConfig()
+
+  f:SetAttribute("_childupdate-vehicle",nil)
+  f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one
+
+  if c.pageactions and #c.pageactions > 1 then
+    for i = 2, #c.pageactions do 
+      self:ReleaseActionID(c.pageactions[i])
+      self:ReleaseActionID(id)
+    end
+  end
+  
+  Super.Destroy(self)
+end
+
+function Action:GetBarConfig()
+  -- this is the per-bar Action module config structure,
+  -- not the config structure of the bar itself
+  return self.barConfig
+end
+
+function Action:Refresh()
+  Super.Refresh(self)
+  self:RefreshPages()
+  self:InstallVehicle()
+  self:ShowGrid(not self:GetBarConfig().hideEmpty)
+  self:UpdateAction()
+end
+
+function Action:InstallVehicle()
+  local f = self:GetFrame()
+  if self.idx == 7 and self:GetBarConfig().vehicle then
+    if not self.vehicleInstalled then
+      self.vehicleInstalled = true
+      -- install vehicle-exit button on 7th button (only)
+      f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
+      f:SetAttribute("macrotext","/run VehicleExit()")
+      self:GetBar():GetFrame().ShowVehicleExit = function(bar,show)
+        self:ShowVehicleExit(show)
+      end
+    end
+    -- setscale blows away tex coords
+    self:UpdateIcon()
+  elseif self.vehicleInstalled then
+    self.vehicleInstalled = false
+    f:SetAttribute("_childupdate-vehicle",nil)
+    f:SetAttribute("macrotext",nil)
+  end
+end
+
+function Action:ShowGrid( show )
+  if not InCombatLockdown() then
+    self.frame:SetAttribute("showgrid", show)
+    self:UpdateShowGrid()
+  end
+end
+
+function Action:ShowGridTemp( show )
+  -- This function only modifies the show-grid when out
+  -- of combat, and is ignored by the secure handler. Use 
+  -- it for configuration modes.
+  if not InCombatLockdown() then
+    local count = self.showGridTempCount or 0
+    if show then
+      count = count + 1
+    else
+      count = count - 1
+    end
+    if count < 0 then count = 0 end
+    self.showGridTempCount = count
+    self:GetFrame():SetAttribute("showgrid-temp",count)
+    self:UpdateShowGrid()
+  end
+end
+
+function Action:UpdateAll()
+  self:UpdateActionIDLabel(ReAction:GetConfigMode())
+  self:UpdateHotkey()
+  self:UpdateShowGrid()
+  self:UpdateIcon()
+  self:UpdateBorder()
+  self:UpdateMacroText()
+  self:UpdateCount()
+  self:UpdateTooltip()
+  self:UpdateCheckedState()
+  self:UpdateUsable()
+  self:UpdateCooldown()
+  self:UpdateFlash()
+end
+
+function Action:UpdateAction()
+  local action = self:GetActionID()
+  if action ~= self.actionID then
+    self.actionID = action
+    self:UpdateAll()
+  end
+end
+
+function Action:UpdateShowGrid()
+  if not InCombatLockdown() then
+    local f = self:GetFrame()
+    local count = (f:GetAttribute("showgrid-event") or 0) +
+                  (self.showGridTempCount or 0) +
+                  (f:GetAttribute("showgrid") and 1 or 0)
+
+    if count <= 0 and not HasAction(self.actionID) then
+      if f:IsShown() then
+        f:Hide()
+      end
+    elseif not f:IsShown() then
+      f:Show()
+    end
+  end
+end
+
+function Action:UpdateIcon()
+  local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture()
+  local icon = self.frames.icon
+  local hotkey = self.frames.hotkey
+  local f = self:GetFrame()
+  
+  if self.vehicleExitMode then
+    texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up"
+    icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
+    icon:SetVertexColor(1,1,1)
+  else
+    icon:SetTexCoord(0,1,0,1)
+  end
+
+  if texture then
+    icon:SetTexture(texture)
+    if tLeft then
+      icon:SetTexCoord(tLeft,tRight,tTop,tBottom)
+    end
+    icon:Show()
+    self.rangeTimer = -1
+    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
+  else
+    icon:Hide()
+    self.frames.cooldown:Hide()
+    self.rangeTimer = nil
+    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
+  end
+end
+
+function Action:GetIconTexture()
+  return GetActionTexture(self.actionID)
+end
+
+function Action:UpdateBorder()
+  local action = self.actionID
+  if ReAction:GetKeybindMode() then
+    self:UpdateKeybindModeDisplay(true)
+  elseif IsEquippedAction(action) then
+    self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
+    self.frames.border:Show()
+  else
+    self.frames.border:Hide()
+  end
+end
+
+function Action:UpdateMacroText()
+  local action = self.actionID
+  if not IsConsumableAction(action) and not IsStackableAction(action) then
+    self.frames.name:SetText(GetActionText(action))
+  else
+    self.frames.name:SetText("")
+  end
+end
+
+function Action:UpdateCount()
+  local action = self.actionID
+  if IsConsumableAction(action) or IsStackableAction(action) then
+    self.frames.count:SetText(GetActionCount(action))
+  else
+    self.frames.count:SetText("")
+  end
+end
+
+function Action:UpdateTooltip()
+  local f = self:GetFrame()
+  if GameTooltip:GetOwner() == f then
+    self:SetTooltip()
+  end
+end
+
+function Action:SetTooltip()
+  local f = self:GetFrame()
+  if GetCVar("UberTooltips") == "1" then
+    GameTooltip_SetDefaultAnchor(GameTooltip, f)
+  else
+    GameTooltip:SetOwner(f,"ANCHOR_RIGHT")
+  end
+  GameTooltip:SetAction(self.actionID)
+end
+
+function Action:UpdateCheckedState()
+  local action = self.actionID
+  if IsCurrentAction(action) or IsAutoRepeatAction(action) then
+    self:GetFrame():SetChecked(1)
+  else
+    self:GetFrame():SetChecked(0)
+  end
+end
+
+function Action:UpdateUsable()
+  local isUsable, notEnoughMana = self:GetUsable()
+  local noRange = self:GetInRange()
+
+  isUsable = self.vehicleExitMode or (isUsable and not noRange)
+
+  if isUsable then
+    if self.usableStatus ~= "usable" then
+      self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
+      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+      self.usableStatus = "usable"
+    end
+  elseif noRange then
+    if self.usableStatus ~= "norange" then
+      self.frames.icon:SetVertexColor(1.0,0.1,0.1)
+      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+      self.usableStatus = "norange"
+    end
+  elseif notEnoughMana then
+    if self.usableStatus ~= "oom" then
+      self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
+      self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
+      self.usableStatus = "oom"
+    end
+  else
+    if self.usableStatus ~= "unusable" then
+      self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
+      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
+      self.usableStatus = "unusable"
+    end
+  end
+end
+
+function Action:GetUsable()
+  return IsUsableAction(self.actionID)
+end
+
+function Action:GetInRange()
+  return IsActionInRange(self.actionID) == 0
+end
+
+function Action:UpdateCooldown()
+  CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown())
+end
+
+function Action:GetCooldown()
+  return GetActionCooldown(self.actionID)
+end
+
+function Action:UpdateFlash()
+  local action = self.actionID
+  self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
+end
+
+function Action:SetFlash(flash)
+  if self.flashing ~= flash then
+    self.flashing = flash
+    self.flashtime = 0
+    if not flash then
+      self.frames.flash:Hide()
+    end
+    self:UpdateCheckedState()
+  end
+end
+
+function Action:RunFlash(elapsed)
+  if self.flashing then
+    local flashtime = self.flashtime - elapsed
+    self.flashtime = flashtime
+    if flashtime <= 0 then
+      local overtime = -flashtime
+      if overtime >= ATTACK_BUTTON_FLASH_TIME then
+        overtime = 0
+      end
+      flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
+      local flash = self.frames.flash
+      if flash:IsShown() then
+        flash:Hide()
+      else
+        flash:Show()
+      end
+    end
+  end
+end
+
+function Action:RunRangeFinder(elapsed)
+  local rangeTimer = self.rangeTimer
+  if rangeTimer then
+    rangeTimer = rangeTimer - elapsed
+    self.rangeTimer = rangeTimer
+    if rangeTimer <= 0 then
+      self:UpdateUsable()
+      self.rangeTimer = TOOLTIP_UPDATE_TIME
+    end
+  end
+end
+
+function Action:GetActionID(page)
+  if page == nil then
+    -- get the effective ID
+    return self:GetFrame():GetAttribute("action")
+  else
+    if page == 1 then
+      return self.config.actionID
+    else
+      return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
+    end
+  end
+end
+
+function Action:SetActionID( id, page )
+  id = tonumber(id)
+  page = tonumber(page)
+  if id == nil or id < 1 or id > 120 then
+    ReAction:UserError(L["Action ID range is 1-120"])
+    return
+  end
+  if page and page ~= 1 then
+    if not self.config.pageactions then
+      self.config.pageactions = { }
+    end
+    self:ReleaseActionID(self.config.pageactions[page])
+    self.config.pageactions[page] = id
+    self:AcquireActionID(self.config.pageactions[page])
+    self.frame:SetAttribute("action-page"..page,id)
+  else
+    self:ReleaseActionID(self.config.actionID)
+    self.config.actionID = id
+    self:AcquireActionID(self.config.actionID)
+    self.frame:SetAttribute("action",id)
+    self.frame:SetAttribute("default-action",id)
+    if self.config.pageactions then
+      self.config.pageactions[1] = id
+      self.frame:SetAttribute("action-page1",id)
+    end
+  end
+end
+
+function Action:RefreshPages( force )
+  local nPages = self:GetBarConfig().nPages
+  if nPages and (nPages ~= self.nPages or force) then
+    local f = self:GetFrame()
+    local c = self.config.pageactions
+    if nPages > 1 and not c then
+      c = { }
+      self.config.pageactions = c
+    end
+    for i = 1, nPages do
+      if i > 1 then
+        c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
+      else
+        c[i] = self.config.actionID  -- page 1 is the same as the base actionID
+      end
+      f:SetAttribute("action-page"..i,c[i])
+    end
+    for i = nPages+1, #c do
+      self:ReleaseActionID(c[i])
+      c[i] = nil
+      f:SetAttribute("action-page"..i,nil)
+    end
+    self.nPages = nPages
+  end
+end
+
+function Action:SetupBar( bar )
+  Super.SetupBar(self,bar)
+
+  local f = bar:GetFrame()
+  local config = bar:GetConfig()
+  f:SetAttribute("mindcontrol",config.mindcontrol)
+  f:SetAttribute("vehicle",config.vehicle)
+  f:Execute(
+    [[
+    doMindControl = self:GetAttribute("mindcontrol")
+    doVehicle = self:GetAttribute("vehicle")
+    control:ChildUpdate()
+    ]])
+
+  f:SetAttribute("_onstate-mc", _onstate_mc)
+  RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none")
+
+  f:SetAttribute("lockbuttons",config.lockButtons)
+  f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat)
+  f:Execute(
+    [[
+      lockButtons = self:GetAttribute("lockbuttons")
+      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+    ]])
+end
+
+
+function Action:SetButtonLock( bar, lock, lockCombat )
+  local f = bar:GetFrame()
+  f:SetAttribute("lockbuttons",lock)
+  f:SetAttribute("lockbuttonscombat",lockCombat)
+  f:Execute(
+    [[
+      lockButtons = self:GetAttribute("lockbuttons")
+      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
+    ]])
+end
+
+
+function Action:ShowVehicleExit(show)
+  self.vehicleExitMode = show and self:GetBarConfig().vehicle
+  self:UpdateIcon()
+end
+
+function Action:OnEnter( )
+  self:SetTooltip()
+end
+
+function Action:OnLeave( )
+  GameTooltip:Hide()
+end
+
+function Action:OnAttributeChanged( attr, value )
+  if attr ~= "statehidden" then
+    self:UpdateAction()
+  end
+  local f = self:GetFrame()
+  f.action = f:GetAttribute("action") -- support ActionButton_UpdateFlyout
+end
+
+function Action:PostClick( )
+  self:UpdateCheckedState()
+end
+
+function Action:OnUpdate( elapsed )
+  self:RunFlash(elapsed)
+  self:RunRangeFinder(elapsed)
+end
+
+function Action:OnDragStart()
+  self:UpdateCheckedState()
+  self:UpdateFlash()
+end
+
+function Action:OnReceiveDrag()
+  self:UpdateCheckedState()
+  self:UpdateFlash()
+end
+
+function Action:OnEvent(event, ...)
+  if self[event] then
+    self[event](self, event, ...)
+  end
+end
+
+function Action:ACTIONBAR_SLOT_CHANGED(event, action)
+  if action == 0 or action == self.actionID then
+    self:UpdateAll()
+  end
+end
+
+function Action:PLAYER_ENTERING_WORLD()
+  self:UpdateAction()
+end
+
+function Action:ACTIONBAR_PAGE_CHANGED()
+  self:UpdateAction()
+end
+
+function Action:UPDATE_BONUS_ACTIONBAR()
+  self:UpdateAction()
+end
+
+function Action:UPDATE_BINDINGS()
+  self:UpdateHotkey()
+end
+
+function Action:PLAYER_TARGET_CHANGED()
+  self.rangeTimer = -1
+end
+
+function Action:ACTIONBAR_UPDATE_STATE()
+  self:UpdateCheckedState()
+end
+
+function Action:TRADE_SKILL_SHOW()
+  self:UpdateCheckedState()
+end
+Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_CLOSE
+
+function Action:UNIT_ENTERED_VEHICLE(event,unit)
+  if unit == "player" then
+    self:UpdateCheckedState()
+  end
+end
+Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE
+
+function Action:COMPANION_UPDATE(event,unit)
+  if unit == "mount" then
+    self:UpdateCheckedState()
+  end
+end
+
+function Action:ACTIONBAR_UPDATE_USABLE()
+  self:UpdateUsable()
+end
+
+function Action:ACTIONBAR_UPDATE_COOLDOWN()
+  self:UpdateCooldown()
+end
+
+function Action:PLAYER_ENTER_COMBAT()
+  if IsAttackAction(self.actionID) then
+    self:SetFlash(true)
+  end
+end
+
+function Action:PLAYER_LEAVE_COMBAT()
+  if IsAttackAction(self.actionID) then
+    self:SetFlash(false)
+  end
+end
+
+function Action:START_AUTOREPEAT_SPELL()
+  if IsAutoRepeatAction(self.actionID) then
+    self:SetFlash(true)
+  end
+end
+
+function Action:STOP_AUTOREPEAT_SPELL()
+  if not IsAttackAction(self.actionID) then
+    self:SetFlash(false)
+  end
+end
+
+function Action:UNIT_INVENTORY_CHANGED(unit)
+  if unit == "player" then
+    self:UpdateTooltip()
+  end
+end
+
+function Action:LEARNED_SPELL_IN_TAB()
+  self:UpdateTooltip()
+end