changeset 130:6e4a11b9d290

Converted PetAction to new class layout
author Flick <flickerstreak@gmail.com>
date Fri, 06 Mar 2009 23:44:55 +0000
parents 28b430de5875
children e39d80bb0b7a
files classes/PetActionButton.lua classes/classes.xml modules/PetAction.lua
diffstat 3 files changed, 311 insertions(+), 314 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/classes/PetActionButton.lua	Fri Mar 06 23:44:55 2009 +0000
@@ -0,0 +1,302 @@
+local ReAction = 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
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+
+ReAction:UpdateRevision("$Revision: 154 $")
+
+--
+-- 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 then -- pet spells on the cursor return nil from GetCursorInfo(), which is very strange
+    return kind, value, ...
+  end
+  return "petaction", self:GetAttribute("action")
+]]
+
+--
+-- private
+--
+local eventList = {
+"PLAYER_CONTROL_LOST",
+"PLAYER_CONTROL_GAINED",
+"PLAYER_FARSIGHT_FOCUS_CHANGED",
+"UNIT_PET",
+"UNIT_FLAGS",
+"UNIT_AURA",
+"PET_BAR_UPDATE",
+"PET_BAR_UPDATE_COOLDOWN",
+"UPDATE_BINDINGS",
+}
+
+--
+-- Pet Action Button class
+--
+local Super = ReAction.Button
+local Pet = setmetatable( { }, { __index = Super } )
+ReAction.Button.PetAction = Pet
+
+function Pet:New( idx, config, bar, idHint )
+  local name = format("ReAction_%s_PetAction_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+
+  local f = self:GetFrame()
+  if not f.autoCastTexture then
+    -- store with the frame for recycling
+    f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate")
+    local tex = f:CreateTexture(nil,"OVERLAY")
+    tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]])
+    tex:SetHeight(58)
+    tex:SetWidth(58)
+    tex:SetPoint("CENTER")
+    f.autoCastTexture = tex
+  end
+  local barFrame = bar:GetFrame()
+
+  local frames = { }
+  self.frames = frames
+  frames.icon          = _G[name.."Icon"]
+  frames.flash         = _G[name.."Flash"]
+  frames.hotkey        = _G[name.."HotKey"]
+  frames.count         = _G[name.."Count"]
+  frames.name          = _G[name.."Name"]
+  frames.border        = _G[name.."Border"]
+  frames.cooldown      = _G[name.."Cooldown"]
+  frames.normalTexture = _G[name.."NormalTexture"]
+
+  -- resize to 30x30
+  f:SetHeight(30)
+  f:SetWidth(30)
+
+  -- move the cooldown around
+	local cd = self.frames.cooldown
+  cd:ClearAllPoints()
+	cd:SetWidth(33)
+	cd:SetHeight(33)
+	cd:SetPoint("CENTER", f, "CENTER", -2, -1)
+
+  self.hotkey = frames.hotkey -- alias for Button methods
+  self.border = frames.border -- alias for Button methods
+
+  -- set up the base action ID
+  self:SetActionIDPool("pet",10)
+  config.actionID = self:AcquireActionID(config.actionID, idHint, true)
+
+  -- attribute setup
+  -- In order to get the full behavior of the pet buttons 
+  -- (petattack, toggle autocast, start/stop attack) we need
+  -- to use a secure click proxy type instead of a "pet" type.
+  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:EnableMouse(true)
+  f:RegisterForDrag("LeftButton", "RightButton")
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  -- attach to skinner
+  bar:SkinButton(self,
+   {
+     AutoCast = f.autoCastShine,
+     AutoCastable = f.autoCastTexture
+   })
+
+  self:Refresh()
+  f:Show()
+
+  return self
+end
+
+function Pet:Destroy()
+  self:GetFrame():UnregisterAllEvents()
+  self:ReleaseActionID(self:GetConfig().actionID)
+  Super.Destroy(self)
+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
+
--- a/classes/classes.xml	Fri Mar 06 23:44:33 2009 +0000
+++ b/classes/classes.xml	Fri Mar 06 23:44:55 2009 +0000
@@ -7,5 +7,6 @@
 <Script file="Overlay.lua"/>
 <Script file="Button.lua"/>
 <Script file="ActionButton.lua"/>
+<Script file="PetActionButton.lua"/>
 
 </Ui>
\ No newline at end of file
--- a/modules/PetAction.lua	Fri Mar 06 23:44:33 2009 +0000
+++ b/modules/PetAction.lua	Fri Mar 06 23:44:55 2009 +0000
@@ -22,8 +22,8 @@
 local moduleID = "PetAction"
 local module = ReAction:NewModule( moduleID )
 
--- Button class declaration
-local Button = { }
+-- Button class
+local Button = ReAction.Button.PetAction
 
 -- private
 local function UpdateButtonLock(bar)
@@ -107,7 +107,7 @@
         btnCfg[i] = {}
       end
       if btns[i] == nil then
-        local success, r = pcall(Button.New,Button,bar,i,btnCfg[i])
+        local success, r = pcall(Button.New,Button,i,btnCfg[i],bar,i>1 and btnCfg[i-1].actionID)
         if success and r then
           btns[i] = r
           bar:AddButton(i,r)
@@ -155,13 +155,11 @@
 
 
 function module:OnConfigModeChanged(event, mode)
-  for _, buttons in pairs(self.buttons) do
-    for _, b in pairs(buttons) do
-      b:ShowActionIDLabel(mode)
-    end
-  end
   for _, bar in ReAction:IterateBars() do
     if bar and self.buttons[bar] then
+      for b in bar:IterateButtons() do
+        b:UpdateActionIDLabel(mode)
+      end
       local f = bar:GetFrame()
       if mode then
         UnregisterUnitWatch(f)
@@ -203,7 +201,7 @@
 end
 
 function Handler:GetLockButtons()
-  return LOCK_ACTIONBAR == "1" or self.config.lockButtons
+  return self.config.lockButtons
 end
 
 function Handler:SetLockButtons(info, value)
@@ -211,10 +209,6 @@
   UpdateButtonLock(self.bar)
 end
 
-function Handler:LockButtonsDisabled()
-  return LOCK_ACTIONBAR == "1"
-end
-
 function Handler:GetLockButtonsCombat()
   return self.config.lockButtonsCombat
 end
@@ -225,7 +219,7 @@
 end
 
 function Handler:LockButtonsCombatDisabled()
-  return LOCK_ACTIONBAR == "1" or not self.config.lockButtons
+  return not self.config.lockButtons
 end
 
 
@@ -241,7 +235,6 @@
           desc = L["Prevents picking up/dragging actions.|nNOTE: This setting is overridden by the global setting in Blizzard's Action Buttons tab"],
           order = 2,
           type = "toggle",
-          disabled = "LockButtonsDisabled",
           get = "GetLockButtons",
           set = "SetLockButtons",
         },
@@ -260,304 +253,3 @@
 end
 
 
-
------- Button class ------
-
--- use-count of action IDs
-local nActionIDs = NUM_PET_ACTION_SLOTS
-local ActionIDList = setmetatable( {}, {
-  __index = function(self, idx)
-    if idx == nil then
-      for i = 1, nActionIDs do
-        if rawget(self,i) == nil then
-          rawset(self,i,1)
-          return i
-        end
-      end
-      error("ran out of pet action IDs")
-    else
-      local c = rawget(self,idx) or 0
-      rawset(self,idx,c+1)
-      return idx
-    end
-  end,
-  __newindex = function(self,idx,value)
-    if value == nil then
-      value = rawget(self,idx)
-      if value == 1 then
-        value = nil
-      elseif value then
-        value = value - 1
-      end
-    end
-    rawset(self,idx,value)
-  end
-})
-
-local frameRecycler = {}
-local trash = CreateFrame("Frame")
-
-local function GetActionName(f)
-  local b = f and f._reactionButton
-  if b then
-    return format("%s:%s", b.bar:GetName(), b.idx)
-  end
-end
-
-local function GetHotkey(f)
-  return KB:ToShortKey(GetBindingKey(format("CLICK %s:LeftButton",f:GetName())))
-end
-
-local function OnEnter( self )
-  if ReAction:GetKeybindMode() then
-    KB:Set(self)
-  elseif self.tooltipName then
-    local uber = GetCVar("UberTooltips")
-    if self.isToken or (uber == "0") then
-      if uber == "0" then
-        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
-      else
-        GameTooltip_SetDefaultAnchor(GameTooltip, self)
-      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, self)
-      GameTooltip:SetPetAction(self:GetID())
-    end
-  end
-end
-
-local function OnLeave()
-  GameTooltip:Hide()
-end
-
-local meta = { __index = Button }
-
-function Button:New( bar, idx, config )
-  -- create new self
-  self = setmetatable( 
-    { 
-      bar = bar,
-      idx = idx,
-      config = config,
-    }, meta )
-
-  local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx)
-  config.name = name
-  self.name = name
-  config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured
-
-  -- have to recycle frames with the same name:
-  -- otherwise you either get references to old textures because named CreateFrame()
-  -- doesn't overwrite existing globals. Can't set them to nil in the global table, 
-  -- as it causes taint.
-  local parent = bar:GetFrame()
-  local f = frameRecycler[name]
-  if f then
-    f:SetParent(parent)
-  else
-    f = CreateFrame("CheckButton", name, parent, "PetActionButtonTemplate")
-    -- ditch the old hotkey text because it's tied in ActionButton_Update() to the
-    -- standard binding. We use override bindings.
-    local hotkey = _G[name.."HotKey"]
-    hotkey:SetParent(trash)
-    hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray")
-    hotkey:SetWidth(36)
-    hotkey:SetHeight(18)
-    hotkey:SetJustifyH("RIGHT")
-    hotkey:SetJustifyV("TOP")
-    hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2)
-    f.hotkey = hotkey
-    f:HookScript("OnDragStart", function() self:Update() end)
-    f:HookScript("OnReceiveDrag", function() self:Update() end)
-    f:SetScript("OnEnter", OnEnter)
-    f:SetScript("OnLeave", OnLeave)
-  end
-  if config.actionID then
-    f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton
-  end
-  f:SetFrameStrata("MEDIUM")
-  self.frame    = f
-  self.icon     = _G[("%sIcon"):format(name)]
-  self.acTex    = _G[("%sAutoCastable"):format(name)]
-  self.acModel  = _G[("%sShine"):format(name)]
-  self.cooldown = _G[("%sCooldown"):format(name)]
-  self.hotkey   = f.hotkey
-  self.border   = _G[("%sBorder"):format(name)]
-
-  f._reactionButton = self
-
-  f:RegisterEvent("PLAYER_CONTROL_LOST")
-	f:RegisterEvent("PLAYER_CONTROL_GAINED")
-	f:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED")
-	f:RegisterEvent("UNIT_PET")
-	f:RegisterEvent("UNIT_FLAGS")
-	f:RegisterEvent("UNIT_AURA")
-	f:RegisterEvent("PET_BAR_UPDATE")
-	f:RegisterEvent("PET_BAR_UPDATE_COOLDOWN")
-
-  f:SetScript("OnEvent",
-    function(event,arg1)
-      if event =="PET_BAR_UPDATE_COOLDOWN" then
-        self:UpdateCooldown()
-      elseif event == "UPDATE_BINDINGS" then
-        self:UpdateHotkey()
-      else
-        self:Update()
-      end
-    end)
-
-  -- install drag wrappers to lock buttons 
-  bar:GetFrame():WrapScript(f, "OnDragStart",
-    -- OnDragStart(self, button, kind, value, ...)
-    [[
-      if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
-        return "clear"
-      end
-    ]])
-
-  -- attach to skinner
-  bar:SkinButton(self,
-    {
-      HotKey = self.hotkey,
-    }
-  )
-
-  self:Refresh()
-  self:UpdateHotkey()
-  self:SetKeybindMode(ReAction:GetKeybindMode())
-
-  return self
-end
-
-function Button:Destroy()
-  local f = self.frame
-  f:UnregisterAllEvents()
-  f:Hide()
-  f:SetParent(UIParent)
-  f:ClearAllPoints()
-  if self.name then
-    frameRecycler[self.name] = f
-    _G[self.name] = nil
-  end
-  if self.config.actionID then
-    ActionIDList[self.config.actionID] = nil
-  end
-  f._reactionButton = nil
-  self.frame = nil
-  self.config = nil
-  self.bar = nil
-end
-
-function Button:Refresh()
-  self.bar:PlaceButton(self, 30, 30)
-  self:Update()
-  self:UpdateHotkey()
-  self.frame:Show()
-end
-
-function Button:GetFrame()
-  return self.frame
-end
-
-function Button:GetName()
-  return self.name
-end
-
-function Button:GetConfig()
-  return self.config
-end
-
-function Button:GetActionID()
-  return self.config.actionID
-end
-
-function Button:Update()
-  local id = self.frame:GetID()
-  local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(id)
-  local f = self.frame
-
-  if isToken then
-    self.icon:SetTexture(_G[texture])
-    f.tooltipName = _G[name]
-  else
-    self.icon:SetTexture(texture)
-    f.tooltipName = name
-  end
-
-  f.isToken = isToken
-	f.tooltipSubtext = subtext
-  f:SetChecked( isActive and 1 or 0)
-
-  if autoCastAllowed then
-    self.acTex:Show()
-  else
-    self.acTex:Hide()
-  end
-
-  if autoCastEnabled then
-    AutoCastShine_AutoCastStart(self.acModel)
-  else
-    AutoCastShine_AutoCastStop(self.acModel)
-  end
-
-  if texture then
-    if GetPetActionSlotUsable(id) then
-      SetDesaturation(self.icon,nil)
-    else
-      SetDesaturation(self.icon,1)
-    end
-    self.icon:Show()
-    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
-  else
-    self.icon:Hide()
-    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
-  end
-
-  self:UpdateCooldown()
-end
-
-function Button:UpdateCooldown()
-	local start, duration, enable = GetPetActionCooldown(self.frame:GetID())
-  CooldownFrame_SetTimer(self.cooldown, start, duration, enable)
-end
-
-function Button:UpdateHotkey()
-  self.hotkey:SetText(GetHotkey(self.frame) or "")
-end
-
-function Button:ShowActionIDLabel(show)
-  if show then
-    -- store the action ID label in the frame due to frame recycling
-    if not self.actionIDLabel and self:GetActionID() then
-      local label = self.frame:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
-      label:SetAllPoints()
-      label:SetJustifyH("CENTER")
-      label:SetShadowColor(0,0,0,1)
-      label:SetShadowOffset(2,-2)
-      label:SetText(tostring(self:GetActionID()))
-      self.actionIDLabel = label
-    end
-    self.actionIDLabel:Show()
-  elseif self.actionIDLabel then
-    self.actionIDLabel:Hide()
-  end
-end
-
-
-function Button:SetKeybindMode(mode)
-  if mode then
-    local f = self.frame
-    f.GetActionName = GetActionName
-    f.GetHotkey     = GetHotkey
-    self.border:SetVertexColor(KB:GetColorKeyBoundMode())
-    self.border:Show()
-  else
-    self.border:Hide()
-  end
-end
-