Quantcast

Update to 30000

p3lim-52096 [10-14-08 - 17:56]
Update to 30000

git-svn-id: svn://svn.wowinterface.com/pMinimap-54/trunk@25 ae24c21f-2f0c-4c94-9256-0092abe71e0d
Filename
pMinimap/Libs/LibSimpleOptions-1.0.lua
pMinimap/Libs/LibStub.lua
pMinimap/pMinimap.lua
pMinimap/pMinimap.toc
pMinimap/pMinimapConfig.lua
diff --git a/pMinimap/Libs/LibSimpleOptions-1.0.lua b/pMinimap/Libs/LibSimpleOptions-1.0.lua
new file mode 100644
index 0000000..b7a21a8
--- /dev/null
+++ b/pMinimap/Libs/LibSimpleOptions-1.0.lua
@@ -0,0 +1,955 @@
+--[[
+Name: LibSimpleOptions-1.0
+Revision: $Rev: 81443 $
+Author(s): ckknight (ckknight@gmail.com)
+Website: http://ckknight.wowinterface.com/
+Description: A library to provide a way to easily create controls for Blizzard's options system
+License: MIT
+]]
+
+local MAJOR_VERSION = "LibSimpleOptions-1.0"
+local MINOR_VERSION = tonumber(("$Revision: 81443 $"):match("(%d+)"))
+
+if not LibStub then error(MAJOR_VERSION .. " requires LibStub") end
+
+-- #AUTODOC_NAMESPACE LibSimpleOptions
+
+local LibSimpleOptions, oldLib = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION)
+if not LibSimpleOptions then
+	return
+end
+if oldLib then
+	oldLib = {}
+	for k, v in pairs(LibSimpleOptions) do
+		LibSimpleOptions[k] = nil
+		oldLib[k] = v
+	end
+end
+
+local getArgs, doneArgs
+do
+	local tmp = {}
+	function getArgs(...)
+		assert(next(tmp) == nil)
+		for i = 1, select('#', ...), 2 do
+			local k, v = select(i, ...)
+			if type(k) ~= "string" then
+				error(("Received a bad key, must be a %q, got %q (%s)"):format("string", type(k), tostring(k)), 3)
+			elseif tmp[k] ~= nil then
+				error(("Received key %q twice"):format(k), 3)
+			end
+			tmp[k] = v
+		end
+		return tmp
+	end
+	function doneArgs(args)
+		assert(args == tmp)
+		for k in pairs(args) do
+			args[k] = nil
+		end
+		return nil
+	end
+end
+
+local WotLK = not not ToggleAchievementFrame
+
+local panels
+if oldLib then
+	panels = oldLib.panels or {}
+else
+	panels = {}
+end
+LibSimpleOptions.panels = panels
+
+local panelMeta
+if oldLib then
+	panelMeta = oldLib.panelMeta or {}
+else
+	panelMeta = {}
+end
+LibSimpleOptions.panelMeta = panelMeta
+for funcName in pairs(panelMeta) do
+	for panel in pairs(panels) do
+		panel[funcName] = nil
+	end
+	panelMeta[funcName] = nil
+end
+
+do
+	local function update(control, ...)
+		if (...) ~= control.value then
+			control:SetValue(...)
+		end
+	end
+	--- Refresh a panel's controls
+	-- This updates any controls that provide a getFunc
+	-- When a panel is shown, this is automatically called
+	-- @name panel:Refresh
+	-- @usage panel:Refresh()
+	function panelMeta:Refresh()
+		for control in pairs(self.controls) do
+			if control.getFunc then
+				update(control, control.getFunc())
+			end
+		end
+		if self.refreshFunc then
+			self:refreshFunc()
+		end
+	end
+	local function panel_OnShow(self)
+		self:SetScript("OnShow", self.Refresh)
+		self:controlCreationFunc()
+		self.controlCreationFunc = nil
+		self:Refresh()
+	end
+	local function panel_okay(self)
+		for control in pairs(self.controls) do
+			control.oldValue = control.value
+			if control.okayFunc then
+				control.okayFunc()
+			end
+		end
+	end
+	local function panel_cancel(self)
+		for control in pairs(self.controls) do
+			control:SetValue(control.oldValue)
+			if control.cancelFunc then
+				control.cancelFunc()
+			end
+		end
+	end
+	local function panel_default(self)
+		for control in pairs(self.controls) do
+			control:SetValue(control.default)
+			if control.defaultFunc then
+				control.defaultFunc()
+			end
+		end
+	end
+	local function makePanel(name, parentName, controlCreationFunc)
+		local panel
+		if not parentName then
+			panel = CreateFrame("Frame", name .. "_Panel")
+		else
+			panel = CreateFrame("Frame", parentName .. "_Panel_" .. name)
+		end
+		panels[panel] = true
+
+		panel.name = name
+		panel.controls = {}
+		panel.parent = parentName
+
+		panel.okay = panel_okay
+		panel.cancel = panel_cancel
+		panel.default = panel_default
+
+		InterfaceOptions_AddCategory(panel)
+
+		panel.controlCreationFunc = controlCreationFunc
+		panel:SetScript("OnShow", panel_OnShow)
+		for k, v in pairs(panelMeta) do
+			panel[k] = v
+		end
+	end
+
+	--- Make a new options panel and add it to the Blizzard Interface Options
+	-- @param name name of your panel
+	-- @param controlCreationFunc function to call when the panel is first shown
+	-- @usage LibStub("LibSimpleOptions-1.0").AddOptionsPanel("My Options", function(panel) ... end)
+	-- @return the created panel
+	function LibSimpleOptions.AddOptionsPanel(name, controlCreationFunc)
+		return makePanel(name, nil, controlCreationFunc)
+	end
+
+	--- Make a new options panel that is a child of another options panel and add it to the Blizzard Interface Options
+	-- @param parentName name of the parent panel
+	-- @param name name of your panel
+	-- @param controlCreationFunc function to call when the panel is first shown
+	-- @usage LibStub("LibSimpleOptions-1.0").AddOptionsPanel("My Options", "My Suboptions", function(panel) ... end)
+	-- @return the created panel
+	function LibSimpleOptions.AddSuboptionsPanel(parentName, name, controlCreationFunc)
+		return makePanel(name, parentName, controlCreationFunc)
+	end
+end
+
+--- Return a new title text and sub-text for a panel.
+-- Note that this automatically places the title and sub-text appropriately
+-- @name panel:MakeTitleTextAndSubText
+-- @param titleText the text to show as the title
+-- @param subTextText the text to show as the sub-text
+-- @usage local title, subText = panel:MakeTitleTextAndSubText("My Options", "These allow you to change assorted options")
+-- @return the title FontString
+-- @return the sub-text FontString
+function panelMeta:MakeTitleTextAndSubText(titleText, subTextText)
+	local title = self:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
+	title:SetText(titleText)
+	title:SetJustifyH("LEFT")
+	title:SetJustifyV("TOP")
+	title:SetPoint("TOPLEFT", 16, -16)
+
+	local subText = self:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+	subText:SetText(subTextText)
+	subText:SetNonSpaceWrap(true)
+	subText:SetJustifyH("LEFT")
+	subText:SetJustifyV("TOP")
+	subText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
+	subText:SetPoint("RIGHT", -32, 0)
+
+	return title, subText
+end
+
+do
+	local backdrop = {
+		bgFile = [=[Interface\Buttons\WHITE8X8]=],
+		edgeFile = [=[Interface\Tooltips\UI-Tooltip-Border]=],
+		tile = true,
+		tileSize = 16,
+		edgeSize = 16,
+		insets = { left = 3, right = 3, top = 3, bottom = 3 },
+	}
+	--- Return a scrollable frame to organize controls within
+	-- This is useful to create if you have too many controls to properly fit within one panel
+	-- @name panel:MakeScrollFrame
+	-- @usage local scrollFrame = panel:MakeScrollFrame()
+	-- @return the ScrollFrame
+	function panelMeta:MakeScrollFrame()
+		local name
+		local i = 0
+		repeat
+			i = i + 1
+			name = self:GetName() .. "_ScrollFrame" .. i
+		until not _G[name]
+		local scrollFrame = CreateFrame("ScrollFrame", name, self, "UIPanelScrollFrameTemplate")
+		scrollFrame:SetFrameLevel(scrollFrame:GetFrameLevel() + 1)
+		local bg = CreateFrame("Frame", nil, self)
+		bg:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", -3, 3)
+		bg:SetPoint("BOTTOMRIGHT", scrollFrame, "BOTTOMRIGHT", 3, -3)
+		bg:SetBackdrop(backdrop)
+		bg:SetBackdropColor(0, 0, 0, 0.25)
+		local scrollChild = CreateFrame("Frame", name .. "_Child", scrollFrame)
+		scrollFrame:SetScrollChild(scrollChild)
+		scrollChild:SetWidth(1)
+		scrollChild:SetHeight(1)
+		return scrollFrame, scrollChild
+	end
+end
+
+do
+	local function slider_OnValueChanged(self)
+		self.value = self:GetValue()
+		self:SetValue(self:GetValue())
+	end
+
+	local function slider_SetValue(self, value)
+		getmetatable(self).__index.SetValue(self, value)
+		self.value = value
+		self.changeFunc(value)
+		if self.currentText then
+			self.currentText:SetText(self.currentTextFunc(value))
+		end
+	end
+
+	--- Return a horizontal slider
+	-- This is primarily for manipulating numbers within a range
+	-- @name panel:MakeSlider
+	-- @param ... tuple of key-value pairs<br/>
+	--     name: What the slider displays above it<br/>
+	--     description: What the tooltip displays when hovering over<br/>
+	--     minText: What the slider shows on the left side<br/>
+	--     maxText: What the slider shows on the right side<br/>
+	--     minValue: The minimum value of the slider<br/>
+	--     maxValue: The maximum value of the slider<br/>
+	--     [optional] step: The amount that the slider steps between movements<br/>
+	--     default: The default value<br/>
+	--     current: The current value - can provide either this or getFunc<br/>
+	--     getFunc: Function to get the current value<br/>
+	--     setFunc: What is called when the value changes<br/>
+	--     [optional] currentTextFunc: What is called to get text value at the bottom<br/>
+	--     [optional] okayFunc: Called when the okay button is pressed<br/>
+	--     [optional] cancelFunc: Called when the cancel button is pressed<br/>
+	--     [optional] defaultFunc: Called when the default button is pressed
+	-- @usage panel:MakeSlider(
+	--     'name', 'Range',
+	--     'description', 'Specify your tooltip description',
+	--     'minText', '0%',
+	--     'maxText', '100%',
+	--     'minValue', 0,
+	--     'maxValue', 1,
+	--     'step', 0.05,
+	--     'default', 0.5,
+	--     'current', db.currentRange,
+	--     'setFunc', function(value) db.currentRange = value end,
+	--     'currentTextFunc', function(value) return ("%.0f%%"):format(value * 100) end
+	-- )
+	-- @return the Slider
+	function panelMeta:MakeSlider(...)
+		local args = getArgs(...)
+		if type(args.name) ~= "string" then
+			error(("name must be %q, got %q (%s)"):format("string", type(args.name), tostring(args.name)), 2)
+		elseif type(args.description) ~= "string" then
+			error(("description must be %q, got %q (%s)"):format("string", type(args.description), tostring(args.description)), 2)
+		elseif type(args.minText) ~= "string" then
+			error(("minText must be %q, got %q (%s)"):format("string", type(args.minText), tostring(args.minText)), 2)
+		elseif type(args.maxText) ~= "string" then
+			error(("maxText must be %q, got %q (%s)"):format("string", type(args.maxText), tostring(args.maxText)), 2)
+		elseif type(args.minValue) ~= "number" then
+			error(("minValue must be %q, got %q (%s)"):format("number", type(args.minValue), tostring(args.minValue)), 2)
+		elseif type(args.maxValue) ~= "number" then
+			error(("maxValue must be %q, got %q (%s)"):format("number", type(args.maxValue), tostring(args.maxValue)), 2)
+		elseif args.step and type(args.step) ~= "number" then
+			error(("step must be %q or %q, got %q (%s)"):format("nil", "number", type(args.step), tostring(args.step)), 2)
+		elseif type(args.default) ~= "number" then
+			error(("default must be %q, got %q (%s)"):format("number", type(args.default), tostring(args.default)), 2)
+		elseif args.default < args.minValue or args.default > args.maxValue then
+			error(("default must be [%s, %s], got %s"):format(args.minValue, args.maxValue, tostring(args.default)), 2)
+		elseif not args.current == not args.getFunc then
+			error(("either current or getFunc must be supplied, but not both"), 2)
+		elseif args.current and type(args.current) ~= "number" then
+			error(("current must be %q, got %q (%s)"):format("number", type(args.current), tostring(args.current)), 2)
+		elseif args.getFunc and type(args.getFunc) ~= "function" then
+			error(("getFunc must be %q, got %q (%s)"):format("function", type(args.getFunc), tostring(args.getFunc)), 2)
+		elseif type(args.setFunc) ~= "function" then
+			error(("setFunc must be %q, got %q (%s)"):format("function", type(args.setFunc), tostring(args.setFunc)), 2)
+		elseif args.currentTextFunc and type(args.currentTextFunc) ~= "function" then
+			error(("currentTextFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.currentTextFunc), tostring(args.currentTextFunc)), 2)
+		elseif args.okayFunc and type(args.okayFunc) ~= "function" then
+			error(("okayFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.okayFunc), tostring(args.okayFunc)), 2)
+		elseif args.cancelFunc and type(args.cancelFunc) ~= "function" then
+			error(("cancelFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.cancelFunc), tostring(args.cancelFunc)), 2)
+		elseif args.defaultFunc and type(args.defaultFunc) ~= "function" then
+			error(("defaultFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.defaultFunc), tostring(args.defaultFunc)), 2)
+		end
+
+		local name
+		local i = 0
+		repeat
+			i = i + 1
+			name = self:GetName() .. "_Slider" .. i
+		until not _G[name]
+		local slider = CreateFrame("Slider", name, self, "InterfaceOptionsSliderTemplate")
+		self.controls[slider] = true
+		_G[slider:GetName() .. "Text"]:SetText(args.name)
+		slider.tooltipText = args.description
+		_G[slider:GetName() .. "Text"]:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
+		_G[slider:GetName() .. "Low"]:SetText(args.minText)
+		_G[slider:GetName() .. "Low"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
+		_G[slider:GetName() .. "High"]:SetText(args.maxText)
+		_G[slider:GetName() .. "High"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
+
+		local current
+		if args.getFunc then
+			slider.getFunc = args.getFunc
+			current = args.getFunc()
+		else
+			current = args.current
+		end
+
+		if args.currentTextFunc then
+			slider.currentTextFunc = args.currentTextFunc
+			local currentText = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+			slider.currentText = currentText
+			currentText:SetPoint("TOP", slider, "CENTER", 0, -8)
+			currentText:SetText(args.currentTextFunc(current))
+		end
+
+		slider.default = args.default
+		slider:SetMinMaxValues(args.minValue, args.maxValue)
+		if args.step then
+			slider:SetValueStep(args.step)
+		end
+		slider.oldValue = current
+		slider.value = current
+		slider:SetValue(current)
+		slider.changeFunc = args.setFunc
+		slider.SetValue = slider_SetValue
+		slider:SetScript("OnValueChanged", slider_OnValueChanged)
+		slider.okayFunc = args.okayFunc
+		slider.cancelFunc = args.cancelFunc
+		slider.defaultFunc = args.defaultFunc
+		args = doneArgs(args)
+		return slider
+	end
+end
+
+local function generic_OnEnter(self)
+	GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT")
+	GameTooltip:SetText(self.tooltipText, nil, nil, nil, nil, 1)
+end
+local function generic_OnLeave(self)
+	GameTooltip:Hide()
+end
+
+do
+	local function dropDown_SetValue(self, value)
+		self.value = value
+		UIDropDownMenu_SetSelectedValue(self, value)
+		self.changeFunc(value)
+	end
+	local helper__num, helper__values
+	local function helper()
+		local value, text = helper__values[helper__num], helper__values[helper__num+1]
+		if value == nil then
+			helper__num, helper__values = nil, nil
+			return nil
+		end
+		helper__num = helper__num + 2
+		return value, text
+	end
+	local function get_iter(values)
+		if type(values) == "function" then
+			return values
+		end
+		helper__num = 1
+		helper__values = values
+		return helper
+	end
+	local SetValue_wrapper
+	if WotLK then
+		function SetValue_wrapper(self, ...)
+			return dropDown_SetValue(...)
+		end
+	else
+		SetValue_wrapper = dropDown_SetValue
+	end
+	local function dropDown_menu(self)
+		for value, text in get_iter(self.values) do
+			local info = UIDropDownMenu_CreateInfo()
+			info.text = text
+			info.value = value
+			info.checked = self.value == value
+			info.func = SetValue_wrapper
+			info.arg1 = self
+			info.arg2 = value
+			UIDropDownMenu_AddButton(info)
+		end
+	end
+
+	local tmp = {}
+	--- Return a single-choice dropdown menu
+	-- This is for choosing a single choice among many
+	-- @name panel:MakeDropDown
+	-- @param ... tuple of key-value pairs<br/>
+	--     name: What shows above the dropdown<br/>
+	--     description: What shows when hovering over the dropdown<br/>
+	--     values: A list of options, in order, where the odd keys are the key and even are its corresponding value<br/>
+	--     default: The default key<br/>
+	--     current: The current key - you can either provide this or getFunc<br/>
+	--     getFunc: Function to return the current key<br/>
+	--     setFunc: What is called when the key changes<br/>
+	--     [optional] okayFunc: Called when the okay button is pressed<br/>
+	--     [optional] cancelFunc: Called when the cancel button is pressed<br/>
+	--     [optional] defaultFunc: Called when the default button is pressed
+	-- @usage panel:MakeDropDown(
+	--     'name', 'Choose',
+	--     'description', 'Specify your tooltip description',
+	--     'values', {
+	--         'ONE', "One",
+	--         'TWO', "Two",
+	--         'THREE', "Three",
+	--      },
+	--     'default', 'ONE',
+	--     'current', db.choice,
+	--     'setFunc', function(value) db.choice = value end,
+	-- )
+	-- @return the DropDown frame
+	function panelMeta:MakeDropDown(...)
+		local args = getArgs(...)
+		if type(args.name) ~= "string" then
+			error(("name must be %q, got %q (%s)"):format("string", type(args.name), tostring(args.name)), 2)
+		elseif type(args.description) ~= "string" then
+			error(("description must be %q, got %q (%s)"):format("string", type(args.description), tostring(args.description)), 2)
+		elseif type(args.values) ~= "function" then
+			if type(args.values) ~= "table" then
+				error(("values must be %q, got %q (%s)"):format("table", type(args.values), tostring(args.values)), 2)
+			elseif #args.values%2 ~= 0 then
+				error(("values must have an even number of items, got %d"):format(#args.values), 2)
+			end
+			for i = 1, #args.values, 2 do
+				local k, v = args.values[i], args.values[2]
+				if type(k) ~= "string" and type(k) ~= "number" then
+					error(("values' keys must be %q or %q, got %q (%s)"):format("string", "number", type(k), tostring(k)))
+				elseif type(v) ~= "string" then
+					error(("values' values must be %q, got %q (%s)"):format("string", type(v), tostring(v)))
+				end
+				tmp[k] = v
+			end
+		end
+		if type(args.default) ~= "number" and type(args.default) ~= "string" then
+			error(("default must be %q or %q, got %q (%s)"):format("number", "string", type(args.default), tostring(args.default)), 2)
+		elseif type(args.values) ~= "function" and not tmp[args.default] then
+			error(("default must be in values, %s is not"):format(tostring(args.default)), 2)
+		elseif not args.current == not args.getFunc then
+			error(("either current or getFunc must be supplied, but not both"), 2)
+		elseif args.current and type(args.current) ~= "string" and type(args.current) ~= "number" then
+			error(("current must be %q or %q, got %q (%s)"):format("string", "number", type(args.current), tostring(args.current)), 2)
+		elseif type(args.values) ~= "function" and args.current and not tmp[args.current] then
+			error(("current must be in values, %s is not"):format(tostring(args.current)), 2)
+		elseif args.getFunc and type(args.getFunc) ~= "function" then
+			error(("getFunc must be %q, got %q (%s)"):format("function", type(args.getFunc), tostring(args.getFunc)), 2)
+		elseif type(args.setFunc) ~= "function" then
+			error(("setFunc must be %q, got %q (%s)"):format("function", type(args.setFunc), tostring(args.setFunc)), 2)
+		elseif args.okayFunc and type(args.okayFunc) ~= "function" then
+			error(("okayFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.okayFunc), tostring(args.okayFunc)), 2)
+		elseif args.cancelFunc and type(args.cancelFunc) ~= "function" then
+			error(("cancelFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.cancelFunc), tostring(args.cancelFunc)), 2)
+		elseif args.defaultFunc and type(args.defaultFunc) ~= "function" then
+			error(("defaultFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.defaultFunc), tostring(args.defaultFunc)), 2)
+		end
+		for k in pairs(tmp) do
+			tmp[k] = nil
+		end
+		local name
+		local i = 0
+		repeat
+			i = i + 1
+			name = self:GetName() .. "_DropDown" .. i
+		until not _G[name]
+
+		local dropDown = CreateFrame("Frame", name, self, "UIDropDownMenuTemplate")
+		self.controls[dropDown] = true
+		if args.name ~= "" then
+			local label = dropDown:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
+			label:SetText(args.name)
+			label:SetPoint("BOTTOMLEFT", dropDown, "TOPLEFT", 16, 3)
+		end
+		dropDown.tooltipText = args.description
+		dropDown.values = args.values
+		UIDropDownMenu_Initialize(dropDown, function()
+			dropDown_menu(dropDown)
+		end)
+		if WotLK then
+			UIDropDownMenu_SetWidth(dropDown, 90)
+		else
+			UIDropDownMenu_SetWidth(90, dropDown)
+		end
+		local current
+		if args.getFunc then
+			dropDown.getFunc = args.getFunc
+			current = args.getFunc()
+		else
+			current = args.current
+		end
+		UIDropDownMenu_SetSelectedValue(dropDown, current)
+		dropDown.default = args.default
+		dropDown.value = args.current
+		dropDown.oldValue = args.current
+		dropDown.changeFunc = args.setFunc
+		dropDown.SetValue = dropDown_SetValue
+		dropDown:EnableMouse(true)
+		dropDown:SetScript("OnEnter", generic_OnEnter)
+		dropDown:SetScript("OnLeave", generic_OnLeave)
+		dropDown.okayFunc = args.okayFunc
+		dropDown.cancelFunc = args.cancelFunc
+		dropDown.defaultFunc = args.defaultFunc
+		args = doneArgs(args)
+		return dropDown
+	end
+end
+
+do
+	local function donothing() end
+	local function button_OnClick(self)
+		self.clickFunc()
+	end
+	--- Return a button
+	-- @name panel:MakeButton
+	-- @param ... tuple of key-value pairs<br/>
+	--     name: What shows above the dropdown<br/>
+	--     description: What shows when hovering over the dropdown<br/>
+	--     func: What is called when the button is pressed
+	-- @usage panel:MakeButton(
+	--     'name', 'Click',
+	--     'description', 'Specify your tooltip description',
+	--     'func', function() DEFAULT_CHAT_FRAME:AddMessage("Clicked!") end
+	-- )
+	-- @return the Button
+	function panelMeta:MakeButton(...)
+		local args = getArgs(...)
+		if type(args.name) ~= "string" then
+			error(("name must be %q, got %q (%s)"):format("string", type(args.name), tostring(args.name)), 2)
+		elseif type(args.description) ~= "string" then
+			error(("description must be %q, got %q (%s)"):format("string", type(args.description), tostring(args.description)), 2)
+		elseif type(args.func) ~= "function" then
+			error(("description must be %q, got %q (%s)"):format("function", type(args.func), tostring(args.func)), 2)
+		end
+		local name
+		local i = 0
+		repeat
+			i = i + 1
+			name = self:GetName() .. "_Button" .. i
+		until not _G[name]
+
+		local button = CreateFrame("Button", name, self, "UIPanelButtonTemplate2")
+		self.controls[button] = true
+		button:SetText(args.name)
+		button.tooltipText = args.description
+		button:SetWidth(120)
+		button:SetHeight(22)
+		button.SetValue = donothing
+		button.clickFunc = args.func
+		button:SetScript("OnClick", button_OnClick)
+		button:SetScript("OnEnter", generic_OnEnter)
+		button:SetScript("OnLeave", generic_OnLeave)
+		args = doneArgs(args)
+		return button
+	end
+end
+
+do
+	local function toggle_SetValue(self, value)
+		value = not not value
+		self.changeFunc(value)
+		self.value = value
+		self:SetChecked(value)
+	end
+	local function toggle_OnClick(self)
+		self:SetValue(not not self:GetChecked())
+	end
+	--- Return a checkbox
+	-- @name panel:MakeToggle
+	-- @param ... tuple of key-value pairs<br/>
+	--     name: What appears to the right of the checkbox<br/>
+	--     description: What the tooltip shows when hovering over<br/>
+	--     default: The default value<br/>
+	--     current: The current value - you can provide this or getFunc<br/>
+	--     getFunc: Function to return the current value<br/>
+	--     setFunc: What is called when the value changes<br/>
+	--     [optional] okayFunc: Called when the okay button is pressed<br/>
+	--     [optional] cancelFunc: Called when the cancel button is pressed<br/>
+	--     [optional] defaultFunc: Called when the default button is pressed
+	-- @usage panel:MakeToggle(
+	--     'name', 'Toggle',
+	--     'description', 'Specify your tooltip description',
+	--     'default', false,
+	--     'getFunc', function() return db.myToggle end
+	--     'setFunc', function(value) db.myToggle = value end
+	-- )
+	-- @return the CheckButton
+	function panelMeta:MakeToggle(...)
+		local args = getArgs(...)
+		if type(args.name) ~= "string" then
+			error(("name must be %q, got %q (%s)"):format("string", type(args.name), tostring(args.name)), 2)
+		elseif type(args.description) ~= "string" then
+			error(("description must be %q, got %q (%s)"):format("string", type(args.description), tostring(args.description)), 2)
+		elseif type(args.default) ~= "boolean" then
+			error(("default must be %q, got %q (%s)"):format("boolean", type(args.default), tostring(args.default)), 2)
+		elseif (args.current == nil) == not args.getFunc then
+			error(("either current or getFunc must be supplied, but not both"), 2)
+		elseif args.current and type(args.current) ~= "boolean" then
+			error(("current must be %q, got %q (%s)"):format("boolean", type(args.current), tostring(args.current)), 2)
+		elseif args.getFunc and type(args.getFunc) ~= "function" then
+			error(("getFunc must be %q, got %q (%s)"):format("function", type(args.getFunc), tostring(args.getFunc)), 2)
+		elseif type(args.setFunc) ~= "function" then
+			error(("setFunc must be %q, got %q (%s)"):format("function", type(args.setFunc), tostring(args.setFunc)), 2)
+		elseif args.okayFunc and type(args.okayFunc) ~= "function" then
+			error(("okayFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.okayFunc), tostring(args.okayFunc)), 2)
+		elseif args.cancelFunc and type(args.cancelFunc) ~= "function" then
+			error(("cancelFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.cancelFunc), tostring(args.cancelFunc)), 2)
+		elseif args.defaultFunc and type(args.defaultFunc) ~= "function" then
+			error(("defaultFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.defaultFunc), tostring(args.defaultFunc)), 2)
+		end
+		local name
+		local i = 0
+		repeat
+			i = i + 1
+			name = self:GetName() .. "_Toggle" .. i
+		until not _G[name]
+
+		local toggle = CreateFrame("CheckButton", name, self, "InterfaceOptionsCheckButtonTemplate")
+		self.controls[toggle] = true
+		_G[toggle:GetName() .. "Text"]:SetText(args.name)
+		toggle:SetHitRectInsets(0, -_G[toggle:GetName() .. "Text"]:GetWidth() - 1, 0, 0)
+		toggle.tooltipText = args.description
+		toggle.default = args.default
+		local current
+		if args.getFunc then
+			toggle.getFunc = args.getFunc
+			current = args.getFunc()
+		else
+			current = args.current
+		end
+		toggle.value = current
+		toggle.oldValue = current
+		toggle.changeFunc = args.setFunc
+		toggle.SetValue = toggle_SetValue
+		toggle:SetScript("OnClick", toggle_OnClick)
+		toggle:SetChecked(current)
+		toggle:SetScript("OnEnter", generic_OnEnter)
+		toggle:SetScript("OnLeave", generic_OnLeave)
+		toggle.okayFunc = args.okayFunc
+		toggle.cancelFunc = args.cancelFunc
+		toggle.defaultFunc = args.defaultFunc
+		args = doneArgs(args)
+		return toggle
+	end
+end
+
+do
+	local function update(self, r, g, b, a)
+		if not self.hasAlpha then
+			a = 1
+		end
+		self.info.r = r
+		self.info.g = g
+		self.info.b = b
+		if self.hasAlpha then
+			self.info.opacity = a
+		end
+		self.color:SetTexture(r, g, b, a)
+		if self.value == self.oldValue then
+			self.value = {}
+		end
+		self.value[1] = r
+		self.value[2] = g
+		self.value[3] = b
+		if self.hasAlpha then
+			self.value[4] = a
+		end
+		self.info.r = r
+		self.info.g = g
+		self.info.b = b
+		if self.hasAlpha then
+			self.info.opacity = 1 - a
+		end
+		if self.hasAlpha then
+			self.changeFunc(r, g, b, a)
+		else
+			self.changeFunc(r, g, b)
+		end
+	end
+	local function button_SetValue(self, ...)
+		if select('#', ...) == 1 and type((...)) == "table" then
+			return button_SetValue(self, unpack(value))
+		end
+		update(self, ...)
+	end
+	local function button_OnClick(self)
+		OpenColorPicker(self.info)
+	end
+	local function swatchFunc(self)
+		local r, g, b = ColorPickerFrame:GetColorRGB()
+		local opacity = 1 - OpacitySliderFrame:GetValue()
+
+		update(self, r, g, b, opacity)
+	end
+	local function cancelFunc(self)
+		local previousValues = ColorPickerFrame.previousValues
+		local r, g, b, opacity = previousValues.r, previousValues.g, previousValues.b, hasAlpha and 1 - previousValues.opacity or 1
+
+		update(self, r, g, b, opacity)
+	end
+	--- Return a color swatch that opens a color picker
+	-- @name panel:MakeColorPicker
+	-- @param ... tuple of key-value pairs<br/>
+	--     name: What shows up next to the swatch<br />
+	--     description: What shows up in the tooltip on hover<br />
+	--     hasAlpha: Whether the color picker should have an alpha setting<br />
+	--     defaultR: Default red value [0, 1]<br />
+	--     defaultG: Default green value [0, 1]<br />
+	--     defaultB: Default blue value [0, 1]<br />
+	--     defaultA: Default alpha value [0, 1], only needed if hasAlpha is true<br />
+	--     currentR: The current red value - you can provide this or getFunc<br />
+	--     currentG: The current green value - you can provide this or getFunc<br />
+	--     currentB: The current blue value - you can provide this or getFunc<br />
+	--     currentA: The current alpha value - you can provide this or getFunc<br />
+	--     getFunc: Function to return the current color as a tuple<br />
+	--     setFunc: What is called when the color changes<br />
+	--     [optional] okayFunc: Called when the okay button is pressed<br />
+	--     [optional] cancelFunc: Called when the cancel button is pressed<br />
+	--     [optional] defaultFunc: Called when the default button is pressed
+	-- @usage panel:MakeColorPicker(
+	--     'name', 'Pick a color',
+	--     'description', 'Specify your tooltip description',
+	--     'hasAlpha', false,
+	--     'defaultR', 1,
+	--     'defaultG', 0.82,
+	--     'defaultB', 0,
+	--     'getFunc', function() return unpack(db.color) end
+	--     'setFunc', function(r, g, b) db.color[1], db.color[2], db.color[3] = r, g, b end
+	-- )
+	-- @usage panel:MakeColorPicker(
+	--     'name', 'Pick a color',
+	--     'description', 'Specify your tooltip description',
+	--     'hasAlpha', true,
+	--     'defaultR', 0,
+	--     'defaultG', 1,
+	--     'defaultB', 0,
+	--     'defaultA', 0.5,
+	--     'currentR', db.color2.r,
+	--     'currentG', db.color2.g,
+	--     'currentB', db.color2.b,
+	--     'currentA', db.color2.a,
+	--     'setFunc', function(r, g, b, a) db.color2.r, db.color2.g db.color2.b, db.color2.a = r, g, b, a end
+	-- )
+	-- @return the color swatch
+	function panelMeta:MakeColorPicker(...)
+		local args = getArgs(...)
+		if type(args.name) ~= "string" then
+			error(("name must be %q, got %q (%s)"):format("string", type(args.name), tostring(args.name)), 2)
+		elseif type(args.description) ~= "string" then
+			error(("description must be %q, got %q (%s)"):format("string", type(args.description), tostring(args.description)), 2)
+		elseif type(args.hasAlpha) ~= "boolean" then
+			error(("hasAlpha must be %q, got %q (%s)"):format("boolean", type(args.hasAlpha), tostring(args.hasAlpha)), 2)
+		elseif type(args.defaultR) ~= "number" then
+			error(("defaultR must be %q, got %q (%s)"):format("number", type(args.defaultR), tostring(args.defaultR)), 2)
+		elseif args.defaultR < 0 or args.defaultR > 1 then
+			error(("defaultR must be [0, 1], got %s"):format(tostring(args.defaultR)), 2)
+		elseif type(args.defaultG) ~= "number" then
+			error(("defaultG must be %q, got %q (%s)"):format("number", type(args.defaultG), tostring(args.defaultG)), 2)
+		elseif args.defaultG < 0 or args.defaultG > 1 then
+			error(("defaultG must be [0, 1], got %s"):format(tostring(args.defaultG)), 2)
+		elseif type(args.defaultB) ~= "number" then
+			error(("defaultB must be %q, got %q (%s)"):format("number", type(args.defaultB), tostring(args.defaultB)), 2)
+		elseif args.defaultB < 0 or args.defaultB > 1 then
+			error(("defaultB must be [0, 1], got %s"):format(tostring(args.defaultB)), 2)
+		elseif args.hasAlpha and type(args.defaultA) ~= "number" then
+			error(("defaultA must be %q, got %q (%s)"):format("number", type(args.defaultA), tostring(args.defaultA)), 2)
+		elseif args.hasAlpha and (args.defaultA < 0 or args.defaultA > 1) then
+			error(("defaultA must be [0, 1], got %s"):format(tostring(args.defaultA)), 2)
+		elseif not args.currentR == not args.getFunc then
+			error(("either currentR or getFunc must be supplied, but not both"), 2)
+		elseif args.currentR and (not args.currentG or not args.currentB or (args.hasAlpha and not args.currentA)) then
+			error(("if you supply currentR, you must supply currentG and currentB (and currentA if hasAlpha)"), 2)
+		elseif args.currentR and type(args.currentR) ~= "number" then
+			error(("current must be %q, got %q (%s)"):format("number", type(args.currentR), tostring(args.currentR)), 2)
+		elseif args.currentG and type(args.currentG) ~= "number" then
+			error(("current must be %q, got %q (%s)"):format("number", type(args.currentG), tostring(args.currentG)), 2)
+		elseif args.currentB and type(args.currentB) ~= "number" then
+			error(("current must be %q, got %q (%s)"):format("number", type(args.currentB), tostring(args.currentB)), 2)
+		elseif args.currentA and type(args.currentA) ~= "number" then
+			error(("current must be %q, got %q (%s)"):format("number", type(args.currentA), tostring(args.currentA)), 2)
+		elseif args.getFunc and type(args.getFunc) ~= "function" then
+			error(("getFunc must be %q, got %q (%s)"):format("function", type(args.getFunc), tostring(args.getFunc)), 2)
+		elseif type(args.setFunc) ~= "function" then
+			error(("setFunc must be %q, got %q (%s)"):format("function", type(args.setFunc), tostring(args.setFunc)), 2)
+		elseif args.okayFunc and type(args.okayFunc) ~= "function" then
+			error(("okayFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.okayFunc), tostring(args.okayFunc)), 2)
+		elseif args.cancelFunc and type(args.cancelFunc) ~= "function" then
+			error(("cancelFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.cancelFunc), tostring(args.cancelFunc)), 2)
+		elseif args.defaultFunc and type(args.defaultFunc) ~= "function" then
+			error(("defaultFunc must be %q or %q, got %q (%s)"):format("nil", "function", type(args.defaultFunc), tostring(args.defaultFunc)), 2)
+		end
+
+		local name
+		local i = 0
+		repeat
+			i = i + 1
+			name = self:GetName() .. "_ColorPicker" .. i
+		until not _G[name]
+
+		if not args.hasAlpha then
+			args.defaultA = 1
+		end
+
+		local button = CreateFrame("Button", name, self)
+		self.controls[button] = true
+
+
+		local currentR, currentG, currentB, currentA
+		if args.getFunc then
+			button.getFunc = args.getFunc
+			currentR, currentG, currentB, currentA = button.getFunc()
+			if not args.hasAlpha then
+				currentA = 1
+			end
+		else
+			currentR = args.currentR
+			currentG = args.currentG
+			currentB = args.currentB
+			if not args.hasAlpha then
+				currentA = 1
+			else
+				currentR = args.currentA
+			end
+		end
+
+		button.tooltipText = args.description
+		local text = button:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
+		text:SetText(args.name)
+		text:SetPoint("LEFT", button, "RIGHT", 0, 1)
+		button:SetHitRectInsets(0, -text:GetWidth() - 1, 0, 0)
+		local color = button:CreateTexture(nil, "ARTWORK")
+		button.color = color
+		color:SetTexture(currentR, currentG, currentB, currentA)
+		local background = button:CreateTexture(nil, "BORDER")
+		background:SetTexture([=[Tileset\Generic\Checkers]=])
+		background:SetTexCoord(0, 0.5, 0, 0.5)
+		local border = button:CreateTexture(nil, "BACKGROUND")
+		border:SetTexture([=[Interface\ChatFrame\ChatFrameColorSwatch]=])
+		button:SetWidth(26)
+		button:SetHeight(26)
+		background:SetPoint("CENTER")
+		background:SetWidth(14)
+		background:SetHeight(14)
+		color:SetPoint("CENTER")
+		color:SetWidth(14)
+		color:SetHeight(14)
+		border:SetAllPoints(button)
+		button.default = { args.defaultR, args.defaultG, args.defaultB }
+		button.oldValue = { currentR, currentG, currentB }
+		if hasAlpha then
+			button.default[4] = args.defaultA
+			button.oldValue[4] = currentA
+		end
+		button.value = button.oldValue
+		button.hasAlpha = args.hasAlpha
+		button.changeFunc = args.setFunc
+		button.SetValue = button_SetValue
+		local function swatchFunc_wrapper()
+			swatchFunc(button)
+		end
+		local function cancelFunc_wrapper()
+			cancelFunc(button)
+		end
+		button.info = {
+			swatchFunc = swatchFunc_wrapper,
+			hasOpacity = args.hasAlpha,
+			opacityFunc = args.hasAlpha and swatchFunc_wrapper or nil,
+			r = currentR,
+			g = currentB,
+			b = currentG,
+			opacity = args.hasAlpha and 1 - currentA or nil,
+			cancelFunc = cancelFunc_wrapper,
+		}
+		button:SetScript("OnClick", button_OnClick)
+		button:SetScript("OnEnter", generic_OnEnter)
+		button:SetScript("OnLeave", generic_OnLeave)
+		button:RegisterForClicks("LeftButtonUp")
+		button.okayFunc = args.okayFunc
+		button.cancelFunc = args.cancelFunc
+		button.defaultFunc = args.defaultFunc
+		args = doneArgs(args)
+		return button
+	end
+end
+
+--- Add a slash command to open a specific options panel
+-- @param name name of the panel to open
+-- @param ... tuple of slash commands
+-- @usage LibStub("LibSimpleOptions-1.0").AddSlashCommand("My Options", "/MyOpt", "/MO")
+function LibSimpleOptions.AddSlashCommand(name, ...)
+	local num = 0
+	local name_upper = name:upper()
+	for i = 1, select('#', ...) do
+		local cmd = select(i, ...)
+		num = num + 1
+		_G["SLASH_" .. name_upper .. num] = cmd
+		local cmd_lower = cmd:lower()
+		if cmd_lower ~= cmd then
+			num = num + 1
+			_G["SLASH_" .. name_upper .. num] = cmd_lower
+		end
+	end
+
+	_G.hash_SlashCmdList[name_upper] = nil
+	_G.SlashCmdList[name_upper] = function()
+		InterfaceOptionsFrame_OpenToFrame(name)
+	end
+end
+
+for funcName, func in pairs(panelMeta) do
+	LibSimpleOptions[funcName] = func
+	for panel in pairs(panels) do
+		panel[funcName] = func
+	end
+end
\ No newline at end of file
diff --git a/pMinimap/Libs/LibStub.lua b/pMinimap/Libs/LibStub.lua
new file mode 100644
index 0000000..f5fc919
--- /dev/null
+++ b/pMinimap/Libs/LibStub.lua
@@ -0,0 +1,51 @@
+-- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $
+-- LibStub is a simple versioning stub meant for use in Libraries.  http://www.wowace.com/wiki/LibStub for more info
+-- LibStub is hereby placed in the Public Domain
+-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
+local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2  -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
+local LibStub = _G[LIBSTUB_MAJOR]
+
+-- Check to see is this version of the stub is obsolete
+if not LibStub or LibStub.minor < LIBSTUB_MINOR then
+	LibStub = LibStub or {libs = {}, minors = {} }
+	_G[LIBSTUB_MAJOR] = LibStub
+	LibStub.minor = LIBSTUB_MINOR
+
+	-- LibStub:NewLibrary(major, minor)
+	-- major (string) - the major version of the library
+	-- minor (string or number ) - the minor version of the library
+	--
+	-- returns nil if a newer or same version of the lib is already present
+	-- returns empty library object or old library object if upgrade is needed
+	function LibStub:NewLibrary(major, minor)
+		assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
+		minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
+
+		local oldminor = self.minors[major]
+		if oldminor and oldminor >= minor then return nil end
+		self.minors[major], self.libs[major] = minor, self.libs[major] or {}
+		return self.libs[major], oldminor
+	end
+
+	-- LibStub:GetLibrary(major, [silent])
+	-- major (string) - the major version of the library
+	-- silent (boolean) - if true, library is optional, silently return nil if its not found
+	--
+	-- throws an error if the library can not be found (except silent is set)
+	-- returns the library object if found
+	function LibStub:GetLibrary(major, silent)
+		if not self.libs[major] and not silent then
+			error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
+		end
+		return self.libs[major], self.minors[major]
+	end
+
+	-- LibStub:IterateLibraries()
+	--
+	-- Returns an iterator for the currently registered libraries
+	function LibStub:IterateLibraries()
+		return pairs(self.libs)
+	end
+
+	setmetatable(LibStub, { __call = LibStub.GetLibrary })
+end
diff --git a/pMinimap/pMinimap.lua b/pMinimap/pMinimap.lua
index 9c2822d..f3cbab5 100644
--- a/pMinimap/pMinimap.lua
+++ b/pMinimap/pMinimap.lua
@@ -1,8 +1,8 @@
 pMinimap = CreateFrame('Frame', 'pMinimap', UIParent)
-pMinimap:SetScript('OnEvent', function(self, event, ...) self[event](self, event, ...) end)
+pMinimap:SetScript('OnEvent', function(self, event, ...) self[event](self, ...) end)
 pMinimap:RegisterEvent('ADDON_LOADED')

-function pMinimap:ADDON_LOADED()
+function pMinimap.ADDON_LOADED(self)
 	local db = pMinimapDB or {point = {'TOPRIGHT', UIParent, 'TOPRIGHT', -15, -15}, scale = 0.9, offset = 1, colors = {0, 0, 0}, durability = true}

 	MinimapBorder:SetTexture()
@@ -23,8 +23,9 @@ function pMinimap:ADDON_LOADED()
 	MinimapZoneText:Hide()
 	MinimapZoneTextButton:Hide()

-	MiniMapTrackingBorder:SetTexture()
+	MiniMapTrackingButtonBorder:SetTexture()
 	MiniMapTrackingBackground:Hide()
+	MiniMapTrackingIconOverlay:SetAlpha(0)
 	MiniMapTrackingIcon:SetTexCoord(0.065, 0.935, 0.065, 0.935)
 	MiniMapTracking:SetParent(Minimap)
 	MiniMapTracking:ClearAllPoints()
@@ -83,7 +84,7 @@ function pMinimap:ADDON_LOADED()
 	self:UnregisterEvent('ADDON_LOADED')
 end

-function pMinimap:UPDATE_INVENTORY_ALERTS()
+function pMinimap.UPDATE_INVENTORY_ALERTS()
 	local db = pMinimapDB or {colors = {0, 0, 0, 1}}
 	local maxStatus = 0
 	for id in pairs(INVENTORY_ALERT_STATUS_SLOTS) do
diff --git a/pMinimap/pMinimap.toc b/pMinimap/pMinimap.toc
index 0e674b1..a679854 100644
--- a/pMinimap/pMinimap.toc
+++ b/pMinimap/pMinimap.toc
@@ -1,13 +1,13 @@
-## Interface: 20400
+## Interface: 30000
 ## Author: p3lim
-## Version: 20400.wowi:revision
+## Version: 30000.wowi:revision
 ## Title: |cffff6000p|rMinimap
 ## Notes: Yet another square minimap addon
 ## OptionalDeps: LibStub, LibSimpleOptions-1.0
 ## SavedVariablesPerCharacter: pMinimapDB

-LibSimpleOptions-1.0\LibStub\LibStub.lua
-LibSimpleOptions-1.0\LibSimpleOptions-1.0.lua
+Libs\LibStub.lua
+Libs\LibSimpleOptions-1.0.lua

 pMinimap.lua
-pMinimapConfig.lua
\ No newline at end of file
+pMinimapConfig.lua
diff --git a/pMinimap/pMinimapConfig.lua b/pMinimap/pMinimapConfig.lua
index 7d5a4fb..273491c 100644
--- a/pMinimap/pMinimapConfig.lua
+++ b/pMinimap/pMinimapConfig.lua
@@ -91,7 +91,7 @@ local function CreateOptions(self, db)
 	):SetPoint('TOPLEFT', sub, 'BOTTOMLEFT', 0, -156)
 end

-function pMinimap:PLAYER_ENTERING_WORLD(event)
+function pMinimap.PLAYER_ENTERING_WORLD(self, event)
 	local db = pMinimapDB or {point = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -15, -15}, scale = 0.9, offset = 1, colors = {0, 0, 0, 1}, durability = true}

 	LibStub('LibSimpleOptions-1.0').AddOptionsPanel('pMinimap', function(self) CreateOptions(self, db) end)