Quantcast
--[[
	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.
	ButtonData         Stores the switches for each button - whether it should glow, etc.
	ThrottleActive     Stores the current throttle state.
	ThrottlePending    Stores the status of any pending mass updates.
	ThrottleTimer      Stores the current throttle timer for mass updates.
----------------------------------------------------------------------------------------------------
--]]
local Buttons          = {};
local ButtonData       = {};
local ThrottleActive   = nil;
local ThrottlePending  = nil;
local ThrottleTimer    = 0;
--[[
----------------------------------------------------------------------------------------------------
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
	-- 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;
				end
			end
		end
	end
	-- Update.
	ButtonData[buttonID] = buttonData;
end
--[[
----------------------------------------------------------------------------------------------------
OnUpdateTrigger

Fired when OnAuraShow/OnAuraHide are called. Performs a mass button update.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:OnUpdateTrigger()
	-- Check to see if update throttling is enabled. If it is, we'll queue this update.
	if(CoreFrame:GetModuleSetting("Buttons", "Throttle") > 0 and ThrottleActive) then
		-- We're throttled.
		ThrottlePending = true;
	else
		-- Throttle further updates (won't do anything if disabled!)
		ModuleFrame:ThrottleUpdates();
		-- Iterate over the active buttons and go to town on it.
		for buttonID, button in pairs(Buttons) do
			-- Buttons that should be made but aren't registered yet are recorded as TRUE values.
			-- On each mass update we try to replace these with actual buttons, this fixes issues
			-- with Dominos.
			if(button and button == true) then
				Buttons[buttonID] = _G[buttonID] or true;
			end
			-- Pass to UpdateButton.
			if(button and button ~= true) then
				ModuleFrame:OnButtonUpdate(Buttons[buttonID]);
			end
		end
	end
end
--[[
----------------------------------------------------------------------------------------------------
ThrottleUpdates

Throttles further updates if the feature is enabled.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:ThrottleUpdates()
	-- Make sure it's enabled.
	if(CoreFrame:GetModuleSetting("Buttons", "Throttle") == 0) then return; end
	-- Stop further updates.
	ThrottleActive = true;
	-- Reset our throttle timer.
	ThrottleTimer = 0;
	-- Register update script.
	ModuleFrame:SetScript("OnUpdate", ModuleFrame.OnUpdate);
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.
----------------------------------------------------------------------------------------------------
--]]
function ModuleFrame:OnUpdate(elapsed)
	-- Update time elapsed.
	ThrottleTimer = ThrottleTimer + elapsed;
	-- Time up?
	if(ThrottleTimer < CoreFrame:GetModuleSetting("Buttons", "Throttle")) then return; end
	-- Remove update script.
	ModuleFrame:SetScript("OnUpdate", nil);
	-- Time up! Rip this off.
	ThrottleActive = nil;
	-- Any updates queued?
	if(ThrottlePending) then
		-- Trigger update, remove the var.
		ThrottlePending = nil;
		-- This will trigger re-throttling if another request comes along while processing this
		-- one. It's intended.
		ModuleFrame:OnUpdateTrigger();
	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.
		Buttons[key .. i] = _G[key .. i] or true;
	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
		};
	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(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;
			end
			-- In addition, make sure this applies to future buttons.
			LAB:RegisterCallback("OnButtonCreated", function(_, button)
				Buttons[button:GetName()] = button;
			end);
			-- Add a button update hook.
			LAB:RegisterCallback("OnButtonUpdate", function(_, button)
				ModuleFrame:OnButtonUpdate(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) 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 CoreFrame:GetModuleSetting("Buttons", "RegisterBlizzardButtons")) then
		-- Hook for button updates.
		hooksecurefunc("ActionButton_Update", function(button)
			ModuleFrame:OnButtonUpdate(button);
		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.OnUpdateTrigger);
	CoreFrame:RegisterModuleEventListener("OnAuraHide", ModuleFrame, ModuleFrame.OnUpdateTrigger);
	CoreFrame:RegisterModuleEventListener("OnActionCreate", ModuleFrame);
	-- Done.
	return true;
end