diff modules/ReAction_PetAction/ReAction_PetAction.lua @ 53:7e09c02ae620

Pet Action support
author Flick <flickerstreak@gmail.com>
date Fri, 25 Apr 2008 20:35:55 +0000
parents 21bcaf8215ff
children 88283658fec4
line wrap: on
line diff
--- a/modules/ReAction_PetAction/ReAction_PetAction.lua	Thu Apr 24 19:19:42 2008 +0000
+++ b/modules/ReAction_PetAction/ReAction_PetAction.lua	Fri Apr 25 20:35:55 2008 +0000
@@ -1,5 +1,9 @@
 --[[
-  ReAction Pet Action Bar module
+  ReAction Pet Action button module
+
+  The button module implements standard action button functionality by wrapping Blizzard's 
+  PetActionButton frame and associated functions. It also provides some button layout
+  modification tools.
 
 --]]
 
@@ -7,59 +11,172 @@
 local ReAction = ReAction
 local L = ReAction.L
 local _G = _G
+local CreateFrame = CreateFrame
 
 -- module declaration
 local moduleID = "PetAction"
 local module = ReAction:NewModule( moduleID )
 
-
 -- module methods
 function module:OnInitialize()
-  self.db = ReAction.db:RegisterNamespace( moduleID, 
+  self.db = ReAction.db:RegisterNamespace( moduleID,
     { 
       profile = {
         buttons = { }
       }
     }
   )
+  self.buttons = { }
 
-  self.buttons = { }
+  ReAction:RegisterOptions("global", self, {
+  })
 end
 
 function module:OnEnable()
+  ReAction:RegisterBarType(L["Pet Action Bar"], 
+    { 
+      type = moduleID ,
+      defaultButtonSize = 30,
+      defaultBarRows = 1,
+      defaultBarCols = 10,
+      defaultBarSpacing = 8
+    })
 end
 
 function module:OnDisable()
+  ReAction:UnregisterBarType(L["Pet Action Bar"])
 end
 
-function module:GetGlobalBarOptions(opts)  
-  if self.globalBarOpts == nil then
-    self.globalBarOpts = {
-      newActionBar = {
-        type = "execute",
-        name = L["New Pet Action Bar"],
-        desc = L["Create a new bar of pet action buttons"],
-        func = function()
-                 ReAction:CreateBar()
-               end,
-        disabled = InCombatLockdown,
-      }
-    }
+function module:ApplyToBar(bar)
+  if bar.config.type == moduleID then
+    -- auto show/hide when pet exists
+    bar:GetFrame():SetAttribute("unit","pet")
+    RegisterUnitWatch(bar:GetFrame())
+    self:RefreshBar(bar)
   end
-  return self.globalBarOpts
 end
 
+function module:RefreshBar(bar)
+  if bar.config.type == moduleID then
+    if self.buttons[bar] == nil then
+      self.buttons[bar] = { }
+    end
+    local btns = self.buttons[bar]
+    local profile = self.db.profile
+    local barName = bar:GetName()
+    if profile.buttons[barName] == nil then
+      profile.buttons[barName] = {}
+    end
+    local btnCfg = profile.buttons[barName]
+
+    local r, c = bar:GetButtonGrid()
+    local n = r*c
+    for i = 1, n do
+      if btnCfg[i] == nil then
+        btnCfg[i] = {}
+      end
+      if btns[i] == nil then
+        local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i])
+        if ok and b then
+          btns[i] = b
+        end
+      else
+        btns[i]:Refresh(bar,i)
+      end
+    end
+    for i = n+1, #btns do
+      if btns[i] then
+        btns[i] = btns[i]:Destroy()
+        if btnCfg[i] then
+          btnCfg[i] = nil
+        end
+      end
+    end
+  end
+end
+
+function module:RemoveFromBar(bar)
+  if self.buttons[bar] then
+    local btns = self.buttons[bar]
+    for _,b in pairs(btns) do
+      if b then
+        b:Destroy()
+      end
+    end
+    self.buttons[bar] = nil
+  end
+end
+
+function module:EraseBarConfig(barName)
+  self.db.profile.buttons[barName] = nil
+end
+
+function module:RenameBarConfig(oldname, newname)
+  local b = self.db.profile.buttons
+  b[newname], b[oldname] = b[oldname], nil
+end
+
+
+function module:ApplyConfigMode(mode,bars)
+  for _, bar in pairs(bars) do
+    if bar and self.buttons[bar] then
+      for _, b in pairs(self.buttons[bar]) do
+        if b then
+          if mode then
+            self:showActionIDLabel(b)
+          else
+            ReAction:Print("Hiding action id "..b:GetActionID())
+            self:hideActionIDLabel(b)
+          end
+        end
+      end
+      local f = bar:GetFrame()
+      if mode then
+        UnregisterUnitWatch(f)
+        f:Show()
+      else
+        RegisterUnitWatch(f)
+      end
+    end
+  end
+end
+
+function module:showActionIDLabel(button)
+  -- store the action ID label in the frame due to frame recycling
+  if not button:GetFrame().actionIDLabel and button:GetActionID() then
+    local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
+    label:SetAllPoints()
+    label:SetJustifyH("CENTER")
+    label:SetShadowColor(0,0,0,1)
+    label:SetShadowOffset(2,-2)
+    label:SetText(tostring(button:GetActionID()))
+    button:GetFrame().actionIDLabel = label
+  end
+  button:GetFrame().actionIDLabel:Show()
+end
+
+function module:hideActionIDLabel(button)
+  if button:GetFrame().actionIDLabel then
+    button:GetFrame().actionIDLabel:Hide()
+  else
+    ReAction:Print("actionIDLabel not found")
+  end
+end
+
+
 
 -- 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, 10 do
+      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)
@@ -79,8 +196,10 @@
   end
 })
 
+local frameRecycler = {}
 
--- button class methods
+
+------ Button class ------
 local Button = { }
 
 local function Constructor( self, bar, idx, config )
@@ -88,18 +207,59 @@
 
   local barFrame = bar:GetFrame()
 
-  self.name = config.name or "ReAction_"..bar:GetName().."_Pet_"..idx
+  local name = config.name or "ReAction_"..bar:GetName().."_Pet_"..idx
+  config.name = name
+  self.name = config.name
   config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured
   
-  local f = CreateFrame("CheckButton", self.name, barFrame, "PetActionButtonTemplate")
-  f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton (question: is this protected? does it cause taint?)
-  self.frame = f
+  -- have to recycle frames with the same name:
+  -- otherwise you either get references to old textures because named CreateFrame()
+  -- doesn't overwrite existing globals (below)
+  -- or, if you set them to nil in the global table, you get taint because of the
+  -- crappy PetActionBar code.
+  local f = frameRecycler[name]
+  if f then
+    f:SetParent(barFrame)
+    f:Show()
+  else
+    f = CreateFrame("CheckButton", name, barFrame, "PetActionButtonTemplate")
+  end
+  if config.actionID then
+    f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton
+  end
+  f:SetFrameStrata("MEDIUM")
+
   barFrame:SetAttribute("addchild",f)
 
-  -- auto show/hide when pet exists
-  -- this gets called once per button, which is inefficient but otherwise harmless
-  barFrame:SetAttribute("unit","pet")
-  RegisterUnitWatch(barFrame)
+  self.frame = f
+  self.icon = _G[("%sIcon"):format(name)]
+  self.acTex = _G[("%sAutoCastable"):format(name)]
+  self.acModel = _G[("%sAutoCast"):format(name)]
+  self.cooldown = _G[("%sCooldown"):format(name)]
+  self.hotkey = _G[("%sHotKey"):format(name)]
+
+  f:HookScript("OnDragStart", function() self:Update() end)
+  f:HookScript("OnReceiveDrag", function() self:Update() end)
+
+	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)
 
   self:Refresh(bar,idx)
 end
@@ -111,14 +271,89 @@
   f:SetParent(UIParent)
   f:ClearAllPoints()
   if self.name then
+    frameRecycler[self.name] = f
     _G[self.name] = nil
   end
-  ActionIDList[self.config.actionID] = nil
+  if self.config.actionID then
+    ActionIDList[self.config.actionID] = nil
+  end
   self.frame = nil
   self.config = nil
   self.bar = nil
 end
 
+function Button:Refresh(bar,idx)
+  bar:PlaceButton(self.frame, idx, 30, 30)
+  self:Update()
+  self:UpdateHotkey()
+end
+
+function Button:GetFrame()
+  return self.frame
+end
+
+function Button:GetName()
+  return self.name
+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
+  --ReAction:Print(("id %d: '%s', '%s', '%s', '%s', '%s', '%s', '%s'"):format(tostring(id), tostring(name),tostring(subtext),tostring(texture),tostring(isToken),tostring(isActive),tostring(autoCastAllowed),tostring(autoCastEnabled)))
+
+  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
+    self.acModel:Show();
+  else
+    self.acModel:Hide();
+  end
+
+  if texture then
+    if GetPetActionsUsable() 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()
+
+end
 
 -- export as a class-factory to module
 module.BtnClass = {