changeset 134:d186e041ca14

Added stance bar support
author Flick <flickerstreak@gmail.com>
date Tue, 17 Mar 2009 23:38:38 +0000
parents 729e284b2576
children 5c0591a31163
files classes/StanceButton.lua classes/classes.xml locale/enUS.lua modules/Stance.lua modules/State.lua modules/modules.xml
diffstat 6 files changed, 509 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/classes/StanceButton.lua	Tue Mar 17 23:38:38 2009 +0000
@@ -0,0 +1,282 @@
+local ReAction = ReAction
+local L = ReAction.L
+local _G = _G
+local CreateFrame = CreateFrame
+local format = string.format
+local GetCVar = GetCVar
+local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
+local CooldownFrame_SetTimer = CooldownFrame_SetTimer
+local InCombatLockdown = InCombatLockdown
+local GetNumShapeshiftForms = GetNumShapeshiftForms
+local GetShapeshiftFormInfo = GetShapeshiftFormInfo
+local IsUsableSpell = IsUsableSpell
+local GetSpellInfo = GetSpellInfo
+
+ReAction:UpdateRevision("$Revision: 154 $")
+
+--
+-- private
+--
+local playerClass = select(2,UnitClass("player"))
+
+local aspects = {
+  -- All rank one, so that the usable check works
+  GetSpellInfo(13163), -- monkey
+  GetSpellInfo(13165), -- hawk
+  GetSpellInfo(5118),  -- cheetah
+  GetSpellInfo(34074), -- viper
+  GetSpellInfo(13161), -- beast
+  GetSpellInfo(13159), -- pack
+  GetSpellInfo(20043), -- wild
+  GetSpellInfo(61846), -- dragonhawk
+}
+
+local aspectLinks = { }
+
+local eventList = {
+  "PLAYER_REGEN_ENABLED",
+  "PLAYER_ENTERING_WORLD",
+  "UPDATE_SHAPESHIFT_FORM",
+  "UPDATE_SHAPESHIFT_FORMS",
+  "UPDATE_SHAPESHIFT_USABLE",
+  "UPDATE_SHAPESHIFT_COOLDOWN",
+  -- "UPDATE_INVENTORY_ALERTS" -- WTF?
+}
+
+local eventListHunter = {
+  "PLAYER_REGEN_ENABLED",
+  "PLAYER_ENTERING_WORLD",
+  "SPELL_UPDATE_COOLDOWN",
+  "SPELL_UPDATE_USABLE",
+  "UNIT_AURA",
+  "SPELLS_CHANGED"
+}
+
+if playerClass == "HUNTER" then
+  eventList = eventListHunter
+end
+
+--
+-- Stance Button class
+--
+local Super = ReAction.Button
+local Stance = setmetatable( { }, { __index = Super } )
+ReAction.Button.Stance = Stance
+
+function Stance:New( idx, moduleConfig, bar, idHint )
+  local name = format("ReAction_%s_Stance_%d",bar:GetName(),idx)
+ 
+  self = Super.New(self, name, moduleConfig.buttons[bar:GetName()][idx], bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
+  self.moduleConfig = moduleConfig
+  self.hunterIdx = 1
+
+  local f = self:GetFrame()
+  local barFrame = bar:GetFrame()
+  local config = self:GetConfig()
+
+  -- set up the base stance ID
+  self:SetActionIDPool("stance",8)
+  config.stanceID = self:AcquireActionID(config.stanceID, idHint, true)
+
+  -- attribute setup
+  f:SetAttribute("type","spell")
+  self:UpdateAction()
+
+  -- 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("PreClick", function(frame, ...) self:PreClick(...) end)
+
+  -- secure handlers
+  -- (none)
+
+  -- event registration
+  f:EnableMouse(true)
+  f:RegisterForClicks("AnyUp")
+  for _, evt in pairs(eventList) do
+    f:RegisterEvent(evt)
+  end
+
+  -- attach to skinner
+  bar:SkinButton(self)
+
+  -- initial display
+  if ReAction:GetConfigMode() then
+    self:GetFrame():Show()
+  end
+
+  self:Refresh()
+
+  return self
+end
+
+function Stance:GetModuleConfig()
+  -- this is the Stance module config structure,
+  -- not the config structure of the bar itself
+  return self.moduleConfig
+end
+
+function Stance:GetActionID()
+  return self.config.stanceID
+end
+
+function Stance:UpdateAction()
+  if InCombatLockdown() then
+    self.updatePending = true
+  else
+    self.updatePending = false
+    local idx = self:GetActionID()
+    local f = self:GetFrame()
+    local c = self:GetModuleConfig()
+    if playerClass == "HUNTER" then
+      if c.showHunterAspects then
+        -- re-map the index in the case of "hide monkey/hawk"
+        if c.hideMonkeyHawk then
+          local usable, outOfMana = IsUsableSpell(aspects[8])
+          if usable or outOfMana then
+            idx = idx + 2
+            if idx > 8 then
+              f:Hide()
+              return
+            end
+          end
+        end
+        self.hunterIdx = idx
+        -- cache the highest rank spellID
+        if not aspectLinks[aspects[idx]] then
+          aspectLinks[aspects[idx]] = GetSpellLink(aspects[idx],"")
+        end
+        local usable, outOfMana = IsUsableSpell(aspects[idx])
+        if usable or outOfMana then
+          f:SetAttribute("spell",aspects[idx])
+          f:Show()
+          self:Update()
+        else
+          -- haven't learned this spell yet
+          f:Hide()
+        end
+      else
+        f:Hide()
+      end
+    elseif idx > GetNumShapeshiftForms() or
+       playerClass == "PALADIN" and c.hidePaladinAuras or
+       playerClass == "DEATHKNIGHT" and c.hideDKPresences then
+      f:Hide()
+    else
+      f:SetAttribute("spell", select(2,GetShapeshiftFormInfo(idx)))
+      f:Show()
+      self:Update()
+    end
+  end
+end
+
+function Stance:Refresh()
+  Super.Refresh(self)
+  self:Update()
+end
+
+function Stance:Update()
+  local texture, isActive, isCastable
+  if playerClass == "HUNTER" then
+    local name, rank
+    local spell = aspects[self.hunterIdx]
+    name, rank, texture = GetSpellInfo(spell)
+    isCastable = IsUsableSpell(spell)
+    for i = 1, 40 do
+      local buff = UnitBuff("player",i,true)
+      if not buff then break end
+      if buff == spell then
+        isActive = true
+        texture = "Interface\\Icons\\Spell_Nature_WispSplode"
+        break
+      end
+    end
+  else
+    local _
+    texture, _, isActive, isCastable = GetShapeshiftFormInfo(self:GetActionID())
+  end
+  
+  local icon = self.frames.icon
+  icon:SetTexture(texture)
+  self:GetFrame():SetChecked( isActive and 1 or 0 )
+  if isCastable then
+    icon:SetVertexColor(1.0, 1.0, 1.0)
+  else
+    icon:SetVertexColor(0.4, 0.4, 0.4)
+  end
+
+  self:UpdateCooldown()
+end
+
+function Stance:UpdateCooldown()
+  local start, duration, enabled
+  if playerClass == "HUNTER" then
+    local spell = aspects[self.hunterIdx]
+    if spell then
+      start, duration, enabled = GetSpellCooldown(spell)
+    end
+  else
+    start, duration, enabled = GetShapeshiftFormCooldown(self:GetActionID())
+  end
+  if start then
+    CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enabled)
+  end
+end
+
+function Stance:SetTooltip()
+  if GetCVar("UberTooltips") == "1" then
+    GameTooltip_SetDefaultAnchor(GameTooltip, self:GetFrame())
+  else
+    GameTooltip:SetOwner(self:GetFrame(), "ANCHOR_RIGHT")
+  end
+  if playerClass == "HUNTER" then
+    local aspect = aspects[self.hunterIdx]
+    if aspect and aspectLinks[aspect] then
+      GameTooltip:SetHyperlink(aspectLinks[aspect])
+    end
+  else
+    GameTooltip:SetShapeshift(self:GetActionID())
+  end
+end
+
+function Stance:OnEnter()
+  self:SetTooltip()
+end
+
+function Stance:OnLeave()
+  GameTooltip:Hide()
+end
+
+function Stance:PreClick()
+  local f = self:GetFrame()
+  f:SetChecked( not f:GetChecked() )
+end
+
+function Stance:OnEvent(event, arg)
+  if event == "PLAYER_REGEN_ENABLED" then
+    if self.updatePending then
+      self:UpdateAction()
+    end
+  elseif event == "UPDATE_SHAPESHIFT_COOLDOWN" then
+    self:UpdateCooldown()
+  elseif event == "UPDATE_SHAPESHIFT_FORMS" or
+         event == "SPELLS_CHANGED" then
+    aspectLinks = { } -- force repopulate of the spellIDs
+    self:UpdateAction()
+  elseif event == "UNIT_AURA" then
+    if arg == "player" then
+      self:Update()
+    end
+  else
+    self:Update()
+  end
+end
+
+function Stance:ShowGridTemp(show)
+  if show then
+    self:GetFrame():Show()
+  else
+    self:UpdateAction()
+  end
+end
--- a/classes/classes.xml	Tue Mar 17 21:55:15 2009 +0000
+++ b/classes/classes.xml	Tue Mar 17 23:38:38 2009 +0000
@@ -8,5 +8,6 @@
 <Script file="Button.lua"/>
 <Script file="ActionButton.lua"/>
 <Script file="PetActionButton.lua"/>
+<Script file="StanceButton.lua"/>
 
 </Ui>
\ No newline at end of file
--- a/locale/enUS.lua	Tue Mar 17 21:55:15 2009 +0000
+++ b/locale/enUS.lua	Tue Mar 17 23:38:38 2009 +0000
@@ -177,6 +177,18 @@
 "Pet Action Bar",
 "Pet Buttons",
 
+-- Stance
+"Stance Bar",
+"Stance Buttons",
+"Show Aspects",
+"Show Hunter aspects as stances",
+"Auto-hide Monkey/Hawk",
+"Hide Aspect of the Monkey and Aspect of the Hawk, only when the hunter knows Aspect of the Dragonhawk",
+"Hide Presences",
+"Do not show Death Knight Presences as stances",
+"Hide Auras",
+"Do not show Paladin Auras as stances",
+
 -- ConfigUI
 "Center",
 "Left",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/Stance.lua	Tue Mar 17 23:38:38 2009 +0000
@@ -0,0 +1,210 @@
+--[[
+  ReAction Stance button module
+
+--]]
+
+-- local imports
+local ReAction = ReAction
+local L = ReAction.L
+local _G = _G
+
+-- Stance button 
+local Button = ReAction.Button.Stance
+
+-- module declaration
+local moduleID = "Stance"
+local module = ReAction:NewModule( moduleID
+  -- mixins go here
+)
+
+-- libraries
+local KB = LibStub("LibKeyBound-1.0")
+
+-- handlers
+function module:OnInitialize()
+  self.db = ReAction.db:RegisterNamespace( moduleID,
+    {
+      profile = { 
+        buttons = { }
+      }
+    }
+  )
+
+  self.buttons = { }
+
+  ReAction:RegisterOptions(self, self:GetOptions())
+
+  ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar")
+  ReAction.RegisterCallback(self, "OnDestroyBar")
+  ReAction.RegisterCallback(self, "OnRefreshBar")
+  ReAction.RegisterCallback(self, "OnEraseBar")
+  ReAction.RegisterCallback(self, "OnRenameBar")
+  ReAction.RegisterCallback(self, "OnConfigModeChanged")
+
+  KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED")
+  KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED")
+  KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
+end
+
+function module:OnEnable()
+  ReAction:RegisterBarType(L["Stance Bar"], 
+    { 
+      type = moduleID ,
+      defaultButtonSize = 36,
+      defaultBarRows = 1,
+      defaultBarCols = 8,
+      defaultBarSpacing = 3
+    })
+
+end
+
+function module:OnDisable()
+  ReAction:UnregisterBarType(L["Stance Bar"])
+end
+
+function module:OnDestroyBar(event, bar, name)
+  local btns = self.buttons[bar]
+  if btns then
+    for _,b in pairs(btns) do
+      if b then
+        b:Destroy()
+      end
+    end
+    self.buttons[bar] = nil
+  end
+end
+
+function module:OnRefreshBar(event, bar, name)
+  if bar.config.type == moduleID then
+    local btns = self.buttons[bar]
+    if btns == nil then
+      btns = { }
+      self.buttons[bar] = btns
+    end
+    local profile = self.db.profile
+    if profile.buttons[name] == nil then
+      profile.buttons[name] = {}
+    end
+    local btnCfg = profile.buttons[name]
+
+    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 success, r = pcall(Button.New,Button,i,profile,bar,i>1 and btnCfg[i-1].stanceID)
+        if success and r then
+          btns[i] = r
+          bar:AddButton(i,r)
+        else
+          n = i - 1
+          bar:ClipNButtons(n)
+          break
+        end
+      end
+      btns[i]:Refresh()
+    end
+    for i = n+1, #btns do
+      if btns[i] then
+        bar:RemoveButton(btns[i])
+        btns[i] = btns[i]:Destroy()
+        if btnCfg[i] then
+          btnCfg[i] = nil
+        end
+      end
+    end
+  end
+
+end
+
+function module:OnEraseBar(event, bar, name)
+  self.db.profile.buttons[name] = nil
+end
+
+function module:OnRenameBar(event, bar, oldName, newName)
+  local b = self.db.profile.buttons
+  b[newname], b[oldname] = b[oldname], nil
+end
+
+function module:OnConfigModeChanged(event, mode)
+  for bar in pairs(self.buttons) do
+    for b in bar:IterateButtons() do
+      b:UpdateActionIDLabel(mode)
+    end
+  end
+end
+
+function module:LIBKEYBOUND_ENABLED(evt)
+  for _, buttons in pairs(self.buttons) do
+    for _, b in pairs(buttons) do
+      b:SetKeybindMode(true)
+    end
+  end
+end
+
+function module:LIBKEYBOUND_DISABLED(evt)
+  for _, buttons in pairs(self.buttons) do
+    for _, b in pairs(buttons) do
+      b:SetKeybindMode(false)
+    end
+  end
+end
+
+function module:RefreshAll()
+  for bar in pairs(self.buttons) do
+    self:OnRefreshBar(nil,bar,bar:GetName())
+  end
+end
+
+
+---- options ----
+function module:GetOptions()
+  return {
+    stance = 
+    {
+      name = L["Stance Buttons"],
+      type = "group",
+      args = {
+        showAspects = {
+          name = L["Show Aspects"],
+          desc = L["Show Hunter aspects as stances"],
+          order = 1,
+          width = "double",
+          type = "toggle",
+          set = function(info,value) self.db.profile.showHunterAspects = value; self:RefreshAll() end,
+          get = function() return self.db.profile.showHunterAspects end,
+        },
+        hideMonkeyHawk = {
+          name = L["Auto-hide Monkey/Hawk"],
+          desc = L["Hide Aspect of the Monkey and Aspect of the Hawk, only when the hunter knows Aspect of the Dragonhawk"],
+          order = 2,
+          width = "double",
+          type = "toggle",
+          set = function(info,value) self.db.profile.hideMonkeyHawk = value; self:RefreshAll() end,
+          get = function() return self.db.profile.hideMonkeyHawk end,
+          disabled = function() return self.db.profile.showHunterAspects == false end,
+        },
+        hidePresences = {
+          name = L["Hide Presences"],
+          desc = L["Do not show Death Knight Presences as stances"],
+          order = 3,
+          width = "double",
+          type = "toggle",
+          set = function(info,value) self.db.profile.hideDKPresences = value; self:RefreshAll() end,
+          get = function() return self.db.profile.hideDKPresences end,
+        },
+        hideAuras = {
+          name = L["Hide Auras"],
+          desc = L["Do not show Paladin Auras as stances"],
+          order = 4,
+          width = "double",
+          type = "toggle",
+          set = function(info,value) self.db.profile.hidePaladinAuras = value; self:RefreshAll() end,
+          get = function() return self.db.profile.hidePaladinAuras end,
+        },
+      }
+    }
+  }
+end
--- a/modules/State.lua	Tue Mar 17 21:55:15 2009 +0000
+++ b/modules/State.lua	Tue Mar 17 23:38:38 2009 +0000
@@ -376,7 +376,7 @@
       -- sort by icon since it's locale-independent
     for i = 1, GetNumShapeshiftForms() do
       local icon, name, active = GetShapeshiftFormInfo(i)
-      -- if it's the current form, the icon is wrong (Ability_Spell_WispSplode)
+      -- if it's the current form, the icon is wrong (Spell_Nature_WispSplode)
       -- so capture it from the spell info directly
       if active then
         local _1, _2
@@ -1342,7 +1342,8 @@
 -- Export methods to Bar class --
 
 function ReAction.Bar:GetState()
-  return GetManagedEnvironment(self:GetFrame()).state
+  local env = GetManagedEnvironment(self:GetFrame())
+  return env and env.state
 end
 
 ReAction.Bar.GetStateProperty = GetProperty
--- a/modules/modules.xml	Tue Mar 17 21:55:15 2009 +0000
+++ b/modules/modules.xml	Tue Mar 17 23:38:38 2009 +0000
@@ -8,5 +8,6 @@
 <Script file="HideBlizzard.lua"/>
 <Script file="Action.lua"/>
 <Script file="PetAction.lua"/>
+<Script file="Stance.lua"/>
 
 </Ui>
\ No newline at end of file