Quantcast

* Anchoring code is here, maybe

James Whitehead II [02-12-09 - 18:57]
* Anchoring code is here, maybe
Filename
Libs/tekKonfigAboutPanel.lua
Libs/tekKonfigScroll.lua
NinjaLogo.tga
NinjaPanel.lua
NinjaPanel.toc
diff --git a/Libs/tekKonfigAboutPanel.lua b/Libs/tekKonfigAboutPanel.lua
new file mode 100644
index 0000000..98022b4
--- /dev/null
+++ b/Libs/tekKonfigAboutPanel.lua
@@ -0,0 +1,115 @@
+
+local lib, oldminor = LibStub:NewLibrary("tekKonfig-AboutPanel", 5)
+if not lib then return end
+
+
+function lib.new(parent, addonname)
+	local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer)
+	frame.name, frame.parent, frame.addonname = parent and "About" or addonname, parent, addonname
+	frame:Hide()
+	frame:SetScript("OnShow", lib.OnShow)
+	InterfaceOptions_AddCategory(frame)
+	return frame
+end
+
+
+local editbox = CreateFrame('EditBox', nil, UIParent)
+editbox:Hide()
+editbox:SetAutoFocus(true)
+editbox:SetHeight(32)
+editbox:SetFontObject('GameFontHighlightSmall')
+lib.editbox = editbox
+
+local left = editbox:CreateTexture(nil, "BACKGROUND")
+left:SetWidth(8) left:SetHeight(20)
+left:SetPoint("LEFT", -5, 0)
+left:SetTexture("Interface\\Common\\Common-Input-Border")
+left:SetTexCoord(0, 0.0625, 0, 0.625)
+
+local right = editbox:CreateTexture(nil, "BACKGROUND")
+right:SetWidth(8) right:SetHeight(20)
+right:SetPoint("RIGHT", 0, 0)
+right:SetTexture("Interface\\Common\\Common-Input-Border")
+right:SetTexCoord(0.9375, 1, 0, 0.625)
+
+local center = editbox:CreateTexture(nil, "BACKGROUND")
+center:SetHeight(20)
+center:SetPoint("RIGHT", right, "LEFT", 0, 0)
+center:SetPoint("LEFT", left, "RIGHT", 0, 0)
+center:SetTexture("Interface\\Common\\Common-Input-Border")
+center:SetTexCoord(0.0625, 0.9375, 0, 0.625)
+
+editbox:SetScript("OnEscapePressed", editbox.ClearFocus)
+editbox:SetScript("OnEnterPressed", editbox.ClearFocus)
+editbox:SetScript("OnEditFocusLost", editbox.Hide)
+editbox:SetScript("OnEditFocusGained", editbox.HighlightText)
+editbox:SetScript("OnTextChanged", function(self)
+	self:SetText(self:GetParent().val)
+	self:HighlightText()
+end)
+
+
+function lib.OpenEditbox(self)
+	editbox:SetText(self.val)
+	editbox:SetParent(self)
+	editbox:SetPoint("LEFT", self)
+	editbox:SetPoint("RIGHT", self)
+	editbox:Show()
+end
+
+
+local fields = {"Version", "Author", "X-Category", "X-License", "X-Email", "X-Website", "X-Credits"}
+local haseditbox = {["Version"] = true, ["X-Website"] = true, ["X-Email"] = true}
+local function HideTooltip() GameTooltip:Hide() end
+local function ShowTooltip(self)
+	GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT")
+	GameTooltip:SetText("Click and press Ctrl-C to copy")
+end
+function lib.OnShow(frame)
+	local notes = GetAddOnMetadata(frame.addonname, "Notes")
+
+	local title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
+	title:SetPoint("TOPLEFT", 16, -16)
+	title:SetText((frame.parent or frame.addonname).." - About")
+
+	local subtitle = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+	subtitle:SetHeight(32)
+	subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
+	subtitle:SetPoint("RIGHT", parent, -32, 0)
+	subtitle:SetNonSpaceWrap(true)
+	subtitle:SetJustifyH("LEFT")
+	subtitle:SetJustifyV("TOP")
+	subtitle:SetText(notes)
+
+	local anchor
+	for _,field in pairs(fields) do
+		local val = GetAddOnMetadata(frame.addonname, field)
+		if val then
+			local title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
+			title:SetWidth(75)
+			if not anchor then title:SetPoint("TOPLEFT", subtitle, "BOTTOMLEFT", -2, -8)
+			else title:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -6) end
+			title:SetJustifyH("RIGHT")
+			title:SetText(field:gsub("X%-", ""))
+
+			local detail = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+			detail:SetPoint("LEFT", title, "RIGHT", 4, 0)
+			detail:SetPoint("RIGHT", -16, 0)
+			detail:SetJustifyH("LEFT")
+			detail:SetText((haseditbox[field] and "|cff9999ff" or "").. val)
+
+			if haseditbox[field] then
+				local button = CreateFrame("Button", nil, frame)
+				button:SetAllPoints(detail)
+				button.val = val
+				button:SetScript("OnClick", lib.OpenEditbox)
+				button:SetScript("OnEnter", ShowTooltip)
+				button:SetScript("OnLeave", HideTooltip)
+			end
+
+			anchor = title
+		end
+	end
+
+	frame:SetScript("OnShow", nil)
+end
diff --git a/Libs/tekKonfigScroll.lua b/Libs/tekKonfigScroll.lua
new file mode 100644
index 0000000..18ad71a
--- /dev/null
+++ b/Libs/tekKonfigScroll.lua
@@ -0,0 +1,80 @@
+
+local lib, oldminor = LibStub:NewLibrary("tekKonfig-Scroll", 2)
+if not lib then return end
+
+lib.bg = {
+	edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
+	tile = true,
+	tileSize = 16,
+	edgeSize = 12,
+	insets = { left = 0, right = 0, top = 5, bottom = 5 }
+}
+
+-- Creates a scrollbar
+-- Parent is required, offset and step are optional
+function lib.new(parent, offset, step)
+	local f = CreateFrame("Slider", nil, parent)
+	f:SetWidth(16)
+
+	f:SetPoint("TOPRIGHT", 0 - (offset or 0), -16 - (offset or 0))
+	f:SetPoint("BOTTOMRIGHT", 0 - (offset or 0), 16 + (offset or 0))
+
+	local up = CreateFrame("Button", nil, f)
+	up:SetPoint("BOTTOM", f, "TOP")
+	up:SetWidth(16) up:SetHeight(16)
+	up:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Up")
+	up:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Down")
+	up:SetDisabledTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Disabled")
+	up:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Highlight")
+
+	up:GetNormalTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	up:GetPushedTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	up:GetDisabledTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	up:GetHighlightTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	up:GetHighlightTexture():SetBlendMode("ADD")
+
+	up:SetScript("OnClick", function(self)
+		local parent = self:GetParent()
+		parent:SetValue(parent:GetValue() - (step or parent:GetHeight()/2))
+		PlaySound("UChatScrollButton")
+	end)
+
+	local down = CreateFrame("Button", nil, f)
+	down:SetPoint("TOP", f, "BOTTOM")
+	down:SetWidth(16) down:SetHeight(16)
+	down:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Up")
+	down:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Down")
+	down:SetDisabledTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Disabled")
+	down:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Highlight")
+
+	down:GetNormalTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	down:GetPushedTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	down:GetDisabledTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	down:GetHighlightTexture():SetTexCoord(1/4, 3/4, 1/4, 3/4)
+	down:GetHighlightTexture():SetBlendMode("ADD")
+
+	down:SetScript("OnClick", function(self)
+		local parent = self:GetParent()
+		parent:SetValue(parent:GetValue() + (step or parent:GetHeight()/2))
+		PlaySound("UChatScrollButton")
+	end)
+
+	f:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
+	local thumb = f:GetThumbTexture()
+	thumb:SetWidth(16) thumb:SetHeight(24)
+	thumb:SetTexCoord(1/4, 3/4, 1/8, 7/8)
+
+	f:SetScript("OnValueChanged", function(self, value)
+		local min, max = self:GetMinMaxValues()
+		if value == min then up:Disable() else up:Enable() end
+		if value == max then down:Disable() else down:Enable() end
+	end)
+
+	local border = CreateFrame("Frame", nil, f)
+	border:SetPoint("TOPLEFT", up, -5, 5)
+	border:SetPoint("BOTTOMRIGHT", down, 5, -3)
+	border:SetBackdrop(lib.bg)
+	border:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5)
+
+	return f, up, down, border
+end
diff --git a/NinjaLogo.tga b/NinjaLogo.tga
new file mode 100644
index 0000000..ea21497
Binary files /dev/null and b/NinjaLogo.tga differ
diff --git a/NinjaPanel.lua b/NinjaPanel.lua
index bcc63ca..d1fbf55 100644
--- a/NinjaPanel.lua
+++ b/NinjaPanel.lua
@@ -1,145 +1,148 @@
-NinjaPanel = {panels = {}, plugins = {}}
+NinjaPanel = {}

 -- Import Data Broker and bail if we can't find it for some reason
 local ldb = LibStub:GetLibrary("LibDataBroker-1.1")
 local jostle = LibStub:GetLibrary("LibJostle-3.0", true)
 local db

+local options = {
+	panels = setmetatable({}, { __index = {
+		TOP = {
+			anchors = {"TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT"},
+			sizes = {25, 2, 23, 23, 23, nil},
+			offsets = {0, 0, 0, 0},
+			gradient = {"VERTICAL", 0.2, 0.2, 0.2, 0, 0, 0},
+			bgradient = {"HORIZONTAL", 203/255, 161/255, 53/255, 0, 0, 0},
+		},
+		RIGHT = {
+			anchors = {"TOPRIGHT", "BOTTOMRIGHT", "TOPLEFT", "BOTTOMLEFT"},
+			sizes = {25, 2, 23, 23, 23, nil},
+			offsets = {0, 0, 0, 0},
+			gradient = {"HORIZONTAL", 0.2, 0.2, 0.2, 0, 0, 0},
+			bgradient = {"VERTICAL", 0, 0, 0, 203/255, 161/255, 53/255},
+		},
+		BOTTOM = {
+			anchors = {"BOTTOMLEFT", "BOTTOMRIGHT", "TOPLEFT", "TOPRIGHT"},
+			sizes = {25, 2, 23, 23, 23, nil},
+			offsets = {0, 0, 0, 0},
+			gradient = {"VERTICAL", 0, 0, 0, 0.2, 0.2, 0.2},
+			bgradient = {"HORIZONTAL", 0, 0, 0, 203/255, 161/255, 53/255},
+		},
+		LEFT = {
+			anchors = {"TOPLEFT", "BOTTOMLEFT", "TOPRIGHT", "BOTTOMRIGHT"},
+			sizes = {25, 2, 23, 23, 23, nil},
+			offsets = {0, 0, 0, 0},
+			gradient = {"HORIZONTAL", 0, 0, 0, 0.2, 0.2, 0.2},
+			bgradient = {"VERTICAL", 203/255, 161/255, 53/255, 0, 0, 0},
+		},
+	}})
+}
+
 local eventFrame = CreateFrame("Frame", "NinjaPanelEventFrame", UIParent)
 eventFrame:RegisterEvent("ADDON_LOADED")
 eventFrame:SetScript("OnEvent", function(self, event, arg1, ...)
 	if arg1 == "NinjaPanel" and event == "ADDON_LOADED" then
-		-- Update addon options once they've been loaded
-		if not NinjaPanelDB then
-			NinjaPanelDB = {}
-		end
-		db = NinjaPanelDB
-		db.panels = db.panels or {}
-		db.plugins = db.plugins or {}
-
 		self:UnregisterEvent("ADDON_LOADED")
-		NinjaPanel:SpawnPanel("NinjaPanelTop", "TOP")
-		if db.DEVELOPMENT then
-			-- Spawn all four bars so we can test
-			NinjaPanel:SpawnPanel("NinjaPanelBottom", "BOTTOM")
-			NinjaPanel:SpawnPanel("NinjaPanelRight", "RIGHT")
-			NinjaPanel:SpawnPanel("NinjaPanelLeft", "LEFT")
-
-			-- Create two plugins for each bar in order to test drag/drop
-			ldb:NewDataObject("TopOne", { type = "data source", text = "Top One" })
-			ldb:NewDataObject("TopTwo", { type = "data source", text = "Top Two" })
-			ldb:NewDataObject("BottomOne", { type = "data source", text = "Bottom One"})
-			ldb:NewDataObject("BottomTwo", { type = "data source", text = "Bottom Two"})
-			ldb:NewDataObject("LeftOne", { type = "launcher", icon = "Interface\\Icons\\Spell_Nature_StormReach"})
-			ldb:NewDataObject("LeftTwo", { type = "launcher", icon = "Interface\\Icons\\Spell_Nature_StormReach"})
-			ldb:NewDataObject("RightOne", { type = "launcher", icon = "Interface\\Icons\\Spell_Nature_StormReach"})
-			ldb:NewDataObject("RightTwo", { type = "launcher", icon = "Interface\\Icons\\Spell_Nature_StormReach"})
-		end

-		NinjaPanel:ScanForPlugins()
+		-- TODO: Set this to actually use the SV
+		NinjaPanel.db = options
+		NinjaPanel.panels = {}

-		if db.DEVELOPMENT then
-			db.plugins["TopOne"].panel = "NinjaPanelTop"
-			db.plugins["TopTwo"].panel = "NinjaPanelTop"
-			db.plugins["BottomOne"].panel = "NinjaPanelBottom"
-			db.plugins["BottomTwo"].panel = "NinjaPanelBottom"
-			NinjaPanel:UpdatePanels()
-		end
+		NinjaPanel:SpawnPanel("NinjaPanelTop", "TOP")
+		NinjaPanel:SpawnPanel("NinjaPanelBottom", "BOTTOM")
+		NinjaPanel:SpawnPanel("NinjaPanelRight", "RIGHT")
+		NinjaPanel:SpawnPanel("NinjaPanelLeft", "LEFT")
+
+		--ldb.RegisterCallback(NinjaPanel, "LibDataBroker_DataObjectCreated", "ScanForPlugins")
 	end
 end)

--- Local functions that are defined below
-local SortWeightName
-local Button_OnEnter, Button_OnLeave
-local Button_OnDragStart, Button_OnDragStop, Button_OnUpdateDragging
-local Button_Tooltip_OnEnter, Button_Tooltip_OnLeave
-local Panel_UpdateLayout
-
 function NinjaPanel:SpawnPanel(name, position)
 	local panel = CreateFrame("Frame", name, eventFrame)
 	panel.bg = panel:CreateTexture(name .. "BG", "BACKGROUND")
 	panel.border = panel:CreateTexture(name .. "Border", "BACKGROUND")
+	panel.boxes = {}
+	panel.left = CreateFrame("Button", nil, panel)
+	panel.center = CreateFrame("Button", nil, panel)
+	panel.right = CreateFrame("Button", nil, panel)
+	panel.left.bg = panel.left:CreateTexture(nil, "BACKGROUND")
+	panel.center.bg = panel.center:CreateTexture(nil, "BACKGROUND")
+	panel.right.bg = panel.right:CreateTexture(nil, "BACKGROUND")
 	panel.name = name
 	panel.position = position

+	local horizontal = (position == "TOP") or (position == "BOTTOM")
+	local opts = self.db.panels[position]
+	local anch = opts.anchors
+
+	-- Anchor the panel in place
 	panel:ClearAllPoints()
-	if position == "TOP" then
-		panel:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 0, 0)
-		panel:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", 0, 0)
-		panel:SetHeight(16)
-		panel.bg:SetTexture(1, 1, 1, 0.8)
-		panel.bg:SetGradient("VERTICAL", 0.2, 0.2, 0.2, 0, 0, 0)
-		panel.bg:SetPoint("TOPLEFT")
-		panel.bg:SetPoint("TOPRIGHT")
-		panel.bg:SetHeight(15)
-		panel.border:SetTexture(1, 1, 1, 0.8)
-		panel.border:SetGradient("HORIZONTAL", 203 / 255, 161 / 255, 53 / 255, 0, 0, 0)
-		panel.border:SetPoint("TOPLEFT", panel.bg, "BOTTOMLEFT", 0, 0)
-		panel.border:SetPoint("TOPRIGHT", panel.bg, "BOTTOMRIGHT", 0, 0)
-		panel.border:SetHeight(1)
-
-		if jostle then
-			jostle:RegisterTop(panel)
-		end
-	elseif position == "BOTTOM" then
-		panel:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 0, 0)
-		panel:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", 0, 0)
-		panel:SetHeight(16)
-		panel.bg:SetTexture(1, 1, 1, 0.8)
-		panel.bg:SetGradient("VERTICAL", 0.2, 0.2, 0.2, 0, 0, 0)
-		panel.bg:SetPoint("BOTTOMLEFT")
-		panel.bg:SetPoint("BOTTOMRIGHT")
-		panel.bg:SetHeight(15)
-		panel.border:SetTexture(1, 1, 1, 0.8)
-		panel.border:SetGradient("HORIZONTAL", 203 / 255, 161 / 255, 53 / 255, 0, 0, 0)
-		panel.border:SetPoint("BOTTOMLEFT", panel.bg, "TOPLEFT", 0, 0)
-		panel.border:SetPoint("BOTTOMRIGHT", panel.bg, "TOPRIGHT", 0, 0)
-		panel.border:SetHeight(1)
-
-		if jostle then
-			jostle:RegisterBottom(panel)
-		end
-	elseif position == "RIGHT" then
-		-- TODO: Fix the colors and gradients here
-		panel:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", 0, 0)
-		panel:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", 0, 0)
-		panel:SetWidth(16)
-		panel.bg:SetTexture(1, 1, 1, 0.8)
-		panel.bg:SetGradient("VERTICAL", 0.2, 0.2, 0.2, 0, 0, 0)
-		panel.bg:SetPoint("TOPRIGHT")
-		panel.bg:SetPoint("BOTTOMRIGHT")
-		panel.bg:SetWidth(15)
-		panel.border:SetTexture(1, 1, 1, 0.8)
-		panel.border:SetGradient("VERTICAL", 203 / 255, 161 / 255, 53 / 255, 0, 0, 0)
-		panel.border:SetPoint("TOPRIGHT", panel.bg, "TOPLEFT", 0, 0)
-		panel.border:SetPoint("BOTTOMRIGHT", panel.bg, "BOTTOMLEFT", 0, 0)
-		panel.border:SetWidth(1)
-	elseif position == "LEFT" then
-		-- TODO: Fix the colors and gradients here
-		panel:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 0, 0)
-		panel:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 0, 0)
-		panel:SetWidth(16)
-		panel.bg:SetTexture(1, 1, 1, 0.8)
-		panel.bg:SetGradient("HORIZONTAL", 0, 0, 0, 0.2, 0.2, 0.2)
-		panel.bg:SetPoint("TOPLEFT")
-		panel.bg:SetPoint("BOTTOMLEFT")
-		panel.bg:SetWidth(15)
-		panel.border:SetTexture(1, 1, 1, 0.8)
-		panel.border:SetGradient("VERTICAL", 203 / 255, 161 / 255, 53 / 255, 0, 0, 0)
-		panel.border:SetPoint("TOPLEFT", panel.bg, "TOPRIGHT", 0, 0)
-		panel.border:SetPoint("BOTTOMLEFT", panel.bg, "BOTTOMRIGHT", 0, 0)
-		panel.border:SetWidth(1)
-	end
-
-
-	-- TODO: Add the panel methods here
-	panel.plugins = {}
-	table.insert(self.panels, panel)
-	self.panels[panel.name] = panel
+	panel:SetPoint(anch[1], UIParent, anch[1], opts.offsets[1], opts.offsets[2])
+	panel:SetPoint(anch[2], UIParent, anch[2], opts.offsets[3], opts.offsets[4])
+	local size = opts.sizes[1] + opts.sizes[2]
+	if horizontal then panel:SetHeight(size) else panel:SetWidth(size) end
+
+	-- Set the gradient/texture for the background
+	panel.bg:SetTexture(1, 1, 1, 0.8)
+	panel.bg:SetGradient(unpack(opts.gradient))
+	if horizontal then panel.bg:SetHeight(size) else panel.bg:SetWidth(size) end
+
+	-- Set the border gradient/texture
+	panel.border:SetTexture(1, 1, 1, 0.8)
+	panel.border:SetGradient(unpack(opts.bgradient))
+	panel.border:SetPoint(anch[1], panel.bg, anch[3], opts.offsets[1], opts.offsets[2])
+	panel.border:SetPoint(anch[2], panel.bg, anch[4], opts.offsets[3], opts.offsets[4])
+	if horizontal then panel.border:SetHeight(opts.sizes[2]) else panel.border:SetWidth(opts.sizes[2]) end
+
+	-- Anchor the drag receive boxes
+	panel.left:SetPoint(anch[1])
+	panel.center:SetPoint("CENTER")
+	panel.right:SetPoint(anch[2])
+
+	-- Spawn a test button on the panel
+	local button = self:SpawnButton(name .. "Test")
+	button:SetHeight(opts.sizes[1])
+	button.icon:SetPoint("LEFT", 2, 0)
+	button.icon:SetWidth(opts.sizes[3])
+	button.icon:SetHeight(opts.sizes[4])
+	--button.text:SetHeight(opts[5])
+	--button.text:SetPoint("LEFT", button.icon, "RIGHT", 2)
+	button:SetWidth(button.icon:GetWidth() + 4)
+	button:SetPoint("LEFT", panel, "LEFT")
+	button:SetParent(panel)

+	table.insert(self.panels, panel)
 	return panel
 end

+function NinjaPanel:SpawnButton(name)
+	local button = CreateFrame("Button", "NinjaPanelButton_" .. name, eventFrame)
+	button.icon = button:CreateTexture(nil, "BACKGROUND")
+	button.text = button:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
+	button.text:SetText("Test Button")
+	button.icon:SetTexture("Interface\\Icons\\INV_RoseBouquet01")
+	button:RegisterForClicks("AnyUp")
+	button:SetMovable(true)
+
+	return button
+end
+
+-- Local functions that are defined below
+local SortWeightName
+local Button_OnEnter, Button_OnLeave
+local Button_OnDragStart, Button_OnDragStop, Button_OnUpdateDragging
+local Button_Tooltip_OnEnter, Button_Tooltip_OnLeave
+local Panel_UpdateLayout
+
+function NinjaPanel:ActivateDragBoxes()
+	for idx,panel in ipairs(self.panels) do
+		print("Updating drag boxes for panel: " .. panel.name)
+		panel.left.bg:SetTexture(1, 1, 1, 0.6)
+		panel.center.bg:SetTexture(1, 1, 1, 0.6)
+		panel.right.bg:SetTexture(1, 1, 1, 0.6)
+	end
+end
+
 function NinjaPanel:HasPlugin(name)
 	return self.plugins[name] and true
 end
@@ -192,15 +195,19 @@ end
 function NinjaPanel:ScanForPlugins()
 	self.warned = self.warned or {}

-	local changed = false
 	for name,dataobj in ldb:DataObjectIterator() do
-		if not self:HasPlugin(name) and not self:PluginIsDisabled(name) then
+		-- Make sure we add it to the full list of plugin names
+		if not self.pluginNames[name] then
+			self.pluginNames[name] = true
+			table.insert(self.pluginNames, name)
+		end
+
+		-- Create any plugins that aren't disabled
+		if not self:HasPlugin(name) and not self:PluginIsDisabled(name) then
 			if dataobj.type == "data source" or dataobj.text then
 				self:SpawnPlugin(name, dataobj, "data source")
-				changed = true
 			elseif dataobj.type == "launcher" or (dataobj.icon and dataobj.OnClick) then
 				self:SpawnPlugin(name, dataobj, "launcher")
-				changed = true
 			elseif not self.warned[name] then
 				print("Skipping unknown broker object for " .. name .. "(" .. tostring(dataobj.type) .. ")")
 				self.warned[name] = true
@@ -289,7 +296,7 @@ function NinjaPanel:UpdateTooltipHandlers(button, dataobj)
 		button:SetScript("OnLeave", Button_OnLeave)
 	end
 end
-
+
 function NinjaPanel:UpdatePanels()
 	-- Ensure the options table exists
 	db.panels = db.panels or {}
@@ -297,12 +304,11 @@ function NinjaPanel:UpdatePanels()
 	-- Iterate over the plugins that have been registered, and claim children
 	local head = self.panels[1]
 	for name,entry in pairs(self.plugins) do
+		local opt = db.plugins[name]
 		if not entry.panel then
-			local opt = db.plugins[name]
-			local panel = opt.panel and self.panels[opt.panel] or head
-			self:AttachPlugin(entry, panel)
-			entry.button:SetParent(panel)
+			opt.panel = opt.panel and self.panels[opt.panel] or head
 		end
+		self:AttachPlugin(entry, opt.panel)
 	end

 	-- Loop through each of the panels, updating the visual display
@@ -322,6 +328,7 @@ function NinjaPanel:UpdatePanels()
 		})

 		-- DEFAULT OPTIONS HERE
+		--[[
 		local height = opt.height
 		local border_height = opt.border_height
 		local gradient = opt.gradient
@@ -334,6 +341,7 @@ function NinjaPanel:UpdatePanels()
 		panel.border:SetHeight(border_height)
 		panel.bg:SetGradientAlpha(gradient_dir, unpack(gradient))
 		panel.border:SetGradientAlpha(border_gradient_dir, unpack(border_gradient))
+		--]]
 	end

 	-- Update the plugins on each panel
@@ -345,6 +353,14 @@ end
 function NinjaPanel:AttachPlugin(plugin, panel)
 	panel.plugins[plugin.name] = plugin
 	plugin.panel = panel
+	plugin.button:SetParent(panel)
+end
+
+function NinjaPanel:DetachPlugin(plugin)
+	plugin.panel.plugins[plugin.name] = nil
+	plugin.panel = nil
+	plugin.button:ClearAllPoints()
+	plugin.button:Hide()
 end

 function NinjaPanel:HardAnchorPlugins()
@@ -361,8 +377,6 @@ function NinjaPanel:HardAnchorPlugins()
 	end
 end

-ldb.RegisterCallback(NinjaPanel, "LibDataBroker_DataObjectCreated", "ScanForPlugins")
-
 function Panel_UpdateLayout(self)
 	local left, right = {}, {}

@@ -375,6 +389,7 @@ function Panel_UpdateLayout(self)
 		local button = entry.button
 		local height = panel_opts.height - (panel_opts.border_height * 2)
 		button:SetHeight(height)
+		button:Show()

 		if entry.object.icon then
 			-- Actually update the layout of the button
@@ -402,7 +417,7 @@ function Panel_UpdateLayout(self)
 			button.icon:Hide()
 		end

-		self:UpdateTooltipHandlers(button, entry.object)
+		NinjaPanel:UpdateTooltipHandlers(button, entry.object)

 		button:SetScript("OnClick", entry.object.OnClick)
 		button:SetScript("OnDragStart", Button_OnDragStart)
@@ -632,3 +647,204 @@ function Button_Tooltip_OnLeave(button)
 	tooltip:Hide()
 end

+--[[-------------------------------------------------------------------------
+-- Interface Options using tekConfig with Ampere's code example
+-------------------------------------------------------------------------]]--
+
+local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer)
+frame.name = "NinjaPanel"
+frame:Hide()
+frame:SetScript("OnShow", function(frame)
+	local function MakeButton(parent)
+		local button = CreateFrame("Button", nil, parent or frame)
+		button:SetWidth(80)
+		button:SetHeight(22)
+
+		button:SetHighlightFontObject(GameFontHighlightSmall)
+		button:SetNormalFontObject(GameFontNormalSmall)
+
+		button:SetNormalTexture("Interface\\Buttons\\UI-Panel-Button-Up")
+		button:SetPushedTexture("Interface\\Buttons\\UI-Panel-Button-Down")
+		button:SetHighlightTexture("Interface\\Buttons\\UI-Panel-Button-Highlight")
+		button:SetDisabledTexture("Interface\\Buttons\\UI-Panel-Button-Disabled")
+		button:GetNormalTexture():SetTexCoord(0, 0.625, 0, 0.6875)
+		button:GetPushedTexture():SetTexCoord(0, 0.625, 0, 0.6875)
+		button:GetHighlightTexture():SetTexCoord(0, 0.625, 0, 0.6875)
+		button:GetDisabledTexture():SetTexCoord(0, 0.625, 0, 0.6875)
+		button:GetHighlightTexture():SetBlendMode("ADD")
+
+		return button
+	end
+
+	local title = frame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
+	title:SetPoint("TOPLEFT", 16, -16)
+	title:SetText("NinjaPanel Configuration")
+
+	local subtitle = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+	--~ 	subtitle:SetHeight(32)
+	subtitle:SetHeight(35)
+	subtitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
+	subtitle:SetPoint("RIGHT", frame, -32, 0)
+	subtitle:SetNonSpaceWrap(true)
+	subtitle:SetJustifyH("LEFT")
+	subtitle:SetJustifyV("TOP")
+	--~ 	subtitle:SetMaxLines(3)
+	subtitle:SetText("This panel can be used to configure the NinjaPanel LDB display.")
+
+	local rows, anchor = {}
+	local EDGEGAP, ROWHEIGHT, ROWGAP, GAP = 16, 20, 2, 4
+
+	local function OnEnter(self)
+		local type = NinjaPanel.plugins[self.name].object.type or "Unknown"
+		GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
+		GameTooltip:AddLine(self.name, nil, nil, nil, true)
+		GameTooltip:AddLine(type, 1, 1, 1, true)
+		GameTooltip:Show()
+	end
+	local function OnLeave() GameTooltip:Hide() end
+	local function OnClick(self)
+		local opts = NinjaPanelDB.plugins[self.name]
+		local plugin = NinjaPanel.plugins[self.name]
+		if opts.disabled then
+			opts.disabled = nil
+		else
+			opts.disabled = true
+			NinjaPanel:DetachPlugin(plugin)
+		end
+		PlaySound(enabled and "igMainMenuOptionCheckBoxOff" or "igMainMenuOptionCheckBoxOn")
+		NinjaPanel:ScanForPlugins()
+		Refresh()
+	end
+
+	-- Create rows for each option
+	for i=1,math.floor((305-22)/(ROWHEIGHT + ROWGAP)) do
+		local row = CreateFrame("Button", nil, frame)
+		if not anchor then row:SetPoint("TOP", subtitle, "BOTTOM", 0, -16)
+		else row:SetPoint("TOP", anchor, "BOTTOM", 0, -ROWGAP) end
+		row:SetPoint("LEFT", EDGEGAP, 0)
+		row:SetPoint("RIGHT", -EDGEGAP*2-8, 0)
+		row:SetHeight(ROWHEIGHT)
+		anchor = row
+		rows[i] = row
+
+		local check = CreateFrame("CheckButton", nil, row)
+		check:SetWidth(ROWHEIGHT+4)
+		check:SetHeight(ROWHEIGHT+4)
+		check:SetPoint("LEFT")
+		check:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
+		check:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down")
+		check:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+		check:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled")
+		check:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
+		check:SetScript("OnClick", OnClick)
+		row.check = check
+
+		local title = row:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
+		title:SetPoint("LEFT", check, "RIGHT", 4, 0)
+		row.title = title
+
+		local status = row:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
+		status:SetPoint("RIGHT", row, "RIGHT", -4, 0)
+		status:SetPoint("LEFT", title, "RIGHT")
+		status:SetJustifyH("RIGHT")
+		row.status = status
+
+		row:SetScript("OnEnter", OnEnter)
+		row:SetScript("OnLeave", OnLeave)
+	end
+
+	local statusColors = {
+		[true] = {0.1, 1.0, 0.1},
+		[false] = {1.0, 0.1, 0.1},
+	}
+
+	local offset = 0
+	Refresh = function()
+		if not frame:IsVisible() then return end
+
+		table.sort(NinjaPanel.pluginNames)
+
+		for i,row in ipairs(rows) do
+			if (i + offset) <= #NinjaPanel.pluginNames then
+				local name = NinjaPanel.pluginNames[i + offset]
+				local entry = NinjaPanel.plugins[name]
+				local opts = NinjaPanelDB.plugins[name]
+				local enabled = not opts.disabled
+				local color = statusColors[enabled]
+
+				row.check:SetChecked(enabled)
+				row.title:SetText(name)
+				row.status:SetText(enabled and "Enabled" or "Disabled")
+				row.status:SetTextColor(unpack(color))
+				row.name = name
+				row.check.name = name
+				row:Show()
+			else
+				row:Hide()
+			end
+		end
+	end
+	frame:SetScript("OnEvent", Refresh)
+	frame:RegisterEvent("ADDON_LOADED")
+	frame:SetScript("OnShow", Refresh)
+	Refresh()
+
+	local scrollbar = LibStub("tekKonfig-Scroll").new(frame, nil, #rows/2)
+	scrollbar:ClearAllPoints()
+	scrollbar:SetPoint("TOP", rows[1], 0, -16)
+	scrollbar:SetPoint("BOTTOM", rows[#rows], 0, 16)
+	scrollbar:SetPoint("RIGHT", -16, 0)
+	scrollbar:SetMinMaxValues(0, math.max(0, #NinjaPanel.pluginNames - #rows))
+	scrollbar:SetValue(0)
+
+	local f = scrollbar:GetScript("OnValueChanged")
+	scrollbar:SetScript("OnValueChanged", function(self, value, ...)
+		offset = value
+		Refresh()
+		return f(self, value, ...)
+	end)
+
+	frame:EnableMouseWheel()
+	frame:SetScript("OnMouseWheel", function(self, val) scrollbar:SetValue(scrollbar:GetValue() - val*#rows/2) end)
+
+	local enableall = MakeButton()
+	enableall:SetPoint("BOTTOMLEFT", 16, 16)
+	enableall:SetText("Enable All")
+	enableall:SetScript("OnClick", function(button)
+		for idx,name in ipairs(NinjaPanel.pluginNames) do
+			NinjaPanelDB.plugins[name].disabled = nil
+		end
+		Refresh()
+	end)
+
+	local disableall = MakeButton()
+	disableall:SetPoint("LEFT", enableall, "RIGHT", 4, 0)
+	disableall:SetText("Disable All")
+	disableall:SetScript("OnClick", function(button)
+		for idx,name in ipairs(NinjaPanel.pluginNames) do
+			NinjaPanelDB.plugins[name].disabled = true
+		end
+		Refresh()
+	end)
+
+	local reload = MakeButton()
+	reload:SetPoint("BOTTOMRIGHT", -16, 16)
+	reload:SetText("Refresh")
+	reload:SetScript("OnClick", ReloadUI)
+end)
+
+InterfaceOptions_AddCategory(frame)
+LibStub("tekKonfig-AboutPanel").new("NinjaPanel", "NinjaPanel")
+
+----------------------------------------
+--      Quicklaunch registration      --
+----------------------------------------
+
+-- Icon provided by NinjaKiller (http://ninjakiller.deviantart.com/art/Ninja-Icon-Package-01-56129382)
+local dataobj = LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject("NinjaPanel-Launcher", {
+	type = "launcher",
+	icon = "Interface\\AddOns\\NinjaPanel\\NinjaLogo",
+	OnClick = function() InterfaceOptionsFrame_OpenToCategory(frame) end,
+})
+
+
diff --git a/NinjaPanel.toc b/NinjaPanel.toc
index b43c0c7..70dba95 100644
--- a/NinjaPanel.toc
+++ b/NinjaPanel.toc
@@ -5,8 +5,13 @@
 ## Notes: A simple no-frills top panel for data broker feeds
 ## SavedVariables: NinjaPanelDB

+## LoadManagers: AddonLoader
+## X-LoadOn-Always: delayed
+
 Libs\LibStub.lua
 Libs\CallbackHandler-1.0.lua
 Libs\LibDataBroker-1.1.lua
 Libs\LibJostle-3.0.lua
+Libs\tekKonfigAboutPanel.lua
+Libs\tekKonfigScroll.lua
 NinjaPanel.lua