Quantcast

Performance optimizations, experimental update change, button blacklist.

Daniel Yates [06-28-11 - 16:41]
Performance optimizations, experimental update change, button blacklist.
Filename
Modules/Buttons.lua
Modules/ButtonsConfig.lua
Modules/Config.lua
PowerAurasButtons.toc
diff --git a/Modules/Buttons.lua b/Modules/Buttons.lua
index 967cdb8..6db4865 100644
--- a/Modules/Buttons.lua
+++ b/Modules/Buttons.lua
@@ -13,18 +13,18 @@ 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.
-	ButtonCache        Stores a cache of the aura actions that apply to specific action buttons.
-	ThrottleActive     Stores the current throttle state.
-	ThrottlePending    Stores the status of any pending mass updates.
+	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 ButtonCache      = setmetatable({}, { __mode = "k" });
-local ThrottleActive   = nil;
-local ThrottlePending  = nil;
+local ButtonQueue      = {};
+local ButtonsQueued    = false;
+local ButtonQueueAll   = false;
 local ThrottleTimer    = 0;
 -- Upvalues.
 local unpack, setmetatable, ActionButton_ShowOverlayGlow, ActionButton_HideOverlayGlow, wipe, type, GetActionInfo,
@@ -42,6 +42,16 @@ local function GetItemInfo(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.
@@ -112,52 +122,31 @@ function ModuleFrame:ProcessButtonActions(button)
 	if(buttonActionType == "macro") then
 		buttonMacro = GetMacroSpell(buttonActionID) or GetMacroItem(buttonActionID);
 	end
-	-- Create cache if needed.
-	if(not ButtonCache[buttonAction]) then
-		ButtonCache[buttonAction] = {};
-	end
-	local buttonCache = ButtonCache[buttonAction];
 	-- 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
-		-- Update cache if needed...
-		if(not buttonCache[auraID]) then
-			buttonCache[auraID] = {};
-		end
-		local auraCache = buttonCache[auraID];
 		-- 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
-					-- Check cache for a shortcut.
-					if(auraCache[auraActionID] == true and CoreFrame:GetModuleSetting("Buttons", "EnableCache")) then
-						-- Enable glows if the action says so.
-						Modules.Auras:MergeAuraAction(buttonData, auraActionData);
-						-- Fire the OnAuraDisplay event.
-						CoreFrame:FireModuleEvent("OnButtonDisplayAura", buttonID, auraID, auraActionData,
-							auraActionID);
-					else
-						-- 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);
-								-- Cache it.
-								auraCache[auraActionID] = true;
-							end
+					-- 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
@@ -191,50 +180,30 @@ function ModuleFrame:ProcessButtonActions(button)
 end
 --[[
 ----------------------------------------------------------------------------------------------------
-OnUpdateTrigger
+UpdateAllButtons

 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
+function ModuleFrame:UpdateAllButtons()
+	-- Queue all buttons for an update.
+	ButtonQueueAll = true;
+	ButtonsQueued = true;
 end
 --[[
 ----------------------------------------------------------------------------------------------------
-ThrottleUpdates
+UpdateButton

-Throttles further updates if the feature is enabled.
+Registers a single button for an update.
 ----------------------------------------------------------------------------------------------------
 --]]
-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);
+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
 --[[
 ----------------------------------------------------------------------------------------------------
@@ -244,23 +213,46 @@ Acts as our function for throttling update requests. It's called OnUpdate but is
 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 + elapsed;
+	ThrottleTimer = ThrottleTimer + (ButtonsQueued and elapsed or 0);
 	-- 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();
+	-- 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
 --[[
 ----------------------------------------------------------------------------------------------------
@@ -274,7 +266,9 @@ function ModuleFrame:RegisterButtons(key, count)
 	local button = nil;
 	for i=1,(count or 12) do
 		-- Register it.
-		Buttons[key .. i] = _G[key .. i] or true;
+		if(not CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")[key .. i]) then
+			Buttons[key .. i] = _G[key .. i] or true;
+		end
 	end
 end
 --[[
@@ -317,9 +311,13 @@ function ModuleFrame:FixSettings(force)
 			["Throttle"] = 0.05,
 			["RegisterBlizzardButtons"] = true,
 			["ShowBlizzardGlows"] = true,
-			["EnableCache"] = true,
+			["IgnoredButtons"] = {},
 		};
 	end
+	-- Compatibility.
+	if(PowerAurasButtons_SettingsDB["Buttons"]["IgnoredButtons"] == nil) then
+		PowerAurasButtons_SettingsDB["Buttons"]["IgnoredButtons"] = {};
+	end
 end
 --[[
 ----------------------------------------------------------------------------------------------------
@@ -336,6 +334,9 @@ function ModuleFrame:OnInitialize()
 		-- 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
@@ -346,20 +347,29 @@ function ModuleFrame:OnInitialize()
 			-- 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)
-				ModuleFrame:OnButtonUpdate(button);
-			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) then
+	if(CoreFrame:GetModuleSetting("Buttons", "RegisterBlizzardButtons") or Dominos or RazerNaga) then
 		CoreFrame:Debug("Registering Blizzard buttons");
 		ModuleFrame:RegisterButtons("ActionButton");
 		ModuleFrame:RegisterButtons("BonusActionButton");
@@ -368,38 +378,32 @@ function ModuleFrame:OnInitialize()
 		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
+--	-- 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.OnUpdateTrigger);
-	CoreFrame:RegisterModuleEventListener("OnAuraHide", ModuleFrame, ModuleFrame.OnUpdateTrigger);
+	CoreFrame:RegisterModuleEventListener("OnAuraShow", ModuleFrame, ModuleFrame.UpdateAllButtons);
+	CoreFrame:RegisterModuleEventListener("OnAuraHide", ModuleFrame, ModuleFrame.UpdateAllButtons);
 	CoreFrame:RegisterModuleEventListener("OnActionCreate", ModuleFrame);
-	-- Cache clearing functions, ABS fires even if macros are updated!
-	if(CoreFrame:GetModuleSetting("Buttons", "EnableCache") == true) then
-		CoreFrame:RegisterBlizzEventListener("ACTIONBAR_SLOT_CHANGED", ModuleFrame, function(self, id)
-			-- Cache macros only.
-			local buttonType, macroID = GetActionInfo(id);
-			if(buttonType ~= "macro" or not ButtonsBySlot[id]
-				or not CoreFrame:GetModuleSetting("Buttons", "EnableCache")) then return; end
-			-- Make sure table exists.
-			if(not ButtonCache[id]) then
-				ButtonCache[id] = {};
-			else
-				wipe(ButtonCache[id]);
-			end
-			-- Trigger re-update.
-			ModuleFrame:OnButtonUpdate(ButtonsBySlot[id]);
-		end);
-	end
+	-- Updates are throttled and processed in an update loop.
+	ModuleFrame:SetScript("OnUpdate", ModuleFrame.OnUpdate);
 	-- Done.
 	return true;
 end
diff --git a/Modules/ButtonsConfig.lua b/Modules/ButtonsConfig.lua
index 7a06736..369c876 100644
--- a/Modules/ButtonsConfig.lua
+++ b/Modules/ButtonsConfig.lua
@@ -113,24 +113,231 @@ function ModuleFrame:OnCreateInterfaceOptionsFrame(name)
 		-- Save.
 		CoreFrame:SetModuleSetting("Buttons", "ShowBlizzardGlows", self:GetChecked());
 	end);
-	-- And another.
-	InterfaceOptions.Cache = CreateFrame("CheckButton", "PowerAurasButtons_ButtonsCacheActions",
-		InterfaceOptions, "ChatConfigCheckButtonTemplate");
-	InterfaceOptions.Cache:SetPoint("TOPLEFT", InterfaceOptions, "TOPLEFT", 10, -165);
-	PowerAurasButtons_ButtonsCacheActionsText:SetText(CoreFrame.L["Enable Action Cache"]);
-	InterfaceOptions.Cache:SetChecked(
-		CoreFrame:GetModuleSetting("Buttons", "EnableCache"));
-	-- Save on click.
-	InterfaceOptions.Cache:SetScript("OnClick", function(self)
-		-- Requires a reload to take effect, so get a glowbox ready and running.
+--	-- And another.
+--	InterfaceOptions.Cache = CreateFrame("CheckButton", "PowerAurasButtons_ButtonsCacheActions",
+--		InterfaceOptions, "ChatConfigCheckButtonTemplate");
+--	InterfaceOptions.Cache:SetPoint("TOPLEFT", InterfaceOptions, "TOPLEFT", 10, -165);
+--	PowerAurasButtons_ButtonsCacheActionsText:SetText(CoreFrame.L["Enable Action Cache"]);
+--	InterfaceOptions.Cache:SetChecked(
+--		CoreFrame:GetModuleSetting("Buttons", "EnableCache"));
+--	-- Save on click.
+--	InterfaceOptions.Cache:SetScript("OnClick", function(self)
+--		-- Requires a reload to take effect, so get a glowbox ready and running.
+--		Modules.Config:CreateGlowBoxWidget(InterfaceOptions);
+--		-- Save.
+--		CoreFrame:SetModuleSetting("Buttons", "EnableCache", self:GetChecked());
+--	end);
+
+	-- Buttons blacklist.
+	InterfaceOptions.BlacklistTitle = InterfaceOptions:CreateFontString(nil, "ARTWORK",
+		"GameFontNormal");
+	InterfaceOptions.BlacklistTitle:SetText(CoreFrame.L["Registered Buttons"]);
+	InterfaceOptions.BlacklistTitle:SetPoint("TOP", InterfaceOptions, "TOP", 0, -190);
+	-- Make a scrolly area.
+	InterfaceOptions.Buttons = CreateFrame("Frame", nil, InterfaceOptions);
+	InterfaceOptions.Buttons:SetBackdrop({
+		bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+		edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+		tile = true, tileSize = 16, edgeSize = 16,
+		insets = { left = 3, right = 3, top = 5, bottom = 3 }
+	});
+	InterfaceOptions.Buttons:SetBackdropColor(0, 0, 0, 0.75);
+	InterfaceOptions.Buttons:SetBackdropBorderColor(0.4, 0.4, 0.4);
+	InterfaceOptions.Buttons:SetPoint("TOP", InterfaceOptions, "TOP", 0, -205);
+	InterfaceOptions.Buttons:SetHeight(200);
+	InterfaceOptions.Buttons:SetWidth(375);
+	-- List frame needs a scroll frame.
+	InterfaceOptions.Buttons.Scroll = CreateFrame("ScrollFrame",
+		"PowerAurasButtons_ButtonsScrollFrame", InterfaceOptions.Buttons,
+		"UIPanelScrollFrameTemplate");
+	InterfaceOptions.Buttons.Scroll:SetPoint("TOPLEFT", InterfaceOptions.Buttons, "TOPLEFT", 5, -5);
+	InterfaceOptions.Buttons.Scroll:SetPoint("BOTTOMRIGHT", InterfaceOptions.Buttons,
+		"BOTTOMRIGHT", -26, 4);
+	-- Scroll frame needs something to actually scroll.
+	InterfaceOptions.Buttons.List = CreateFrame("Frame", nil, InterfaceOptions.Buttons.Scroll);
+	InterfaceOptions.Buttons.List:SetPoint("TOPLEFT", InterfaceOptions.Buttons.Scroll, "TOPLEFT");
+	-- Height needs to be set.
+	InterfaceOptions.Buttons.List:SetHeight(0);
+	-- The height needs to match the content, but the width can be that of the box...
+	InterfaceOptions.Buttons.List:SetWidth(350);
+	-- Add the list frame as a scroll child of our SUPER SCROLL FRAME.
+	InterfaceOptions.Buttons.Scroll:SetScrollChild(InterfaceOptions.Buttons.List);
+	-- Store the row frames in this table - we'll reuse them as needed.
+	InterfaceOptions.Buttons.List.Items = {};
+	InterfaceOptions.Buttons.List.Rows = {};
+	-- Make a small function, hook it to OnShow. It'll scan the Buttons and update the list.
+	local scanButtons;
+	scanButtons = function()
+		-- Make a table of all Buttons that can be enabled/disabled.
+		wipe(InterfaceOptions.Buttons.List.Items);
+		for buttonID, _ in pairs(Modules.Buttons:GetButtons()) do
+			tinsert(InterfaceOptions.Buttons.List.Items, buttonID);
+		end
+		-- Merge in the configured ones.
+		for buttonID, state in pairs(CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")) do
+			if(not tContains(InterfaceOptions.Buttons.List.Items, buttonID)) then
+				tinsert(InterfaceOptions.Buttons.List.Items, buttonID);
+			end
+		end
+		-- Sort list.
+		sort(InterfaceOptions.Buttons.List.Items);
+		-- Hide existing rows.
+		for _, row in pairs(InterfaceOptions.Buttons.List.Rows) do
+			row:Hide();
+		end
+		-- Using that, fill in the rows.
+		for i, buttonID in pairs(InterfaceOptions.Buttons.List.Items) do
+			-- Make rows dynamically and reuse existing ones.
+			if(not InterfaceOptions.Buttons.List.Rows[i]) then
+				local row = CreateFrame("Frame", nil, InterfaceOptions.Buttons.List);
+				-- Add textures.
+				row.Texture = row:CreateTexture(nil, "BACKGROUND");
+				row.Texture:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight");
+				row.Texture:SetAllPoints(row);
+				row.Texture:SetVertexColor(1, 1, 1, 0.15);
+				-- Height, anchor.
+				row:SetHeight(20);
+				row:SetPoint("TOPLEFT", InterfaceOptions.Buttons.List, "TOPLEFT", 0, -((i-1)*20));
+				row:SetPoint("TOPRIGHT", InterfaceOptions.Buttons.List, "TOPRIGHT", 0, -((i-1)*20));
+				-- Label.
+				row.Label = row:CreateFontString(nil, "ARTWORK", "GameFontNormal");
+				row.Label:SetHeight(20);
+				row.Label:SetPoint("TOPLEFT", row, "TOPLEFT", 10, 0);
+				row.Label:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 10, 0);
+				-- And a delete button.
+				row.Button = CreateFrame("Button", nil, row);
+				row.Button:SetPoint("RIGHT", row, "RIGHT", -2, 0);
+				row.Button:SetWidth(16);
+				row.Button:SetHeight(16);
+				-- Register the row.
+				InterfaceOptions.Buttons.List.Rows[i] = row;
+				-- And when you click, we toggle.
+				row.Button:SetScript("OnClick", function()
+					local id = row.Label:GetText();
+					-- Toggle state.
+					CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")[id] =
+						not CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")[buttonID];
+					-- ReloadUI is needed :)
+					Modules.Config:CreateGlowBoxWidget(InterfaceOptions);
+					-- Rescan.
+					scanButtons();
+				end);
+				-- Tooltip.
+				Modules.Config:RegisterConfigTooltip(row.Button, {
+					override = function()
+						-- Check status.
+						if(not CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")[buttonID]) then
+							GameTooltip:SetText(CoreFrame.L["Disable Button"]);
+							GameTooltip:AddLine(CoreFrame.L["Click to disable this button from being registered and processed."], 1, 1, 1, 1);
+						else
+							GameTooltip:SetText(CoreFrame.L["Enable Button"]);
+							GameTooltip:AddLine(CoreFrame.L["Click to enable this button for processing."], 1, 1, 1, 1);
+						end
+					end
+				});
+			end
+			-- Get row.
+			local row = InterfaceOptions.Buttons.List.Rows[i];
+			-- Set stuff.
+			row.Label:SetText(buttonID);
+			-- Is the button enabled?
+			if(not CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")[buttonID]) then
+				-- Enabled, so show disable stuff and color the background greenish.
+				row.Button:SetNormalTexture("Interface\\FriendsFrame\\StatusIcon-DnD");
+				row.Button:SetHighlightTexture("Interface\\FriendsFrame\\StatusIcon-DnD", "BLEND");
+				row.Button:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5);
+				row.Button:GetHighlightTexture():SetVertexColor(1.0, 1.0, 1.0, 1.0);
+				row.Texture:SetVertexColor(0.3, 0.8, 0.3, 0.6);
+			else
+				-- Disabled. Show enable stuff and color BG red.
+				row.Button:SetNormalTexture("Interface\\FriendsFrame\\StatusIcon-Online");
+				row.Button:SetHighlightTexture("Interface\\FriendsFrame\\StatusIcon-Online",
+					"BLEND");
+				row.Button:GetNormalTexture():SetVertexColor(1.0, 1.0, 1.0, 0.5);
+				row.Button:GetHighlightTexture():SetVertexColor(1.0, 1.0, 1.0, 1.0);
+				row.Texture:SetVertexColor(1.0, 0.5, 0.5, 1.0);
+			end
+			-- Add height to the list.
+			InterfaceOptions.Buttons.List:SetHeight(i*20);
+			row:Show();
+		end
+	end
+	-- Set the script.
+	InterfaceOptions:SetScript("OnShow", scanButtons);
+	-- Optimize!
+	InterfaceOptions.Optimize = CreateFrame("Button", "PowerAurasButtons_OptimizeStuff", InterfaceOptions, "UIPanelButtonTemplate2");
+	InterfaceOptions.Optimize:SetPoint("TOPRIGHT", InterfaceOptions.Buttons, "BOTTOMRIGHT", 0, -5);
+	InterfaceOptions.Optimize:SetSize(118, 23);
+	InterfaceOptions.Optimize:SetText(CoreFrame.L["Optimize"]);
+	InterfaceOptions.Optimize:SetScript("OnClick", function(self)
+		-- Create a copy of the buttons list.
+		local buttons = {};
+		for id, button in pairs(Modules.Buttons:GetButtons()) do
+			-- Resolve global ref if needed.
+			if(button == true and _G[id]) then
+				button = _G[id];
+			end
+			-- Copy entry.
+			if(button and button ~= true) then
+				buttons[id] = button;
+			end
+		end
+		-- Merge in blacklisted ones too.
+		for buttonID, state in pairs(CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons")) do
+			buttons[buttonID] = _G[buttonID] or buttons[buttonID] or nil;
+		end
+		-- Settings table shortcut.
+		local blacklist = CoreFrame:GetModuleSetting("Buttons", "IgnoredButtons");
+		-- Go over all auras and their actions.
+		local settingTables = { PowerAurasButtons_AurasDB, PowerAurasButtons_CharacterAurasDB };
+		for _, settingTable in pairs(settingTables) do
+			for auraID, actions in pairs(settingTable) do
+				for actionID, action in pairs(actions) do
+					-- Sanity check.
+					if(type(action) == "table") then
+						-- Go over remaining buttons.
+						for id, button in pairs(buttons) do
+							-- Make sure it's a valid button.
+							local buttonActionID = button and (button._state_action or button.action);
+							if(type(buttonActionID) == "number") then
+								-- Get action data.
+								local actionType, actionID = GetActionInfo(buttonActionID);
+								-- Is it a macro?
+								if(actionType ~= "macro") then
+									-- Right, valid action?
+									if(actionType == action["type"] and actionID == action["id"]) then
+										-- Enable!
+										buttons[id] = nil;
+										blacklist[id] = false;
+									end
+								else
+									-- Perma-enable!
+									buttons[id] = nil;
+									blacklist[id] = false;
+								end
+							end
+						end
+					end
+				end
+			end
+		end
+		-- Blacklist the rest of the buttons.
+		for id, button in pairs(buttons) do
+			if(button) then
+				blacklist[id] = true;
+			else
+				blacklist[id] = false;
+			end
+		end
+		-- Rescan.
+		scanButtons();
+		-- ReloadUI is needed :)
 		Modules.Config:CreateGlowBoxWidget(InterfaceOptions);
-		-- Save.
-		CoreFrame:SetModuleSetting("Buttons", "EnableCache", self:GetChecked());
 	end);
 	-- Tooltips.
 	Modules.Config:RegisterConfigTooltip(InterfaceOptions.ThrottleSlider, {
 		title = "Update Throttle",
-		text = "Controls the throttle for mass button updates. This affects both " ..
+		text = "Controls the throttle for button updates. This affects both " ..
 			"performance and responsiveness, so leaving it at around 0.05 to 0.1 is a good idea."
 	});
 	Modules.Config:RegisterConfigTooltip(InterfaceOptions.Blizz, {
@@ -142,9 +349,11 @@ function ModuleFrame:OnCreateInterfaceOptionsFrame(name)
 		title = "Show Blizzard Glows |cFFFF0000*BETA*|r",
 		text = "Select this if you want Blizzard's default action button glows to be displayed."
 	});
-	Modules.Config:RegisterConfigTooltip(InterfaceOptions.Cache, {
-		title = "Enable Action Cache",
-		text = "Attempts to cache data to speed up performance, may cause issues."
+	Modules.Config:RegisterConfigTooltip(InterfaceOptions.Optimize, {
+		title = "Optimize |cFFFF0000*BETA*|r",
+		text = "Scans your current configuration and automatically disables any buttons that are not used. " ..
+			"Buttons that contain macros are not disabled with this tool.\n\nHold Shift to also include buttons " ..
+			"that are not visible in the scan."
 	});
 end
 --[[
diff --git a/Modules/Config.lua b/Modules/Config.lua
index fa90da0..0b67bad 100644
--- a/Modules/Config.lua
+++ b/Modules/Config.lua
@@ -141,7 +141,6 @@ function ModuleFrame:CreateInterfaceOptions()
 	end

 	-- Now for the module switcher. Make a title...
-
 	InterfaceOptions.ModulesTitle = InterfaceOptions:CreateFontString(nil, "ARTWORK",
 		"GameFontNormal");
 	InterfaceOptions.ModulesTitle:SetText(L["Module Manager"]);
@@ -966,6 +965,7 @@ function ModuleFrame:OnInitialize()
 		else
 			-- Hide if it's not valid or not open.
 			ActionEditorBase:Hide();
+
 		end
 	end
 	-- Add needed hooks.
@@ -1029,4 +1029,4 @@ function ModuleFrame:OnInitialize()
 	end);
 	-- Done.
 	return true;
-end
\ No newline at end of file
+end
diff --git a/PowerAurasButtons.toc b/PowerAurasButtons.toc
index 71301ad..de05a3b 100644
--- a/PowerAurasButtons.toc
+++ b/PowerAurasButtons.toc
@@ -4,7 +4,7 @@
 ## Title: Power Auras Classic: Buttons
 ## Notes: Allows you to use various displays on action buttons when a Power Auras aura is activated.
 ## Dependencies: PowerAuras
-## OptionalDeps: LibActionButton-1.0, LibSharedMedia-3.0, SharedMedia, LibStub, Bartender4, Dominos
+## OptionalDeps: LibActionButton-1.0, LibSharedMedia-3.0, SharedMedia, LibStub, Bartender4, Dominos, RazerNaga
 ## SavedVariables: PowerAurasButtons_AurasDB, PowerAurasButtons_SettingsDB
 ## SavedVariablesPerCharacter: PowerAurasButtons_CharacterAurasDB