--[[
PowerAurasButtons
Module: Buttons
--]]
-- Create module frames.
local CoreFrame = PowerAurasButtons;
local ModuleFrame = CoreFrame:RegisterModule("Buttons", { "Auras" });
local Modules = CoreFrame.Modules;
--[[
----------------------------------------------------------------------------------------------------
Variables
Buttons Stores all registered buttons in a table.
ButtonsBySlot All button objects by their action/slot ID.
ButtonData Stores the switches for each button - whether it should glow, etc.
ButtonQueue Stores a queue of buttons to be updated.
ButtonsQueued Boolean value set to true when buttons are queued.
ButtonQueueAll Updates all buttons next time.
ThrottleTimer Stores the current throttle timer for mass updates.
----------------------------------------------------------------------------------------------------
--]]
local Buttons = {};
local ButtonsBySlot = {};
local ButtonData = {};
local ButtonQueue = {};
local ButtonsQueued = false;
local ButtonQueueAll = false;
local ThrottleTimer = 0;
-- Upvalues.
local unpack, setmetatable, ActionButton_ShowOverlayGlow, ActionButton_HideOverlayGlow, wipe, type, GetActionInfo,
GetMacroSpell, GetMacroItem, pairs, IsSpellOVerlayed, hooksecurefunc = unpack, setmetatable,
ActionButton_ShowOverlayGlow, ActionButton_HideOverlayGlow, wipe, type, GetActionInfo, GetMacroSpell, GetMacroItem,
pairs, IsSpellOVerlayed, hooksecurefunc;
-- Caches.
local spellcache = setmetatable({}, {__index=function(t,v) local a = {GetSpellInfo(v)} if GetSpellInfo(v) then t[v] = a end return a end});
local function GetSpellInfo(a)
return unpack(spellcache[a]);
end
local itemcache = setmetatable({}, {__index=function(t,v) local a = {GetItemInfo(v)} if GetItemInfo(v) then t[v] = a end return a end});
local function GetItemInfo(a)
return unpack(spellcache[a]);
end
--[[
----------------------------------------------------------------------------------------------------
GetButtons
Returns all the buttons!
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:GetButtons()
return Buttons;
end
--[[
----------------------------------------------------------------------------------------------------
OnButtonUpdate
Event handler for button updates. Updates glows depending on assigned auras, etc.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:OnButtonUpdate(button)
-- Only bother updating if we can see it.
if(not button or not button:IsShown()) then return; end
-- Test the button for glowability.
ModuleFrame:ProcessButtonActions(button);
-- Fire button update event.
CoreFrame:FireModuleEvent("OnButtonUpdate", button:GetName());
-- So, does the glow need showing or hiding?
if(ModuleFrame:GetButtonData(button:GetName())["glow"]) then
-- Show the glow.
ActionButton_ShowOverlayGlow(button);
else
-- Hide the glow.
ActionButton_HideOverlayGlow(button);
end
end
--[[
----------------------------------------------------------------------------------------------------
GetButtonData
Retrieves the button data table for the given button ID. Returns nil on failure.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:GetButtonData(buttonID)
-- Go.
return ButtonData[buttonID] or nil;
end
--[[
----------------------------------------------------------------------------------------------------
ProcessButtonActions
Processes all of the assigned actions on a button. This will determine whether a button should
be glowing, showing displays, etc.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:ProcessButtonActions(button)
-- Few locals.
local buttonID = button:GetName();
-- Get the button data table if it exists. Otherwise, make a new one. We recycle the old one
-- so the memory size won't fluctuate.
local buttonData = ButtonData[buttonID] or {};
-- Wipe the data.
wipe(buttonData);
-- Fire button processing event.
CoreFrame:FireModuleEvent("OnButtonProcess", buttonID);
-- Get the non blizzard auras.
local CustomAuras, BlizzAuras = Modules.Auras:GetAuras();
-- More locals.
local buttonAction, buttonActionType, buttonActionID, buttonMacro, displayCount;
-- Get the button action ID.
buttonAction = button._state_action or button.action;
-- Action needs to be integer.
if(not buttonAction or type(buttonAction) ~= "number") then
-- Action isn't valid.
ButtonData[buttonID] = buttonData;
return;
end
-- Make sure button is cached by slot.
ButtonsBySlot[buttonAction] = button;
-- Get the button action data.
buttonActionType, buttonActionID = GetActionInfo(buttonAction);
-- Get macro names if needed.
if(buttonActionType == "macro") then
buttonMacro = GetMacroSpell(buttonActionID) or GetMacroItem(buttonActionID);
end
-- Right, first off we need to go over all the auras see if they're linked to this one.
for auraID, _ in pairs(CustomAuras) do
-- Aura needs to be active.
if(Modules.Auras:IsAuraShown(auraID)) then
-- And go over the actions.
for auraActionID, auraActionData in pairs(Modules.Auras:GetAuraActions(auraID)) do
-- Action needs to be a valid ID (> 0)
if(auraActionData["id"] and auraActionData["id"] > 0) then
-- If the type/data keys match, or this is a macro/spell combo then continue.
if(buttonActionType == auraActionData["type"]
or (buttonActionType == "macro" and auraActionData["type"] == "spell")
or (buttonActionType == "macro" and auraActionData["type"] == "item")) then
-- Compare ID's. If they match, we're golden. If they don't, do macro
-- comparisons.
if((buttonActionID == auraActionData["id"]
and buttonActionType == auraActionData["type"])
or buttonMacro and (auraActionData["type"] == "spell"
and GetSpellInfo(auraActionData["id"]) == buttonMacro
or auraActionData["type"] == "item"
and GetItemInfo(auraActionData["id"]) == buttonMacro)) then
-- Enable glows if the action says so.
Modules.Auras:MergeAuraAction(buttonData, auraActionData);
-- Fire the OnAuraDisplay event.
CoreFrame:FireModuleEvent("OnButtonDisplayAura", buttonID, auraID,
auraActionData, auraActionID);
end
end
end
end
end
end
-- Blizzard auras need checking if glow isn't on, and if enabled.
if(CoreFrame:GetModuleSetting("Buttons", "ShowBlizzardGlows")) then
if(not buttonData["glow"] and buttonActionType == "spell"
and IsSpellOverlayed(buttonActionID)) then
-- It needs to glow.
buttonData["glow"] = true;
elseif(not buttonData["glow"] and buttonActionType == "macro") then
-- Macros should glow too.
buttonMacro = GetMacroSpell(buttonActionID) or GetMacroItem(buttonActionID);
-- Loop over active Blizzard auras.
for blizzAuraID, _ in pairs(BlizzAuras) do
-- Check ID.
if(not buttonData["glow"] and buttonMacro
and (buttonMacro == GetSpellInfo(blizzAuraID)
or GetItemInfo(blizzAuraID) == buttonMacro)) then
-- Yeah, it's a match. Timers/Stacks aren't on for blizz ones.
buttonData["glow"] = true;
break; -- Break early, it doesn't matter if any others are glowing or not.
end
end
end
end
-- Update.
ButtonData[buttonID] = buttonData;
end
--[[
----------------------------------------------------------------------------------------------------
UpdateAllButtons
Fired when OnAuraShow/OnAuraHide are called. Performs a mass button update.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:UpdateAllButtons()
-- Queue all buttons for an update.
ButtonQueueAll = true;
ButtonsQueued = true;
end
--[[
----------------------------------------------------------------------------------------------------
UpdateButton
Registers a single button for an update.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:UpdateButton(button)
-- Register button for update.
if(not ButtonQueueAll and Buttons[button:GetName()]) then
ButtonQueue[button:GetName()] = button;
end
-- Flag queue.
ButtonsQueued = true;
end
--[[
----------------------------------------------------------------------------------------------------
OnUpdate
Acts as our function for throttling update requests. It's called OnUpdate but is only present
while we're throttling - we unregister it after.
----------------------------------------------------------------------------------------------------
--]]
do
local throttle = 0;
function ModuleFrame:OnUpdate(elapsed)
throttle = throttle+elapsed;
if(throttle >= 1) then
throttle = throttle-1;
end
-- Update time elapsed.
ThrottleTimer = ThrottleTimer + (ButtonsQueued and elapsed or 0);
-- Time up?
if(ThrottleTimer < CoreFrame:GetModuleSetting("Buttons", "Throttle")) then return; end
-- Process queue.
for buttonID, state in pairs((ButtonQueueAll and Buttons or ButtonQueue)) do
-- Increment counter.
if(state) then
-- Remove from queue...
ButtonQueue[buttonID] = false;
-- This one is weird, since the ButtonQueue stores a state boolean but ButtonQueueAll iterates over the
-- Buttons table directly.
local button = (ButtonQueueAll and state or Buttons[buttonID]);
-- If button is true, resolve it to an actual button.
if(button == true) then
Buttons[buttonID] = _G[buttonID] or true;
button = Buttons[buttonID];
end
-- Does button exist now?
if(button and button ~= true) then
ModuleFrame:OnButtonUpdate(button);
end
end
end
-- Clear booleans.
ButtonsQueued = false;
ButtonQueueAll = false;
-- Reset throttle.
ThrottleTimer = ThrottleTimer - CoreFrame:GetModuleSetting("Buttons", "Throttle");
end
end
--[[
----------------------------------------------------------------------------------------------------
RegisterButtons
Registers buttons into our button array for glow activation purposes.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:RegisterButtons(key, count)
-- Register, nils included (it's a Dominos thing)
local button = nil;
for i=1,(count or 12) do
-- Register it.
if(not CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")[key .. i]) then
Buttons[key .. i] = _G[key .. i] or true;
end
end
end
--[[
----------------------------------------------------------------------------------------------------
OnActionCreate
Fired when an action is created. Used to set defaults in the newly made action ID.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:OnActionCreate(auraID, actionID)
-- Get action.
local actionData = Modules.Auras:GetAuraAction(auraID, actionID);
-- Write.
actionData["glow"] = true;
-- Save.
Modules.Auras:SetAuraAction(auraID, actionID, actionData);
end
--[[
----------------------------------------------------------------------------------------------------
IsEnabled
Checks to see if the module is enabled.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:IsEnabled()
return true;
end
--[[
----------------------------------------------------------------------------------------------------
FixSettings
Fixes all saved variables and migrates older ones across.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:FixSettings(force)
-- Do the module settings exist?
if(not CoreFrame:GetSetting("Buttons") or force) then
-- We'd best fix that then.
PowerAurasButtons_SettingsDB["Buttons"] = {
["Throttle"] = 0.05,
["RegisterBlizzardButtons"] = true,
["ShowBlizzardGlows"] = true,
["IgnoredButtons"] = {},
};
end
-- Compatibility.
if(PowerAurasButtons_SettingsDB["Buttons"]["IgnoredButtons"] == nil) then
PowerAurasButtons_SettingsDB["Buttons"]["IgnoredButtons"] = {};
end
end
--[[
----------------------------------------------------------------------------------------------------
OnInitialize
Fired by the module handler. Put all the loading code into here.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:OnInitialize()
-- Fix settings first.
ModuleFrame:FixSettings();
-- Register the needed buttons.
if(Dominos) then
-- Dominos reuses the Blizzard AB's and creates 60 of its own.
CoreFrame:Debug("Dominos detected");
ModuleFrame:RegisterButtons("DominosActionButton", 60);
elseif(RazerNaga) then
-- Register additional buttons. Dominos style.
ModuleFrame:RegisterButtons("RazerNagaActionButton", 60);
elseif(LibStub) then
-- Bartender4 is a tad more tricky. It uses LAB which makes buttons as needed.
-- So we need to check for LAB (and LibStub), then scan all loaded buttons and make
-- sure future ones are added.
local LAB = LibStub("LibActionButton-1.0", true);
if(LAB) then
CoreFrame:Debug("Bartender4/LibActionButton detected");
-- LibActionButton found. Go over all of the buttons.
for button in pairs(LAB:GetAllButtons()) do
Buttons[button:GetName()] = button;
-- Store by slot too.
if(button._state_action) then
ButtonsBySlot[button._state_action] = button;
end
end
-- In addition, make sure this applies to future buttons.
LAB:RegisterCallback("OnButtonCreated", function(_, button)
Buttons[button:GetName()] = button;
-- Store by slot too.
if(button._state_action) then
ButtonsBySlot[button._state_action] = button;
end
end);
-- Add a button update hook.
LAB:RegisterCallback("OnButtonUpdate", function(_, button)
if(not button:IsShown()) then return; end
ModuleFrame:UpdateButton(button);
end);
end
end
-- Odds are you're using the default buttons if you're not using Dominos/BT.
-- Register them if not told otherwise.
if(CoreFrame:GetModuleSetting("Buttons", "RegisterBlizzardButtons") or Dominos or RazerNaga) then
CoreFrame:Debug("Registering Blizzard buttons");
ModuleFrame:RegisterButtons("ActionButton");
ModuleFrame:RegisterButtons("BonusActionButton");
ModuleFrame:RegisterButtons("MultiBarRightButton");
ModuleFrame:RegisterButtons("MultiBarLeftButton");
ModuleFrame:RegisterButtons("MultiBarBottomRightButton");
ModuleFrame:RegisterButtons("MultiBarBottomLeftButton");
end
-- If you use Dominos or have the Blizzard buttons on, you need this.
if(Dominos or RazerNaga or CoreFrame:GetModuleSetting("Buttons", "RegisterBlizzardButtons")) then
-- Hook for button updates.
hooksecurefunc("ActionButton_Update", function(button)
if(not button:IsShown()) then return; end
ModuleFrame:UpdateButton(button);
end);
end
-- -- Update only if slot data changes.
-- CoreFrame:RegisterBlizzEventListener("ACTIONBAR_SLOT_CHANGED", ModuleFrame, function(self, id)
-- if(id == 0 or not ButtonsBySlot[id]) then
-- ModuleFrame:UpdateAllButtons();
-- else
-- ModuleFrame:UpdateButton(ButtonsBySlot[id]);
-- end
-- end);
-- Create some events for modules to hook on to.
CoreFrame:RegisterModuleEvent("OnButtonUpdate");
CoreFrame:RegisterModuleEvent("OnButtonProcess");
CoreFrame:RegisterModuleEvent("OnButtonDisplayAura");
-- Register OnAuraShow/OnAuraHide.
CoreFrame:RegisterModuleEventListener("OnAuraShow", ModuleFrame, ModuleFrame.UpdateAllButtons);
CoreFrame:RegisterModuleEventListener("OnAuraHide", ModuleFrame, ModuleFrame.UpdateAllButtons);
CoreFrame:RegisterModuleEventListener("OnActionCreate", ModuleFrame);
-- Updates are throttled and processed in an update loop.
ModuleFrame:SetScript("OnUpdate", ModuleFrame.OnUpdate);
-- Done.
return true;
end