flickerstreak@175: local addonName, addonTable = ... flickerstreak@175: local ReAction = addonTable.ReAction flickerstreak@130: local L = ReAction.L flickerstreak@130: local _G = _G flickerstreak@130: local CreateFrame = CreateFrame flickerstreak@130: local format = string.format flickerstreak@130: local GetCVar = GetCVar flickerstreak@130: local InCombatLockdown = InCombatLockdown flickerstreak@130: local GetPetActionInfo = GetPetActionInfo flickerstreak@130: local GetPetActionSlotUsable = GetPetActionSlotUsable flickerstreak@130: local GetPetActionCooldown = GetPetActionCooldown flickerstreak@130: local AutoCastShine_AutoCastStart = AutoCastShine_AutoCastStart flickerstreak@130: local AutoCastShine_AutoCastStop = AutoCastShine_AutoCastStop flickerstreak@130: local SetDesaturation = SetDesaturation flickerstreak@130: local CooldownFrame_SetTimer = CooldownFrame_SetTimer flickerstreak@130: local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor flickerstreak@130: flickerstreak@130: -- flickerstreak@130: -- Secure snippets flickerstreak@130: -- These are run within the context of the bar's sandbox, as the flickerstreak@130: -- buttons themselves do not have their own sandbox. flickerstreak@130: -- flickerstreak@130: local _onDragStart = -- function(self, button, kind, value, ...) flickerstreak@130: [[ flickerstreak@130: if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then flickerstreak@130: return kind, value, ... flickerstreak@130: else flickerstreak@130: return "petaction", self:GetAttribute("action") flickerstreak@130: end flickerstreak@130: ]] flickerstreak@130: flickerstreak@130: local _onReceiveDrag = -- function(self, button, kind, value, ...) flickerstreak@130: [[ flickerstreak@130: if kind then -- pet spells on the cursor return nil from GetCursorInfo(), which is very strange flickerstreak@130: return kind, value, ... flickerstreak@130: end flickerstreak@130: return "petaction", self:GetAttribute("action") flickerstreak@130: ]] flickerstreak@130: flickerstreak@130: -- flickerstreak@130: -- private flickerstreak@130: -- flickerstreak@130: local eventList = { flickerstreak@130: "PLAYER_CONTROL_LOST", flickerstreak@130: "PLAYER_CONTROL_GAINED", flickerstreak@130: "PLAYER_FARSIGHT_FOCUS_CHANGED", flickerstreak@130: "UNIT_PET", flickerstreak@130: "UNIT_FLAGS", flickerstreak@130: "UNIT_AURA", flickerstreak@130: "PET_BAR_UPDATE", flickerstreak@130: "PET_BAR_UPDATE_COOLDOWN", flickerstreak@165: "PET_BAR_UPDATE_USABLE", flickerstreak@130: "UPDATE_BINDINGS", flickerstreak@130: } flickerstreak@130: flickerstreak@130: -- flickerstreak@130: -- Pet Action Button class flickerstreak@130: -- flickerstreak@218: local buttonTypeID = "PetAction" flickerstreak@130: local Super = ReAction.Button flickerstreak@218: local Pet = setmetatable( flickerstreak@218: { flickerstreak@218: defaultBarConfig = { flickerstreak@218: type = buttonTypeID, flickerstreak@218: btnWidth = 30, flickerstreak@218: btnHeight = 30, flickerstreak@218: btnRows = 1, flickerstreak@218: btnColumns = 10, flickerstreak@218: spacing = 8 flickerstreak@218: }, flickerstreak@218: flickerstreak@218: barType = L["Pet Action Bar"], flickerstreak@218: }, flickerstreak@218: { __index = Super } ) flickerstreak@130: ReAction.Button.PetAction = Pet flickerstreak@130: flickerstreak@130: function Pet:New( idx, config, bar, idHint ) flickerstreak@130: local name = format("ReAction_%s_PetAction_%d",bar:GetName(),idx) flickerstreak@130: flickerstreak@130: self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) flickerstreak@130: flickerstreak@130: local f = self:GetFrame() flickerstreak@130: if not f.autoCastTexture then flickerstreak@131: -- store autocast stuff with the frame for recycling flickerstreak@130: local tex = f:CreateTexture(nil,"OVERLAY") flickerstreak@130: tex:SetTexture([[Interface\Buttons\UI-AutoCastableOverlay]]) flickerstreak@130: tex:SetHeight(58) flickerstreak@130: tex:SetWidth(58) flickerstreak@130: tex:SetPoint("CENTER") flickerstreak@130: f.autoCastTexture = tex flickerstreak@158: f.autoCastShine = CreateFrame("Frame",name.."Shine",f,"AutoCastShineTemplate") -- create after autocast texture so it's on top flickerstreak@131: -- move the cooldown around flickerstreak@131: local cd = self.frames.cooldown flickerstreak@131: cd:ClearAllPoints() flickerstreak@131: cd:SetWidth(33) flickerstreak@131: cd:SetHeight(33) flickerstreak@131: cd:SetPoint("CENTER", f, "CENTER", -2, -1) flickerstreak@131: -- resize to 30x30 flickerstreak@131: f:SetHeight(30) flickerstreak@131: f:SetWidth(30) flickerstreak@142: local nt = _G[name.."NormalTexture"] flickerstreak@142: nt:SetHeight(54) flickerstreak@142: nt:SetWidth(54) flickerstreak@130: end flickerstreak@130: local barFrame = bar:GetFrame() flickerstreak@130: flickerstreak@130: -- set up the base action ID flickerstreak@130: self:SetActionIDPool("pet",10) flickerstreak@130: config.actionID = self:AcquireActionID(config.actionID, idHint, true) flickerstreak@130: flickerstreak@130: -- attribute setup flickerstreak@131: -- There's no secure way to do PetAutoCastToggle by actionID, so use flickerstreak@131: -- a click-through proxy to the Blizzard pet buttons for right-click flickerstreak@131: -- Note that technically this doesn't do PetStopAttack() when flickerstreak@131: -- IsPetAttackActive() is true: however that's only true when using flickerstreak@131: -- Eyes of the Beast and appears not to really do anything (at least flickerstreak@131: -- I can't find any difference) flickerstreak@130: f:SetAttribute("type","pet") flickerstreak@130: f:SetAttribute("type2","click") flickerstreak@130: f:SetAttribute("clickbutton2",_G["PetActionButton"..config.actionID]) flickerstreak@130: f:SetAttribute("action",config.actionID) flickerstreak@130: f:SetAttribute("checkselfcast", true) flickerstreak@130: f:SetAttribute("checkfocuscast", true) flickerstreak@130: flickerstreak@130: -- non secure scripts flickerstreak@130: f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) flickerstreak@130: f:SetScript("OnEnter", function(frame) self:OnEnter() end) flickerstreak@130: f:SetScript("OnLeave", function(frame) self:OnLeave() end) flickerstreak@130: f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) flickerstreak@130: f:SetScript("PreClick", function(frame) self:PreClick() end) flickerstreak@130: f:SetScript("OnDragStart", function(frame) self:OnDragStart() end) flickerstreak@130: f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end) flickerstreak@130: flickerstreak@130: -- secure handlers flickerstreak@130: barFrame:WrapScript(f, "OnDragStart", _onDragStart) flickerstreak@130: barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag) flickerstreak@130: flickerstreak@130: -- event registration flickerstreak@130: f:EnableMouse(true) flickerstreak@130: f:RegisterForDrag("LeftButton", "RightButton") flickerstreak@130: f:RegisterForClicks("AnyUp") flickerstreak@130: for _, evt in pairs(eventList) do flickerstreak@130: f:RegisterEvent(evt) flickerstreak@130: end flickerstreak@130: flickerstreak@130: -- attach to skinner flickerstreak@130: bar:SkinButton(self, flickerstreak@130: { flickerstreak@130: AutoCast = f.autoCastShine, flickerstreak@130: AutoCastable = f.autoCastTexture flickerstreak@130: }) flickerstreak@130: flickerstreak@130: self:Refresh() flickerstreak@130: f:Show() flickerstreak@130: flickerstreak@130: return self flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:Refresh() flickerstreak@130: Super.Refresh(self) flickerstreak@130: self:Update() flickerstreak@130: self:UpdateHotkey() flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:GetActionID() flickerstreak@130: return self.config.actionID flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:SetActionID(id) flickerstreak@130: if not InCombatLockdown() then flickerstreak@130: if id < 0 or id > 10 then flickerstreak@130: ReAction:UserError(L["Pet action ID range is 1-10"]) flickerstreak@130: return flickerstreak@130: end flickerstreak@130: self.config.actionID = id flickerstreak@130: f:SetAttribute("clickbutton2",_G["PetActionButton"..id]) flickerstreak@130: f:SetAttribute("action",id) flickerstreak@130: self:Update() flickerstreak@130: self:UpdateHotkey() flickerstreak@130: end flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:Update() flickerstreak@130: local action = self.config.actionID flickerstreak@130: local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(action) flickerstreak@130: local f = self:GetFrame() flickerstreak@130: local icon = self.frames.icon flickerstreak@130: flickerstreak@130: if isToken then flickerstreak@130: icon:SetTexture(_G[texture]) flickerstreak@130: self.tooltipName = _G[name] flickerstreak@130: else flickerstreak@130: icon:SetTexture(texture) flickerstreak@130: self.tooltipName = name flickerstreak@130: end flickerstreak@130: flickerstreak@130: self.isToken = isToken flickerstreak@130: self.tooltipSubtext = subtext flickerstreak@130: f:SetChecked( isActive and 1 or 0 ) flickerstreak@130: flickerstreak@130: if autoCastAllowed then flickerstreak@130: f.autoCastTexture:Show() flickerstreak@130: else flickerstreak@130: f.autoCastTexture:Hide() flickerstreak@130: end flickerstreak@130: flickerstreak@130: if autoCastEnabled then flickerstreak@130: AutoCastShine_AutoCastStart(f.autoCastShine) flickerstreak@130: else flickerstreak@130: AutoCastShine_AutoCastStop(f.autoCastShine) flickerstreak@130: end flickerstreak@130: flickerstreak@130: if texture then flickerstreak@130: if GetPetActionSlotUsable(action) then flickerstreak@130: SetDesaturation(icon,nil) flickerstreak@130: else flickerstreak@130: SetDesaturation(icon,1) flickerstreak@130: end flickerstreak@130: icon:Show() flickerstreak@130: f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") flickerstreak@130: else flickerstreak@130: icon:Hide() flickerstreak@130: f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot") flickerstreak@130: end flickerstreak@130: flickerstreak@130: self:UpdateCooldown() flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:UpdateCooldown() flickerstreak@130: CooldownFrame_SetTimer(self.frames.cooldown, GetPetActionCooldown(self.config.actionID)) flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:SetTooltip() flickerstreak@130: if self.tooltipName then flickerstreak@130: local f = self:GetFrame() flickerstreak@130: local uber = GetCVar("UberTooltips") flickerstreak@130: if self.isToken or (uber == "0") then flickerstreak@130: if uber == "0" then flickerstreak@130: GameTooltip:SetOwner(f, "ANCHOR_RIGHT") flickerstreak@130: else flickerstreak@130: GameTooltip_SetDefaultAnchor(GameTooltip, f) flickerstreak@130: end flickerstreak@130: GameTooltip:SetText(self.tooltipName) flickerstreak@130: if self.tooltipSubtext then flickerstreak@130: GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5) flickerstreak@130: end flickerstreak@130: GameTooltip:Show() flickerstreak@130: else flickerstreak@130: GameTooltip_SetDefaultAnchor(GameTooltip, f) flickerstreak@130: GameTooltip:SetPetAction(self.config.actionID) flickerstreak@130: end flickerstreak@130: else flickerstreak@130: GameTooltip:Hide() flickerstreak@130: end flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:OnEvent(event, unit) flickerstreak@130: if event =="PET_BAR_UPDATE_COOLDOWN" then flickerstreak@130: self:UpdateCooldown() flickerstreak@130: elseif event == "UPDATE_BINDINGS" then flickerstreak@130: self:UpdateHotkey() flickerstreak@130: elseif event == "UNIT_PET" then flickerstreak@130: if unit == "player" then flickerstreak@130: self:Update() flickerstreak@130: end flickerstreak@130: elseif event == "UNIT_FLAGS" or event == "UNIT_AURA" then flickerstreak@130: if unit == "pet" then flickerstreak@130: self:Update() flickerstreak@130: end flickerstreak@130: else flickerstreak@130: self:Update() flickerstreak@130: end flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:OnEnter() flickerstreak@130: self:SetTooltip() flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:OnLeave() flickerstreak@130: GameTooltip:Hide() flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:OnAttributeChanged(attr,value) flickerstreak@130: self:Update() flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:PreClick() flickerstreak@130: self:GetFrame():SetChecked(0) flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:OnDragStart() flickerstreak@130: self:SetChecked(0) flickerstreak@130: self:Update() flickerstreak@130: end flickerstreak@130: flickerstreak@130: function Pet:OnReceiveDrag() flickerstreak@130: self:SetChecked(0) flickerstreak@130: self:Update() flickerstreak@130: end flickerstreak@130: