--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--
--|	GypsyMod HotBar - Gypsy_ActionBar.lua
--|	Action button functions
--|	Action bar setting manipulation functions
--| Action bar capsule management functions
--| Action bar drop-down menu functions
--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--

--= Libraries =--

local color = Gypsy_Color:New();
local utility = Gypsy_Utility:New();
local capsule = Gypsy_Capsule:New();
local hotlib = Gypsy_HotLib:New();

-- HotLib label filter setup
hotlib:LoadLabelFilters(HOTBAR_TEXT:Get("labelFilters"));

-- Custom action button color setup
color:Add("ab_lightred", 1.0, 0.5, 0.5);
color:Add("ab_darkred", 1.0, 0.1, 0.1);
color:Add("ab_lightgrey", 0.6);
color:Add("ab_darkgrey", 0.4);
color:Add("ab_darkblue", 0.5, 0.5, 1.0);

--= Variables =--

-- Saved variable shortcut table
local saved = nil;

-- Bar information
local numButtons = 72;
local numButtonsPerBar = 12;
local numBars = 6;

-- Paging information
local numButtonsPerPage = 12;
local numPages = 6;
local maxButtonsPerPage = 12;
local maxPages = 6;
local currentPage = 1;
local actionPrefix = "Gypsy_ActionButton";

-- Docked positioning data
local dockedData = {
	["HORI"] = {
		["BOTTOMRIGHT"] = {
			["point"] = "BOTTOMLEFT";
			["relPoint"] = "TOPLEFT";
		};
		["BOTTOMLEFT"] = {
			["point"] = "BOTTOMLEFT";
			["relPoint"] = "TOPLEFT";
		};
		["TOPRIGHT"] = {
			["point"] = "TOPLEFT";
			["relPoint"] = "BOTTOMLEFT";
		};
		["TOPLEFT"] = {
			["point"] = "TOPLEFT";
			["relPoint"] = "BOTTOMLEFT";
		};		
	};
	["VERT"] = {
		["BOTTOMRIGHT"] = {
			["point"] = "TOPRIGHT";
			["relPoint"] = "TOPLEFT";
		};
		["BOTTOMLEFT"] = {
			["point"] = "TOPLEFT";
			["relPoint"] = "TOPRIGHT";
		};
		["TOPRIGHT"] = {
			["point"] = "TOPRIGHT";
			["relPoint"] = "TOPLEFT";
		};
		["TOPLEFT"] = {
			["point"] = "TOPLEFT";
			["relPoint"] = "TOPRIGHT";
		};
	};
};

--= Helper Functions =--

-- Returns a scaling ratio used for determining capsule size
local function getRatio (size)
	return hotlib:GetScale(size);
end

-- Quick check to determine which saved size property to use
local function getButtonSize (bar)
	if (saved.setScale == 1) then
		return saved.size;
	else
		return saved["actionbar"..bar.."_buttonSize"];
	end
end

-- Calculate the minimum number of buttons to show while keeping display integrity
local function getMinDockedButtons ()
	if (PetHasActionBar() and saved.petactionbar_shown == 1 and saved.petactionbar_docked == 1) then
		return 11;
	elseif (GetNumShapeshiftForms() > 0 and saved.specialactionbar_shown == 1 and saved.specialactionbar_docked == 1) then
		if (saved.bagbar_shown == 1 and saved.bagbar_docked == 1) then
			return GetNumShapeshiftForms() + 1 - 5;
		else
			return GetNumShapeshiftForms() + 1;
		end
	end
	return 0;
end

-- General routine to determine action bar capsule sizes
local function getDistance (dimension, bar)
	if (not dimension or not bar or bar < 1 or bar > numBars) then
		return nil;
	end	

	local size;
	
	if (saved["actionbar"..bar.."_docked"] == 1) then
		size = getButtonSize(1);
	else
		size = getButtonSize(bar);
	end
	
	local ratio = getRatio(size);
	
	if (dimension == "width") then
		if (bar > 1 and saved["actionbar"..bar.."_docked"] == 0) then
			return hotlib:GetGroupWidth(saved["actionbar"..bar.."_orient"], saved["actionbar"..bar.."_numButtons"], size, size, saved.gap * ratio);
		else
			return hotlib:GetGroupWidth(saved.actionbar1_orient, saved.actionbar1_numButtons, size, size, saved.gap * ratio);
		end
	elseif (dimension == "height") then
		if (bar > 1 and saved["actionbar"..bar.."_docked"] == 0) then
			return hotlib:GetGroupHeight(saved["actionbar"..bar.."_orient"], saved["actionbar"..bar.."_numButtons"], size, size, saved.gap * ratio);
		else
			return hotlib:GetGroupHeight(saved.actionbar1_orient, saved.actionbar1_numButtons, size, size, saved.gap * ratio);
		end
	end
	
	return nil;
end

-- Specific calculations for action bar 1 width and height
local function getActionBar1Distances ()
	local width = getDistance("width", 1);	
	local height = getDistance("height", 1);
	local size = getButtonSize(1);
	local adj = 0;
	local count = 0;
	
	for i=2, numBars do
		if (saved["actionbar"..i.."_docked"] == 1 and saved["actionbar"..i.."_shown"] == 1) then
			count = count + 1;
		end
	end
	
	if (saved.petactionbar_docked == 1 and saved.petactionbar_shown == 1 and PetHasActionBar()) then
		if (saved.setScale == 1) then
			adj = adj + saved.size + (saved.gap * getRatio(saved.size));
		else
			adj = adj + saved.petactionbar_buttonSize + (saved.gap * getRatio(saved.petactionbar_buttonSize));
		end
	elseif (saved.specialactionbar_docked == 1 and saved.specialactionbar_shown == 1 and GetNumShapeshiftForms() > 0) then
		if (saved.setScale == 1) then
			adj = adj + saved.size + (saved.gap * getRatio(saved.size));
		else
			adj = adj + saved.specialactionbar_buttonSize + (saved.gap * getRatio(saved.specialactionbar_buttonSize));
		end
	end
	
	if (saved.actionbar1_orient == "HORI") then
		height = height + (size * count) + ((saved.gap * getRatio(size)) * count);
		height = height + adj;
	else
		width = width + (size * count) + ((saved.gap * getRatio(size)) * count);
		width = width + adj;
	end
	
	if (saved.bagbar_docked == 1 and saved.bagbar_shown == 1) then
		local num
		
		if (saved.bagbar_backpackOnly == 1) then
			num = 1;
		else
			num = 5;
		end
		
		if (saved.actionbar1_orient == "HORI") then
			width = width + hotlib:GetGroupWidth(saved.actionbar1_orient, num, size, size, saved.gap * getRatio(size));
			width = width + (saved.gap * getRatio(size));
			height = getDistance("height", 1);
		else
			width = getDistance("width", 1);
			height = height + hotlib:GetGroupHeight(saved.actionbar1_orient, num, size, size, saved.gap * getRatio(size));
			height = height + (saved.gap * getRatio(size));
		end
	end
	
	return width, height;
end

-- General routine to update button scaling, called with the update function and when UIParent scale changes
local function generalizedScale (bar)
	local first = ((bar - 1) * numButtonsPerBar) + 1;
	local last = bar * numButtonsPerBar;
	local size;
	
	if (saved["actionbar"..bar.."_docked"] == 0 or saved["actionbar"..(bar-1).."_docked"] == 0 or saved.actionbar1_shown == 0) then
		size = getButtonSize(bar);
	else
		size = getButtonSize(1);
	end
	
	for i=first, last do
		hotlib:ScaleButton(getglobal(actionPrefix..i), size);
	end
end

-- General routine to update positioning and display properties for bars 2-5
local function generalizedUpdate (bar)
	Gypsy_ActionBar_ValidateSettingsSingle(bar);
	
	local keyword = "actionbar"..bar.."_";
	local first = ((bar - 1) * numButtonsPerBar) + 1;
	local last = bar * numButtonsPerBar;
	local frame = getglobal("Gypsy_ActionBar"..bar.."_Capsule");
	local anchorFrame = getglobal(actionPrefix..first);
	local lastBar = bar - 1;

	if (saved.enabled == 1 and saved[keyword.."shown"] == 1) then
		local data, numShown, orient, size;
		
		if (saved[keyword.."docked"] == 0 or saved["actionbar"..lastBar.."_docked"] == 0 or saved.actionbar1_shown == 0) then
			numShown = saved[keyword.."numButtons"];
			orient = saved[keyword.."orient"];
			size = getButtonSize(bar);
			
			capsule:Enable(frame);
			
			if (not frame:IsUserPlaced()) then
				frame:ClearAllPoints();
				frame:SetPoint("BOTTOM", "UIParent", "BOTTOM", 0, (getDistance("height", bar) * bar) + (capsule.padding * ((bar-1) * 2)));
			end
						
			anchorFrame:ClearAllPoints();
			anchorFrame:SetPoint("TOPLEFT", frame:GetName(), "TOPLEFT", capsule.padding, -capsule.padding);
		else
			numShown = saved.actionbar1_numButtons;
			orient = saved.actionbar1_orient;
			size = getButtonSize(1);
			
			capsule:Disable(frame);
			
			if (Gypsy_ActionBar1_Capsule.quadrant) then
				data = dockedData[orient][Gypsy_ActionBar1_Capsule.quadrant];
				
				local x = 0;
				local y = 0;
				
				if (orient == "HORI") then
					if (strfind(Gypsy_ActionBar1_Capsule.quadrant, "TOP")) then
						y = -saved.gap;
					else
						y = saved.gap;
					end
				else
					if (strfind(Gypsy_ActionBar1_Capsule.quadrant, "LEFT")) then
						x = saved.gap;
					else
						x = -saved.gap;
					end
				end
				
				anchorFrame:ClearAllPoints();
				anchorFrame:SetPoint(data.point, actionPrefix..first - numButtonsPerBar, data.relPoint, x, y);
			end
		end
		
		hotlib:UpdateButtonGrid(getglobal(actionPrefix..first), saved.showPlaceholders);
		hotlib:UpdateButtonHotkey(getglobal(actionPrefix..first));
		hotlib:ShowButton(getglobal(actionPrefix..first));
		
		for i=first+1, last do
			if (i <= numShown + ((bar - 1) * numButtonsPerBar)) then
				hotlib:UpdateButtonGrid(getglobal(actionPrefix..i), saved.showPlaceholders);
				hotlib:UpdateButtonHotkey(getglobal(actionPrefix..i));
				hotlib:ShowButton(getglobal(actionPrefix..i), orient, saved.gap, actionPrefix..i-1);
			else
				hotlib:HideButton(getglobal(actionPrefix..i));
			end
		end
		
		generalizedScale(bar);
		
		if (frame.initialized and frame.enabled == 1) then
			frame.ratio = getRatio(size);
			frame.width = getDistance("width", bar);
			frame.height = getDistance("height", bar);
			capsule:Size(frame);
			if (frame.orient ~= orient) then
				capsule:UpdateOrientation(frame, orient);
			end
		end		
	else
		capsule:Disable(frame);
		hotlib:HideGroup(actionPrefix, first, last);
	end
end

local actionButtonDownOriginal = ActionButtonDown;
local actionButtonUpOriginal = ActionButtonUp;

-- Hook default action button down/up functions to utilize the default 1-12 bindings for action bar 1
local function actionButtonDownHook (id)
	if (saved and saved.enabled == 1 and id <= 12) then
		Gypsy_ActionButton_Down(id);
	else
		actionButtonDownOriginal(id);
	end
end

local function actionButtonUpHook (id, onSelf)	
	if (saved and saved.enabled == 1 and id <= 12) then
		Gypsy_ActionButton_Up(id);
	else
		actionButtonUpOriginal(id, onSelf);
	end
end

--= ActionBar Functions =--

-- Config loading and capsule registration
function Gypsy_ActionBar_Initialize (player)
	Gypsy_ActionBar_LoadConfig(player);

	--= Capsule registrations =--
	
	-- Action bar 1, the main capsule
	local args = {};
	args.frame = "Gypsy_ActionBar1_Capsule";
	if (saved.enabled == 0 or saved.actionbar1_shown == 0) then
		args.enabled = 0;
	end
	args.locked = saved.actionbar1_locked;
	args.doDir = 0;
	args.orient = saved.actionbar1_orient;
	args.initFunc = "Gypsy_ActionBar1_Update";
	args.orientFunc = "Gypsy_ActionBar1_Update";
	args.ordFunc = "Gypsy_ActionBar1_Update";
	args.menuFunc = "Gypsy_ActionBar1_DropDown_Toggle";
	args.saveFunc = "Gypsy_ActionBar_SaveLocking";
	args.title = HOTBAR_TEXT:Get("hotbar");
	args.tooltipTitle = HOTBAR_TEXT:Get("hotbar");
	args.tooltipText = HOTBAR_TEXT:Get("capsuleTooltip");
	args.ratio = getRatio(getButtonSize(1));
	args.width, args.height = getActionBar1Distances();
	args.lockButton = Gypsy_HotBar_LockButton;
	capsule:Register(args);
	
	-- Action bar 2
	args = {};
	args.frame = "Gypsy_ActionBar2_Capsule";
	if (saved.enabled == 0 or saved.actionbar2_shown == 0 or saved.actionbar2_docked == 1) then
		args.enabled = 0;
	end
	args.locked = saved.actionbar2_locked;
	args.doDir = 0;
	if (saved.actionbar2_docked == 1) then
		args.orient = saved.actionbar1_orient
	else
		args.orient = saved.actionbar2_orient;
	end
	args.initFunc = "Gypsy_ActionBar2_Update";
	args.orientFunc = "Gypsy_ActionBar2_Update";
	args.ordFunc = "Gypsy_ActionBar2_Update";
	args.menuFunc = "Gypsy_ActionBar2_DropDown_Toggle";
	args.saveFunc = "Gypsy_ActionBar_SaveLocking";
	args.title = HOTBAR_TEXT:Get("actionbar2");
	args.tooltipTitle = HOTBAR_TEXT:Get("actionbar2");
	args.tooltipText = HOTBAR_TEXT:Get("capsuleTooltip");
	args.ratio = getRatio(getButtonSize(2));
	args.width = getDistance("width", 2);
	args.height = getDistance("height", 2);
	capsule:Register(args);
	
	-- Action bar 3
	args = {};
	args.frame = "Gypsy_ActionBar3_Capsule";
	if (saved.enabled == 0 or saved.actionbar3_shown == 0 or saved.actionbar3_docked == 1) then
		args.enabled = 0;
	end
	args.locked = saved.actionbar3_locked;
	args.doDir = 0;
	if (saved.actionbar3_docked == 1) then
		args.orient = saved.actionbar1_orient
	else
		args.orient = saved.actionbar3_orient;
	end
	args.initFunc = "Gypsy_ActionBar3_Update";
	args.orientFunc = "Gypsy_ActionBar3_Update";
	args.ordFunc = "Gypsy_ActionBar3_Update";
	args.menuFunc = "Gypsy_ActionBar3_DropDown_Toggle";
	args.saveFunc = "Gypsy_ActionBar_SaveLocking";
	args.title = HOTBAR_TEXT:Get("actionbar3");
	args.tooltipTitle = HOTBAR_TEXT:Get("actionbar3");
	args.tooltipText = HOTBAR_TEXT:Get("capsuleTooltip");
	args.ratio = getRatio(getButtonSize(3));
	args.width = getDistance("width", 3);
	args.height = getDistance("height", 3);
	capsule:Register(args);	

	-- Action bar 4
	args = {};
	args.frame = "Gypsy_ActionBar4_Capsule";
	if (saved.enabled == 0 or saved.actionbar4_shown == 0 or saved.actionbar4_docked == 1) then
		args.enabled = 0;
	end
	args.locked = saved.actionbar4_locked;
	args.doDir = 0;
	if (saved.actionbar4_docked == 1) then
		args.orient = saved.actionbar1_orient
	else
		args.orient = saved.actionbar4_orient;
	end
	args.initFunc = "Gypsy_ActionBar4_Update";
	args.orientFunc = "Gypsy_ActionBar4_Update";
	args.ordFunc = "Gypsy_ActionBar4_Update";
	args.menuFunc = "Gypsy_ActionBar4_DropDown_Toggle";
	args.saveFunc = "Gypsy_ActionBar_SaveLocking";
	args.title = HOTBAR_TEXT:Get("actionbar4");
	args.tooltipTitle = HOTBAR_TEXT:Get("actionbar4");
	args.tooltipText = HOTBAR_TEXT:Get("capsuleTooltip");
	args.ratio = getRatio(getButtonSize(4));
	args.width = getDistance("width", 4);
	args.height = getDistance("height", 4);
	capsule:Register(args);
	
	-- Action bar 5
	args = {};
	args.frame = "Gypsy_ActionBar5_Capsule";
	if (saved.enabled == 0 or saved.actionbar5_shown == 0 or saved.actionbar5_docked == 1) then
		args.enabled = 0;
	end
	args.locked = saved.actionbar5_locked;
	args.doDir = 0;
	if (saved.actionbar5_docked == 1) then
		args.orient = saved.actionbar1_orient
	else
		args.orient = saved.actionbar5_orient;
	end
	args.initFunc = "Gypsy_ActionBar5_Update";
	args.orientFunc = "Gypsy_ActionBar5_Update";
	args.ordFunc = "Gypsy_ActionBar5_Update";
	args.menuFunc = "Gypsy_ActionBar5_DropDown_Toggle";
	args.saveFunc = "Gypsy_ActionBar_SaveLocking";
	args.title = HOTBAR_TEXT:Get("actionbar5");
	args.tooltipTitle = HOTBAR_TEXT:Get("actionbar5");
	args.tooltipText = HOTBAR_TEXT:Get("capsuleTooltip");
	args.ratio = getRatio(getButtonSize(5));
	args.width = getDistance("width", 5);
	args.height = getDistance("height", 5);
	capsule:Register(args);
	
	-- Action bar 6
	args = {};
	args.frame = "Gypsy_ActionBar6_Capsule";
	if (saved.enabled == 0 or saved.actionbar6_shown == 0 or saved.actionbar6_docked == 1) then
		args.enabled = 0;
	end
	args.locked = saved.actionbar6_locked;
	args.doDir = 0;
	if (saved.actionbar6_docked == 1) then
		args.orient = saved.actionbar1_orient
	else
		args.orient = saved.actionbar6_orient;
	end
	args.initFunc = "Gypsy_ActionBar6_Update";
	args.orientFunc = "Gypsy_ActionBar6_Update";
	args.ordFunc = "Gypsy_ActionBar6_Update";
	args.menuFunc = "Gypsy_ActionBar6_DropDown_Toggle";
	args.saveFunc = "Gypsy_ActionBar_SaveLocking";
	args.title = HOTBAR_TEXT:Get("actionbar6");
	args.tooltipTitle = HOTBAR_TEXT:Get("actionbar6");
	args.tooltipText = HOTBAR_TEXT:Get("capsuleTooltip");
	args.ratio = getRatio(getButtonSize(6));
	args.width = getDistance("width", 6);
	args.height = getDistance("height", 6);
	capsule:Register(args);
	
	-- Drop down menu initializations
	for i=1, numBars do
		UIDropDownMenu_Initialize(getglobal("Gypsy_ActionBar"..i.."_DropDown"), getglobal("Gypsy_ActionBar"..i.."_UpdateDropDown"), "MENU");
	end
	
	-- Add hooks
	if (saved.enabled == 1) then
		utility:Hook("replace", "ActionButtonDown", actionButtonDownHook);
		utility:Hook("replace", "ActionButtonUp", actionButtonUpHook);
	end
	
	-- Initial paging mode
	Gypsy_ActionBar_UpdatePagingMode();
end

-- Load player's settings, not only an init function
function Gypsy_ActionBar_LoadConfig (player)
	saved = GYPSY_SAVED_HOTBAR[player];
end

-- Check and correct all settings
function Gypsy_ActionBar_ValidateSettings ()
	-- If a bar of a lower order is not shown, then you can not dock those higher
	--[[local undock = nil;
	for i=1, numBars do
		if (undock) then
			saved["actionbar"..i.."_docked"] = 0;
		elseif (saved["actionbar"..i.."_shown"] == 0) then
			undock = 1;
		end
	end
	
	-- By the same token, if one is not docked, then you can not dock others higher
	undock = nil;
	for i=2, numBars do
		if (undock) then
			saved["actionbar"..i.."_docked"] = 0;
		elseif (saved["actionbar"..i.."_docked"] == 0) then
			undock = 1;
		end
	end]]
	
	for i=2, 6 do
		Gypsy_ActionBar_ValidateSettingsSingle (i);
	end
	
	-- Reliant components
	Gypsy_BagBar_ValidateSettings();
	Gypsy_MenuBar_ValidateSettings();
	Gypsy_PetActionBar_ValidateSettings();
	Gypsy_SpecialActionBar_ValidateSettings();
end

function Gypsy_ActionBar_ValidateSettingsSingle (bar)
	if (saved["actionbar"..(bar-1).."_shown"] == 0 and saved["actionbar"..bar.."_shown"] == 1) then
		saved["actionbar"..bar.."_docked"] = 0;
	elseif (saved["actionbar"..(bar-1).."_docked"] == 0 and saved["actionbar"..bar.."_shown"] == 1) then
		saved["actionbar"..bar.."_docked"] = 0;
	end
end

-- All-bar update
function Gypsy_ActionBar_Update ()
	Gypsy_ActionBar1_Update();
	Gypsy_ActionBar2_Update();
	Gypsy_ActionBar3_Update();
	Gypsy_ActionBar4_Update();
	Gypsy_ActionBar5_Update();
	Gypsy_ActionBar6_Update();
	
	-- Fair idea, but UnHook could cause compatibility problems
	if (saved.enabled == 1) then
		-- May safely attempt to hook an already hooked function
		utility:Hook("replace", "ActionButtonDown", actionButtonDownHook);
		utility:Hook("replace", "ActionButtonUp", actionButtonUpHook);
	--else
	--	utility:UnHook("ActionButtonDown");
	--	utility:UnHook("ActionButtonUp");
	end
end

-- All-bar scale
function Gypsy_ActionBar_Scale ()
	for i=1, 6 do
		if (saved["actionbar"..i.."_shown"] == 1) then
			generalizedScale(i);
		end
	end
end

-- All-bar reset
function Gypsy_ActionBar_Reset ()
	Gypsy_ActionBar1_Reset();
	Gypsy_ActionBar2_Reset();
	Gypsy_ActionBar3_Reset();
	Gypsy_ActionBar4_Reset();
	Gypsy_ActionBar5_Reset();
	Gypsy_ActionBar6_Reset();
end

-- Action bar 1 specific update since it's the "main bar" upon which everything stands
function Gypsy_ActionBar1_Update ()
	if (saved.enabled == 1 and saved.actionbar1_shown == 1) then
		capsule:Enable(Gypsy_ActionBar1_Capsule);
		
		-- Position action button 1 to the capsule, all other buttons anchor off of this
		Gypsy_ActionButton1:ClearAllPoints();
		
		if (saved.actionbar1_orient == "HORI") then			
			if (strfind(Gypsy_ActionBar1_Capsule.quadrant, "TOP")) then
				Gypsy_ActionButton1:SetPoint("TOPLEFT", "Gypsy_ActionBar1_Capsule", "TOPLEFT", capsule.padding, -capsule.padding);
			else
				Gypsy_ActionButton1:SetPoint("BOTTOMLEFT", "Gypsy_ActionBar1_Capsule", "BOTTOMLEFT", capsule.padding, capsule.padding);
			end
		else
			if (strfind(Gypsy_ActionBar1_Capsule.quadrant, "LEFT")) then
				Gypsy_ActionButton1:SetPoint("TOPLEFT", "Gypsy_ActionBar1_Capsule", "TOPLEFT", capsule.padding, -capsule.padding);
			else
				Gypsy_ActionButton1:SetPoint("TOPRIGHT", "Gypsy_ActionBar1_Capsule", "TOPRIGHT", -capsule.padding, -capsule.padding);
			end
		end
		
		-- Managing settings here, the first button will never be hidden
		local size = getButtonSize(1);
		
		local numButtonsShown = saved.actionbar1_numButtons;
		
		if (getMinDockedButtons() > numButtonsShown) then
			numButtonsShown = getMinDockedButtons();
		end
		
		hotlib:UpdateButtonGrid(Gypsy_ActionButton1, saved.showPlaceholders);
		hotlib:UpdateButtonHotkey(Gypsy_ActionButton1);
		hotlib:ShowButton(Gypsy_ActionButton1);
					
		for i=2, numButtonsPerBar do
			if (i <= numButtonsShown) then
				hotlib:UpdateButtonGrid(getglobal(actionPrefix..i), saved.showPlaceholders);
				hotlib:UpdateButtonHotkey(getglobal(actionPrefix..i));
				hotlib:ShowButton(getglobal(actionPrefix..i), saved.actionbar1_orient, saved.gap, actionPrefix..i-1);
			else
				hotlib:HideButton(getglobal(actionPrefix..i));
			end
		end
		
		generalizedScale(1);
		
		-- This is not set the first time this function is run upon initialization, as the library does all this for us
		if (Gypsy_ActionBar1_Capsule.initialized) then
			Gypsy_ActionBar1_Capsule.ratio = getRatio(size);
			Gypsy_ActionBar1_Capsule.width, Gypsy_ActionBar1_Capsule.height = getActionBar1Distances();
			capsule:Size(Gypsy_ActionBar1_Capsule);
		end
		
		-- And finally position the capsule itself if needed
		if (not Gypsy_ActionBar1_Capsule:IsUserPlaced()) then
			Gypsy_ActionBar1_Capsule:ClearAllPoints();				
			Gypsy_ActionBar1_Capsule:SetPoint("BOTTOM", "UIParent", "BOTTOM");
		end
	else
		capsule:Disable(Gypsy_ActionBar1_Capsule);
		hotlib:HideGroup(actionPrefix, 1, 12);
	end
	
	-- Need to update all other components due to docking
	if (saved.actionbar2_shown == 1 and (saved.actionbar2_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_ActionBar2_Update();
	end
	if (saved.actionbar3_shown == 1 and (saved.actionbar3_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_ActionBar3_Update();
	end
	if (saved.actionbar4_shown == 1 and (saved.actionbar4_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_ActionBar4_Update();
	end
	if (saved.actionbar5_shown == 1 and (saved.actionbar5_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_ActionBar5_Update();
	end
	if (saved.actionbar6_shown == 1 and (saved.actionbar6_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_ActionBar6_Update();
	end
	if (saved.bagbar_shown == 1 and (saved.bagbar_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_BagBar_Update();
	end
	if (saved.petactionbar_shown == 1 and (saved.petactionbar_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_PetActionBar_Update();
	end
	if (saved.specialactionbar_shown == 1 and (saved.specialactionbar_docked == 1 or saved.actionbar1_shown == 0)) then
		Gypsy_SpecialActionBar_Update();
	end
end

-- Auxiliary function to call an action bar 1 capsule size check without looping updates
function Gypsy_ActionBar1_UpdateSize ()
	if (Gypsy_ActionBar1_Capsule.initialized) then
		Gypsy_ActionBar1_Capsule.ratio = getRatio(getButtonSize(1));
		Gypsy_ActionBar1_Capsule.width, Gypsy_ActionBar1_Capsule.height = getActionBar1Distances();
		capsule:Size(Gypsy_ActionBar1_Capsule);
	end
end

function Gypsy_ActionBar2_Update ()
	generalizedUpdate(2);
end

function Gypsy_ActionBar3_Update ()
	generalizedUpdate(3);
end

function Gypsy_ActionBar4_Update ()
	generalizedUpdate(4);
end

function Gypsy_ActionBar5_Update ()
	generalizedUpdate(5);
end

function Gypsy_ActionBar6_Update ()
	generalizedUpdate(6);
end

function Gypsy_ActionBar1_Reset ()
	Gypsy_ActionBar1_Capsule:SetUserPlaced(0);
end

function Gypsy_ActionBar2_Reset ()
	Gypsy_ActionBar2_Capsule:SetUserPlaced(0);
end

function Gypsy_ActionBar3_Reset ()
	Gypsy_ActionBar3_Capsule:SetUserPlaced(0);
end

function Gypsy_ActionBar4_Reset ()
	Gypsy_ActionBar4_Capsule:SetUserPlaced(0);
end

function Gypsy_ActionBar5_Reset ()
	Gypsy_ActionBar5_Capsule:SetUserPlaced(0);
end

function Gypsy_ActionBar6_Reset ()
	Gypsy_ActionBar6_Capsule:SetUserPlaced(0);
end

-- Lock save call-back
function Gypsy_ActionBar_SaveLocking (frame)
	local name = frame:GetName();
	name = gsub(name, "Gypsy_", "");
	name = gsub(name, "_Capsule", "");
	name = string.lower(name);
	
	saved[name.."_locked"] = frame.locked;
	saved.locked = Gypsy_Capsule.locked;
end

-- Global options execution callbacks

function Gypsy_ActionBar_UpdateButtons ()
	hotlib:UpdateGroup(actionPrefix, 1, numButtons);
end

function Gypsy_ActionBar_UpdateButtonCounts ()
	hotlib:UpdateGroupCount(actionPrefix, 1, numButtons);
end

function Gypsy_ActionBar_UpdateButtonGrids ()
	hotlib:UpdateGroupGrid(actionPrefix, 1, numButtons, saved.showPlaceholders, 1);
end

function Gypsy_ActionBar_UpdateButtonHotkeys ()
	hotlib:UpdateGroupHotkey(actionPrefix, 1, numButtons);
end

function Gypsy_ActionBar_UpdateButtonScales ()
	if (saved.setScale == 1) then
		hotlib:ScaleGroup(actionPrefix, 1, numButtons, saved.size);
	else
		hotlib:ScaleGroup(actionPrefix, 1, 12, saved.actionbar1_buttonSize);
		hotlib:ScaleGroup(actionPrefix, 13, 24, saved.actionbar2_buttonSize);
		hotlib:ScaleGroup(actionPrefix, 25, 36, saved.actionbar3_buttonSize);
		hotlib:ScaleGroup(actionPrefix, 37, 48, saved.actionbar4_buttonSize);
		hotlib:ScaleGroup(actionPrefix, 49, 60, saved.actionbar5_buttonSize);
		hotlib:ScaleGroup(actionPrefix, 61, 72, saved.actionbar6_buttonSize);
	end
end

function Gypsy_ActionBar_UpdatePagingMode ()
	if (saved.pagingMode == "disallow") then
		numPages = maxPages;
		numButtonsPerPage = maxButtonsPerPage;
		currentPage = 1;
	else
		numPages = maxPages / tonumber(saved.pagingMode);
		numButtonsPerPage = numButtons / numPages;
	end
	ChangeActionBarPage();
end

-- So much nicer than in 0.90
function Gypsy_ActionBar_QuickPage (state, modKey)
	if (saved.enabled == 0 or saved.useQuickPage == 0 or (saved.useQuickPageModKey == 1 and not modKey)) then
		return;
	end
	
	if (state == "down") then
		CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE + 1;
		
		if (CURRENT_ACTIONBAR_PAGE > maxPages) then
			CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE - maxPages;
		end
		
		ChangeActionBarPage();
	elseif (state == "up" and saved.quickPageSnapBack == 1) then
		CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE - 1;
		
		if (CURRENT_ACTIONBAR_PAGE == 0) then
			CURRENT_ACTIONBAR_PAGE = CURRENT_ACTIONBAR_PAGE + maxPages;
		end
		
		ChangeActionBarPage();
	end
end

-- Manual show for those foolish enough to hide action bar 1!
function Gypsy_ActionBar1_Show ()
	if (saved.actionbar1_shown == 0) then
		saved.actionbar1_shown = 1;
		Gypsy_ActionBar1_Update();
	end
end

--= DropDown Functions =--

function Gypsy_ActionBar1_DropDown_OnShow ()
	UIDropDownMenu_Initialize(this, Gypsy_ActionBar1_UpdateDropDown, "MENU");
end

function Gypsy_ActionBar2_DropDown_OnShow ()
	UIDropDownMenu_Initialize(this, Gypsy_ActionBar2_UpdateDropDown, "MENU");
end

function Gypsy_ActionBar3_DropDown_OnShow ()
	UIDropDownMenu_Initialize(this, Gypsy_ActionBar3_UpdateDropDown, "MENU");
end

function Gypsy_ActionBar4_DropDown_OnShow ()
	UIDropDownMenu_Initialize(this, Gypsy_ActionBar4_UpdateDropDown, "MENU");
end

function Gypsy_ActionBar5_DropDown_OnShow ()
	UIDropDownMenu_Initialize(this, Gypsy_ActionBar5_UpdateDropDown, "MENU");
end

function Gypsy_ActionBar6_DropDown_OnShow ()
	UIDropDownMenu_Initialize(this, Gypsy_ActionBar6_UpdateDropDown, "MENU");
end

function Gypsy_ActionBar1_DropDown_Toggle ()
	hotlib:ToggleDropDown("Gypsy_ActionBar1");
end

function Gypsy_ActionBar2_DropDown_Toggle ()
	hotlib:ToggleDropDown("Gypsy_ActionBar2");
end

function Gypsy_ActionBar3_DropDown_Toggle ()
	hotlib:ToggleDropDown("Gypsy_ActionBar3");
end

function Gypsy_ActionBar4_DropDown_Toggle ()
	hotlib:ToggleDropDown("Gypsy_ActionBar4");
end

function Gypsy_ActionBar5_DropDown_Toggle ()
	hotlib:ToggleDropDown("Gypsy_ActionBar5");
end

function Gypsy_ActionBar6_DropDown_Toggle ()
	hotlib:ToggleDropDown("Gypsy_ActionBar6");
end

local function loadOrientationMenu (bar, level)
	local barCaps = gsub(bar, "bar", "Bar");
	barCaps = string.upper(strsub(barCaps, 1, 1))..strsub(barCaps, 2);
	
	local frame = getglobal("Gypsy_"..barCaps.."_Capsule");
	
	local info = {};
	info.text = HOTBAR_TEXT:Get("horizontal");
	if (saved[bar.."_orient"] == "HORI") then
		info.checked = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_orient"] = "HORI";
			capsule:UpdateOrientation(frame, "HORI");
		end
	end
	UIDropDownMenu_AddButton(info, level);
	
	info = {};
	info.text = HOTBAR_TEXT:Get("vertical");
	if (saved[bar.."_orient"] == "VERT") then
		info.checked = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_orient"] = "VERT";
			capsule:UpdateOrientation(frame, "VERT");
			
		end
	end
	UIDropDownMenu_AddButton(info, level);
end

local function loadNumButtonsMenu (bar, level)
	local barCaps = gsub(bar, "bar", "Bar");
	barCaps = string.upper(strsub(barCaps, 1, 1))..strsub(barCaps, 2);

	local limit;
	
	if (bar == "actionbar1") then
		limit = getMinDockedButtons();
	else
		limit = 0;
	end
	
	local info = {};
	info.text = 1;
	if (saved[bar.."_numButtons"] == 1) then
		info.checked = 1;
	end
	if (limit > 1) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 1;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 2;
	if (saved[bar.."_numButtons"] == 2) then
		info.checked = 1;
	end
	if (limit > 2) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 2;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 3;
	if (saved[bar.."_numButtons"] == 3) then
		info.checked = 1;
	end
	if (limit > 3) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 3;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 4;
	if (saved[bar.."_numButtons"] == 4) then
		info.checked = 1;
	end
	if (limit > 4) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 4;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 5;
	if (saved[bar.."_numButtons"] == 5) then
		info.checked = 1;
	end
	if (limit > 5) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 5;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 6;
	if (saved[bar.."_numButtons"] == 6) then
		info.checked = 1;
	end
	if (limit > 6) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 6;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 7;
	if (saved[bar.."_numButtons"] == 7) then
		info.checked = 1;
	end
	if (limit > 7) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 7;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 8;
	if (saved[bar.."_numButtons"] == 8) then
		info.checked = 1;
	end
	if (limit > 8) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 8;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 9;
	if (saved[bar.."_numButtons"] == 9) then
		info.checked = 1;
	end
	if (limit > 9) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 9;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 10;
	if (saved[bar.."_numButtons"] == 10) then
		info.checked = 1;
	end
	if (limit > 10) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 10;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 11;
	if (saved[bar.."_numButtons"] == 11) then
		info.checked = 1;
	end
	if (limit > 11) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 11;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = 12;
	if (saved[bar.."_numButtons"] == 12) then
		info.checked = 1;
	end
	if (limit > 12) then
		info.disabled = 1;
	end
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_numButtons"] = 12;
			Gypsy_ActionBar_Update();
		end
	end
	UIDropDownMenu_AddButton(info, level);
end

local function loadButtonSizeMenu (bar, level)
	local barCaps = gsub(bar, "bar", "Bar");
	barCaps = string.upper(strsub(barCaps, 1, 1))..strsub(barCaps, 2);

	local info = {};
	info.text = "18"..HOTBAR_TEXT:Get("px");
	if (saved[bar.."_buttonSize"] == 18) then
		info.checked = 1;
	end
	info.value = "Gypsy_"..barCaps.."_Update";
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_buttonSize"] = 18;
			if (saved[bar.."_docked"] == 1) then
				Gypsy_ActionBar1_Update();
			else
				getglobal(this.value)();
			end
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = "24"..HOTBAR_TEXT:Get("px");
	if (saved[bar.."_buttonSize"] == 24) then
		info.checked = 1;
	end
	info.value = "Gypsy_"..barCaps.."_Update";
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_buttonSize"] = 24;
			if (saved[bar.."_docked"] == 1) then
				Gypsy_ActionBar1_Update();
			else
				getglobal(this.value)();
			end
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = "30"..HOTBAR_TEXT:Get("px");
	if (saved[bar.."_buttonSize"] == 30) then
		info.checked = 1;
	end
	info.value = "Gypsy_"..barCaps.."_Update";
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_buttonSize"] = 30;
			if (saved[bar.."_docked"] == 1) then
				Gypsy_ActionBar1_Update();
			else
				getglobal(this.value)();
			end
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = "36"..HOTBAR_TEXT:Get("px");
	if (saved[bar.."_buttonSize"] == 36) then
		info.checked = 1;
	end
	info.value = "Gypsy_"..barCaps.."_Update";
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_buttonSize"] = 36;
			if (saved[bar.."_docked"] == 1) then
				Gypsy_ActionBar1_Update();
			else
				getglobal(this.value)();
			end
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = "42"..HOTBAR_TEXT:Get("px");
	if (saved[bar.."_buttonSize"] == 42) then
		info.checked = 1;
	end
	info.value = "Gypsy_"..barCaps.."_Update";
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_buttonSize"] = 42;
			if (saved[bar.."_docked"] == 1) then
				Gypsy_ActionBar1_Update();
			else
				getglobal(this.value)();
			end
		end
	end
	UIDropDownMenu_AddButton(info, level);
	info = {};
	info.text = "48"..HOTBAR_TEXT:Get("px");
	if (saved[bar.."_buttonSize"] == 48) then
		info.checked = 1;
	end
	info.value = "Gypsy_"..barCaps.."_Update";
	info.func = function ()
		if (not this.checked) then
			saved[bar.."_buttonSize"] = 48;
			if (saved[bar.."_docked"] == 1) then
				Gypsy_ActionBar1_Update();
			else
				getglobal(this.value)();
			end
		end
	end
	UIDropDownMenu_AddButton(info, level);
end

local function loadActionBar1Menu (level)
	-- Show/hide
	local info = {};
	info.text = HOTBAR_TEXT:Get("show");
	info.tooltipTitle = HOTBAR_TEXT:Get("hideActionBar1WarningTitle");
	info.tooltipText = HOTBAR_TEXT:Get("hideActionBar1WarningText");
	if (saved.actionbar1_shown == 1) then
		info.checked = 1;
	end
	info.func = function ()
		if (this.checked) then
			saved.actionbar1_shown = 0;
		else
			saved.actionbar1_shown = 1;
		end
		Gypsy_ActionBar_ValidateSettings();
		Gypsy_ActionBar_Update();
		Gypsy_BagBar_Update();
		Gypsy_PetActionBar_Update();
		Gypsy_SpecialActionBar_Update();
		CloseDropDownMenus();
	end
	UIDropDownMenu_AddButton(info, level);
	-- Allow paging
	info = {};
	info.text = HOTBAR_TEXT:Get("allowPaging");
	if (saved.actionbar1_allowPaging == 1) then
		info.checked = 1;
	end
	info.func = function ()
		if (this.checked) then
			saved.actionbar1_allowPaging = 0;
		else
			saved.actionbar1_allowPaging = 1;
		end
		ChangeActionBarPage();
	end
	if (saved.actionbar1_shown == 0) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Orientation
	info = {};
	info.text = HOTBAR_TEXT:Get("orientation");
	info.hasArrow = 1;
	info.notCheckable = 1;
	info.value = "actionbar1_orientation";
	if (saved.actionbar1_shown == 0) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Number of buttons
	info = {};
	info.text = HOTBAR_TEXT:Get("buttonsShown");
	info.hasArrow = 1;
	info.notCheckable = 1;
	info.value = "actionbar1_numbuttons";
	if (saved.actionbar1_shown == 0) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Button size
	info = {};
	info.text = HOTBAR_TEXT:Get("buttonSize");
	info.hasArrow = 1;
	info.notCheckable = 1;
	info.value = "actionbar1_buttonsize";
	if (saved.actionbar1_shown == 0) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
end

local function generalizedMenuLoad (bar, level)
	-- Show/hide
	local info = {};
	info.text = HOTBAR_TEXT:Get("show");
	if (saved["actionbar"..bar.."_shown"] == 1) then
		info.checked = 1;
	end
	info.func = function ()
		if (this.checked) then
			saved["actionbar"..bar.."_shown"] = 0;
		else
			saved["actionbar"..bar.."_shown"] = 1;
		end
		Gypsy_ActionBar_ValidateSettings();
		Gypsy_ActionBar_Update();
		CloseDropDownMenus();
		Gypsy_ActionBar1_DropDown_Toggle();
	end
	UIDropDownMenu_AddButton(info, level);
	-- Dock/undock
	info = {};
	info.text = HOTBAR_TEXT:Get("docked");
	if (saved["actionbar"..bar.."_docked"] == 1) then
		info.checked = 1;
	end
	info.func = function ()
		if (this.checked) then
			saved["actionbar"..bar.."_docked"] = 0;
		else
			saved["actionbar"..bar.."_docked"] = 1;
		end
		Gypsy_ActionBar_ValidateSettings();
		Gypsy_ActionBar_Update();
	end
	if (saved["actionbar"..bar.."_shown"] == 0 or saved["actionbar"..(bar - 1).."_docked"] == 0 or saved["actionbar"..(bar - 1).."_shown"] == 0) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Allow paging
	info = {};
	info.text = HOTBAR_TEXT:Get("allowPaging");
	if (saved["actionbar"..bar.."_allowPaging"] == 1) then
		info.checked = 1;
	end
	info.func = function ()
		if (this.checked) then
			saved["actionbar"..bar.."_allowPaging"] = 0;
		else
			saved["actionbar"..bar.."_allowPaging"] = 1;
		end
		ChangeActionBarPage();
	end
	if (saved["actionbar"..bar.."_shown"] == 0) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Orientation
	info = {};
	info.text = HOTBAR_TEXT:Get("orientation");
	info.hasArrow = 1;
	info.notCheckable = 1;
	info.value = "actionbar"..bar.."_orientation";
	if (saved["actionbar"..bar.."_shown"] == 0 or saved["actionbar"..bar.."_docked"] == 1) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Number of buttons
	info = {};
	info.text = HOTBAR_TEXT:Get("buttonsShown");
	info.hasArrow = 1;
	info.notCheckable = 1;
	info.value = "actionbar"..bar.."_numbuttons";
	if (saved["actionbar"..bar.."_shown"] == 0 or saved["actionbar"..bar.."_docked"] == 1) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
	-- Button size
	info = {};
	info.text = HOTBAR_TEXT:Get("buttonSize");
	info.hasArrow = 1;
	info.notCheckable = 1;
	info.value = "actionbar"..bar.."_buttonsize";
	if (saved["actionbar"..bar.."_shown"] == 0 or saved["actionbar"..bar.."_docked"] == 1) then
		info.disabled = 1;
	end
	UIDropDownMenu_AddButton(info, level);
end

local function loadActionBar2Menu (level)
	generalizedMenuLoad(2, level);
end

local function loadActionBar3Menu (level)
	generalizedMenuLoad(3, level);
end

local function loadActionBar4Menu (level)
	generalizedMenuLoad(4, level);
end

local function loadActionBar5Menu (level)
	generalizedMenuLoad(5, level);
end

local function loadActionBar6Menu (level)
	generalizedMenuLoad(6, level);
end

function generalizedUndockedMenuLoad (bar)
	local value = UIDROPDOWNMENU_MENU_VALUE;
	
	if (UIDROPDOWNMENU_MENU_LEVEL == 2) then
		-- Orientation choices	
		if (strfind(value, "orientation")) then
			loadOrientationMenu("actionbar"..bar, 2);
			
		-- Button count choices
		elseif (strfind(value, "numbuttons")) then
			loadNumButtonsMenu("actionbar"..bar, 2);
			
		-- Button size choices
		elseif (strfind(value, "buttonsize")) then
			loadButtonSizeMenu("actionbar"..bar, 2);
		end
		
		return;
	end
	
	local info = {};
	info.text = HOTBAR_TEXT:Get("actionbar"..bar);
	info.isTitle = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	generalizedMenuLoad(bar);
end

function Gypsy_ActionBar1_UpdateDropDown ()
	-- The value is set to the moused over menu item's text
	local value = UIDROPDOWNMENU_MENU_VALUE;
	
	if (UIDROPDOWNMENU_MENU_LEVEL == 3) then
		local bar = strsub(value, 1, strfind(value, "_") - 1);
		
		-- Orientation choices	
		if (strfind(value, "orientation")) then
			loadOrientationMenu(bar, 3);
			
		-- Button count choices
		elseif (strfind(value, "numbuttons")) then
			loadNumButtonsMenu(bar, 3);
			
		-- Button size
		elseif (strfind(value, "buttonsize")) then
			loadButtonSizeMenu(bar, 3);
		end
		
		return;
	end
	
	if (UIDROPDOWNMENU_MENU_LEVEL == 2) then		
		if (value == HOTBAR_TEXT:Get("actionbar1")) then
			loadActionBar1Menu(2);
		elseif (value == HOTBAR_TEXT:Get("actionbar2")) then
			loadActionBar2Menu(2);
		elseif (value == HOTBAR_TEXT:Get("actionbar3")) then
			loadActionBar3Menu(2);
		elseif (value == HOTBAR_TEXT:Get("actionbar4")) then
			loadActionBar4Menu(2);
		elseif (value == HOTBAR_TEXT:Get("actionbar5")) then
			loadActionBar5Menu(2);
		elseif (value == HOTBAR_TEXT:Get("actionbar6")) then
			loadActionBar6Menu(2);
		elseif (value == HOTBAR_TEXT:Get("bagbar")) then
			Gypsy_BagBar_LoadMenu(2);
		elseif (value == HOTBAR_TEXT:Get("menubar")) then
			Gypsy_MenuBar_LoadMenu(2);
		elseif (value == HOTBAR_TEXT:Get("petactionbar")) then
			Gypsy_PetActionBar_LoadMenu(2);
		elseif (value == HOTBAR_TEXT:Get("specialactionbar")) then
			Gypsy_SpecialActionBar_LoadMenu(2);
		end
		
		return;
	end
	
	-- HotBar title
	local info = {};
	info.text = HOTBAR_TEXT:Get("hotbar");
	info.isTitle = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Action bar 1 menu
	info = {};
	info.text = HOTBAR_TEXT:Get("actionbar1");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Action bar 2 menu
	info = {};
	info.text = HOTBAR_TEXT:Get("actionbar2");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Action bar 3 menu
	info = {};
	info.text = HOTBAR_TEXT:Get("actionbar3");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Action bar 4 menu
	info = {};
	info.text = HOTBAR_TEXT:Get("actionbar4");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Action bar 5 menu
	info = {};
	info.text = HOTBAR_TEXT:Get("actionbar5");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Action bar 6 menu
	info = {};
	info.text = HOTBAR_TEXT:Get("actionbar6");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Bag bar menu
	info = {};
	info.text = HOTBAR_TEXT:Get("bagbar");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	-- Menu bar menu
	info = {};
	info.text = HOTBAR_TEXT:Get("menubar");
	info.hasArrow = 1;
	info.notCheckable = 1;
	UIDropDownMenu_AddButton(info);
	
	--if (hotlib:IsPetClass()) then
		-- Pet action bar menu
		info = {};
		info.text = HOTBAR_TEXT:Get("petactionbar");
		info.hasArrow = 1;
		info.notCheckable = 1;
		if (not PetHasActionBar()) then
			info.disabled = 1;
		end
		UIDropDownMenu_AddButton(info);
	--end
	
	--if (hotlib:IsSpecialActionClass()) then
		-- Special action bar menu
		info = {};
		info.text = HOTBAR_TEXT:Get("specialactionbar");
		info.hasArrow = 1;
		info.notCheckable = 1;
		if (not hotlib:IsSpecialActionClass()) then
			info.disabled = 1;
		end
		UIDropDownMenu_AddButton(info);
	--end
end

function Gypsy_ActionBar2_UpdateDropDown ()
	generalizedUndockedMenuLoad(2);
end

function Gypsy_ActionBar3_UpdateDropDown ()
	generalizedUndockedMenuLoad(3);
end

function Gypsy_ActionBar4_UpdateDropDown ()
	generalizedUndockedMenuLoad(4);
end

function Gypsy_ActionBar5_UpdateDropDown ()
	generalizedUndockedMenuLoad(5);
end

function Gypsy_ActionBar6_UpdateDropDown ()
	generalizedUndockedMenuLoad(6);
end

--= ActionButton Functions =--

function Gypsy_ActionButton_OnLoad ()
	this.showgrid = 0;
	this.flashing = 0;
	this.flashtime = 0;
	this.shown = 0;
		
	this:RegisterForDrag("LeftButton", "RightButton");
	this:RegisterForClicks("LeftButtonUp", "RightButtonUp");
	this:RegisterEvent("ACTIONBAR_SHOWGRID");
	this:RegisterEvent("ACTIONBAR_HIDEGRID");
	this:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
	this:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
	this:RegisterEvent("ACTIONBAR_UPDATE_STATE");
	this:RegisterEvent("ACTIONBAR_UPDATE_USABLE");
	this:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
	this:RegisterEvent("UPDATE_INVENTORY_ALERTS");
	this:RegisterEvent("PLAYER_AURAS_CHANGED");
	this:RegisterEvent("PLAYER_TARGET_CHANGED");
	this:RegisterEvent("UNIT_AURASTATE");
	this:RegisterEvent("UNIT_INVENTORY_CHANGED");
	this:RegisterEvent("CRAFT_SHOW");
	this:RegisterEvent("CRAFT_CLOSE");
	this:RegisterEvent("TRADE_SKILL_SHOW");
	this:RegisterEvent("TRADE_SKILL_CLOSE");
	this:RegisterEvent("UNIT_HEALTH");
	this:RegisterEvent("UNIT_MANA");
	this:RegisterEvent("UNIT_RAGE");
	this:RegisterEvent("UNIT_FOCUS");
	this:RegisterEvent("UNIT_ENERGY");
	this:RegisterEvent("UPDATE_BONUS_ACTIONBAR");
	this:RegisterEvent("PLAYER_ENTER_COMBAT");
	this:RegisterEvent("PLAYER_LEAVE_COMBAT");
	this:RegisterEvent("PLAYER_COMBO_POINTS");
	this:RegisterEvent("UPDATE_BINDINGS");
	this:RegisterEvent("START_AUTOREPEAT_SPELL");
	this:RegisterEvent("STOP_AUTOREPEAT_SPELL");
	
	Gypsy_ActionButton_Update();
	Gypsy_ActionButton_UpdateHotkeys();
end

function Gypsy_ActionButton_OnShow ()
	Gypsy_ActionButton_Update();
end

function Gypsy_ActionButton_OnEvent (event)	
	if (event == "ACTIONBAR_SLOT_CHANGED") then
		if (arg1 == -1 or arg1 == Gypsy_ActionButton_GetPagedID(this)) then
			Gypsy_ActionButton_Update();
		end
		return;
	end
	if (event == "ACTIONBAR_PAGE_CHANGED" or event == "PLAYER_AURAS_CHANGED" or event == "UPDATE_BONUS_ACTIONBAR") then
		Gypsy_ActionButton_SyncPage();		
		Gypsy_ActionButton_Update();
		Gypsy_ActionButton_UpdateState();
		Gypsy_ActionButton_UpdateHotkeys();
		return;
	end
	if (event == "ACTIONBAR_SHOWGRID") then
		Gypsy_ActionButton_ShowGrid();
		return;
	end
	if (event == "ACTIONBAR_HIDEGRID") then
		Gypsy_ActionButton_HideGrid();
		return;
	end
	if (event == "UPDATE_BINDINGS") then
		Gypsy_ActionButton_UpdateHotkeys();
	end

	-- All event handlers below this line MUST only be valid when the button is visible
	if (not this:IsVisible()) then
		return;
	end

	if (event == "PLAYER_TARGET_CHANGED") then
		Gypsy_ActionButton_UpdateUsable();
		return;
	end
	if (event == "UNIT_AURASTATE") then
		if (arg1 == "player" or arg1 == "target") then
			Gypsy_ActionButton_UpdateUsable();
		end
		return;
	end
	if (event == "UNIT_INVENTORY_CHANGED") then
		if (arg1 == "player") then
			Gypsy_ActionButton_Update();
		end
		return;
	end
	if (event == "ACTIONBAR_UPDATE_STATE") then
		Gypsy_ActionButton_UpdateState();
		return;
	end
	if (event == "ACTIONBAR_UPDATE_USABLE" or event == "UPDATE_INVENTORY_ALERTS" or event == "ACTIONBAR_UPDATE_COOLDOWN") then
		Gypsy_ActionButton_UpdateUsable();
		Gypsy_ActionButton_UpdateCooldown();
		return;
	end
	if (event == "CRAFT_SHOW" or event == "CRAFT_CLOSE" or event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE") then
		Gypsy_ActionButton_UpdateState();
		return;
	end
	if (arg1 == "player" and (event == "UNIT_HEALTH" or event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_FOCUS" or event == "UNIT_ENERGY")) then
		Gypsy_ActionButton_UpdateUsable();
		return;
	end
	if (event == "PLAYER_ENTER_COMBAT") then
		IN_ATTACK_MODE = 1;
		if (IsAttackAction(Gypsy_ActionButton_GetPagedID(this))) then
			Gypsy_ActionButton_StartFlash();
		end
		return;
	end
	if (event == "PLAYER_LEAVE_COMBAT") then
		IN_ATTACK_MODE = nil;
		if (IsAttackAction(Gypsy_ActionButton_GetPagedID(this))) then
			Gypsy_ActionButton_StopFlash();
		end
		return;
	end
	if (event == "PLAYER_COMBO_POINTS") then
		Gypsy_ActionButton_UpdateUsable();
		return;
	end
	if (event == "START_AUTOREPEAT_SPELL") then
		IN_AUTOREPEAT_MODE = 1;
		if (IsAutoRepeatAction(Gypsy_ActionButton_GetPagedID(this))) then
			Gypsy_ActionButton_StartFlash();
		end
		return;
	end
	if (event == "STOP_AUTOREPEAT_SPELL") then
		IN_AUTOREPEAT_MODE = nil;
		if ( Gypsy_ActionButton_IsFlashing() and not IsAttackAction(Gypsy_ActionButton_GetPagedID(this)) ) then
			Gypsy_ActionButton_StopFlash();
		end
		return;
	end
end

function Gypsy_ActionButton_OnClick ()
	if (IsShiftKeyDown()) then
		PickupAction(Gypsy_ActionButton_GetPagedID(this));
	else
		if (MacroFrame_SaveMacro) then
			MacroFrame_SaveMacro();
		end
		UseAction(Gypsy_ActionButton_GetPagedID(this), 1);
	end
	Gypsy_ActionButton_UpdateState();
end

function Gypsy_ActionButton_OnDragStart ()
	if (LOCK_ACTIONBAR ~= "1" or IsShiftKeyDown()) then
		PickupAction(Gypsy_ActionButton_GetPagedID(this));
		Gypsy_ActionButton_UpdateState();
	end
end

function Gypsy_ActionButton_OnRecieveDrag ()
	PlaceAction(Gypsy_ActionButton_GetPagedID(this));
	Gypsy_ActionButton_UpdateState();
end

function Gypsy_ActionButton_OnEnter ()
	Gypsy_ActionButton_SetTooltip();
end

function Gypsy_ActionButton_OnLeave ()
	this.updateTooltip = nil;
	GameTooltip:Hide();
end

function Gypsy_ActionButton_OnUpdate (elapsed)
	if (Gypsy_ActionButton_IsFlashing()) then
		this.flashtime = this.flashtime - elapsed;
		if (this.flashtime <= 0) then
			local overtime = -this.flashtime;
			if (overtime >= ATTACK_BUTTON_FLASH_TIME) then
				overtime = 0;
			end
			this.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;

			local flashTexture = getglobal(this:GetName().."Flash");
			if (flashTexture:IsVisible()) then
				flashTexture:Hide();
			else
				flashTexture:Show();
			end
		end
	end
	
	-- Handle range indicator
	if (saved and this.updateTimer) then
		-- Custom action button update timer
		if (this.updateTimer < 0) then
			Gypsy_ActionButton_UpdateRange(this);
			
			this.updateTimer = saved.updateTime;
		else
			this.updateTimer = this.updateTimer - elapsed;
		end
	elseif (this.rangeTimer) then
		if (this.rangeTimer < 0) then			
			Gypsy_ActionButton_UpdateRange(this);
			
			this.rangeTimer = TOOLTIP_UPDATE_TIME;
		else
			this.rangeTimer = this.rangeTimer - elapsed;
		end
	end
	
	if (not this.updateTooltip) then
		return;
	end

	this.updateTooltip = this.updateTooltip - elapsed;
	if (this.updateTooltip > 0) then
		return;
	end

	if (GameTooltip:IsOwned(this)) then
		Gypsy_ActionButton_SetTooltip();
	else
		this.updateTooltip = nil;
	end
end

--= Action Button Helper Functions =--

function Gypsy_ActionButton_Down (id)
	local button = getglobal(actionPrefix..id);
	if (button:GetButtonState() == "NORMAL") then
		button:SetButtonState("PUSHED");
	end
end

function Gypsy_ActionButton_Up (id)
	local button = getglobal(actionPrefix..id);
	
	if (button:GetButtonState() == "PUSHED") then
		button:SetButtonState("NORMAL");
		if (MacroFrame_SaveMacro) then
			MacroFrame_SaveMacro();
		end
	end	

	UseAction(Gypsy_ActionButton_GetPagedID(button), 0);
	
	if (IsCurrentAction(Gypsy_ActionButton_GetPagedID(button))) then
		button:SetChecked(1);
	else
		button:SetChecked(0);
	end
end

function Gypsy_ActionButton_Update (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	-- Determine whether or not the button should be flashing or not since the button may have missed the enter combat event
	local pagedID = Gypsy_ActionButton_GetPagedID(button);
	
	if (IsAttackAction(pagedID) and IsCurrentAction(pagedID)) then
		IN_ATTACK_MODE = 1;
	else
		IN_ATTACK_MODE = nil;
	end
	IN_AUTOREPEAT_MODE = IsAutoRepeatAction(pagedID);
	
	local icon = getglobal(button:GetName().."Icon");
	local buttonCooldown = getglobal(button:GetName().."Cooldown");
	local texture = GetActionTexture(Gypsy_ActionButton_GetPagedID(button));
	local indicator = getglobal(button:GetName().."Indicator");
	local indicatorBorder = getglobal(indicator:GetName().."Border");
	
	if (texture) then
		icon:SetTexture(texture);
		icon:Show();
		button.rangeTimer = TOOLTIP_UPDATE_TIME;
		if (saved and saved.useUpdateTimer == 1) then
			button.updateTimer = saved.updateTime;
		else
			button.updateTimer = nil;
		end
		button:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
		if (saved and saved.useIndicator == 1) then
			indicator:Show();
			indicatorBorder:Show();
		else
			indicator:Hide();
			indicatorBorder:Hide();
		end	
	else
		icon:Hide();
		buttonCooldown:Hide();
		button.rangeTimer = nil;
		button.updateTimer = nil;
		button:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
		getglobal(button:GetName().."HotKey"):SetVertexColor(color:Parse("ab_lightgrey"));
		indicator:Hide();
		indicatorBorder:Hide();
	end
	
	Gypsy_ActionButton_UpdateCount(button);
	
	if (HasAction(Gypsy_ActionButton_GetPagedID(button)) and button.shown == 1) then
		button:Show();
		Gypsy_ActionButton_UpdateUsable(button);
		Gypsy_ActionButton_UpdateCooldown(button);
	elseif (button.showgrid > 0 and button.shown == 1) then
		button:Show();
	elseif (button.showgrid == 0) then
		button:Hide();
	else
		getglobal(button:GetName().."Cooldown"):Hide();
	end
	
	if (IN_ATTACK_MODE or IN_AUTOREPEAT_MODE) then
		Gypsy_ActionButton_StartFlash(button);
	else
		Gypsy_ActionButton_StopFlash(button);
	end

	local border = getglobal(button:GetName().."Border");
	if ((IsEquippedAction(Gypsy_ActionButton_GetPagedID(button))) and (not saved or saved.showEquippedBorder == 1)) then
		border:SetVertexColor(0, 1.0, 0, 0.35);
		border:Show();
	else
		border:Hide();
	end

	if (GameTooltip:IsOwned(button)) then
		Gypsy_ActionButton_SetTooltip(button);
	else
		button.updateTooltip = nil;
	end

	-- Update Macro Text
	
	local macroName = getglobal(button:GetName().."Name");
	local text = GetActionText(Gypsy_ActionButton_GetPagedID(button));
	
	if (saved and saved.showMacroText == 0) then
		text = "";
	end
	
	macroName:SetText(text);
end

function Gypsy_ActionButton_UpdateHotkeys (button, prefix)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (not prefix) then
		prefix = string.upper(string.gsub(button:GetName(), "%d", ""));
	end
	
	local hotkey = getglobal(button:GetName().."HotKey");
	local label = "";
	
	local mode = "full";
	
	if (saved) then
		mode = saved.bindingLabelMode;
	end
	
	if (mode == "id") then
		label = Gypsy_ActionButton_GetPagedID(button);
	elseif (mode ~= "hidden") then
		local action;
		if (button:GetID() <= 12) then
			action = "ACTIONBUTTON"..button:GetID();
		else
			action = prefix..button:GetID();
		end
		
		label = GetBindingText(GetBindingKey(action), "KEY_");		
		
		label = hotlib:CondenseLabel(label);
		
		if (mode == "stripped") then
			label = hotlib:StripCondensedLabel(label);
		end
	end
	
	hotkey:SetText(label);
end

function Gypsy_ActionButton_UpdateUsable (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	local label = getglobal(button:GetName().."HotKey");
	local icon = getglobal(button:GetName().."Icon");
	local normalTexture = getglobal(button:GetName().."NormalTexture");
	local indicator = getglobal(button:GetName().."Indicator");
	
	local mode, isInRange, isUsable, notEnoughMana, isCoolingDown;
	
	if (saved) then
		mode = saved.rangeDetectionMode;
		if (saved.useUpdateTime == 1) then
			button.updateTime = saved.updateTime;
		else
			button.updateTime = nil;
		end
	else
		mode = "label";
		button.updateTime = nil;
	end
	
	isInRange = IsActionInRange(Gypsy_ActionButton_GetPagedID(button));
	isUsable, notEnoughMana = IsUsableAction(Gypsy_ActionButton_GetPagedID(button));
	isCoolingDown = Gypsy_ActionButton_IsCoolingDown(button);
		
	if (isInRange == 0) then
		indicator:SetVertexColor(color:Parse("ab_darkred"));
		
		if (mode == "label" or mode == "full") then
			label:SetVertexColor(color:Parse("ab_lightred"));
		end
		
		if (mode == "button" or mode == "full") then
			icon:SetVertexColor(color:Parse("ab_darkred"));
			normalTexture:SetVertexColor(color:Parse("ab_lightred"));
		end
	else
		label:SetVertexColor(color:Parse("ab_lightgrey"));
		label.color = "ab_lightgrey";
		
		if (isCoolingDown) then
			button.isCoolingDown = 1;
			indicator:SetVertexColor(color:Parse("ab_darkred"));
			indicator.color = "ab_darkred";
		elseif (isUsable) then
			indicator:SetVertexColor(color:Parse("green"));
			indicator.color = "green";
		elseif (notEnoughMana) then
			indicator:SetVertexColor(color:Parse("blue"));
			indicator.color = "blue";
		else
			indicator:SetVertexColor(color:Parse("yellow"));
			indicator.color = "yellow";
		end
		
		if (isUsable) then
			icon:SetVertexColor(color:Parse("white"));
			icon.color = "white";
			normalTexture:SetVertexColor(color:Parse("white"));
			normalTexture.color = "white";
		elseif (notEnoughMana) then
			icon:SetVertexColor(color:Parse("ab_darkblue"));
			icon.color = "ab_darkblue";
			normalTexture:SetVertexColor(color:Parse("ab_darkblue"));
			normalTexture.color = "ab_darkblue";
		else
			icon:SetVertexColor(color:Parse("ab_darkgrey"));
			icon.color = "ab_darkgrey";
			normalTexture:SetVertexColor(color:Parse("white"));
			normalTexture.color = "white";
		end
	end
end

function Gypsy_ActionButton_UpdateRange (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	local indicator = getglobal(button:GetName().."Indicator");
	local icon = getglobal(button:GetName().."Icon");
	local normalTexture = getglobal(button:GetName().."NormalTexture");
	local label = getglobal(button:GetName().."HotKey");

	if (saved) then
		mode = saved.rangeDetectionMode;
	else
		mode = "label";
	end

	if (button.isCoolingDown and not getglobal(button:GetName().."Cooldown"):IsVisible()) then
		button.isCoolingDown = nil;
		indicator:SetVertexColor(color:Parse(indicator.color));
	end
	
	if (IsActionInRange(Gypsy_ActionButton_GetPagedID(button)) == 0) then
		indicator:SetVertexColor(color:Parse("ab_darkred"));

		if (mode == "label" or mode == "full") then
			label:SetVertexColor(color:Parse("ab_lightred"));
		elseif (label.color) then
			label:SetVertexColor(color:Parse(label.color));
		end

		if (mode == "button" or mode == "full") then
			icon:SetVertexColor(color:Parse("ab_darkred"));
			normalTexture:SetVertexColor(color:Parse("ab_lightred"));
		else
			if (icon.color) then
				icon:SetVertexColor(color:Parse(icon.color));
			end
			if (normalTexture.color) then
				normalTexture:SetVertexColor(color:Parse(normalTexture.color));
			end
		end
	else
		if (indicator.color) then
			indicator:SetVertexColor(color:Parse(indicator.color));
		end
		if (icon.color) then
			icon:SetVertexColor(color:Parse(icon.color));
		end
		if (normalTexture.color) then
			normalTexture:SetVertexColor(color:Parse(normalTexture.color));
		end
		if (label.color) then
			label:SetVertexColor(color:Parse(label.color));
		end
	end
end

function Gypsy_ActionButton_UpdateCount (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	local text = getglobal(button:GetName().."Count");
	local count = GetActionCount(Gypsy_ActionButton_GetPagedID(button));

	if ((saved and saved.showCountText == 0) or count <= 1) then
		count = "";
	end
	
	text:SetText(count);
end

function Gypsy_ActionButton_UpdateCooldown (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	local cooldown = getglobal(button:GetName().."Cooldown");
	local start, duration, enable = GetActionCooldown(Gypsy_ActionButton_GetPagedID(button));
	CooldownFrame_SetTimer(cooldown, start, duration, enable);
end

function Gypsy_ActionButton_UpdateState (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (IsCurrentAction(Gypsy_ActionButton_GetPagedID(button)) or IsAutoRepeatAction(Gypsy_ActionButton_GetPagedID(button))) then
		button:SetChecked(1);
	else
		button:SetChecked(0);
	end
end

function Gypsy_ActionButton_GetPagedID (button)
	if (not button) then		
		return 0;
	end
	
	local mode;
	
	if (not saved) then
		mode = 0;
	else
		mode = saved.pagingMode;
	end
	
	if (Gypsy_ActionButton_HasBonusActions() and Gypsy_ActionButton_IsBonusAction(button) and GetBonusBarOffset() > 0) then
		return button:GetID() + ((maxPages + GetBonusBarOffset() - 1) * maxButtonsPerPage);
	else
		if (saved and saved["actionbar"..ceil(button:GetID() / numButtonsPerBar).."_allowPaging"] == 0) then
			if (Gypsy_ActionButton_HasBonusActions() and button:GetID() <= 12 and  GetBonusBarOffset() > 0) then
				return button:GetID() + ((maxPages + GetBonusBarOffset() - 1) * maxButtonsPerPage);
			end
			
			return button:GetID();
		end
		
		local id = button:GetID() + ((currentPage - 1) * numButtonsPerPage);
		
		if (id > numButtons) then
			id = id - numButtons;
			if (Gypsy_ActionButton_HasBonusActions() and id <= 12 and GetBonusBarOffset() > 0) then
				return id + ((maxPages + GetBonusBarOffset() - 1) * maxButtonsPerPage);
			end
		end
		
		return id;
	end
end

function Gypsy_ActionButton_ShowGrid (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (not saved or saved.enabled == 0) then
		return;
	end
	
	if (button.shown == 1) then
		button.showgrid = button.showgrid+1;
		getglobal(button:GetName().."NormalTexture"):SetVertexColor(color:Parse("white"));
		button:Show();
	end
end

function Gypsy_ActionButton_HideGrid (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (not saved or saved.enabled == 0) then
		return;
	end
	
	if (button.shown == 1) then
		button.showgrid = button.showgrid-1;
		if (button.showgrid == 0 and not HasAction(Gypsy_ActionButton_GetPagedID(button))) then
			button:Hide();
		end
	end
end

function Gypsy_ActionButton_StartFlash (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	button.flashing = 1;
	button.flashtime = 0;
	Gypsy_ActionButton_UpdateState(button);
end

function Gypsy_ActionButton_StopFlash (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	button.flashing = 0;
	getglobal(button:GetName().."Flash"):Hide();
	Gypsy_ActionButton_UpdateState(button);
end

function Gypsy_ActionButton_SetTooltip (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (GetCVar("UberTooltips") == "1") then
		GameTooltip_SetDefaultAnchor(GameTooltip, button);
	else
		GameTooltip:SetOwner(button, "ANCHOR_RIGHT");
	end
	
	if (GameTooltip:SetAction(Gypsy_ActionButton_GetPagedID(button))) then
		button.updateTooltip = TOOLTIP_UPDATE_TIME;
	else
		button.updateTooltip = nil;
	end
end

function Gypsy_ActionButton_SyncPage ()
	if (saved and saved.pagingMode == "disallow") then
		currentPage = 1;
		return;
	end

	currentPage = CURRENT_ACTIONBAR_PAGE;
	
	if (currentPage > numPages) then
		currentPage = currentPage - numPages;
		if (currentPage > numPages) then
			currentPage = currentPage - numPages;
		end
	end
end

function Gypsy_ActionButton_HasBonusActions ()
	if (GetNumShapeshiftForms() > 0) then
		return 1;
	else
		return nil;
	end
end

function Gypsy_ActionButton_IsBonusAction (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return nil;
	end
	
	if (currentPage == 1 and button:GetID() <= 12) then
		return 1;
	else
		return nil;
	end
end

function Gypsy_ActionButton_IsCoolingDown (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (getglobal(button:GetName().."Cooldown"):IsVisible()) then
		return 1;
	else
		return nil;
	end
end

function Gypsy_ActionButton_IsFlashing (button)
	if (this and not button) then
		button = this;
	elseif (not button) then
		return;
	end
	
	if (button.flashing == 1) then
		return 1;
	else
		return nil;
	end
end