view classes/ReAction_ActionType.lua @ 8:c05fd3e18b4f

Version 0.31
author Flick <flickerstreak@gmail.com>
date Tue, 20 Mar 2007 21:33:59 +0000
parents f920db5fc6b1
children
line wrap: on
line source
-- The ReAction.ActionType mixin defines 'regular' action button functionality 
-- and is an implementation of the ReAction.IActionType interface.
--
-- The Mixin assumes that it is being mixed in with a ReAction-derived class
-- which implements the ReAction.IDisplay and ReAction.ActionType.IDisplay interfaces.
--
-- This mixin using the following configuration properties:
--
-- self.config = {
--   selfcast = nil / "alt" / "ctrl" / "shift" / "auto" / "none". nil (default) = use Interface Options menu setting.
-- }
--

local AceOO = AceLibrary("AceOO-2.0")

ReAction.ActionType = AceOO.Mixin {
  -- ReAction.IActionType interface
  "SetID",
  "GetID",
  "SetupAction",
  "UpdateAction",
  "PickupAction",
  "PlaceAction",
  "IsActionEmpty",
  "UpdateTooltip",

  -- event handlers
  "ACTIONBAR_SLOT_CHANGED",
  "PLAYER_ENTERING_WORLD",
  "ACTIONBAR_SHOWGRID",
  "ACTIONBAR_HIDEGRID",
  "ACTIONBAR_UPDATE_STATE",
  "ACTIONBAR_UPDATE_USABLE",
  "UNIT_INVENTORY_CHANGED",
  "CRAFT_SHOW",
  "PLAYER_ENTER_COMBAT",
  "PLAYER_LEAVE_COMBAT",
  "START_AUTOREPEAT_SPELL",
  "STOP_AUTOREPEAT_SPELL",
  "OnAttributeChanged",
  
  -- internal functions
  "UpdateSelfcast",
  "UpdateIcon",
  "UpdateInUse",
  "UpdateCount",
  "UpdateMacroText",
  "UpdateUsable",
  "UpdateCooldown",
  "UpdateActionEvents",
}

local RAAT = ReAction.ActionType


-- Required display elements
RAAT.IDisplay = AceOO.Interface {
  DisplayUsable      = "function", -- DisplayUsable(bool, notEnoughMana, outOfRange), change display to indicate action usable/unusable
  DisplayEquipped    = "function", -- DisplayEquipped(bool)
  DisplayAutoRepeat  = "function", -- DisplayAutoRepeat(bool)
  DisplayInUse       = "function", -- DisplayInUse(bool)
  DisplayIcon        = "function", -- DisplayIcon(texture), nil means empty slot
  DisplayName        = "function", -- DisplayName(text), macro names
  DisplayCount       = "function", -- DisplayCount(number), stack count
  DisplayCooldown    = "function", -- DisplayCooldown(start,duration,enable)
}


---------------------------------------
-- ReAction.IActionType interface implementation
---------------------------------------
function RAAT:SetID( id, page )
  local f = self:GetActionFrame()
  id = tonumber(id) -- force data integrity
  page = tonumber(page)
  local button = page and ("-page"..page) or "*"
  if id then
    f:SetAttribute("*action"..button, id)
    if page and page > 1 and self.config.selfcast == "right-click" then
      -- disable right-click auto-cast
      self.config.selfcast = nil
    end
  elseif page then
    f:SetAttribute("*action"..button, ATTRIBUTE_NOOP)
  end
  self:UpdateSelfcast()
end

function RAAT:GetID(page)
  local f = self:GetActionFrame()
  page = tonumber(page)
  local button = page and ("page"..page) or SecureStateChild_GetEffectiveButton(f)
  return SecureButton_GetModifiedAttribute(f, "action", button)
end

function RAAT:SetupAction()
  local f = self:GetActionFrame()
	f:SetAttribute("useparent*", true)
  f:SetAttribute("type", "action")

  self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
  self:RegisterEvent("ACTIONBAR_SHOWGRID")
  self:RegisterEvent("ACTIONBAR_HIDEGRID")

  self:UpdateSelfcast()

  f:SetScript("OnAttributeChanged",  function(frame,name,value) self:OnAttributeChanged(name,value) end)
end

function RAAT:UpdateAction()
  self:UpdateIcon()
  self:UpdateCount()
  self:UpdateMacroText()
  self:UpdateUsable()
  self:UpdateCooldown()
  self:UpdateActionEvents()
end

function RAAT:PickupAction()
  PickupAction(self:GetID())
  self:UpdateAction()
end

function RAAT:PlaceAction()
  if not InCombatLockdown() then
    -- PlaceAction() is protected. However the user can still drop a new action
    -- onto a button while in combat by dragging then clicking, because
    -- UseAction() appears to swap the cursor action for the current action if
    -- an action is on the cursor.
    PlaceAction(self:GetID())
    -- the ACTIONBAR_SLOT_CHANGED event will handle the update
  end
end

function RAAT:IsActionEmpty()
  local slot = self:GetID()
  return not(slot and HasAction(slot))
end

function RAAT:UpdateTooltip()
  local action = self:GetID()
	if action and GameTooltip:IsOwned(self:GetActionFrame()) then
    GameTooltip:SetAction(action)
  end
end







-----------------------------
-- Event Handling
-----------------------------
function RAAT:ACTIONBAR_SLOT_CHANGED(slot)
  if slot == 0 or slot == self:GetID() then
    self:UpdateAction()
  end
end

function RAAT:PLAYER_ENTERING_WORLD()
  self:UpdateAction()
end

function RAAT:ACTIONBAR_SHOWGRID()
  self:TempShow(true)
end

function RAAT:ACTIONBAR_HIDEGRID()
  self:TempShow(false)
end

function RAAT:ACTIONBAR_UPDATE_STATE()
  self:UpdateInUse()
end

function RAAT:ACTIONBAR_UPDATE_USABLE()
  self:UpdateUsable()
  self:UpdateCooldown()
end

function RAAT:UNIT_INVENTORY_CHANGED(unit)
  if unit == "player" then
    self:UpdateIcon()
    self:UpdateCount()
  end
end

function RAAT:CRAFT_SHOW()
  self:UpdateInUse()
end

function RAAT:PLAYER_ENTER_COMBAT()
  if IsAttackAction(self:GetID()) then
    self:DisplayAutoRepeat(true)
    self:UpdateInUse()
  end
end

function RAAT:PLAYER_LEAVE_COMBAT()
  if IsAttackAction(self:GetID()) then
    self:DisplayAutoRepeat(false)
    self:UpdateInUse()
  end
end

function RAAT:START_AUTOREPEAT_SPELL()
  if IsAutoRepeatAction(self:GetID()) then
    self:DisplayAutoRepeat(true)
  end
end

function RAAT:STOP_AUTOREPEAT_SPELL()
  if not IsAttackAction(self:GetID()) then
    self:DisplayAutoRepeat(false)
    self:UpdateInUse()
  end
end

function RAAT:OnAttributeChanged(name, value)
  if self.config then
    self:UpdateAction()
    self:UpdateDisplay()
  end
end




---------------------------------
-- Internal methods
---------------------------------
function RAAT:UpdateSelfcast()
  if not InCombatLockdown() then
    local c = self.config and self.config.selfcast
    local f = self:GetActionFrame()

    f:SetAttribute("alt-unit*",nil)
    f:SetAttribute("ctrl-unit*",nil)
    f:SetAttribute("shift-unit*",nil)
    f:SetAttribute("*unit2",nil)
    if c == nil then
      f:SetAttribute("unit",nil)
      f:SetAttribute("checkselfcast", true)
    else
      f:SetAttribute("checkselfcast",ATTRIBUTE_NOOP)
      f:SetAttribute("unit","none") -- "none" gives you the glowing cast hand if no target selected, or casts on target if target selected
      if c == "none" then
        -- nothing to do
      elseif c == "alt" or c == "ctrl" or c == "shift" then
        f:SetAttribute(c.."-unit*","player")
      elseif c == "right-click" then
        if f:GetAttribute("*action-page2") then
          -- right-click modifier not supported with multipage
          self.config.selfcast = nil
          f:SetAttribute("unit",nil)
          f:SetAttribute("checkselfcast",true)
        else
          f:SetAttribute("*unit2","player")
        end
      end
    end
  end
end

function RAAT:UpdateIcon()
  local action = self:GetID()
  local texture = action and GetActionTexture(action)

  self:DisplayIcon(action and texture)
  self:DisplayEquipped(action and IsEquippedAction(action))
  self:UpdateInUse()
  self:UpdateUsable()
  self:UpdateCooldown()
end

function RAAT:UpdateInUse()
  local action = self:GetID()
	if action and (IsCurrentAction(action) or IsAutoRepeatAction(action)) then
		self:DisplayInUse(true)
	else
    self:DisplayInUse(false)
	end
end

function RAAT:UpdateCount()
  local action = self:GetID()
  if action and (IsConsumableAction(action) or IsStackableAction(action)) then
    self:DisplayCount(GetActionCount(action)) -- will display a 0 if none remaining
  else
    self:DisplayCount(nil) -- will display nothing
  end
end

function RAAT:UpdateMacroText()
  local action = self:GetID()
  self:DisplayName(action and GetActionText(action))
end

function RAAT:UpdateUsable()
  local action = self:GetID()
  if action and HasAction(action) then
    local isUsable, notEnoughMana = IsUsableAction(action)
    local outOfRange = IsActionInRange(action) == 0
    self:DisplayUsable(isUsable and not outOfRange, notEnoughMana, outOfRange)
  else
    self:DisplayUsable(false, false, false)
  end
end

function RAAT:UpdateCooldown()
  local action = self:GetID()
  if action then
    self:DisplayCooldown(GetActionCooldown(action))
  end
end

function RAAT:UpdateActionEvents()
  local action = self:GetID()
	if action and HasAction(action) then
    if not self.actionEventsRegistered then
      self:RegisterEvent("ACTIONBAR_UPDATE_STATE")
      self:RegisterEvent("ACTIONBAR_UPDATE_USABLE")
      self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", "ACTIONBAR_UPDATE_USABLE")
      self:RegisterEvent("UPDATE_INVENTORY_ALERTS", "ACTIONBAR_UPDATE_USABLE")
      self:RegisterEvent("PLAYER_AURAS_CHANGED", "ACTIONBAR_UPDATE_USABLE")
      self:RegisterEvent("PLAYER_TARGET_CHANGED", "ACTIONBAR_UPDATE_USABLE")
      self:RegisterEvent("UNIT_INVENTORY_CHANGED")
      self:RegisterEvent("CRAFT_SHOW")
      self:RegisterEvent("CRAFT_CLOSE", "CRAFT_SHOW")
      self:RegisterEvent("TRADE_SKILL_SHOW", "CRAFT_SHOW")
      self:RegisterEvent("TRADE_SKILL_CLOSE", "CRAFT_SHOW")
      self:RegisterEvent("PLAYER_ENTER_COMBAT")
      self:RegisterEvent("PLAYER_LEAVE_COMBAT")
      self:RegisterEvent("START_AUTOREPEAT_SPELL")
      self:RegisterEvent("STOP_AUTOREPEAT_SPELL")
      self.actionEventsRegistered = true
    end
  elseif self.actionEventsRegistered then
    self:UnregisterEvent("ACTIONBAR_UPDATE_STATE")
    self:UnregisterEvent("ACTIONBAR_UPDATE_USABLE")
    self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN")
    self:UnregisterEvent("UPDATE_INVENTORY_ALERTS")
    self:UnregisterEvent("PLAYER_AURAS_CHANGED")
    self:UnregisterEvent("PLAYER_TARGET_CHANGED")
    self:UnregisterEvent("UNIT_INVENTORY_CHANGED")
    self:UnregisterEvent("CRAFT_SHOW")
    self:UnregisterEvent("CRAFT_CLOSE")
    self:UnregisterEvent("TRADE_SKILL_SHOW")
    self:UnregisterEvent("TRADE_SKILL_CLOSE")
    self:UnregisterEvent("PLAYER_ENTER_COMBAT")
    self:UnregisterEvent("PLAYER_LEAVE_COMBAT")
    self:UnregisterEvent("START_AUTOREPEAT_SPELL")
    self:UnregisterEvent("STOP_AUTOREPEAT_SPELL")
    self.actionEventsRegistered = false
	end
end