flickerstreak@7: -- The ReAction.ActionType mixin defines 'regular' action button functionality flickerstreak@7: -- and is an implementation of the ReAction.IActionType interface. flickerstreak@7: -- flickerstreak@7: -- The Mixin assumes that it is being mixed in with a ReAction-derived class flickerstreak@7: -- which implements the ReAction.IDisplay and ReAction.ActionType.IDisplay interfaces. flickerstreak@7: -- flickerstreak@7: -- This mixin using the following configuration properties: flickerstreak@7: -- flickerstreak@7: -- self.config = { flickerstreak@7: -- selfcast = nil / "alt" / "ctrl" / "shift" / "auto" / "none". nil (default) = use Interface Options menu setting. flickerstreak@7: -- } flickerstreak@7: -- flickerstreak@7: flickerstreak@7: local AceOO = AceLibrary("AceOO-2.0") flickerstreak@7: flickerstreak@7: ReAction.ActionType = AceOO.Mixin { flickerstreak@7: -- ReAction.IActionType interface flickerstreak@7: "SetID", flickerstreak@7: "GetID", flickerstreak@7: "SetupAction", flickerstreak@7: "UpdateAction", flickerstreak@7: "PickupAction", flickerstreak@7: "PlaceAction", flickerstreak@7: "IsActionEmpty", flickerstreak@7: "UpdateTooltip", flickerstreak@7: flickerstreak@7: -- event handlers flickerstreak@7: "ACTIONBAR_SLOT_CHANGED", flickerstreak@7: "PLAYER_ENTERING_WORLD", flickerstreak@7: "ACTIONBAR_SHOWGRID", flickerstreak@7: "ACTIONBAR_HIDEGRID", flickerstreak@7: "ACTIONBAR_UPDATE_STATE", flickerstreak@7: "ACTIONBAR_UPDATE_USABLE", flickerstreak@7: "UNIT_INVENTORY_CHANGED", flickerstreak@7: "CRAFT_SHOW", flickerstreak@7: "PLAYER_ENTER_COMBAT", flickerstreak@7: "PLAYER_LEAVE_COMBAT", flickerstreak@7: "START_AUTOREPEAT_SPELL", flickerstreak@7: "STOP_AUTOREPEAT_SPELL", flickerstreak@7: "OnAttributeChanged", flickerstreak@7: flickerstreak@7: -- internal functions flickerstreak@7: "UpdateSelfcast", flickerstreak@7: "UpdateIcon", flickerstreak@7: "UpdateInUse", flickerstreak@7: "UpdateCount", flickerstreak@7: "UpdateMacroText", flickerstreak@7: "UpdateUsable", flickerstreak@7: "UpdateCooldown", flickerstreak@7: "UpdateActionEvents", flickerstreak@7: } flickerstreak@7: flickerstreak@7: local RAAT = ReAction.ActionType flickerstreak@7: flickerstreak@7: flickerstreak@7: -- Required display elements flickerstreak@7: RAAT.IDisplay = AceOO.Interface { flickerstreak@7: DisplayUsable = "function", -- DisplayUsable(bool, notEnoughMana, outOfRange), change display to indicate action usable/unusable flickerstreak@7: DisplayEquipped = "function", -- DisplayEquipped(bool) flickerstreak@7: DisplayAutoRepeat = "function", -- DisplayAutoRepeat(bool) flickerstreak@7: DisplayInUse = "function", -- DisplayInUse(bool) flickerstreak@7: DisplayIcon = "function", -- DisplayIcon(texture), nil means empty slot flickerstreak@7: DisplayName = "function", -- DisplayName(text), macro names flickerstreak@7: DisplayCount = "function", -- DisplayCount(number), stack count flickerstreak@7: DisplayCooldown = "function", -- DisplayCooldown(start,duration,enable) flickerstreak@7: } flickerstreak@7: flickerstreak@7: flickerstreak@7: --------------------------------------- flickerstreak@7: -- ReAction.IActionType interface implementation flickerstreak@7: --------------------------------------- flickerstreak@7: function RAAT:SetID( id, page ) flickerstreak@7: local f = self:GetActionFrame() flickerstreak@7: id = tonumber(id) -- force data integrity flickerstreak@7: page = tonumber(page) flickerstreak@7: local button = page and ("-page"..page) or "*" flickerstreak@7: if id then flickerstreak@7: f:SetAttribute("*action"..button, id) flickerstreak@7: if page and page > 1 and self.config.selfcast == "right-click" then flickerstreak@7: -- disable right-click auto-cast flickerstreak@7: self.config.selfcast = nil flickerstreak@7: end flickerstreak@7: elseif page then flickerstreak@7: f:SetAttribute("*action"..button, ATTRIBUTE_NOOP) flickerstreak@7: end flickerstreak@7: self:UpdateSelfcast() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:GetID(page) flickerstreak@7: local f = self:GetActionFrame() flickerstreak@7: page = tonumber(page) flickerstreak@7: local button = page and ("page"..page) or SecureStateChild_GetEffectiveButton(f) flickerstreak@7: return SecureButton_GetModifiedAttribute(f, "action", button) flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:SetupAction() flickerstreak@7: local f = self:GetActionFrame() flickerstreak@7: f:SetAttribute("useparent*", true) flickerstreak@7: f:SetAttribute("type", "action") flickerstreak@7: flickerstreak@7: self:RegisterEvent("PLAYER_ENTERING_WORLD") flickerstreak@7: self:RegisterEvent("ACTIONBAR_SLOT_CHANGED") flickerstreak@7: self:RegisterEvent("ACTIONBAR_SHOWGRID") flickerstreak@7: self:RegisterEvent("ACTIONBAR_HIDEGRID") flickerstreak@7: flickerstreak@7: self:UpdateSelfcast() flickerstreak@7: flickerstreak@7: f:SetScript("OnAttributeChanged", function(frame,name,value) self:OnAttributeChanged(name,value) end) flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateAction() flickerstreak@7: self:UpdateIcon() flickerstreak@7: self:UpdateCount() flickerstreak@7: self:UpdateMacroText() flickerstreak@7: self:UpdateUsable() flickerstreak@7: self:UpdateCooldown() flickerstreak@7: self:UpdateActionEvents() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:PickupAction() flickerstreak@7: PickupAction(self:GetID()) flickerstreak@7: self:UpdateAction() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:PlaceAction() flickerstreak@7: if not InCombatLockdown() then flickerstreak@7: -- PlaceAction() is protected. However the user can still drop a new action flickerstreak@7: -- onto a button while in combat by dragging then clicking, because flickerstreak@7: -- UseAction() appears to swap the cursor action for the current action if flickerstreak@7: -- an action is on the cursor. flickerstreak@7: PlaceAction(self:GetID()) flickerstreak@8: -- the ACTIONBAR_SLOT_CHANGED event will handle the update flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:IsActionEmpty() flickerstreak@7: local slot = self:GetID() flickerstreak@7: return not(slot and HasAction(slot)) flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateTooltip() flickerstreak@7: local action = self:GetID() flickerstreak@7: if action and GameTooltip:IsOwned(self:GetActionFrame()) then flickerstreak@7: GameTooltip:SetAction(action) flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: ----------------------------- flickerstreak@7: -- Event Handling flickerstreak@7: ----------------------------- flickerstreak@7: function RAAT:ACTIONBAR_SLOT_CHANGED(slot) flickerstreak@7: if slot == 0 or slot == self:GetID() then flickerstreak@7: self:UpdateAction() flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:PLAYER_ENTERING_WORLD() flickerstreak@7: self:UpdateAction() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:ACTIONBAR_SHOWGRID() flickerstreak@7: self:TempShow(true) flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:ACTIONBAR_HIDEGRID() flickerstreak@7: self:TempShow(false) flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:ACTIONBAR_UPDATE_STATE() flickerstreak@7: self:UpdateInUse() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:ACTIONBAR_UPDATE_USABLE() flickerstreak@7: self:UpdateUsable() flickerstreak@7: self:UpdateCooldown() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UNIT_INVENTORY_CHANGED(unit) flickerstreak@7: if unit == "player" then flickerstreak@7: self:UpdateIcon() flickerstreak@7: self:UpdateCount() flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:CRAFT_SHOW() flickerstreak@7: self:UpdateInUse() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:PLAYER_ENTER_COMBAT() flickerstreak@7: if IsAttackAction(self:GetID()) then flickerstreak@7: self:DisplayAutoRepeat(true) flickerstreak@7: self:UpdateInUse() flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:PLAYER_LEAVE_COMBAT() flickerstreak@7: if IsAttackAction(self:GetID()) then flickerstreak@7: self:DisplayAutoRepeat(false) flickerstreak@7: self:UpdateInUse() flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:START_AUTOREPEAT_SPELL() flickerstreak@7: if IsAutoRepeatAction(self:GetID()) then flickerstreak@7: self:DisplayAutoRepeat(true) flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:STOP_AUTOREPEAT_SPELL() flickerstreak@7: if not IsAttackAction(self:GetID()) then flickerstreak@7: self:DisplayAutoRepeat(false) flickerstreak@7: self:UpdateInUse() flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:OnAttributeChanged(name, value) flickerstreak@7: if self.config then flickerstreak@7: self:UpdateAction() flickerstreak@7: self:UpdateDisplay() flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: flickerstreak@7: --------------------------------- flickerstreak@7: -- Internal methods flickerstreak@7: --------------------------------- flickerstreak@7: function RAAT:UpdateSelfcast() flickerstreak@7: if not InCombatLockdown() then flickerstreak@7: local c = self.config and self.config.selfcast flickerstreak@7: local f = self:GetActionFrame() flickerstreak@7: flickerstreak@7: f:SetAttribute("alt-unit*",nil) flickerstreak@7: f:SetAttribute("ctrl-unit*",nil) flickerstreak@7: f:SetAttribute("shift-unit*",nil) flickerstreak@7: f:SetAttribute("*unit2",nil) flickerstreak@7: if c == nil then flickerstreak@7: f:SetAttribute("unit",nil) flickerstreak@7: f:SetAttribute("checkselfcast", true) flickerstreak@7: else flickerstreak@7: f:SetAttribute("checkselfcast",ATTRIBUTE_NOOP) flickerstreak@7: f:SetAttribute("unit","none") -- "none" gives you the glowing cast hand if no target selected, or casts on target if target selected flickerstreak@7: if c == "none" then flickerstreak@7: -- nothing to do flickerstreak@7: elseif c == "alt" or c == "ctrl" or c == "shift" then flickerstreak@7: f:SetAttribute(c.."-unit*","player") flickerstreak@7: elseif c == "right-click" then flickerstreak@7: if f:GetAttribute("*action-page2") then flickerstreak@7: -- right-click modifier not supported with multipage flickerstreak@7: self.config.selfcast = nil flickerstreak@7: f:SetAttribute("unit",nil) flickerstreak@7: f:SetAttribute("checkselfcast",true) flickerstreak@7: else flickerstreak@7: f:SetAttribute("*unit2","player") flickerstreak@7: end flickerstreak@7: end flickerstreak@7: end flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateIcon() flickerstreak@7: local action = self:GetID() flickerstreak@7: local texture = action and GetActionTexture(action) flickerstreak@7: flickerstreak@7: self:DisplayIcon(action and texture) flickerstreak@7: self:DisplayEquipped(action and IsEquippedAction(action)) flickerstreak@7: self:UpdateInUse() flickerstreak@7: self:UpdateUsable() flickerstreak@7: self:UpdateCooldown() flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateInUse() flickerstreak@7: local action = self:GetID() flickerstreak@7: if action and (IsCurrentAction(action) or IsAutoRepeatAction(action)) then flickerstreak@7: self:DisplayInUse(true) flickerstreak@7: else flickerstreak@7: self:DisplayInUse(false) flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateCount() flickerstreak@7: local action = self:GetID() flickerstreak@7: if action and (IsConsumableAction(action) or IsStackableAction(action)) then flickerstreak@7: self:DisplayCount(GetActionCount(action)) -- will display a 0 if none remaining flickerstreak@7: else flickerstreak@7: self:DisplayCount(nil) -- will display nothing flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateMacroText() flickerstreak@7: local action = self:GetID() flickerstreak@7: self:DisplayName(action and GetActionText(action)) flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateUsable() flickerstreak@7: local action = self:GetID() flickerstreak@7: if action and HasAction(action) then flickerstreak@7: local isUsable, notEnoughMana = IsUsableAction(action) flickerstreak@7: local outOfRange = IsActionInRange(action) == 0 flickerstreak@7: self:DisplayUsable(isUsable and not outOfRange, notEnoughMana, outOfRange) flickerstreak@7: else flickerstreak@7: self:DisplayUsable(false, false, false) flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateCooldown() flickerstreak@7: local action = self:GetID() flickerstreak@7: if action then flickerstreak@7: self:DisplayCooldown(GetActionCooldown(action)) flickerstreak@7: end flickerstreak@7: end flickerstreak@7: flickerstreak@7: function RAAT:UpdateActionEvents() flickerstreak@7: local action = self:GetID() flickerstreak@7: if action and HasAction(action) then flickerstreak@7: if not self.actionEventsRegistered then flickerstreak@7: self:RegisterEvent("ACTIONBAR_UPDATE_STATE") flickerstreak@7: self:RegisterEvent("ACTIONBAR_UPDATE_USABLE") flickerstreak@7: self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", "ACTIONBAR_UPDATE_USABLE") flickerstreak@7: self:RegisterEvent("UPDATE_INVENTORY_ALERTS", "ACTIONBAR_UPDATE_USABLE") flickerstreak@7: self:RegisterEvent("PLAYER_AURAS_CHANGED", "ACTIONBAR_UPDATE_USABLE") flickerstreak@7: self:RegisterEvent("PLAYER_TARGET_CHANGED", "ACTIONBAR_UPDATE_USABLE") flickerstreak@7: self:RegisterEvent("UNIT_INVENTORY_CHANGED") flickerstreak@7: self:RegisterEvent("CRAFT_SHOW") flickerstreak@7: self:RegisterEvent("CRAFT_CLOSE", "CRAFT_SHOW") flickerstreak@7: self:RegisterEvent("TRADE_SKILL_SHOW", "CRAFT_SHOW") flickerstreak@7: self:RegisterEvent("TRADE_SKILL_CLOSE", "CRAFT_SHOW") flickerstreak@7: self:RegisterEvent("PLAYER_ENTER_COMBAT") flickerstreak@7: self:RegisterEvent("PLAYER_LEAVE_COMBAT") flickerstreak@7: self:RegisterEvent("START_AUTOREPEAT_SPELL") flickerstreak@7: self:RegisterEvent("STOP_AUTOREPEAT_SPELL") flickerstreak@7: self.actionEventsRegistered = true flickerstreak@7: end flickerstreak@7: elseif self.actionEventsRegistered then flickerstreak@7: self:UnregisterEvent("ACTIONBAR_UPDATE_STATE") flickerstreak@7: self:UnregisterEvent("ACTIONBAR_UPDATE_USABLE") flickerstreak@7: self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN") flickerstreak@7: self:UnregisterEvent("UPDATE_INVENTORY_ALERTS") flickerstreak@7: self:UnregisterEvent("PLAYER_AURAS_CHANGED") flickerstreak@7: self:UnregisterEvent("PLAYER_TARGET_CHANGED") flickerstreak@7: self:UnregisterEvent("UNIT_INVENTORY_CHANGED") flickerstreak@7: self:UnregisterEvent("CRAFT_SHOW") flickerstreak@7: self:UnregisterEvent("CRAFT_CLOSE") flickerstreak@7: self:UnregisterEvent("TRADE_SKILL_SHOW") flickerstreak@7: self:UnregisterEvent("TRADE_SKILL_CLOSE") flickerstreak@7: self:UnregisterEvent("PLAYER_ENTER_COMBAT") flickerstreak@7: self:UnregisterEvent("PLAYER_LEAVE_COMBAT") flickerstreak@7: self:UnregisterEvent("START_AUTOREPEAT_SPELL") flickerstreak@7: self:UnregisterEvent("STOP_AUTOREPEAT_SPELL") flickerstreak@7: self.actionEventsRegistered = false flickerstreak@7: end flickerstreak@7: end flickerstreak@7: