view PetActionButton.lua @ 306:f2ac74e69034 1.1 beta 13

TOC update 5.04 for real this time, without the fail
author Flick
date Wed, 14 Nov 2012 20:31:11 -0800
parents f7a5676c9517
children
line wrap: on
line source
local _, ns = ...
local ReAction = ns.ReAction
local L = ReAction.L
local _G = _G
local CreateFrame = CreateFrame
local format = string.format
local GetCVar = GetCVar
local InCombatLockdown = InCombatLockdown
local GetPetActionInfo = GetPetActionInfo
local GetPetActionSlotUsable = GetPetActionSlotUsable
local GetPetActionCooldown = GetPetActionCooldown
local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart
local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop
local SetDesaturation = SetDesaturation
-- local CooldownFrame_SetTimer = CooldownFrame_SetTimer  -- don't stash this API, look it up every time to support some mods that hook it, e.g. Cooldowns
local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor

--
-- Secure snippets
-- These are run within the context of the bar's sandbox, as the
-- buttons themselves do not have their own sandbox.
--
local _onDragStart = -- function(self, button, kind, value, ...)
[[
  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
    return kind, value, ...
  else
    return "petaction", self:GetAttribute("action")
  end
]]

local _onReceiveDrag = -- function(self, button, kind, value, ...)
[[
  if kind == "petaction" then
    return "petaction", self:GetAttribute("action")
  else
    return kind, value, ...
  end
]]

--
-- private
--
local eventList = {
"PLAYER_CONTROL_LOST",
"PLAYER_CONTROL_GAINED",
"PLAYER_FARSIGHT_FOCUS_CHANGED",
"UNIT_PET",
"UNIT_FLAGS",
"PET_BAR_UPDATE",
"PET_BAR_UPDATE_COOLDOWN",
"PET_BAR_UPDATE_USABLE",
"UPDATE_BINDINGS",
}

--
-- Pet Action Button class
--
local buttonTypeID = "PetAction"
local Super = ReAction.Button
local Pet = setmetatable( 
  { 
    defaultBarConfig = { 
      type = buttonTypeID,
      btnWidth = 30,
      btnHeight = 30,
      btnRows = 1,
      btnColumns = 10,
      spacing = 8,
      buttons = { }
    },

    barType = L["Pet Action Bar"], 
    buttonTypeID = buttonTypeID
  },
  { __index = Super } )

ReAction.Button.PetAction = Pet
ReAction:RegisterBarType(Pet)

function Pet:New( config, bar, idx, idHint )
  self = Super.New(self, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )

  local name = self:GetFrame():GetName()

  local f = self:GetFrame()
  if not f.autoCastTexture then
    -- store autocast stuff with the frame for recycling
    local tex = f:CreateTexture(nil,"OVERLAY")
    tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]])
    tex:SetHeight(58)
    tex:SetWidth(58)
    tex:SetPoint("CENTER")
    f.autoCastTexture = tex
    f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate") -- create after autocast texture so it's on top
    -- move the cooldown around
    local cd = self.frames.cooldown
    cd:ClearAllPoints()
    cd:SetWidth(33)
    cd:SetHeight(33)
    cd:SetPoint("CENTER", f, "CENTER", -2, -1)
    -- resize to 30x30
    f:SetHeight(30)
    f:SetWidth(30)
    local nt = _G[name.."NormalTexture"]
    nt:SetHeight(54)
    nt:SetWidth(54)
  end
  local barFrame = bar:GetFrame()

  -- set up the base action ID
  self:SetActionIDPool("pet",10)
  config.actionID = self:AcquireActionID(config.actionID, idHint, true)

  -- attribute setup
  -- There's no secure way to do PetAutoCastToggle by actionID, so use
  -- a click-through proxy to the Blizzard pet buttons for right-click
  -- Note that technically this doesn't do PetStopAttack() when 
  -- IsPetAttackActive() is true: however that's only true when using
  -- Eyes of the Beast and appears not to really do anything (at least
  -- I can't find any difference)
  f:SetAttribute("type","pet")
  f:SetAttribute("type2","click")
  f:SetAttribute("clickbutton2",_G["PetActionButton"..config.actionID])
  f:SetAttribute("action",config.actionID)
  f:SetAttribute("checkselfcast", true)
  f:SetAttribute("checkfocuscast", true)

  -- 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("PreClick", function(frame) self:PreClick() end)
  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)

  -- secure handlers
  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)

  -- event registration
  f:RegisterForDrag("LeftButton", "RightButton")
  for _, evt in pairs(eventList) do
    f:RegisterEvent(evt)
  end
  f:RegisterUnitEvent("UNIT_AURA","pet")

  -- attach to skinner
  bar:SkinButton(self,
   {
     AutoCast = f.autoCastShine,
     AutoCastable = f.autoCastTexture
   })

  self:Refresh()
  f:Show()

  return self
end

function Pet:SetupBar(bar)
  Super.SetupBar(self,bar)

  -- auto show/hide when pet exists
  bar:RegisterUnitWatch("pet",not ReAction:GetConfigMode())

  self:UpdateButtonLock(bar)
end

function Pet:UpdateButtonLock(bar)
  local f = bar:GetFrame()
  f:SetAttribute("lockbuttons",bar.config.lockButtons)
  f:SetAttribute("lockbuttonscombat",bar.config.lockButtonsCombat)
  f:Execute(
    [[
      lockButtons = self:GetAttribute("lockbuttons")
      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
    ]])
end

function Pet:Refresh()
  Super.Refresh(self)
  self:Update()
  self:UpdateHotkey()
end

function Pet:GetActionID()
  return self.config.actionID
end

function Pet:SetActionID(id)
  if not InCombatLockdown() then
    if id < 0 or id > 10 then
      ReAction:UserError(L["Pet action ID range is 1-10"])
      return
    end
    self.config.actionID = id
    f:SetAttribute("clickbutton2",_G["PetActionButton"..id])
    f:SetAttribute("action",id)
    self:Update()
    self:UpdateHotkey()
  end
end

function Pet:Update()
  local action = self.config.actionID
  local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(action)
  local f = self:GetFrame()
  local icon = self.frames.icon

  if isToken then
    icon:SetTexture(_G[texture])
    self.tooltipName = _G[name]
  else
    icon:SetTexture(texture)
    self.tooltipName = name
  end

  self.isToken = isToken
	self.tooltipSubtext = subtext
  f:SetChecked( isActive and 1 or 0 )

  if autoCastAllowed then
    f.autoCastTexture:Show()
  else
    f.autoCastTexture:Hide()
  end

  if autoCastEnabled then
    AutoCastShine_AutoCastStart(f.autoCastShine)
  else
    AutoCastShine_AutoCastStop(f.autoCastShine)
  end

  if texture then
    if GetPetActionSlotUsable(action) then
      SetDesaturation(icon,nil)
    else
      SetDesaturation(icon,1)
    end
    icon:Show()
    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
  else
    icon:Hide()
    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
  end

  self:UpdateCooldown()
end

function Pet:UpdateCooldown()
  CooldownFrame_SetTimer(self.frames.cooldown, GetPetActionCooldown(self.config.actionID))
end

function Pet:SetTooltip()
  if self.tooltipName then
    local f = self:GetFrame()
    local uber = GetCVar("UberTooltips")
    if self.isToken or (uber == "0") then
      if uber == "0" then
        GameTooltip:SetOwner(f, "ANCHOR_RIGHT")
      else
        GameTooltip_SetDefaultAnchor(GameTooltip, f)
      end
      GameTooltip:SetText(self.tooltipName)
      if self.tooltipSubtext then
        GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5)
      end
      GameTooltip:Show()
    else
      GameTooltip_SetDefaultAnchor(GameTooltip, f)
      GameTooltip:SetPetAction(self.config.actionID)
    end
  else
    GameTooltip:Hide()
  end
end

function Pet:OnEvent(event, unit)
  if event =="PET_BAR_UPDATE_COOLDOWN" then
    self:UpdateCooldown()
  elseif event == "UPDATE_BINDINGS" then
    self:UpdateHotkey()
  elseif event == "UNIT_PET" then
    if unit == "player" then
      self:Update()
    end
  elseif event == "UNIT_FLAGS" or event == "UNIT_AURA" then
    if unit == "pet" then
      self:Update()
    end
  else
    self:Update()
  end
end

function Pet:OnEnter()
  self:SetTooltip()
end

function Pet:OnLeave()
  GameTooltip:Hide()
end

function Pet:OnAttributeChanged(attr,value)
  self:Update()
end

function Pet:PreClick()
  self:GetFrame():SetChecked(0)
end

function Pet:OnDragStart()
  self:SetChecked(0)
  self:Update()
end

function Pet:OnReceiveDrag()
  self:SetChecked(0)
  self:Update()
end