Quantcast

Make modules separate addons

Scott Sibley [09-30-10 - 13:13]
Make modules separate addons
Filename
.pkgmeta
Modules/Appearance.lua
Modules/Appearance/Appearance.lua
Modules/Appearance/StarTip_Appearance.toc
Modules/Bars.lua
Modules/Bars/Bars.lua
Modules/Bars/StarTip_Bars.toc
Modules/DeadlyAnnounce.lua
Modules/Debug.lua
Modules/Debug/Debug.lua
Modules/Fade.lua
Modules/Fade/Fade.lua
Modules/Fade/StarTip_Fade.toc
Modules/Histograms.lua
Modules/Histograms/Histograms.lua
Modules/Histograms/StarTip_Histograms.toc
Modules/LCDDisplay.lua
Modules/Position.lua
Modules/Position/Position.lua
Modules/Position/StarTip_Position.toc
Modules/PvP.lua
Modules/PvP/PvP.lua
Modules/PvP/StarTip_PvP.toc
Modules/RaidIcon.lua
Modules/RaidIcon/RaidIcon.lua
Modules/RaidIcon/StarTip_RaidIcon.toc
Modules/Targeting.lua
Modules/Targeting/StarTip_Targeting.toc
Modules/Targeting/Targeting.lua
Modules/Text.lua
Modules/Texts/StarTip_Texts.toc
Modules/Texts/Texts.lua
Modules/UnitTooltip.lua
Modules/UnitTooltip/StarTip_UnitTooltip.toc
Modules/UnitTooltip/UnitTooltip.lua
StarTip.toc
modules.xml
diff --git a/.pkgmeta b/.pkgmeta
index f42caac..6c5df90 100644
--- a/.pkgmeta
+++ b/.pkgmeta
@@ -49,4 +49,15 @@ externals:
         url: git://github.com/tekkub/libdatabroker-1-1.git
         tag: v1.1.4
     Libs/StarLibs-1.0:
-        url: svn://svn.curseforge.net/wow/starlibs-1-0/mainline/trunk
\ No newline at end of file
+        url: svn://svn.curseforge.net/wow/starlibs-1-0/mainline/trunk
+move-folders:
+    StarTip/Modules/Appearance: StarTip_Appearance
+    StarTip/Modules/Bars: StarTip_Bars
+    StarTip/Modules/Fade: StarTip_Fade
+    StarTip/Modules/Histograms: StarTip_Histograms
+    StarTip/Modules/Position: StarTip_Position
+    StarTip/Modules/PvP: StarTip_PvP
+    StarTip/Modules/RaidIcon: StarTip_RaidIcon
+    StarTip/Modules/Targeting: StarTip_Targeting
+    StarTip/Modules/Texts: StarTip_Texts
+    StarTip/Modules/UnitTooltip: StarTip_UnitTooltip
\ No newline at end of file
diff --git a/Modules/Appearance.lua b/Modules/Appearance.lua
deleted file mode 100644
index d290a8e..0000000
--- a/Modules/Appearance.lua
+++ /dev/null
@@ -1,500 +0,0 @@
-local mod = StarTip:NewModule("Appearance")
-mod.name = "Appearance"
-mod.noToggle = true
-local _G = _G
-local StarTip = _G.StarTip
-local GameTooltip = _G.GameTooltip
-local ShoppingTooltip1 = _G.ShoppingTooltip1
-local ShoppingTooltip2 = _G.ShoppingTooltip2
-local self = mod
-local LSM = _G.LibStub("LibSharedMedia-3.0")
-
-local defaults = {
-	profile = {
-		scale = 1,
-		font = StarTip:GetLSMIndexByName("font", LSM:GetDefault("font")),
-		fontSizeNormal = 12,
-		fontSizeBold = 14,
-		edgeFile = StarTip:GetLSMIndexByName("border", "Blizzard Tooltip"),
-		background = StarTip:GetLSMIndexByName("background", "Blizzard Tooltip"),
-		bgColor = { -- Default colors from CowTip
-			guild = {0, 0.15, 0, 1},
-			hostilePC = {0.25, 0, 0, 1},
-			hostileNPC = {0.15, 0, 0, 1},
-			neutralNPC = {0.15, 0.15, 0, 1},
-			friendlyPC = {0, 0, 0.25, 1},
-			friendlyNPC = {0, 0, 0.15, 1},
-			other = {0, 0, 0, 1},
-			dead = {0.15, 0.15, 0.15, 1},
-			tapped = {0.25, 0.25, 0.25, 1},
-		},
-		borderColor = { 1, 1, 1, 1 },
-		paddingTop = 4,
-		paddingBottom = 4,
-		paddingLeft = 4,
-		paddinRight = 4,
-		edgeSize = 16
-	}
-}
-
-local backdropParts = {bgFile = true, edgeFile = true, edgeSize = true, background = true}
-local otherParts = {scale = "SetScale", font = "SetFont"}
-
-local get = function(info)
-	return self.db.profile[info[#info]]
-end
-
-local set = function(info, v)
-	self.db.profile[info[#info]] = v
-	if info[#info] == "bgColor" then return end
-	if backdropParts[info[#info]] then
-		self:SetBackdrop()
-	elseif info[#info] == "scale" then
-		self:SetScale()
-	else
-		self:SetFont()
-	end
-end
-
-local options = {
-	scale = {
-		name = "Scale Slider",
-		desc = "Adjust tooltip scale",
-		type = "range",
-		min = 0.25,
-		max = 4,
-		step = 0.01,
-		bigStep = 0.05,
-		isPercent = true,
-		get = get,
-		set = set,
-		order = 4
-	},
-	font = {
-		name = "Tooltip Font",
-		desc = "Set the tooltip's font",
-		type = "select",
-		values = LSM:List("font"),
-		get = get,
-		set = set,
-		order = 5
-	},
-	fontSizeNormal = {
-		name = "Normal font size",
-		desc = "Set the normal font size",
-		type = "input",
-		pattern = "%d",
-		get = function() return tostring(mod.db.profile.fontSizeNormal) end,
-		set = function(info, v) mod.db.profile.fontSizeNormal = tonumber(v) end,
-		order = 6
-	},
-	fontSizeBold = {
-		name = "Bold font size",
-		desc = "Set the bold font size",
-		type = "input",
-		pattern = "%d",
-		get = function() return tostring(mod.db.profile.fontSizeBold) end,
-		set = function(info, v) mod.db.profile.fontSizeBold = tonumber(v) end,
-		pattern = "%d",
-		order = 7
-	},
-	edgeFile = {
-		name = "Tooltip Border",
-		desc = "Set the tooltip's border style",
-		type = "select",
-		values = LSM:List("border"),
-		get = get,
-		set = set,
-		order = 8
-	},
-	background = {
-		name = "Tooltip Background",
-		desc = "Set the tooltip's background style",
-		type = "select",
-		values = LSM:List("background"),
-		get = get,
-		set = set,
-		order = 9
-	},
-	borderColor = {
-		name = "Tooltip Border Color",
-		desc = "Set the color of the tooltip's border",
-		type = "color",
-		hasAlpha = true,
-		get = function() return unpack(self.db.profile.borderColor) end,
-		set = function(info, r, g, b, a)
-			self.db.profile.borderColor[1] = r
-			self.db.profile.borderColor[2] = g
-			self.db.profile.borderColor[3] = b
-			self.db.profile.borderColor[4] = a
-		end,
-		order = 10
-	},
-	paddingTop = {
-		name = "Tooltip Top Padding",
-		desc = "Set the tooltip's top side padding",
-		type = "range",
-		min = -20,
-		max = 20,
-		step = 1,
-		get = get,
-		set = set,
-		order = 11
-	},
-	paddingBottom = {
-		name = "Tooltip Bottom Padding",
-		desc = "Set the tooltip's bottom side padding",
-		type = "range",
-		min = -20,
-		max = 20,
-		step = 1,
-		get = get,
-		set = set,
-		order = 12
-	},
-	paddingLeft = {
-		name = "Tooltip Left Padding",
-		desc = "Set the tooltip's left side padding",
-		type = "range",
-		min = -20,
-		max = 20,
-		step = 1,
-		get = get,
-		set = set,
-		order = 13
-	},
-	paddingRight = {
-		name = "Tooltip Right Padding",
-		desc = "Set the tooltip's right side padding",
-		type = "range",
-		min = -20,
-		max = 20,
-		step = 1,
-		get = get,
-		set = set,
-		order = 14
-	},
-	edgeSize = {
-		name = "Tooltip Edge Size",
-		desc = "Set the tooltip's edge size",
-		type = "range",
-		min = 0,
-		max = 20,
-		step = 1,
-		get = get,
-		set = set,
-		order = 15
-	},
-	bgColor = {
-		name = "Background Color",
-		desc = "Set options for background color",
-		type = "group",
-		order = 16,
-		get = function(info)
-			return unpack(self.db.profile.bgColor[info[#info]])
-		end,
-		set = function(info, r, g, b, a)
-			self.db.profile.bgColor[info[#info]][1] = r
-			self.db.profile.bgColor[info[#info]][2] = g
-			self.db.profile.bgColor[info[#info]][3] = b
-			self.db.profile.bgColor[info[#info]][4] = a
-			self:SetBackdropColor(true)
-		end,
-		args = {
-			header = {
-				name = "Background Color",
-				type = "header",
-				order = 1
-			},
-			guild = {
-				name = "Guild and friends",
-				desc = "Background color for your guildmates and friends.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 2
-			},
-			hostilePC = {
-				name = "Hostile players",
-				desc = "Background color for hostile players.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 3
-			},
-			hostileNPC = {
-				name = "Hostile non-player characters",
-				desc = "Background color for hostile non-player characters.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 4
-			},
-			neutralNPC = {
-				name = "Neutral non-player characters",
-				desc = "Background color for neutral non-player characters.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 5
-			},
-			friendlyPC = {
-				name = "Friendly players",
-				desc = "Background color for friendly players.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 6
-			},
-			friendlyNPC = {
-				name = "Friendly non-player characters",
-				desc = "Background color for friendly non-player characters.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 7
-			},
-			dead = {
-				name = "Dead",
-				desc = "Background color for dead units.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 8
-			},
-			tapped = {
-				name = "Tapped",
-				desc = "Background color for when a unit is tapped by another.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 9
-			},
-			other = {
-				name = "Other Tooltips",
-				desc = "Background color for other tooltips.",
-				type = "color",
-				hasAlpha = true,
-				width = "full",
-				order = 10
-			}
-		}
-	}
-}
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-
-	StarTip:SetOptionsDisabled(options, true)
-	self.st1left, self.st1right, self.st2left, self.st2right = {}, {}, {}, {}
-	for i = 1, 50 do
-		ShoppingTooltip1:AddDoubleLine(' ', ' ')
-		ShoppingTooltip2:AddDoubleLine(' ', ' ')
-		self.st1left[i] = _G["ShoppingTooltip1TextLeft" .. i]
-		self.st1right[i] = _G["ShoppingTooltip1TextLeft" .. i]
-		self.st2left[i] = _G["ShoppingTooltip2TextRight" .. i]
-		self.st2right[i] = _G["ShoppingTooltip2TextRight" .. i]
-	end
-	ShoppingTooltip1:Show()
-	ShoppingTooltip1:Hide()
-	ShoppingTooltip2:Show()
-	ShoppingTooltip2:Hide()
-end
-
-function mod:OnEnable()
-	self:SetScale()
-	self:SetFont()
-	self:SetBackdrop()
-	self:SetBorderColor()
-	self:SetBackdropColor(true)
-	StarTip:SetOptionsDisabled(options, false)
-end
-
-function mod:OnDisable()
-	self:SetScale(true)
-	self:SetFont(true)
-	self:SetBorderColor(true)
-	self:SetBackdrop(true)
-	self:SetBackdropColor(true)
-	StarTip:SetOptionsDisabled(options, true)
-end
-
-function mod:GetOptions()
-	return options
-end
-
-function mod:SetUnit()
-	self.origBackdrop = self.origBackdrop or GameTooltip:GetBackdrop()
-	self.origBackdropColor = self.origBackdropColor or {GameTooltip:GetBackdropColor()}
-	self:SetBackdropColor()
-end
-
-function mod:OnHide()
-	self:SetBackdropColor(true)
-end
-
-function mod:OnShow()
-	self:SetBackdropColor()
-end
-
-function mod:SetScale(reset)
-	if reset then
-		GameTooltip:SetScale(1)
-		ShoppingTooltip1:SetScale(1)
-		ShoppingTooltip2:SetScale(1)
-
-	else
-		GameTooltip:SetScale(self.db.profile.scale)
-		ShoppingTooltip1:SetScale(self.db.profile.scale)
-		ShoppingTooltip2:SetScale(self.db.profile.scale)
-
-	end
-end
-
-function mod:SetFont(reset)
-	local font
-	if reset then
-		font = "Friz Quadrata TT"
-	else
-		font = LSM:Fetch('font', LSM:List("font")[self.db.profile.font])
-	end
-
-	if StarTip.leftLines[1]:GetFont() == font then
-		return
-	end
-	for i = 1, 50 do
-		local left = StarTip.leftLines[i]
-		local right = StarTip.rightLines[i]
-		local _, size, style = left:GetFont()
-		left:SetFont(font, size, style)
-		_, size, style = right:GetFont()
-		right:SetFont(font, size, style)
-
-		left = self.st1left[i]
-		right = self.st1right[i]
-		_, size, style = left:GetFont()
-		left:SetFont(font, size, style)
-		_, size, style = right:GetFont()
-		right:SetFont(font, size, style)
-
-		left = self.st2left[i]
-		right = self.st2right[i]
-		_, size, style = left:GetFont()
-		left:SetFont(font, size, style)
-		_, size, style = right:GetFont()
-		right:SetFont(font, size, style)
-	end
-end
-
-
-local tmp, tmp2 = {}, {}
-function mod:SetBackdrop()
-	if reset then
-		GameTooltip:SetBackdrop(self.origBackdrop)
-		ShoppingTooltip1:SetBackdrop(self.origBackdrop)
-		ShoppingTooltip2:SetBackdrop(self.origBackdrop)
-	else
-		local bd = GameTooltip:GetBackdrop()
-		local changed = false
-		local bgFile = LSM:Fetch('background', LSM:List('background')[self.db.profile.background])
-		local edgeFile = LSM:Fetch('border', LSM:List('border')[self.db.profile.edgeFile])
-
-		if bd.bgFile ~= bgFile or bd.edgeFile ~= edgeFile or bd.edgeSize ~= self.db.profile.edgeSize or bd.insets.left ~= self.db.profile.padding then
-			changed = true
-		end
-
-		if changed then
-			tmp.bgFile = bgFile
-			tmp.edgeFile = edgeFile
-			tmp.tile = false
-			tmp.edgeSize = self.db.profile.edgeSize
-			tmp.insets = tmp2
-			tmp2.left = self.db.profile.paddingLeft
-			tmp2.right = self.db.profile.paddingRight
-			tmp2.top = self.db.profile.paddingTop
-			tmp2.bottom = self.db.profile.paddingBottom
-			GameTooltip:SetBackdrop(tmp)
-			ShoppingTooltip1:SetBackdrop(tmp)
-			ShoppingTooltip2:SetBackdrop(tmp)
-		end
-	end
-end
-
-function mod:SetBackdropColor(reset)
-	if reset then
-		if self.origBackdropColor then
-			GameTooltip:SetBackdropColor(unpack(self.origBackdropColor))
-			ShoppingTooltip1:SetBackdropColor(unpack(self.origBackdropColor))
-			ShoppingTooltip2:SetBackdropColor(unpack(self.origBackdropColor))
-		else
-			GameTooltip:SetBackdropColor(0,0,0,1)
-			ShoppingTooltip1:SetBackdropColor(0,0,0,1)
-			ShoppingTooltip2:SetBackdropColor(0,0,0,1)
-		end
-	else -- Snagged from CowTip
-		local kind
-		if UnitExists("mouseover") then
-			if UnitIsDeadOrGhost("mouseover") then
-				kind = 'dead'
-			elseif UnitIsTapped("mouseover") and not UnitIsTappedByPlayer("mouseover") then
-				kind = 'tapped'
-			elseif UnitIsPlayer("mouseover") then
-				if UnitIsFriend("player", "mouseover") then
-					local playerGuild = GetGuildInfo("player")
-					if playerGuild and playerGuild == GetGuildInfo("mouseover") or UnitIsUnit("player", "mouseover") then
-						kind = 'guild'
-					else
-						local friend = false
-						local name = UnitName("mouseover")
-						for i = 1, GetNumFriends() do
-							if GetFriendInfo(i) == name then
-								friend = true
-								break
-							end
-						end
-						if friend then
-							kind = 'guild'
-						else
-							kind = 'friendlyPC'
-						end
-					end
-				else
-					kind = 'hostilePC'
-				end
-			else
-				if UnitIsFriend("player", "mouseover") then
-					kind = 'friendlyNPC'
-				else
-					local reaction = UnitReaction("mouseover", "player")
-					if not reaction or reaction <= 2 then
-						kind = 'hostileNPC'
-					else
-						kind = 'neutralNPC'
-					end
-				end
-			end
-		else
-			kind = 'other'
-		end
-		GameTooltip:SetBackdropColor(unpack(self.db.profile.bgColor[kind]))
-		if kind == 'other' then
-			ShoppingTooltip1:SetBackdropColor(unpack(self.db.profile.bgColor[kind]))
-			ShoppingTooltip2:SetBackdropColor(unpack(self.db.profile.bgColor[kind]))
-		end
-	end
-end
-
-function mod:SetBorderColor(reset)
-	if reset then
-		GameTooltip:SetBackdropBorderColor(1,1,1,1)
-		ShoppingTooltip1:SetBackdropBorderColor(1,1,1,1)
-		ShoppingTooltip2:SetBackdropBorderColor(1,1,1,1)
-	else
-		GameTooltip:SetBackdropBorderColor(unpack(self.db.profile.borderColor))
-		ShoppingTooltip1:SetBackdropBorderColor(unpack(self.db.profile.borderColor))
-		ShoppingTooltip2:SetBackdropBorderColor(unpack(self.db.profile.borderColor))
-	end
-end
-
-
-
diff --git a/Modules/Appearance/Appearance.lua b/Modules/Appearance/Appearance.lua
new file mode 100644
index 0000000..d290a8e
--- /dev/null
+++ b/Modules/Appearance/Appearance.lua
@@ -0,0 +1,500 @@
+local mod = StarTip:NewModule("Appearance")
+mod.name = "Appearance"
+mod.noToggle = true
+local _G = _G
+local StarTip = _G.StarTip
+local GameTooltip = _G.GameTooltip
+local ShoppingTooltip1 = _G.ShoppingTooltip1
+local ShoppingTooltip2 = _G.ShoppingTooltip2
+local self = mod
+local LSM = _G.LibStub("LibSharedMedia-3.0")
+
+local defaults = {
+	profile = {
+		scale = 1,
+		font = StarTip:GetLSMIndexByName("font", LSM:GetDefault("font")),
+		fontSizeNormal = 12,
+		fontSizeBold = 14,
+		edgeFile = StarTip:GetLSMIndexByName("border", "Blizzard Tooltip"),
+		background = StarTip:GetLSMIndexByName("background", "Blizzard Tooltip"),
+		bgColor = { -- Default colors from CowTip
+			guild = {0, 0.15, 0, 1},
+			hostilePC = {0.25, 0, 0, 1},
+			hostileNPC = {0.15, 0, 0, 1},
+			neutralNPC = {0.15, 0.15, 0, 1},
+			friendlyPC = {0, 0, 0.25, 1},
+			friendlyNPC = {0, 0, 0.15, 1},
+			other = {0, 0, 0, 1},
+			dead = {0.15, 0.15, 0.15, 1},
+			tapped = {0.25, 0.25, 0.25, 1},
+		},
+		borderColor = { 1, 1, 1, 1 },
+		paddingTop = 4,
+		paddingBottom = 4,
+		paddingLeft = 4,
+		paddinRight = 4,
+		edgeSize = 16
+	}
+}
+
+local backdropParts = {bgFile = true, edgeFile = true, edgeSize = true, background = true}
+local otherParts = {scale = "SetScale", font = "SetFont"}
+
+local get = function(info)
+	return self.db.profile[info[#info]]
+end
+
+local set = function(info, v)
+	self.db.profile[info[#info]] = v
+	if info[#info] == "bgColor" then return end
+	if backdropParts[info[#info]] then
+		self:SetBackdrop()
+	elseif info[#info] == "scale" then
+		self:SetScale()
+	else
+		self:SetFont()
+	end
+end
+
+local options = {
+	scale = {
+		name = "Scale Slider",
+		desc = "Adjust tooltip scale",
+		type = "range",
+		min = 0.25,
+		max = 4,
+		step = 0.01,
+		bigStep = 0.05,
+		isPercent = true,
+		get = get,
+		set = set,
+		order = 4
+	},
+	font = {
+		name = "Tooltip Font",
+		desc = "Set the tooltip's font",
+		type = "select",
+		values = LSM:List("font"),
+		get = get,
+		set = set,
+		order = 5
+	},
+	fontSizeNormal = {
+		name = "Normal font size",
+		desc = "Set the normal font size",
+		type = "input",
+		pattern = "%d",
+		get = function() return tostring(mod.db.profile.fontSizeNormal) end,
+		set = function(info, v) mod.db.profile.fontSizeNormal = tonumber(v) end,
+		order = 6
+	},
+	fontSizeBold = {
+		name = "Bold font size",
+		desc = "Set the bold font size",
+		type = "input",
+		pattern = "%d",
+		get = function() return tostring(mod.db.profile.fontSizeBold) end,
+		set = function(info, v) mod.db.profile.fontSizeBold = tonumber(v) end,
+		pattern = "%d",
+		order = 7
+	},
+	edgeFile = {
+		name = "Tooltip Border",
+		desc = "Set the tooltip's border style",
+		type = "select",
+		values = LSM:List("border"),
+		get = get,
+		set = set,
+		order = 8
+	},
+	background = {
+		name = "Tooltip Background",
+		desc = "Set the tooltip's background style",
+		type = "select",
+		values = LSM:List("background"),
+		get = get,
+		set = set,
+		order = 9
+	},
+	borderColor = {
+		name = "Tooltip Border Color",
+		desc = "Set the color of the tooltip's border",
+		type = "color",
+		hasAlpha = true,
+		get = function() return unpack(self.db.profile.borderColor) end,
+		set = function(info, r, g, b, a)
+			self.db.profile.borderColor[1] = r
+			self.db.profile.borderColor[2] = g
+			self.db.profile.borderColor[3] = b
+			self.db.profile.borderColor[4] = a
+		end,
+		order = 10
+	},
+	paddingTop = {
+		name = "Tooltip Top Padding",
+		desc = "Set the tooltip's top side padding",
+		type = "range",
+		min = -20,
+		max = 20,
+		step = 1,
+		get = get,
+		set = set,
+		order = 11
+	},
+	paddingBottom = {
+		name = "Tooltip Bottom Padding",
+		desc = "Set the tooltip's bottom side padding",
+		type = "range",
+		min = -20,
+		max = 20,
+		step = 1,
+		get = get,
+		set = set,
+		order = 12
+	},
+	paddingLeft = {
+		name = "Tooltip Left Padding",
+		desc = "Set the tooltip's left side padding",
+		type = "range",
+		min = -20,
+		max = 20,
+		step = 1,
+		get = get,
+		set = set,
+		order = 13
+	},
+	paddingRight = {
+		name = "Tooltip Right Padding",
+		desc = "Set the tooltip's right side padding",
+		type = "range",
+		min = -20,
+		max = 20,
+		step = 1,
+		get = get,
+		set = set,
+		order = 14
+	},
+	edgeSize = {
+		name = "Tooltip Edge Size",
+		desc = "Set the tooltip's edge size",
+		type = "range",
+		min = 0,
+		max = 20,
+		step = 1,
+		get = get,
+		set = set,
+		order = 15
+	},
+	bgColor = {
+		name = "Background Color",
+		desc = "Set options for background color",
+		type = "group",
+		order = 16,
+		get = function(info)
+			return unpack(self.db.profile.bgColor[info[#info]])
+		end,
+		set = function(info, r, g, b, a)
+			self.db.profile.bgColor[info[#info]][1] = r
+			self.db.profile.bgColor[info[#info]][2] = g
+			self.db.profile.bgColor[info[#info]][3] = b
+			self.db.profile.bgColor[info[#info]][4] = a
+			self:SetBackdropColor(true)
+		end,
+		args = {
+			header = {
+				name = "Background Color",
+				type = "header",
+				order = 1
+			},
+			guild = {
+				name = "Guild and friends",
+				desc = "Background color for your guildmates and friends.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 2
+			},
+			hostilePC = {
+				name = "Hostile players",
+				desc = "Background color for hostile players.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 3
+			},
+			hostileNPC = {
+				name = "Hostile non-player characters",
+				desc = "Background color for hostile non-player characters.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 4
+			},
+			neutralNPC = {
+				name = "Neutral non-player characters",
+				desc = "Background color for neutral non-player characters.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 5
+			},
+			friendlyPC = {
+				name = "Friendly players",
+				desc = "Background color for friendly players.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 6
+			},
+			friendlyNPC = {
+				name = "Friendly non-player characters",
+				desc = "Background color for friendly non-player characters.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 7
+			},
+			dead = {
+				name = "Dead",
+				desc = "Background color for dead units.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 8
+			},
+			tapped = {
+				name = "Tapped",
+				desc = "Background color for when a unit is tapped by another.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 9
+			},
+			other = {
+				name = "Other Tooltips",
+				desc = "Background color for other tooltips.",
+				type = "color",
+				hasAlpha = true,
+				width = "full",
+				order = 10
+			}
+		}
+	}
+}
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+
+	StarTip:SetOptionsDisabled(options, true)
+	self.st1left, self.st1right, self.st2left, self.st2right = {}, {}, {}, {}
+	for i = 1, 50 do
+		ShoppingTooltip1:AddDoubleLine(' ', ' ')
+		ShoppingTooltip2:AddDoubleLine(' ', ' ')
+		self.st1left[i] = _G["ShoppingTooltip1TextLeft" .. i]
+		self.st1right[i] = _G["ShoppingTooltip1TextLeft" .. i]
+		self.st2left[i] = _G["ShoppingTooltip2TextRight" .. i]
+		self.st2right[i] = _G["ShoppingTooltip2TextRight" .. i]
+	end
+	ShoppingTooltip1:Show()
+	ShoppingTooltip1:Hide()
+	ShoppingTooltip2:Show()
+	ShoppingTooltip2:Hide()
+end
+
+function mod:OnEnable()
+	self:SetScale()
+	self:SetFont()
+	self:SetBackdrop()
+	self:SetBorderColor()
+	self:SetBackdropColor(true)
+	StarTip:SetOptionsDisabled(options, false)
+end
+
+function mod:OnDisable()
+	self:SetScale(true)
+	self:SetFont(true)
+	self:SetBorderColor(true)
+	self:SetBackdrop(true)
+	self:SetBackdropColor(true)
+	StarTip:SetOptionsDisabled(options, true)
+end
+
+function mod:GetOptions()
+	return options
+end
+
+function mod:SetUnit()
+	self.origBackdrop = self.origBackdrop or GameTooltip:GetBackdrop()
+	self.origBackdropColor = self.origBackdropColor or {GameTooltip:GetBackdropColor()}
+	self:SetBackdropColor()
+end
+
+function mod:OnHide()
+	self:SetBackdropColor(true)
+end
+
+function mod:OnShow()
+	self:SetBackdropColor()
+end
+
+function mod:SetScale(reset)
+	if reset then
+		GameTooltip:SetScale(1)
+		ShoppingTooltip1:SetScale(1)
+		ShoppingTooltip2:SetScale(1)
+
+	else
+		GameTooltip:SetScale(self.db.profile.scale)
+		ShoppingTooltip1:SetScale(self.db.profile.scale)
+		ShoppingTooltip2:SetScale(self.db.profile.scale)
+
+	end
+end
+
+function mod:SetFont(reset)
+	local font
+	if reset then
+		font = "Friz Quadrata TT"
+	else
+		font = LSM:Fetch('font', LSM:List("font")[self.db.profile.font])
+	end
+
+	if StarTip.leftLines[1]:GetFont() == font then
+		return
+	end
+	for i = 1, 50 do
+		local left = StarTip.leftLines[i]
+		local right = StarTip.rightLines[i]
+		local _, size, style = left:GetFont()
+		left:SetFont(font, size, style)
+		_, size, style = right:GetFont()
+		right:SetFont(font, size, style)
+
+		left = self.st1left[i]
+		right = self.st1right[i]
+		_, size, style = left:GetFont()
+		left:SetFont(font, size, style)
+		_, size, style = right:GetFont()
+		right:SetFont(font, size, style)
+
+		left = self.st2left[i]
+		right = self.st2right[i]
+		_, size, style = left:GetFont()
+		left:SetFont(font, size, style)
+		_, size, style = right:GetFont()
+		right:SetFont(font, size, style)
+	end
+end
+
+
+local tmp, tmp2 = {}, {}
+function mod:SetBackdrop()
+	if reset then
+		GameTooltip:SetBackdrop(self.origBackdrop)
+		ShoppingTooltip1:SetBackdrop(self.origBackdrop)
+		ShoppingTooltip2:SetBackdrop(self.origBackdrop)
+	else
+		local bd = GameTooltip:GetBackdrop()
+		local changed = false
+		local bgFile = LSM:Fetch('background', LSM:List('background')[self.db.profile.background])
+		local edgeFile = LSM:Fetch('border', LSM:List('border')[self.db.profile.edgeFile])
+
+		if bd.bgFile ~= bgFile or bd.edgeFile ~= edgeFile or bd.edgeSize ~= self.db.profile.edgeSize or bd.insets.left ~= self.db.profile.padding then
+			changed = true
+		end
+
+		if changed then
+			tmp.bgFile = bgFile
+			tmp.edgeFile = edgeFile
+			tmp.tile = false
+			tmp.edgeSize = self.db.profile.edgeSize
+			tmp.insets = tmp2
+			tmp2.left = self.db.profile.paddingLeft
+			tmp2.right = self.db.profile.paddingRight
+			tmp2.top = self.db.profile.paddingTop
+			tmp2.bottom = self.db.profile.paddingBottom
+			GameTooltip:SetBackdrop(tmp)
+			ShoppingTooltip1:SetBackdrop(tmp)
+			ShoppingTooltip2:SetBackdrop(tmp)
+		end
+	end
+end
+
+function mod:SetBackdropColor(reset)
+	if reset then
+		if self.origBackdropColor then
+			GameTooltip:SetBackdropColor(unpack(self.origBackdropColor))
+			ShoppingTooltip1:SetBackdropColor(unpack(self.origBackdropColor))
+			ShoppingTooltip2:SetBackdropColor(unpack(self.origBackdropColor))
+		else
+			GameTooltip:SetBackdropColor(0,0,0,1)
+			ShoppingTooltip1:SetBackdropColor(0,0,0,1)
+			ShoppingTooltip2:SetBackdropColor(0,0,0,1)
+		end
+	else -- Snagged from CowTip
+		local kind
+		if UnitExists("mouseover") then
+			if UnitIsDeadOrGhost("mouseover") then
+				kind = 'dead'
+			elseif UnitIsTapped("mouseover") and not UnitIsTappedByPlayer("mouseover") then
+				kind = 'tapped'
+			elseif UnitIsPlayer("mouseover") then
+				if UnitIsFriend("player", "mouseover") then
+					local playerGuild = GetGuildInfo("player")
+					if playerGuild and playerGuild == GetGuildInfo("mouseover") or UnitIsUnit("player", "mouseover") then
+						kind = 'guild'
+					else
+						local friend = false
+						local name = UnitName("mouseover")
+						for i = 1, GetNumFriends() do
+							if GetFriendInfo(i) == name then
+								friend = true
+								break
+							end
+						end
+						if friend then
+							kind = 'guild'
+						else
+							kind = 'friendlyPC'
+						end
+					end
+				else
+					kind = 'hostilePC'
+				end
+			else
+				if UnitIsFriend("player", "mouseover") then
+					kind = 'friendlyNPC'
+				else
+					local reaction = UnitReaction("mouseover", "player")
+					if not reaction or reaction <= 2 then
+						kind = 'hostileNPC'
+					else
+						kind = 'neutralNPC'
+					end
+				end
+			end
+		else
+			kind = 'other'
+		end
+		GameTooltip:SetBackdropColor(unpack(self.db.profile.bgColor[kind]))
+		if kind == 'other' then
+			ShoppingTooltip1:SetBackdropColor(unpack(self.db.profile.bgColor[kind]))
+			ShoppingTooltip2:SetBackdropColor(unpack(self.db.profile.bgColor[kind]))
+		end
+	end
+end
+
+function mod:SetBorderColor(reset)
+	if reset then
+		GameTooltip:SetBackdropBorderColor(1,1,1,1)
+		ShoppingTooltip1:SetBackdropBorderColor(1,1,1,1)
+		ShoppingTooltip2:SetBackdropBorderColor(1,1,1,1)
+	else
+		GameTooltip:SetBackdropBorderColor(unpack(self.db.profile.borderColor))
+		ShoppingTooltip1:SetBackdropBorderColor(unpack(self.db.profile.borderColor))
+		ShoppingTooltip2:SetBackdropBorderColor(unpack(self.db.profile.borderColor))
+	end
+end
+
+
+
diff --git a/Modules/Appearance/StarTip_Appearance.toc b/Modules/Appearance/StarTip_Appearance.toc
new file mode 100644
index 0000000..f55c4d6
--- /dev/null
+++ b/Modules/Appearance/StarTip_Appearance.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip_Appearance
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Appearance.lua
\ No newline at end of file
diff --git a/Modules/Bars.lua b/Modules/Bars.lua
deleted file mode 100644
index 2251029..0000000
--- a/Modules/Bars.lua
+++ /dev/null
@@ -1,565 +0,0 @@
-local mod = StarTip:NewModule("Bars", "AceTimer-3.0")
-mod.name = "Bars"
-mod.toggled = true
---mod.childGroup = true
-local _G = _G
-local StarTip = _G.StarTip
-local GameTooltip = _G.GameTooltip
-local GameTooltipStatusBar = _G.GameTooltipStatusBar
-local UnitIsPlayer = _G.UnitIsPlayer
-local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
-local UnitSelectionColor = _G.UnitSelectionColor
-local UnitClass = _G.UnitClass
-local self = mod
-local timer
-local LSM = LibStub("LibSharedMedia-3.0")
-local WidgetBar = LibStub("StarLibWidgetBar-1.0")
-local LibCore = LibStub("StarLibCore-1.0")
-local Utils = LibStub("StarLibPluginUtils-1.0")
-local LibTimer = LibStub("StarLibTimer-1.0")
-
-local environment = {}
-
-local unit
-
-local anchors = {
-	"TOP",
-	"TOPRIGHT",
-	"TOPLEFT",
-	"BOTTOM",
-	"BOTTOMRIGHT",
-	"BOTTOMLEFT",
-	"RIGHT",
-	"LEFT",
-	"CENTER"
-}
-
-local anchorsDict = {}
-
-for i, v in ipairs(anchors) do
-	anchorsDict[v] = i
-end
-
-local createBars
-local widgets = {}
-
-local function copy(tbl)
-	if type(tbl) ~= "table" then return tbl end
-	local newTbl = {}
-	for k, v in pairs(tbl) do
-		newTbl[k] = copy(v)
-	end
-	return newTbl
-end
-
-local defaultWidgets = {
-	[1] = {
-		name = "Health Bar",
-		type = "bar",
-		expression = [[
-return UnitHealth(unit)
-]],
-		min = "return 0",
-		max = "assert(unit); return UnitHealthMax(unit)",
-		color1 = [[
-if true or self.visitor.visitor.db.profile.classColors then
-    return ClassColor(unit)
-else
-    local min, max = UnitHealth(unit), UnitHealthMax(unit)
-    return HPColor(min, max)
-end
-]],
-		height = 6,
-		points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 0}, {"LEFT", "GameTooltip", "LEFT", 5, 0}, {"RIGHT", "GameTooltip", "RIGHT", -5, 0}},
-		texture1 = LSM:GetDefault("statusbar"),
-		enabled = true,
-		layer = 1,
-		level = 100
-	},
-	[2] = {
-		name = "Mana Bar",
-		type = "bar",
-		expression = [[
-if not UnitExists(unit) then return end
-return UnitMana(unit)
-]],
-		min = "return 0",
-		max = "return UnitManaMax('mouseover')",
-		color1 = [[
-return PowerColor(nil, unit)
-]],
-		height = 6,
-		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, 0}, {"LEFT", "GameTooltip", "LEFT", 5, 0}, {"RIGHT", "GameTooltip", "RIGHT", -5, 0}},
-		texture1 = LSM:GetDefault("statusbar"),
-		enabled = true,
-		layer = 1,
-		level = 100
-	},
-
-
-}
-
-local defaults = {
-	profile = {
-		classColors = true,
-		bars = {}
-	}
-}
-
-local options = {}
-local optionsDefaults = {
-	add = {
-		name = "Add Bar",
-		desc = "Add a bar",
-		type = "input",
-		set = function(info, v)
-			local widget = {
-				name = v,
-				type = "bar",
-				min = "return 0",
-				max = "return 100",
-				height = 6,
-				points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 0}},
-				level = 100,
-				strata = 1,
-				texture = LSM:GetDefault("statusbar"),
-				expression = "",
-				custom = true
-			}
-			tinsert(mod.db.profile.bars, widget)
-			StarTip:RebuildOpts()
-			mod:ClearBars()
-		end,
-		order = 5
-	},
-	defaults = {
-		name = "Restore Defaults",
-		desc = "Restore Defaults",
-		type = "execute",
-		func = function()
-			mod.db.profile.bars = copy(defaultWidgets);
-			StarTip:RebuildOpts()
-		end,
-		order = 6
-	},
-}
-
-local intersectTimer
-local intersectUpdate = function()
-	WidgetBar.IntersectUpdate(mod.bars)
-end
-
-
-function updateBar(widget, bar)
-	bar:SetValue(widget.val1 * 100)
-
-	local r, g, b = 0, 0, 1
-
-	if widget.color1 and widget.bar1 then
-		r, g, b = widget.color1.res1, widget.color1.res2, widget.color1.res3
-	elseif widget.color2 and widget.color2.is_valid then
-		r, g, b = widget.color2.res1, widget.color2.res2, widget.color2.res3
-	end
-
-	if type(r) == "number" then
-		bar:SetStatusBarColor(r, g, b)
-	else
-		--bar:Hide()
-	end
-
-end
-
-local textureDict = {}
-
-local new, del
-do
-	local pool = {}
-	function new()
-		local bar = next(pool)
-
-		if bar then
-			pool[bar] = nil
-		else
-			bar = CreateFrame("StatusBar", nil, GameTooltip)
-		end
-
-		return bar
-	end
-	function del(bar)
-		pool[bar] = true
-	end
-end
-
-local defaultPoint = {"BOTTOMLEFT", "GameTooltip", "TOPLEFT"}
-
-local strataNameList = {
-	"TOOLTIP", "FULLSCREEN_DIALOG", "FULLSCREEN", "DIALOG", "HIGH", "MEDIUM", "LOW", "BACKGROUND"
-}
-
-local strataLocaleList = {
-	"Tooltip", "Fullscreen Dialog", "Fullscreen", "Dialog", "High", "Medium", "Low", "Background"
-}
-
-local function clearBar(obj)
-	obj = mod.bars and mod.bars[obj]
-	if not obj then return end
-	obj.bar:ClearAllPoints()
-	obj.bar:Hide()
-	del(obj.bar)
-	obj:Del()
-	if obj.secondBar then
-		obj.secondBar.bar:Hide()
-		del(obj.secondBar.bar)
-		obj.secondBar:Del()
-	end
-end
-
-function mod:ClearBars()
-	for k, v in pairs(mod.bars) do
-		clearBar(v)
-	end
-	wipe(mod.bars)
-end
-
-local function createBars()
-	if type(mod.bars) ~= "table" then mod.bars = {} end
-
-	for k, v in pairs(self.db.profile.bars) do
-		if v.enabled and not v.deleted then
-
-			local widget = mod.bars[v]
-			if not widget then
-				local bar = new()
-				widget = WidgetBar:New(mod.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateBar, bar)
-				bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture1))
-				bar:ClearAllPoints()
-				for j, point in ipairs(v.points) do
-					local arg1, arg2, arg3, arg4, arg5 = unpack(point)
-					arg4 = (arg4 or 0)
-					arg5 = (arg5 or 0)
-					bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
-				end
-				bar:SetWidth(v.width or 20)
-				bar:SetHeight(v.height)
-				bar:SetMinMaxValues(0, 100)
-				bar:Show()
-				bar:SetFrameStrata(strataNameList[v.layer])
-				bar:SetFrameLevel(v.level)
-				widget.bar1 = true
-				widget.bar = bar
-				mod.bars[v] = widget
-				v.bar = bar
-
-				if v.expression2 then
-					bar = new()
-					widget = WidgetBar:New(mod.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateBar, bar)
-					bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture2 or v.texutre1 or "Blizzard"))
-					bar:ClearAllPoints()
-					for i, point in ipairs(v.points) do
-						local arg1, arg2, arg3, arg4, arg5 = unpack(point)
-						arg4 = (arg4 or 0)
-						if v.top then
-							arg5 = (arg5 or 0) - (v.height or 12)
-						else
-							arg5 = (arg5 or 0) + (v.height or 12)
-						end
-						bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
-					end
-					bar:SetWidth(v.width or 10)
-					bar:SetHeight(v.height)
-					bar:SetMinMaxValues(0, 100)
-					bar:Show()
-					bar:SetFrameStrata(strataNameList[widget.layer])
-					bar:SetFrameLevel(v.level)
-					mod.bars[v].secondBar = widget
-				end
-			end
-			widget.config.unit = StarTip.unit
-		end
-	end
-end
-
-function mod:CreateBars()
-	createBars()
-end
-
-function mod:ReInit()
-	if not self.db.profile.bars then
-		self.db.profile.bars = {}
-	end
-
-	for k in pairs(self.db.profile.bars) do
-		if type(k) == "string" then
-			wipe(self.db.profile.bars)
-			break
-		end
-	end
-
-	for k, v in pairs(defaultWidgets) do
-		for j, vv in ipairs(self.db.profile.bars) do
-			if v.name == vv.name and not vv.custom then
-				for k, val in pairs(v) do
-					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
-						vv[k] = v[k]
-					end
-				end
-				v.tagged = true
-				v.deleted = vv.deleted
-			end
-		end
-	end
-
-	for k, v in pairs(defaultWidgets) do
-		if not v.tagged and not v.deleted then
-			self.db.profile.bars[k] = copy(v)
-		end
-	end
-end
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-
-	self:ReInit()
-
-	self.core = LibCore:New(mod, environment, "StarTip.Bars", {["StarTip.Bars"] = {}}, nil, StarTip.db.profile.errorLevel)
-
-	StarTip:SetOptionsDisabled(options, true)
-
-	self.bars = {}
-end
-
-function mod:OnEnable()
-	GameTooltip:SetClampRectInsets(0, 0, 10, 10)
-	StarTip:SetOptionsDisabled(options, false)
-	intersectTimer = intersectTimer or LibTimer:New("Texts.intersectTimer", 100, true, intersectUpdate)
-	self:ClearBars()
-	for k, bar in pairs(self.bars) do
-		if bar.config.alwaysShown then
-			bar:Start()
-			bar.bar:Show()
-			if bar.secondBar then
-				bar.secondBar:Start()
-				bar.secondBar:Show()
-			end
-		end
-	end
-end
-
-function mod:OnDisable()
-	self:ClearBars()
-	GameTooltip:SetClampRectInsets(0, 0, 0, 0)
-	StarTip:SetOptionsDisabled(options, true)
-	if type(intersectTimer) == "table" then intersectTimer:Stop() end
-end
-
---[[function mod:RebuildOpts()
-	for k, v in ipairs(self.db.profile.bars) do
-		options.bars.args[k] = WidgetBar:GetOptions(v)
-	end
-end]]
-
-function mod:GetOptions()
-	return options
-end
-
-function mod:SetUnit()
-	unit = GameTooltip:GetUnit()
-	GameTooltipStatusBar:Hide()
-	createBars()
-	for i, bar in pairs(self.bars) do
-		bar:Start()
-		bar.bar:Show()
-		if bar.secondBar then
-			bar.secondBar:Start()
-			bar.secondBar.bar:Show()
-		end
-	end
-	intersectTimer:Start()
-end
-
-function mod:SetItem()
-	for i, bar in pairs(self.bars) do
-		if not bar.config.alwaysShown then
-			bar:Stop()
-			bar.bar:Hide()
-			if bar.secondBar then
-				bar.secondBar:Stop()
-				bar.secondBar.bar:Hide()
-			end
-		end
-	end
-	intersectTimer:Start()
-end
-
-function mod:SetSpell()
-	for i, bar in pairs(self.bars) do
-		if not bar.config.alwaysShown then
-			bar:Stop()
-			bar.bar:Hide()
-			if bar.secondBar then
-				bar.secondBar:Stop()
-				bar.secondBar.bar:Hide()
-			end
-		end
-	end
-	intersectTimer:Start()
-end
-
-function mod:OnHide()
-	if timer then
-		self:CancelTimer(timer)
-		timer = nil
-	end
-	for i, bar in pairs(self.bars) do
-		if not bar.config.alwaysShown then
-			bar:Stop()
-			bar.bar:Hide()
-			if bar.secondBar then
-				bar.secondBar:Stop()
-				bar.secondBar.bar:Hide()
-			end
-		end
-	end
-	intersectTimer:Stop()
-end
-
-local function colorGradient(perc)
-    if perc <= 0.5 then
-        return 1, perc*2, 0
-    else
-        return 2 - perc*2, 1, 0
-    end
-end
-
-function mod:RebuildOpts()
-	local defaults = WidgetBar.defaults
-	self:ClearBars()
-	wipe(options)
-	for k, v in pairs(optionsDefaults) do
-		options[k] = v
-	end
-
-	for i, db in ipairs(self.db.profile.bars) do
-		options[db.name:gsub(" ", "_")] = {
-			name = db.name,
-			type="group",
-			order = i,
-			args = WidgetBar:GetOptions(db, StarTip.RebuildOpts, StarTip),
-		}
-		options[db.name:gsub(" ", "_")].args.delete = {
-			name = "Delete",
-			type = "execute",
-			func = function()
-				local delete = true
-				for i, v in ipairs(defaultWidgets) do
-					if db.name == v.name then
-						db.deleted = true
-						delete = false
-					end
-				end
-				if delete then
-					tremove(self.db.profile.bars, i)
-				end
-				self:ClearTexts()
-				StarTip:RebuildOpts()
-			end,
-			order = 100
-		}
-		options[db.name:gsub(" ", "_")].args.enabled = {
-			name = "Enabled",
-			desc = "Whether the histogram's enabled or not",
-			type = "toggle",
-			get = function() return db.enabled end,
-			set = function(info, v)
-				db.enabled = v;
-				db["enabledDirty"] = true
-				self:ClearBars()
-			end,
-			order = 1
-		}
-
-	end
-end
-
--- Colors, snagged from oUF
-local power = {
-	[0] = { r = 48/255, g = 113/255, b = 191/255}, -- Mana
-	[1] = { r = 226/255, g = 45/255, b = 75/255}, -- Rage
-	[2] = { r = 255/255, g = 178/255, b = 0}, -- Focus
-	[3] = { r = 1, g = 1, b = 34/255}, -- Energy
-	[4] = { r = 0, g = 1, b = 1}, -- Happiness
-	[5] = {}, --Unknown
-	[6] = { r = 0.23, g = 0.12, b = 0.77 } -- Runic Power
-}
-local health = {
-	[0] = {r = 49/255, g = 207/255, b = 37/255}, -- Health
-	[1] = {r = .6, g = .6, b = .6} -- Tapped targets
-}
-local happiness = {
-	[1] = {r = 1, g = 0, b = 0}, -- need.... | unhappy
-	[2] = {r = 1 ,g = 1, b = 0}, -- new..... | content
-	[3] = {r = 0, g = 1, b = 0}, -- colors.. | happy
-}
-
---[[
-function mod:UpdateBar()
-	local unit = "mouseover"
-	if not UnitExists(unit) then return end
-	local min, max = UnitHealth(unit), UnitHealthMax(unit)
-	self.hpBar:SetMinMaxValues(0, max)
-	self.hpBar:SetValue(min)
-
-	local color
-	if self.db.profile.useGradient then
-		color = StarTip.new()
-		color.r, color.g, color.b = colorGradient(min/max)
-	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
-		color = health[1]
-	elseif UnitIsPlayer(unit) then
-		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
-	else
-		color = StarTip.new()
-		color.r, color.g, color.b = UnitSelectionColor(unit)
-	end
-	if not color then color = health[0] end
-	self.hpBar:SetStatusBarColor(color.r, color.g, color.b)
-	StarTip.del(color)
-end
-]]
--- Logic snagged from oUF
---[[
-function mod:UpdateHealth()
-	local unit = "mouseover"
-	if not UnitExists(unit) then return end
-	local min, max = UnitHealth(unit), UnitHealthMax(unit)
-	self.hpBar:SetMinMaxValues(0, max)
-	self.hpBar:SetValue(min)
-
-	local color
-	if self.db.profile.useGradient then
-		color = StarTip.new()
-		color.r, color.g, color.b = colorGradient(min/max)
-	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
-		color = health[1]
-	elseif UnitIsPlayer(unit) then
-		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
-	else
-		color = StarTip.new()
-		color.r, color.g, color.b = UnitSelectionColor(unit)
-	end
-	if not color then color = health[0] end
-	self.hpBar:SetStatusBarColor(color.r, color.g, color.b)
-	StarTip.del(color)
-end
-
-function mod:UpdateMana()
-	local unit = "mouseover"
-	if not UnitExists(unit) then return end
-	local min, max = UnitMana(unit), UnitManaMax(unit)
-	self.mpBar:SetMinMaxValues(0, max)
-	self.mpBar:SetValue(min)
-
-	local color = power[UnitPowerType(unit)]
-	self.mpBar:SetStatusBarColor(color.r, color.g, color.b)
-end
-]]
\ No newline at end of file
diff --git a/Modules/Bars/Bars.lua b/Modules/Bars/Bars.lua
new file mode 100644
index 0000000..2251029
--- /dev/null
+++ b/Modules/Bars/Bars.lua
@@ -0,0 +1,565 @@
+local mod = StarTip:NewModule("Bars", "AceTimer-3.0")
+mod.name = "Bars"
+mod.toggled = true
+--mod.childGroup = true
+local _G = _G
+local StarTip = _G.StarTip
+local GameTooltip = _G.GameTooltip
+local GameTooltipStatusBar = _G.GameTooltipStatusBar
+local UnitIsPlayer = _G.UnitIsPlayer
+local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
+local UnitSelectionColor = _G.UnitSelectionColor
+local UnitClass = _G.UnitClass
+local self = mod
+local timer
+local LSM = LibStub("LibSharedMedia-3.0")
+local WidgetBar = LibStub("StarLibWidgetBar-1.0")
+local LibCore = LibStub("StarLibCore-1.0")
+local Utils = LibStub("StarLibPluginUtils-1.0")
+local LibTimer = LibStub("StarLibTimer-1.0")
+
+local environment = {}
+
+local unit
+
+local anchors = {
+	"TOP",
+	"TOPRIGHT",
+	"TOPLEFT",
+	"BOTTOM",
+	"BOTTOMRIGHT",
+	"BOTTOMLEFT",
+	"RIGHT",
+	"LEFT",
+	"CENTER"
+}
+
+local anchorsDict = {}
+
+for i, v in ipairs(anchors) do
+	anchorsDict[v] = i
+end
+
+local createBars
+local widgets = {}
+
+local function copy(tbl)
+	if type(tbl) ~= "table" then return tbl end
+	local newTbl = {}
+	for k, v in pairs(tbl) do
+		newTbl[k] = copy(v)
+	end
+	return newTbl
+end
+
+local defaultWidgets = {
+	[1] = {
+		name = "Health Bar",
+		type = "bar",
+		expression = [[
+return UnitHealth(unit)
+]],
+		min = "return 0",
+		max = "assert(unit); return UnitHealthMax(unit)",
+		color1 = [[
+if true or self.visitor.visitor.db.profile.classColors then
+    return ClassColor(unit)
+else
+    local min, max = UnitHealth(unit), UnitHealthMax(unit)
+    return HPColor(min, max)
+end
+]],
+		height = 6,
+		points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 0}, {"LEFT", "GameTooltip", "LEFT", 5, 0}, {"RIGHT", "GameTooltip", "RIGHT", -5, 0}},
+		texture1 = LSM:GetDefault("statusbar"),
+		enabled = true,
+		layer = 1,
+		level = 100
+	},
+	[2] = {
+		name = "Mana Bar",
+		type = "bar",
+		expression = [[
+if not UnitExists(unit) then return end
+return UnitMana(unit)
+]],
+		min = "return 0",
+		max = "return UnitManaMax('mouseover')",
+		color1 = [[
+return PowerColor(nil, unit)
+]],
+		height = 6,
+		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, 0}, {"LEFT", "GameTooltip", "LEFT", 5, 0}, {"RIGHT", "GameTooltip", "RIGHT", -5, 0}},
+		texture1 = LSM:GetDefault("statusbar"),
+		enabled = true,
+		layer = 1,
+		level = 100
+	},
+
+
+}
+
+local defaults = {
+	profile = {
+		classColors = true,
+		bars = {}
+	}
+}
+
+local options = {}
+local optionsDefaults = {
+	add = {
+		name = "Add Bar",
+		desc = "Add a bar",
+		type = "input",
+		set = function(info, v)
+			local widget = {
+				name = v,
+				type = "bar",
+				min = "return 0",
+				max = "return 100",
+				height = 6,
+				points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 0}},
+				level = 100,
+				strata = 1,
+				texture = LSM:GetDefault("statusbar"),
+				expression = "",
+				custom = true
+			}
+			tinsert(mod.db.profile.bars, widget)
+			StarTip:RebuildOpts()
+			mod:ClearBars()
+		end,
+		order = 5
+	},
+	defaults = {
+		name = "Restore Defaults",
+		desc = "Restore Defaults",
+		type = "execute",
+		func = function()
+			mod.db.profile.bars = copy(defaultWidgets);
+			StarTip:RebuildOpts()
+		end,
+		order = 6
+	},
+}
+
+local intersectTimer
+local intersectUpdate = function()
+	WidgetBar.IntersectUpdate(mod.bars)
+end
+
+
+function updateBar(widget, bar)
+	bar:SetValue(widget.val1 * 100)
+
+	local r, g, b = 0, 0, 1
+
+	if widget.color1 and widget.bar1 then
+		r, g, b = widget.color1.res1, widget.color1.res2, widget.color1.res3
+	elseif widget.color2 and widget.color2.is_valid then
+		r, g, b = widget.color2.res1, widget.color2.res2, widget.color2.res3
+	end
+
+	if type(r) == "number" then
+		bar:SetStatusBarColor(r, g, b)
+	else
+		--bar:Hide()
+	end
+
+end
+
+local textureDict = {}
+
+local new, del
+do
+	local pool = {}
+	function new()
+		local bar = next(pool)
+
+		if bar then
+			pool[bar] = nil
+		else
+			bar = CreateFrame("StatusBar", nil, GameTooltip)
+		end
+
+		return bar
+	end
+	function del(bar)
+		pool[bar] = true
+	end
+end
+
+local defaultPoint = {"BOTTOMLEFT", "GameTooltip", "TOPLEFT"}
+
+local strataNameList = {
+	"TOOLTIP", "FULLSCREEN_DIALOG", "FULLSCREEN", "DIALOG", "HIGH", "MEDIUM", "LOW", "BACKGROUND"
+}
+
+local strataLocaleList = {
+	"Tooltip", "Fullscreen Dialog", "Fullscreen", "Dialog", "High", "Medium", "Low", "Background"
+}
+
+local function clearBar(obj)
+	obj = mod.bars and mod.bars[obj]
+	if not obj then return end
+	obj.bar:ClearAllPoints()
+	obj.bar:Hide()
+	del(obj.bar)
+	obj:Del()
+	if obj.secondBar then
+		obj.secondBar.bar:Hide()
+		del(obj.secondBar.bar)
+		obj.secondBar:Del()
+	end
+end
+
+function mod:ClearBars()
+	for k, v in pairs(mod.bars) do
+		clearBar(v)
+	end
+	wipe(mod.bars)
+end
+
+local function createBars()
+	if type(mod.bars) ~= "table" then mod.bars = {} end
+
+	for k, v in pairs(self.db.profile.bars) do
+		if v.enabled and not v.deleted then
+
+			local widget = mod.bars[v]
+			if not widget then
+				local bar = new()
+				widget = WidgetBar:New(mod.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateBar, bar)
+				bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture1))
+				bar:ClearAllPoints()
+				for j, point in ipairs(v.points) do
+					local arg1, arg2, arg3, arg4, arg5 = unpack(point)
+					arg4 = (arg4 or 0)
+					arg5 = (arg5 or 0)
+					bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
+				end
+				bar:SetWidth(v.width or 20)
+				bar:SetHeight(v.height)
+				bar:SetMinMaxValues(0, 100)
+				bar:Show()
+				bar:SetFrameStrata(strataNameList[v.layer])
+				bar:SetFrameLevel(v.level)
+				widget.bar1 = true
+				widget.bar = bar
+				mod.bars[v] = widget
+				v.bar = bar
+
+				if v.expression2 then
+					bar = new()
+					widget = WidgetBar:New(mod.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateBar, bar)
+					bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture2 or v.texutre1 or "Blizzard"))
+					bar:ClearAllPoints()
+					for i, point in ipairs(v.points) do
+						local arg1, arg2, arg3, arg4, arg5 = unpack(point)
+						arg4 = (arg4 or 0)
+						if v.top then
+							arg5 = (arg5 or 0) - (v.height or 12)
+						else
+							arg5 = (arg5 or 0) + (v.height or 12)
+						end
+						bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
+					end
+					bar:SetWidth(v.width or 10)
+					bar:SetHeight(v.height)
+					bar:SetMinMaxValues(0, 100)
+					bar:Show()
+					bar:SetFrameStrata(strataNameList[widget.layer])
+					bar:SetFrameLevel(v.level)
+					mod.bars[v].secondBar = widget
+				end
+			end
+			widget.config.unit = StarTip.unit
+		end
+	end
+end
+
+function mod:CreateBars()
+	createBars()
+end
+
+function mod:ReInit()
+	if not self.db.profile.bars then
+		self.db.profile.bars = {}
+	end
+
+	for k in pairs(self.db.profile.bars) do
+		if type(k) == "string" then
+			wipe(self.db.profile.bars)
+			break
+		end
+	end
+
+	for k, v in pairs(defaultWidgets) do
+		for j, vv in ipairs(self.db.profile.bars) do
+			if v.name == vv.name and not vv.custom then
+				for k, val in pairs(v) do
+					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
+						vv[k] = v[k]
+					end
+				end
+				v.tagged = true
+				v.deleted = vv.deleted
+			end
+		end
+	end
+
+	for k, v in pairs(defaultWidgets) do
+		if not v.tagged and not v.deleted then
+			self.db.profile.bars[k] = copy(v)
+		end
+	end
+end
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+
+	self:ReInit()
+
+	self.core = LibCore:New(mod, environment, "StarTip.Bars", {["StarTip.Bars"] = {}}, nil, StarTip.db.profile.errorLevel)
+
+	StarTip:SetOptionsDisabled(options, true)
+
+	self.bars = {}
+end
+
+function mod:OnEnable()
+	GameTooltip:SetClampRectInsets(0, 0, 10, 10)
+	StarTip:SetOptionsDisabled(options, false)
+	intersectTimer = intersectTimer or LibTimer:New("Texts.intersectTimer", 100, true, intersectUpdate)
+	self:ClearBars()
+	for k, bar in pairs(self.bars) do
+		if bar.config.alwaysShown then
+			bar:Start()
+			bar.bar:Show()
+			if bar.secondBar then
+				bar.secondBar:Start()
+				bar.secondBar:Show()
+			end
+		end
+	end
+end
+
+function mod:OnDisable()
+	self:ClearBars()
+	GameTooltip:SetClampRectInsets(0, 0, 0, 0)
+	StarTip:SetOptionsDisabled(options, true)
+	if type(intersectTimer) == "table" then intersectTimer:Stop() end
+end
+
+--[[function mod:RebuildOpts()
+	for k, v in ipairs(self.db.profile.bars) do
+		options.bars.args[k] = WidgetBar:GetOptions(v)
+	end
+end]]
+
+function mod:GetOptions()
+	return options
+end
+
+function mod:SetUnit()
+	unit = GameTooltip:GetUnit()
+	GameTooltipStatusBar:Hide()
+	createBars()
+	for i, bar in pairs(self.bars) do
+		bar:Start()
+		bar.bar:Show()
+		if bar.secondBar then
+			bar.secondBar:Start()
+			bar.secondBar.bar:Show()
+		end
+	end
+	intersectTimer:Start()
+end
+
+function mod:SetItem()
+	for i, bar in pairs(self.bars) do
+		if not bar.config.alwaysShown then
+			bar:Stop()
+			bar.bar:Hide()
+			if bar.secondBar then
+				bar.secondBar:Stop()
+				bar.secondBar.bar:Hide()
+			end
+		end
+	end
+	intersectTimer:Start()
+end
+
+function mod:SetSpell()
+	for i, bar in pairs(self.bars) do
+		if not bar.config.alwaysShown then
+			bar:Stop()
+			bar.bar:Hide()
+			if bar.secondBar then
+				bar.secondBar:Stop()
+				bar.secondBar.bar:Hide()
+			end
+		end
+	end
+	intersectTimer:Start()
+end
+
+function mod:OnHide()
+	if timer then
+		self:CancelTimer(timer)
+		timer = nil
+	end
+	for i, bar in pairs(self.bars) do
+		if not bar.config.alwaysShown then
+			bar:Stop()
+			bar.bar:Hide()
+			if bar.secondBar then
+				bar.secondBar:Stop()
+				bar.secondBar.bar:Hide()
+			end
+		end
+	end
+	intersectTimer:Stop()
+end
+
+local function colorGradient(perc)
+    if perc <= 0.5 then
+        return 1, perc*2, 0
+    else
+        return 2 - perc*2, 1, 0
+    end
+end
+
+function mod:RebuildOpts()
+	local defaults = WidgetBar.defaults
+	self:ClearBars()
+	wipe(options)
+	for k, v in pairs(optionsDefaults) do
+		options[k] = v
+	end
+
+	for i, db in ipairs(self.db.profile.bars) do
+		options[db.name:gsub(" ", "_")] = {
+			name = db.name,
+			type="group",
+			order = i,
+			args = WidgetBar:GetOptions(db, StarTip.RebuildOpts, StarTip),
+		}
+		options[db.name:gsub(" ", "_")].args.delete = {
+			name = "Delete",
+			type = "execute",
+			func = function()
+				local delete = true
+				for i, v in ipairs(defaultWidgets) do
+					if db.name == v.name then
+						db.deleted = true
+						delete = false
+					end
+				end
+				if delete then
+					tremove(self.db.profile.bars, i)
+				end
+				self:ClearTexts()
+				StarTip:RebuildOpts()
+			end,
+			order = 100
+		}
+		options[db.name:gsub(" ", "_")].args.enabled = {
+			name = "Enabled",
+			desc = "Whether the histogram's enabled or not",
+			type = "toggle",
+			get = function() return db.enabled end,
+			set = function(info, v)
+				db.enabled = v;
+				db["enabledDirty"] = true
+				self:ClearBars()
+			end,
+			order = 1
+		}
+
+	end
+end
+
+-- Colors, snagged from oUF
+local power = {
+	[0] = { r = 48/255, g = 113/255, b = 191/255}, -- Mana
+	[1] = { r = 226/255, g = 45/255, b = 75/255}, -- Rage
+	[2] = { r = 255/255, g = 178/255, b = 0}, -- Focus
+	[3] = { r = 1, g = 1, b = 34/255}, -- Energy
+	[4] = { r = 0, g = 1, b = 1}, -- Happiness
+	[5] = {}, --Unknown
+	[6] = { r = 0.23, g = 0.12, b = 0.77 } -- Runic Power
+}
+local health = {
+	[0] = {r = 49/255, g = 207/255, b = 37/255}, -- Health
+	[1] = {r = .6, g = .6, b = .6} -- Tapped targets
+}
+local happiness = {
+	[1] = {r = 1, g = 0, b = 0}, -- need.... | unhappy
+	[2] = {r = 1 ,g = 1, b = 0}, -- new..... | content
+	[3] = {r = 0, g = 1, b = 0}, -- colors.. | happy
+}
+
+--[[
+function mod:UpdateBar()
+	local unit = "mouseover"
+	if not UnitExists(unit) then return end
+	local min, max = UnitHealth(unit), UnitHealthMax(unit)
+	self.hpBar:SetMinMaxValues(0, max)
+	self.hpBar:SetValue(min)
+
+	local color
+	if self.db.profile.useGradient then
+		color = StarTip.new()
+		color.r, color.g, color.b = colorGradient(min/max)
+	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
+		color = health[1]
+	elseif UnitIsPlayer(unit) then
+		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
+	else
+		color = StarTip.new()
+		color.r, color.g, color.b = UnitSelectionColor(unit)
+	end
+	if not color then color = health[0] end
+	self.hpBar:SetStatusBarColor(color.r, color.g, color.b)
+	StarTip.del(color)
+end
+]]
+-- Logic snagged from oUF
+--[[
+function mod:UpdateHealth()
+	local unit = "mouseover"
+	if not UnitExists(unit) then return end
+	local min, max = UnitHealth(unit), UnitHealthMax(unit)
+	self.hpBar:SetMinMaxValues(0, max)
+	self.hpBar:SetValue(min)
+
+	local color
+	if self.db.profile.useGradient then
+		color = StarTip.new()
+		color.r, color.g, color.b = colorGradient(min/max)
+	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
+		color = health[1]
+	elseif UnitIsPlayer(unit) then
+		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
+	else
+		color = StarTip.new()
+		color.r, color.g, color.b = UnitSelectionColor(unit)
+	end
+	if not color then color = health[0] end
+	self.hpBar:SetStatusBarColor(color.r, color.g, color.b)
+	StarTip.del(color)
+end
+
+function mod:UpdateMana()
+	local unit = "mouseover"
+	if not UnitExists(unit) then return end
+	local min, max = UnitMana(unit), UnitManaMax(unit)
+	self.mpBar:SetMinMaxValues(0, max)
+	self.mpBar:SetValue(min)
+
+	local color = power[UnitPowerType(unit)]
+	self.mpBar:SetStatusBarColor(color.r, color.g, color.b)
+end
+]]
\ No newline at end of file
diff --git a/Modules/Bars/StarTip_Bars.toc b/Modules/Bars/StarTip_Bars.toc
new file mode 100644
index 0000000..9515795
--- /dev/null
+++ b/Modules/Bars/StarTip_Bars.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip_Bars
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Bars.lua
\ No newline at end of file
diff --git a/Modules/DeadlyAnnounce.lua b/Modules/DeadlyAnnounce.lua
deleted file mode 100644
index 024e892..0000000
--- a/Modules/DeadlyAnnounce.lua
+++ /dev/null
@@ -1,327 +0,0 @@
---if not DBM and not BigWigs then return end
-do return end
-local mod = StarTip:NewModule("DeadlyAnnounce")
-mod.name = "DeadlyAnnounce"
-mod.toggled = true
-mod.desc = "Show the last DBM announcements."
-mod.defaultOff = true
-local LibQTip = LibStub('LibQTip-1.0')
-local _G = _G
-local StarTip = _G.StarTip
-local GameTooltip = _G.GameTooltip
-local ShoppingTooltip1 = _G.ShoppingTooltip1
-local ShoppingTooltip2 = _G.ShoppingTooltip2
-local self = mod
-local begin = GetTime()
-
-local anchorText = {
-	"Top",
-	"Top-right",
-	"Top-left",
-	"Bottom",
-	"Bottom-right",
-	"Bottom-left",
-	"Left",
-	"Right",
-	"Single Tooltip"
-}
-
-local defaults = {
-	profile = {
-		delay = 3,
-		hide = true,
-		position = #anchorText,
-		onctrl = true
-	},
-}
-
-local options = {
-	hide = {
-		name = "Hide DeadlyAnnounce",
-		desc = "Toggle whether to hide DeadlyAnnounce after a delay",
-		type = "toggle",
-		get = function()
-			return mod.db.profile.hide
-		end,
-		set = function(info, v)
-			mod.db.profile.hide = v
-		end,
-		order = 5
-	},
-	delay = {
-		name = "Hide Delay",
-		desc = "Enter the time to delay before hiding DeadlyAnnounce",
-		type = "input",
-		get = function()
-			return mod.db.profile.delay
-		end,
-		set = function(info, v)
-			mod.db.profile.delay = v
-		end,
-		pattern = "%d",
-		order = 6
-	},
-	position = {
-		name = "Position",
-		desc = "Select where to place tooltip.",
-		type = "select",
-		values = anchorText,
-		get = function() return mod.db.profile.position end,
-		set = function(info, v) mod.db.profile.position = v end,
-		order = 7
-	},
-	onctrl = {
-		name = "Hide On Ctrl",
-		desc = "Whether to hide DeadlyAnnounce when you press the CTRL key.",
-		type = "toggle",
-		get = function() return mod.db.profile.onctrl end,
-		set = function(info, v) mod.db.profile.onctrl = true end,
-		order = 8
-	}
-}
-
-local history = {}
-
--- Borrowed from BosModTTS
-function mod:InitializeDBM()
-	local sound = nil
-	local timer = nil
-	local text = nil
-
-	local function ShowAnnounce(t)
-		local new = StarTip.new()
-		new.text = t.text
-		new.time = _G.GetTime()
-		tinsert(history, new)
-	end
-
-	local function NewAnnounce(announce, _, spellId, ...)
-	if announce == nil then
-		local spellName = spellId
-		text = self.localization.warnings[spellId]
-	else
-		local spellName = GetSpellInfo(spellId) or "unknown"
-
-		if announce == "move" or announce == "you" or announce == "warningspell" then
-			if announce == "warningspell" then
-				announce = "spell"
-			end
-
-			text = DBM_CORE_AUTO_SPEC_WARN_TEXTS[announce]:format(spellName)
-
-		else
-            local spellHaste = select(7, GetSpellInfo(53142)) / 10000 -- 53142 = Dalaran Portal, should have 10000 ms cast time
-            local timer = (select(7, GetSpellInfo(spellId)) or 1000) / spellHaste
-
-            text = DBM_CORE_AUTO_ANNOUNCE_TEXTS[announce]:format(spellName, (timer / 1000))
-		end
-	end
-
-	end
-
-	local function HookAnnounce(boss)
-		local mod = DBM:GetModByName(boss)
-		local announces = mod.announces
-
-		for i=1, #announces do
-			StarTip:Hook(announces[i], "Show", ShowAnnounce)
-		end
-	end
-
-
-	local function NewMod(_, boss, ...)
-		local mod = DBM:GetModByName(boss)
-
-		self.localization = DBM:GetModLocalization(boss)
-
-		StarTip:SecureHook(mod, "NewTargetAnnounce", function(...) NewAnnounce("target", ...) end)
-		StarTip:SecureHook(mod, "NewSpellAnnounce", function(...) NewAnnounce("spell", ...) end)
-		StarTip:SecureHook(mod, "NewCastAnnounce", function(...) NewAnnounce("cast", ...) end)
-		StarTip:SecureHook(mod, "NewAnnounce", function(...) NewAnnounce(nil, ...) end)
-		StarTip:SecureHook(mod, "NewSpecialWarningMove", function(...) NewAnnounce("move", ...) end)
-		StarTip:SecureHook(mod, "NewSpecialWarningYou", function(...) NewAnnounce("you", ...) end)
-		StarTip:SecureHook(mod, "NewSpecialWarningSpell", function(...) NewAnnounce("warningspell", ...) end)
-
-		timer = StarTip:ScheduleTimer(function() HookAnnounce(boss) end, 1)
-	end
-
-	StarTip:SecureHook(DBM, "NewMod", NewMod)
-end
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-	StarTip:SetOptionsDisabled(options, true)
-end
-
-function mod:OnEnable()
-	if DBM then
-		self:InitializeDBM()
-	elseif BigWigs then
-		local mod = BigWigs:GetBossModule(module)
-
-		local function NewBoss(module, ...)
-			local mod = BigWigs:GetBossModule(module)
-			StarTip:SecureHook(mod, "DelayedMessage", function(key, delay, text, ...) tinsert(history, {text = text, time = GetTime()}) end)
-		end
-
-		StarTip:SecureHook(BigWigs, "NewBoss", NewBoss)
-	end
-
-	--tinsert(history, {text = "Test", time = GetTime() - 5})
-	--tinsert(history, {text = "Fobar", time = GetTime()})
-end
-
-function mod:OnDisable()
-	if BigWigs then
-		local mod = BigWigs:GetBossModule(module)
-		StarTip:RemoveHook(mod, "DelayMessage")
-	end
-end
-
-function mod:GetOptions()
-	return options
-end
-
-local newFont, delFont
-do
-	local pool = {}
-	newFont = function()
-		local font = next(pool)
-		if not font then
-			font = CreateFont("DA")
-		end
-		pool[font] = nil
-	end
-
-	delFont = function(font)
-		pool[font] = true
-	end
-
-
-end
-
-local line = 1
-function mod:AddLine(text1, text2, r, g, b)
-
-	if not text1 then return end
-
-	if not r then
-		r = 1
-		g = 1
-		b = 1
-	end
-
-	if mod.db.profile.position == #anchorText then
-		if text2 then
-			GameTooltip:AddDoubleLine(text1, text2)
-			StarTip.leftLines[line]:SetVertexColor(r, g, b)
-			StarTip.rightLines[line]:SetVertexColor(r, g, b)
-		else
-			GameTooltip:AddLine(text1)
-			StarTip.leftLines[line]:SetVertexColor(r, g, b)
-		end
-	else
-		local font = newFont()
-		font:CopyFontObject(StarTip.leftLines[1]:GetFontObject())
-		font:SetTextColor(r, g, b)
-		self.tooltip:SetFont(font)
-		delFont(font)
-		self.tooltip:AddLine(text1, text2)
-	end
-
-	line = line + 1
-end
-
-local function hideAll()
-	StarTip.HideAll()
-	mod.hideTimer = nil
-end
-
-local skip
-function hideDW()
-	skip = true
-	GameTooltip:SetUnit("mouseover")
-	skip = false
-	mod.shown = false
-	mod.hideDWTimer = nil
-	mod.count = 0
-end
-
-local lastGuid
-function mod:SetUnit()
-
-	if self.modifier  or IsResting() then return end
-
-	line = 1
-
-	if mod.shown and (mod.count or 0) > 3 then
-		mod.count = 0
-		return
-	end
-
-	if self.hideDWTimer and mod.shown then
-		StarTip:CancelTimer(self.hideDWTimer)
-		mod.shown = false
-	end
-
-	if skip or mod.shown then return end
-
-	if mod.db.profile.position == #anchorText then
-		GameTooltip:ClearLines()
-	else
-		self.tooltip = LibQTip:Acquire("DeadlyAnnounce", 2, "LEFT", "CENTER", "CENTER", "CENTER","RIGHT")
-	end
-
-	self:AddLine("--- Deadly Announce ---")
-
-	if #history == 0 then
-		self:AddLine("Nothing to show", nil, 1, 0, 0)
-		StarTip:ScheduleTimer(hideDW, self.db.profile.delay)
-		return
-	end
-
-	if #history > 10 then
-		local tmp = history[#history]
-		StarTip.del(tmp)
-		tremove(history, #history)
-	end
-
-	local length = 0
-
-	for i = #history - 1, 1, -1 do
-		local time = history[i].time - history[i + 1].time
-		length = length + time
-	end
-
-	for i = #history, 1, -1 do
-		local time = GetTime()
-		time = time - history[i].time
-		self:AddLine(history[i].text, nil, 1, 0, 0)
-	end
-
-	self.hideTimer = StarTip:ScheduleTimer(hideAll, .1)
-
-	self.hideDWTimer = StarTip:ScheduleTimer(hideDW, self.db.profile.delay)
-
-	self.shown = true
-
-	self.count = (self.count or 0) + 1
-end
-
-function mod:MODIFIER_STATE_CHANGED(ev, modifier, up, ...)
-	local mod = (modifier == "LCTRL" or modifier == "RCTRL") and "LCTRL"
-
-	if mod ~= "LCTRL" or not self:IsEnabled() then
-		return
-	end
-
-	if self.db.profile.onctrl then
-		if self.hideTimer and StarTip.TimeLeft and StarTip:TimeLeft(self.hideTimer) > 0 then
-			StarTip:CancelTimer(self.hideTimer)
-		end
-		if self.hideDWTimer and StarTip.TimeLeft and StarTip:TimeLeft(self.hideDWTimer) > 0 then
-			StarTip:CancelTimer(self.hideDWTimer)
-		end
-		hideDW()
-	end
-end
\ No newline at end of file
diff --git a/Modules/Debug.lua b/Modules/Debug.lua
deleted file mode 100644
index 3d9de6e..0000000
--- a/Modules/Debug.lua
+++ /dev/null
@@ -1,152 +0,0 @@
---@debug@
-local mod = StarTip:NewModule("Debug", "AceEvent-3.0")
-mod.name = "Debug"
-mod.toggled = true
-mod.defaultOff = true
-local LibTimer = LibStub("StarLibTimer-1.0")
-local LibBuffer = LibStub("StarLibBuffer-1.0")
-local WidgetText = LibStub("StarLibWidgetText-1.0")
-local LibProperty = LibStub("StarLibProperty-1.0")
-local LibCore = LibStub("StarLibCore-1.0")
-
-local environment = {}
-
-local core = LibCore:New(mod, environment, "StarTip.Debug", {["StarTip.Debug"] = {}})
-local objects = {}
-local defaults = {profile={debug=false}}
-local timer
-local cfg = {
-		enabled = true,
-		value = [[
-if not UnitExists(unit) then return end
-return '--' .. select(1, UnitName(unit)) .. '--'
-]],
-		color = [[
-if not UnitExists(unit) then return end
-return ClassColor(unit)
-]],
-		cols = 500,
-		align = WidgetText.ALIGN_PINGPONG,
-		update = 1000,
-		speed = 100,
-		direction = SCROLL_LEFT,
-		dontRtrim = true,
-		point = {"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 12},
-		parent = "GameTooltip",
-}
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-end
-
-local function new1()
-	return LibBuffer:New("Debug buffer", random(1000), " ")
-end
-
-local function updateText(widget)
-
-end
-
-local function new2()
-	return WidgetText:New(core, "Debug text", cfg, 0, 0, 0, StarTip.db.profile.errorLevel, updateText)
-end
-
-local function new3()
-	return LibProperty:New(nil, core,	"debug property", "", "")
-end
-
-local plugin = {}
-LibStub("StarLibPluginUtils-1.0"):New(plugin)
-
-local function update()
-	mod.frame1:ClearAllPoints()
-	mod.frame2:ClearAllPoints()
-	local width = UIParent:GetWidth()
-	local height = UIParent:GetHeight()
-	mod.frame2:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 550 / 0.5 / 0.2, 550 / 0.5 / 0.2)
-	mod.frame3:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 550, 550)
-	if plugin.Intersect(mod.frame2, mod.frame3) then
-		StarTip:Print("---------------intersection-----------------")
-	end
-end
-
-function mod:OnEnable()
-	timer = timer or LibTimer:New("Debug timer", 1000, true, update)
-	if false then
-		timer:Start()
-	end
-	do return end
-			local frame = CreateFrame("Frame")
-			frame:SetParent(UIParent)
-			frame:SetParent(UIParent)
-				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
-					tile = true,
-					tileSize = 4,
-					edgeSize=4,
-					insets = { left = 0, right = 0, top = 0, bottom = 0}})
-			frame:ClearAllPoints()
-			frame:SetAlpha(1)
-			frame:SetBackdropColor(1, 1, 0)
-			frame:SetHeight(250)
-			frame:SetWidth(250)
-			frame:Show()
-			frame:SetScale(0.2)
-			self.frame0 = frame
-
-			local frame = CreateFrame("Frame")
-			frame:SetParent(self.frame0)
-				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
-					tile = true,
-					tileSize = 4,
-					edgeSize=4,
-					insets = { left = 0, right = 0, top = 0, bottom = 0}})
-			frame:ClearAllPoints()
-			frame:SetAlpha(1)
-			frame:SetBackdropColor(1, 1, 0)
-			frame:SetHeight(250)
-			frame:SetWidth(250)
-			frame:Show()
-			frame:SetScale(0.5)
-			self.frame1 = frame
-
-			local frame = CreateFrame("Frame")
-			frame:SetParent(self.frame1)
-				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
-					tile = true,
-					tileSize = 4,
-					edgeSize=4,
-					insets = { left = 0, right = 0, top = 0, bottom = 0}})
-			frame:ClearAllPoints()
-			frame:SetAlpha(1)
-			frame:SetBackdropColor(1, 1, 0)
-			frame:SetHeight(250)
-			frame:SetWidth(250)
-			frame:Show()
-			self.frame2 = frame
-
-			local frame = CreateFrame("Frame")
-			frame:SetParent(UIParent)
-				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
-					tile = true,
-					tileSize = 4,
-					edgeSize=4,
-					insets = { left = 0, right = 0, top = 0, bottom = 0}})
-			frame:ClearAllPoints()
-			frame:SetAlpha(1)
-			frame:SetBackdropColor(1, 1, 0)
-			frame:SetHeight(250)
-			frame:SetWidth(250)
-			frame:Show()
-			self.frame3 = frame
-end
-
-function mod:OnDisable()
-	timer:Stop()
-end
-
-function mod:SetUnit()
-end
-
-function mod:OnHide()
-end
---@end-debug
\ No newline at end of file
diff --git a/Modules/Debug/Debug.lua b/Modules/Debug/Debug.lua
new file mode 100644
index 0000000..3d9de6e
--- /dev/null
+++ b/Modules/Debug/Debug.lua
@@ -0,0 +1,152 @@
+--@debug@
+local mod = StarTip:NewModule("Debug", "AceEvent-3.0")
+mod.name = "Debug"
+mod.toggled = true
+mod.defaultOff = true
+local LibTimer = LibStub("StarLibTimer-1.0")
+local LibBuffer = LibStub("StarLibBuffer-1.0")
+local WidgetText = LibStub("StarLibWidgetText-1.0")
+local LibProperty = LibStub("StarLibProperty-1.0")
+local LibCore = LibStub("StarLibCore-1.0")
+
+local environment = {}
+
+local core = LibCore:New(mod, environment, "StarTip.Debug", {["StarTip.Debug"] = {}})
+local objects = {}
+local defaults = {profile={debug=false}}
+local timer
+local cfg = {
+		enabled = true,
+		value = [[
+if not UnitExists(unit) then return end
+return '--' .. select(1, UnitName(unit)) .. '--'
+]],
+		color = [[
+if not UnitExists(unit) then return end
+return ClassColor(unit)
+]],
+		cols = 500,
+		align = WidgetText.ALIGN_PINGPONG,
+		update = 1000,
+		speed = 100,
+		direction = SCROLL_LEFT,
+		dontRtrim = true,
+		point = {"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 12},
+		parent = "GameTooltip",
+}
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+end
+
+local function new1()
+	return LibBuffer:New("Debug buffer", random(1000), " ")
+end
+
+local function updateText(widget)
+
+end
+
+local function new2()
+	return WidgetText:New(core, "Debug text", cfg, 0, 0, 0, StarTip.db.profile.errorLevel, updateText)
+end
+
+local function new3()
+	return LibProperty:New(nil, core,	"debug property", "", "")
+end
+
+local plugin = {}
+LibStub("StarLibPluginUtils-1.0"):New(plugin)
+
+local function update()
+	mod.frame1:ClearAllPoints()
+	mod.frame2:ClearAllPoints()
+	local width = UIParent:GetWidth()
+	local height = UIParent:GetHeight()
+	mod.frame2:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 550 / 0.5 / 0.2, 550 / 0.5 / 0.2)
+	mod.frame3:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 550, 550)
+	if plugin.Intersect(mod.frame2, mod.frame3) then
+		StarTip:Print("---------------intersection-----------------")
+	end
+end
+
+function mod:OnEnable()
+	timer = timer or LibTimer:New("Debug timer", 1000, true, update)
+	if false then
+		timer:Start()
+	end
+	do return end
+			local frame = CreateFrame("Frame")
+			frame:SetParent(UIParent)
+			frame:SetParent(UIParent)
+				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+					tile = true,
+					tileSize = 4,
+					edgeSize=4,
+					insets = { left = 0, right = 0, top = 0, bottom = 0}})
+			frame:ClearAllPoints()
+			frame:SetAlpha(1)
+			frame:SetBackdropColor(1, 1, 0)
+			frame:SetHeight(250)
+			frame:SetWidth(250)
+			frame:Show()
+			frame:SetScale(0.2)
+			self.frame0 = frame
+
+			local frame = CreateFrame("Frame")
+			frame:SetParent(self.frame0)
+				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+					tile = true,
+					tileSize = 4,
+					edgeSize=4,
+					insets = { left = 0, right = 0, top = 0, bottom = 0}})
+			frame:ClearAllPoints()
+			frame:SetAlpha(1)
+			frame:SetBackdropColor(1, 1, 0)
+			frame:SetHeight(250)
+			frame:SetWidth(250)
+			frame:Show()
+			frame:SetScale(0.5)
+			self.frame1 = frame
+
+			local frame = CreateFrame("Frame")
+			frame:SetParent(self.frame1)
+				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+					tile = true,
+					tileSize = 4,
+					edgeSize=4,
+					insets = { left = 0, right = 0, top = 0, bottom = 0}})
+			frame:ClearAllPoints()
+			frame:SetAlpha(1)
+			frame:SetBackdropColor(1, 1, 0)
+			frame:SetHeight(250)
+			frame:SetWidth(250)
+			frame:Show()
+			self.frame2 = frame
+
+			local frame = CreateFrame("Frame")
+			frame:SetParent(UIParent)
+				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+					tile = true,
+					tileSize = 4,
+					edgeSize=4,
+					insets = { left = 0, right = 0, top = 0, bottom = 0}})
+			frame:ClearAllPoints()
+			frame:SetAlpha(1)
+			frame:SetBackdropColor(1, 1, 0)
+			frame:SetHeight(250)
+			frame:SetWidth(250)
+			frame:Show()
+			self.frame3 = frame
+end
+
+function mod:OnDisable()
+	timer:Stop()
+end
+
+function mod:SetUnit()
+end
+
+function mod:OnHide()
+end
+--@end-debug
\ No newline at end of file
diff --git a/Modules/Fade.lua b/Modules/Fade.lua
deleted file mode 100644
index e1a6fce..0000000
--- a/Modules/Fade.lua
+++ /dev/null
@@ -1,211 +0,0 @@
-local mod = StarTip:NewModule("Fade", "AceHook-3.0")
-mod.name = "Fade"
-local _G = _G
-local GameTooltip = _G.GameTooltip
-local StarTip = _G.StarTip
-local UnitExists = _G.UnitExists
-local self = mod
-
-local defaults = {
-	profile = {
-		unitFrames = 2,
-		otherFrames = 1,
-		units = 2,
-		objects = 2,
-	}
-}
-
-local choices = {
-	"Hide",
-	"Fade out"
-}
-
-local get = function(info)
-	return self.db.profile[info[#info]]
-end
-
-local set = function(info, v)
-	self.db.profile[info[#info]] = v
-end
-
-local options = {
-	units = {
-		name = "World Units",
-		desc = "What to do with tooltips for world frames",
-		type = "select",
-		values = choices,
-		get = get,
-		set = set,
-		order = 4
-	},
-	unitFrames = {
-		name = "Unit Frames",
-		desc = "What to do with tooltips for unit frames",
-		type = "select",
-		values = choices,
-		get = get,
-		set = set,
-		order = 5
-	},
-	otherFrames = {
-		name = "Other Frames",
-		desc = "What to do with tooltips for other frames (spells, macros, items, etc..)",
-		type = "select",
-		values = choices,
-		get = get,
-		set = set,
-		order = 6
-	},
-	objects = {
-		name = "World Objects",
-		desc = "What to do with tooltips for world objects (mailboxes, portals, etc..)",
-		type = "select",
-		values = choices,
-		get = get,
-		set = set,
-		order = 7
-	},
-	test = {
-		name = "test",
-		type = "group",
-		args = {
-			test = {
-				name = "Test",
-				type = "toggle"
-			}
-		}
-	}
-}
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-	StarTip:SetOptionsDisabled(options, true)
-end
-
-function mod:OnEnable()
-	self:RawHook(GameTooltip, "FadeOut", "GameTooltipFadeOut", true)
-	self:RawHook(GameTooltip, "Hide", "GameTooltipHide", true)
-	StarTip:SetOptionsDisabled(options, false)
-end
-
-function mod:OnDisable()
-	self:Unhook(GameTooltip, "FadeOut")
-	self:Unhook(GameTooltip, "Hide")
-	StarTip:SetOptionsDisabled(options, true)
-	if timer then
-		self:CancelTimer(timer)
-		timer = nil
-	end
-end
-
-function mod:GetOptions()
-	return options
-end
-
--- CowTip's solution below
-local updateExistenceFrame = CreateFrame("Frame")
-local updateAlphaFrame = CreateFrame("Frame")
-
-local checkExistence = function()
-	if not UnitExists(StarTip.unit or "mouseover") then
-		updateExistenceFrame:SetScript("OnUpdate", nil)
-		local kind
-		if StarTip.unit == "mousever" then
-			kind = self.db.profile.units
-		else
-			kind = self.db.profile.unitFrames
-		end
-		if kind == 2 then
-			GameTooltip:FadeOut()
-		else
-			GameTooltip:Hide()
-		end
-	end
-end
-
-local checkTooltipAlpha = function()
-	if GameTooltip:GetAlpha() < 1 then
-		updateAlphaFrame:SetScript("OnUpdate", nil)
-		local kind
-		if GameTooltip:IsOwned(UIParent) then
-			kind = self.db.profile.objects
-		else
-			kind = self.db.profile.otherFrames
-		end
-		if kind == 2 then
-			GameTooltip:FadeOut()
-		else
-			GameTooltip:Hide()
-		end
-	end
-end
-
-function mod:OnShow()
-	if UnitExists(StarTip.unit or "mouseover") then
-		updateExistenceFrame:SetScript("OnUpdate", checkExistence)
-	else
-		updateAlphaFrame:SetScript("OnUpdate", checkTooltipAlpha)
-	end
-end
-
-function mod:GameTooltipFadeOut(this, ...)
-	if self.justFade then
-		self.justFade = nil
-		self.hooks[this].FadeOut(this, ...)
-		return
-	end
-	local kind
-	if self.isUnit then
-		if GameTooltip:IsOwned(UIParent) then
-			kind = self.db.profile.units
-		else
-			kind = self.db.profile.unitFrames
-		end
-		self.isUnit = nil
-	else
-		if GameTooltip:IsOwned(UIParent) then
-			kind = self.db.profile.objects
-		else
-			kind = self.db.profile.otherFrames
-		end
-	end
-	if kind == 2 then
-		self.hooks[this].FadeOut(this, ...)
-	else
-		self.justHide = true
-		GameTooltip:Hide()
-	end
-end
-
-function mod:GameTooltipHide(this, ...)
-	if self.justHide then
-		self.justHide = nil
-		return self.hooks[this].Hide(this, ...)
-	end
-	local kind
-	if self.isUnit then
-		if GameTooltip:IsOwned(UIParent) then
-			kind = self.db.profile.units
-		else
-			kind = self.db.profile.unitFrames
-		end
-		self.isUnit = nil
-	else
-		if GameTooltip:IsOwned(UIParent) then
-			kind = self.db.profile.objects
-		else
-			kind = self.db.profile.otherFrames
-		end
-	end
-	if kind == 2 then
-		self.justFade = true
-		return GameTooltip:FadeOut()
-	else
-		return self.hooks[this].Hide(this, ...)
-	end
-end
-
-function mod:SetUnit()
-	self.isUnit = true
-end
-
diff --git a/Modules/Fade/Fade.lua b/Modules/Fade/Fade.lua
new file mode 100644
index 0000000..e1a6fce
--- /dev/null
+++ b/Modules/Fade/Fade.lua
@@ -0,0 +1,211 @@
+local mod = StarTip:NewModule("Fade", "AceHook-3.0")
+mod.name = "Fade"
+local _G = _G
+local GameTooltip = _G.GameTooltip
+local StarTip = _G.StarTip
+local UnitExists = _G.UnitExists
+local self = mod
+
+local defaults = {
+	profile = {
+		unitFrames = 2,
+		otherFrames = 1,
+		units = 2,
+		objects = 2,
+	}
+}
+
+local choices = {
+	"Hide",
+	"Fade out"
+}
+
+local get = function(info)
+	return self.db.profile[info[#info]]
+end
+
+local set = function(info, v)
+	self.db.profile[info[#info]] = v
+end
+
+local options = {
+	units = {
+		name = "World Units",
+		desc = "What to do with tooltips for world frames",
+		type = "select",
+		values = choices,
+		get = get,
+		set = set,
+		order = 4
+	},
+	unitFrames = {
+		name = "Unit Frames",
+		desc = "What to do with tooltips for unit frames",
+		type = "select",
+		values = choices,
+		get = get,
+		set = set,
+		order = 5
+	},
+	otherFrames = {
+		name = "Other Frames",
+		desc = "What to do with tooltips for other frames (spells, macros, items, etc..)",
+		type = "select",
+		values = choices,
+		get = get,
+		set = set,
+		order = 6
+	},
+	objects = {
+		name = "World Objects",
+		desc = "What to do with tooltips for world objects (mailboxes, portals, etc..)",
+		type = "select",
+		values = choices,
+		get = get,
+		set = set,
+		order = 7
+	},
+	test = {
+		name = "test",
+		type = "group",
+		args = {
+			test = {
+				name = "Test",
+				type = "toggle"
+			}
+		}
+	}
+}
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+	StarTip:SetOptionsDisabled(options, true)
+end
+
+function mod:OnEnable()
+	self:RawHook(GameTooltip, "FadeOut", "GameTooltipFadeOut", true)
+	self:RawHook(GameTooltip, "Hide", "GameTooltipHide", true)
+	StarTip:SetOptionsDisabled(options, false)
+end
+
+function mod:OnDisable()
+	self:Unhook(GameTooltip, "FadeOut")
+	self:Unhook(GameTooltip, "Hide")
+	StarTip:SetOptionsDisabled(options, true)
+	if timer then
+		self:CancelTimer(timer)
+		timer = nil
+	end
+end
+
+function mod:GetOptions()
+	return options
+end
+
+-- CowTip's solution below
+local updateExistenceFrame = CreateFrame("Frame")
+local updateAlphaFrame = CreateFrame("Frame")
+
+local checkExistence = function()
+	if not UnitExists(StarTip.unit or "mouseover") then
+		updateExistenceFrame:SetScript("OnUpdate", nil)
+		local kind
+		if StarTip.unit == "mousever" then
+			kind = self.db.profile.units
+		else
+			kind = self.db.profile.unitFrames
+		end
+		if kind == 2 then
+			GameTooltip:FadeOut()
+		else
+			GameTooltip:Hide()
+		end
+	end
+end
+
+local checkTooltipAlpha = function()
+	if GameTooltip:GetAlpha() < 1 then
+		updateAlphaFrame:SetScript("OnUpdate", nil)
+		local kind
+		if GameTooltip:IsOwned(UIParent) then
+			kind = self.db.profile.objects
+		else
+			kind = self.db.profile.otherFrames
+		end
+		if kind == 2 then
+			GameTooltip:FadeOut()
+		else
+			GameTooltip:Hide()
+		end
+	end
+end
+
+function mod:OnShow()
+	if UnitExists(StarTip.unit or "mouseover") then
+		updateExistenceFrame:SetScript("OnUpdate", checkExistence)
+	else
+		updateAlphaFrame:SetScript("OnUpdate", checkTooltipAlpha)
+	end
+end
+
+function mod:GameTooltipFadeOut(this, ...)
+	if self.justFade then
+		self.justFade = nil
+		self.hooks[this].FadeOut(this, ...)
+		return
+	end
+	local kind
+	if self.isUnit then
+		if GameTooltip:IsOwned(UIParent) then
+			kind = self.db.profile.units
+		else
+			kind = self.db.profile.unitFrames
+		end
+		self.isUnit = nil
+	else
+		if GameTooltip:IsOwned(UIParent) then
+			kind = self.db.profile.objects
+		else
+			kind = self.db.profile.otherFrames
+		end
+	end
+	if kind == 2 then
+		self.hooks[this].FadeOut(this, ...)
+	else
+		self.justHide = true
+		GameTooltip:Hide()
+	end
+end
+
+function mod:GameTooltipHide(this, ...)
+	if self.justHide then
+		self.justHide = nil
+		return self.hooks[this].Hide(this, ...)
+	end
+	local kind
+	if self.isUnit then
+		if GameTooltip:IsOwned(UIParent) then
+			kind = self.db.profile.units
+		else
+			kind = self.db.profile.unitFrames
+		end
+		self.isUnit = nil
+	else
+		if GameTooltip:IsOwned(UIParent) then
+			kind = self.db.profile.objects
+		else
+			kind = self.db.profile.otherFrames
+		end
+	end
+	if kind == 2 then
+		self.justFade = true
+		return GameTooltip:FadeOut()
+	else
+		return self.hooks[this].Hide(this, ...)
+	end
+end
+
+function mod:SetUnit()
+	self.isUnit = true
+end
+
diff --git a/Modules/Fade/StarTip_Fade.toc b/Modules/Fade/StarTip_Fade.toc
new file mode 100644
index 0000000..1661e51
--- /dev/null
+++ b/Modules/Fade/StarTip_Fade.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [Fade]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Fade.lua
\ No newline at end of file
diff --git a/Modules/Histograms.lua b/Modules/Histograms.lua
deleted file mode 100644
index a8782c0..0000000
--- a/Modules/Histograms.lua
+++ /dev/null
@@ -1,612 +0,0 @@
-local mod = StarTip:NewModule("Histograms", "AceTimer-3.0")
-mod.name = "Histograms"
-mod.toggled = true
---mod.childGroup = true
-mod.defaultOff = true
-local _G = _G
-local StarTip = _G.StarTip
-local GameTooltip = _G.GameTooltip
-local GameTooltipStatusBar = _G.GameTooltipStatusBar
-local UnitIsPlayer = _G.UnitIsPlayer
-local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
-local UnitSelectionColor = _G.UnitSelectionColor
-local UnitClass = _G.UnitClass
-local self = mod
-local LSM = LibStub("LibSharedMedia-3.0")
-local WidgetHistogram = LibStub("StarLibWidgetHistogram-1.0")
-local LibCore = LibStub("StarLibCore-1.0")
-local LibTimer = LibStub("StarLibTimer-1.0")
-
-local unit
-local environment = {}
-
-local createHistograms
-local widgets = {}
-
-local anchors = {
-	"TOP",
-	"TOPRIGHT",
-	"TOPLEFT",
-	"BOTTOM",
-	"BOTTOMRIGHT",
-	"BOTTOMLEFT",
-	"RIGHT",
-	"LEFT",
-	"CENTER"
-}
-
-local anchorsDict = {}
-
-for i, v in ipairs(anchors) do
-	anchorsDict[v] = i
-end
-
-local function copy(tbl)
-	local newTbl = {}
-	for k, v in pairs(tbl) do
-		if type(v) == "table" then
-			v = copy(v)
-		end
-		newTbl[k] = v
-	end
-	return newTbl
-end
-
-local defaultWidgets = {
-	[1] = {
-		name = "Health",
-		expression = "return UnitHealth(unit)",
-		min = "return 0",
-		max = "return UnitHealthMax(unit)",
-		enabled = true,
-		width = 10,
-		height = 50,
-		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -12}},
-		color = [[
-return HPColor(UnitHealth(unit), UnitHealthMax(unit))
-]],
-		layer = 1,
-		update = 1000
-	},
-	[2] = {
-		name = "Power",
-		expression = "return UnitMana(unit)",
-		min = "return 0",
-		max = "return UnitManaMax(unit)",
-		enabled = true,
-		width = 10,
-		height = 50,
-		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", -100, -12}},
-		color = [[
-return PowerColor("RAGE", unit)
-]],
-		layer = 1,
-		update = 1000
-	},
-	[3] = {
-		name = "Mem",
-		type = "histogram",
-		expression = [[
-local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
-if mem then
-    return memperc
-end
-]],
-		color = [[
-local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
-if mem then
-    local num = floor(memperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return r, g, b
-end
-
-]],
-		min = "return 0",
-		max = "return 100",
-		enabled = false,
-		reversed = true,
-		char = "0",
-		width = 10,
-		height = 50,
-		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -77}},
-		layer = 1,
-		update = 1000,
-		persistent = true,
-		intersect = true,
-		intersectPad = 1000,
-	},
-	[4] = {
-		name = "CPU",
-		type = "histogram",
-		expression = [[
-if not scriptProfile then return 0 end
-local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
-return cpuperc
-]],
-		color = [[
-if not scriptProfile then return 0, 1, 0 end
-local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
-if cpu then
-    local num = floor(cpuperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return r, g, b
-end
-
-]],
-		min = "return 0",
-		max = "return 100",
-		enabled = false,
-		reversed = true,
-		char = "0",
-		width = 10,
-		height = 50,
-		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", -100, -77}},
-		layer = 1,
-		update = 1000,
-		persistent = true,
-		intersect = true,
-		intersectPad = 100
-	},
-
-}
-
-local defaults = {
-	profile = {
-		classColors = true,
-		histograms = {},
-		intersect = true
-	}
-}
-
-local options = {}
-local optionsDefaults = {
-	add = {
-		name = "Add Histogram",
-		desc = "Add a histogram",
-		type = "input",
-		set = function(info, v)
-			local widget = {
-				name = v,
-				type = "histogram",
-				min = "return 0",
-				max = "return 100",
-				height = WidgetHistogram.defaults.height,
-				width = WidgetHistogram.defaults.width,
-				enabled = true,
-				points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -50}},
-				texture = LSM:GetDefault("statusbar"),
-				expression = "return random(100)",
-				color = "return 0, 0, 1",
-				custom = true
-			}
-			tinsert(mod.db.profile.histograms, widget)
-			StarTip:RebuildOpts()
-
-		end,
-		order = 5
-	},
-	defaults = {
-		name = "Restore Defaults",
-		desc = "Restore Defaults",
-		type = "execute",
-		func = function()
-			mod.db.profile.histograms = copy(defaultWidgets);
-			StarTip:RebuildOpts()
-		end,
-		order = 6
-	},
-}
-
-local intersectUpdate = function()
-	if type(mod.histograms) == "table" then
-		WidgetHistogram.IntersectUpdate(mod.histograms)
-	end
-end
-
-function updateHistogram(widget)
-	for i = 1, #widget.history do
-		local bar = widget.bars[i]
-		local segment = widget.history[i]
-		if not segment then break end
-		if type(segment) == "table" then
-			bar:SetValue((segment[1] or 0) * 100)
-			local r, g, b, a = widget.history[i][2], widget.history[i][3], widget.history[i][4]
-			bar:SetStatusBarColor(r, g, b, a)
-		elseif type(segment) == "number" then
-			bar:SetValue(0) --segment * 100)
-			bar:SetStatusBarColor(0, 0, 1, 1)
-		end
-		if not UnitExists(StarTip.unit) and not widget.config.alwaysShown then bar:Hide() end
-	end
-end
-
-local textureDict = {}
-
-local new, del
-do
-	local pool = {}
-	function new()
-		local histogram = next(pool)
-
-		if histogram then
-			pool[histogram] = nil
-		else
-			histogram = CreateFrame("StatusBar", nil, GameTooltip)
-		end
-
-		return histogram
-	end
-	function del(histogram)
-		pool[histogram] = true
-	end
-end
-
-local function clearHistogram(obj)
-	obj = mod.histograms and mod.histograms[obj]
-	if not obj then return end
-	for k, v in pairs(obj.bars) do
-		del(v)
-		v:Hide()
-	end
-	obj:Del()
-end
-
-function mod:ClearHistograms()
-	for k, v in pairs(mod.histograms) do
-		clearHistogram(v)
-	end
-	wipe(mod.histograms)
-end
-
-local function createHistograms()
-	if type(mod.histograms) ~= "table" then mod.histograms = {} end
-	--[[for k, widget in pairs(mod.histograms) do
-		for i = 1, widget.width or WidgetHistogram.defaults.width do
-			widget.bars[i]:Hide()
-			if widget.bars[i] then
-				del(widget.bars[i])
-			end
-		end
-		wipe(widget.bars)
-	end]]
-
-	environment.unit = "mouseover"
-	if UnitInRaid("player") then
-		for i=1, GetNumRaidMembers() do
-			if UnitGUID("mouseover") == UnitGUID("raid" .. i) then
-				environment.unit = "raid" .. i
-			end
-		end
-	end
-
-	for k, v in pairs(self.db.profile.histograms) do
-		if v.enabled and not v.deleted then
-			v.width = v.width or WidgetHistogram.defaults.width
-			local widget = mod.histograms[v]
-			local newWidget
-			if not mod.histograms then mod.histograms = {} end
-			if not widget then
-				widget = WidgetHistogram:New(mod.core, v.name, v, v.row or 0, v.col or 0, 0, StarTip.db.profile.errorLevel, updateHistogram)
-				widget.persistent = v.persistent
-				newWidget = true
-				for i = 0, v.width - 1 do
-					local bar = new()
-					bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture))
-					bar:ClearAllPoints()
-					for _, point in ipairs(v.points) do
-						local arg1, arg2, arg3, arg4, arg5 = unpack(point)
-						if (v.width > 100) then
-							arg4 = (arg4 or 0) + i * (v.width / 100)
-						else
-							arg4 = (arg4 or 0) + i * v.width
-						end
-						arg5 = (arg5 or 0)
-						bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
-					end
-					if v.width then
-						if (v.width > 100) then
-							bar:SetWidth(v.width / 100)
-						else
-							bar:SetWidth(v.width or 6)
-						end
-					else
-					bar:SetPoint("TOPLEFT", GameTooltip, "TOPLEFT")
-						bar:SetPoint("BOTTOMLEFT", GameTooltip, "BOTTOMLEFT")
-					end
-					bar:SetHeight(v.height)
-					bar:SetMinMaxValues(0, 100)
-					bar:SetOrientation("VERTICAL")
-					bar:SetValue(0)
-					widget.frame = bar
-					bar.widget = widget
-					if not widget.bars then widget.bars = {} end
-					tinsert(widget.bars, bar)
-				end
-			end
-			widget.config.unit = StarTip.unit
-			mod.histograms[v] = widget
-		end
-	end
-end
-
-function mod:CreateHistograms()
-	createHistograms()
-end
-
-function mod:ReInit()
-	if not self.db.profile.histograms then
-		self.db.profile.histograms = {}
-	end
-
-	for i, v in ipairs(defaultWidgets) do
-		for j, vv in ipairs(self.db.profile.histograms) do
-			if v.name == vv.name and not vv.custom then
-				for k, val in pairs(v) do
-					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
-						vv[k] = v[k]
-					end
-				end
-				v.tagged = true
-				v.deleted = vv.deleted
-			end
-		end
-	end
-
-	for i, v in ipairs(defaultWidgets) do
-		if not v.tagged and not v.deleted then
-			tinsert(self.db.profile.histograms, copy(v))
-		end
-	end
-end
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-
-	self:ReInit()
-
-	self.core = LibCore:New(mod, environment, "StarTip.Histograms", {["StarTip.Histograms"] = {}}, nil, StarTip.db.profile.errorLevel)
-
-	self.offset = 0
-
-	StarTip:SetOptionsDisabled(options, true)
-
-	self.histograms = {}
-end
-
-function mod:OnEnable()
-	StarTip:SetOptionsDisabled(options, false)
-	if StarTip.db.profile.intersectRate > 0 then
-		self.intersectTimer = self.intersectTimer or LibTimer:New("Texts.intersectTimer", self.db.profile.intersectRate or 200, true, intersectUpdate)
-	end
-	self:ClearHistograms()
-	createHistograms()
-	for k, histogram in pairs(self.histograms) do
-		if histogram.config.alwaysShown then
-			histogram:Start()
-			for _, bar in pairs(histogram.bars) do
-				bar:Show()
-			end
-		end
-	end
-end
-
-function mod:OnDisable()
-	self:ClearHistograms()
-	GameTooltip:SetClampRectInsets(0, 0, 0, 0)
-	StarTip:SetOptionsDisabled(options, true)
-	if self.intersectTimer then self.intersectTimer:Stop() end
-end
-
-function mod:GetOptions()
-	return options
-end
-
-local plugin = LibStub("StarLibPluginString-1.0")
-function mod:SetUnit()
-
-	GameTooltipStatusBar:Hide()
-	self.offset = 0
-	createHistograms()
-	for k, widget in pairs(self.histograms) do
-		for i = 1, widget.width or WidgetHistogram.defaults.width do
-			widget.bars[i]:Show()
-		end
-		widget:Start()
-	end
-	if self.intersectTimer then
-		self.intersectTimer:Start()
-	end
-
-end
-
-function mod:SetItem()
-	for k, widget in pairs(self.histograms) do
-		if not widget.config.alwaysShown then
-			for i, bar in pairs(widget.bars) do
-				bar:Hide()
-			end
-			if not widget.persistent then
-				widget:Stop()
-			end
-		end
-	end
-	if self.intersectTimer then
-		self.intersectTimer:Start()
-	end
-end
-
-function mod:SetSpell()
-	for k, widget in pairs(self.histograms) do
-		if not widget.config.alwaysShown then
-			for i, bar in pairs(widget.bars) do
-				bar:Hide()
-			end
-			if not widget.persistent then
-				widget:Stop()
-			end
-		end
-	end
-	if self.intersectTimer then
-		self.intersectTimer:Start()
-	end
-end
-
-function mod:OnHide()
-	for k, widget in pairs(self.histograms) do
-		if not widget.config.alwaysShown then
-			for i, bar in pairs(widget.bars) do
-				bar:Hide()
-			end
-			if not widget.persistent then
-				widget:Stop()
-			end
-		end
-	end
-	if self.intersectTimer then
-		self.intersectTimer:Stop()
-	end
-end
-
-local function colorGradient(perc)
-    if perc <= 0.5 then
-        return 1, perc*2, 0
-    else
-        return 2 - perc*2, 1, 0
-    end
-end
-
-function mod:RebuildOpts()
-	local defaults = WidgetHistogram.defaults
-	self:ClearHistograms()
-	wipe(options)
-	for k, v in pairs(optionsDefaults) do
-		options[k] = v
-	end
-	for i, db in ipairs(self.db.profile.histograms) do
-		options[db.name:gsub(" ", "_")] = {
-			name = db.name,
-			type="group",
-			order = i,
-			args=WidgetHistogram:GetOptions(db, StarTip.RebuildOpts, StarTip)
-		}
-		options[db.name:gsub(" ", "_")].args.delete = {
-			name = "Delete",
-			desc = "Delete this widget",
-			type = "execute",
-			func = function()
-				local delete = true
-				for i, v in ipairs(defaultWidgets) do
-					if db.name == v.name then
-						db.deleted = true
-						delete = false
-					end
-				end
-				if delete then
-					self.db.profile.histograms[i] = nil
-				end
-				self:ClearHistograms()
-				StarTip:RebuildOpts()
-			end,
-			order = 13
-		}
-		options[db.name:gsub(" ", "_")].args.enabled = {
-			name = "Enable",
-			desc = "Toggle whether this histogram is enabled or not",
-			type = "toggle",
-			get = function() return db.enabled end,
-			set = function(info, v)
-				db.enabled = v
-				db["enabledDirty"] = true
-				self:ClearHistograms()
-			end,
-			order = 1
-		}
-	end
-end
-
--- Colors, snagged from oUF
-local power = {
-	[0] = { r = 48/255, g = 113/255, b = 191/255}, -- Mana
-	[1] = { r = 226/255, g = 45/255, b = 75/255}, -- Rage
-	[2] = { r = 255/255, g = 178/255, b = 0}, -- Focus
-	[3] = { r = 1, g = 1, b = 34/255}, -- Energy
-	[4] = { r = 0, g = 1, b = 1}, -- Happiness
-	[5] = {}, --Unknown
-	[6] = { r = 0.23, g = 0.12, b = 0.77 } -- Runic Power
-}
-local health = {
-	[0] = {r = 49/255, g = 207/255, b = 37/255}, -- Health
-	[1] = {r = .6, g = .6, b = .6} -- Tapped targets
-}
-local happiness = {
-	[1] = {r = 1, g = 0, b = 0}, -- need.... | unhappy
-	[2] = {r = 1 ,g = 1, b = 0}, -- new..... | content
-	[3] = {r = 0, g = 1, b = 0}, -- colors.. | happy
-}
-
---[[
-function mod:UpdateHistogram()
-	local unit = "mouseover"
-	if not UnitExists(unit) then return end
-	local min, max = UnitHealth(unit), UnitHealthMax(unit)
-	self.hpHistogram:SetMinMaxValues(0, max)
-	self.hpHistogram:SetValue(min)
-
-	local color
-	if self.db.profile.useGradient then
-		color = StarTip.new()
-		color.r, color.g, color.b = colorGradient(min/max)
-	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
-		color = health[1]
-	elseif UnitIsPlayer(unit) then
-		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
-	else
-		color = StarTip.new()
-		color.r, color.g, color.b = UnitSelectionColor(unit)
-	end
-	if not color then color = health[0] end
-	self.hpHistogram:SetStatusBarColor(color.r, color.g, color.b)
-	StarTip.del(color)
-end
-]]
--- Logic snagged from oUF
---[[
-function mod:UpdateHealth()
-	local unit = "mouseover"
-	if not UnitExists(unit) then return end
-	local min, max = UnitHealth(unit), UnitHealthMax(unit)
-	self.hpHistogram:SetMinMaxValues(0, max)
-	self.hpHistogram:SetValue(min)
-
-	local color
-	if self.db.profile.useGradient then
-		color = StarTip.new()
-		color.r, color.g, color.b = colorGradient(min/max)
-	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
-		color = health[1]
-	elseif UnitIsPlayer(unit) then
-		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
-	else
-		color = StarTip.new()
-		color.r, color.g, color.b = UnitSelectionColor(unit)
-	end
-	if not color then color = health[0] end
-	self.hpHistogram:SetStatusBarColor(color.r, color.g, color.b)
-	StarTip.del(color)
-end
-
-function mod:UpdateMana()
-	local unit = "mouseover"
-	if not UnitExists(unit) then return end
-	local min, max = UnitMana(unit), UnitManaMax(unit)
-	self.mpHistogram:SetMinMaxValues(0, max)
-	self.mpHistogram:SetValue(min)
-
-	local color = power[UnitPowerType(unit)]
-	self.mpHistogram:SetStatusBarColor(color.r, color.g, color.b)
-end
-]]
\ No newline at end of file
diff --git a/Modules/Histograms/Histograms.lua b/Modules/Histograms/Histograms.lua
new file mode 100644
index 0000000..a8782c0
--- /dev/null
+++ b/Modules/Histograms/Histograms.lua
@@ -0,0 +1,612 @@
+local mod = StarTip:NewModule("Histograms", "AceTimer-3.0")
+mod.name = "Histograms"
+mod.toggled = true
+--mod.childGroup = true
+mod.defaultOff = true
+local _G = _G
+local StarTip = _G.StarTip
+local GameTooltip = _G.GameTooltip
+local GameTooltipStatusBar = _G.GameTooltipStatusBar
+local UnitIsPlayer = _G.UnitIsPlayer
+local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
+local UnitSelectionColor = _G.UnitSelectionColor
+local UnitClass = _G.UnitClass
+local self = mod
+local LSM = LibStub("LibSharedMedia-3.0")
+local WidgetHistogram = LibStub("StarLibWidgetHistogram-1.0")
+local LibCore = LibStub("StarLibCore-1.0")
+local LibTimer = LibStub("StarLibTimer-1.0")
+
+local unit
+local environment = {}
+
+local createHistograms
+local widgets = {}
+
+local anchors = {
+	"TOP",
+	"TOPRIGHT",
+	"TOPLEFT",
+	"BOTTOM",
+	"BOTTOMRIGHT",
+	"BOTTOMLEFT",
+	"RIGHT",
+	"LEFT",
+	"CENTER"
+}
+
+local anchorsDict = {}
+
+for i, v in ipairs(anchors) do
+	anchorsDict[v] = i
+end
+
+local function copy(tbl)
+	local newTbl = {}
+	for k, v in pairs(tbl) do
+		if type(v) == "table" then
+			v = copy(v)
+		end
+		newTbl[k] = v
+	end
+	return newTbl
+end
+
+local defaultWidgets = {
+	[1] = {
+		name = "Health",
+		expression = "return UnitHealth(unit)",
+		min = "return 0",
+		max = "return UnitHealthMax(unit)",
+		enabled = true,
+		width = 10,
+		height = 50,
+		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -12}},
+		color = [[
+return HPColor(UnitHealth(unit), UnitHealthMax(unit))
+]],
+		layer = 1,
+		update = 1000
+	},
+	[2] = {
+		name = "Power",
+		expression = "return UnitMana(unit)",
+		min = "return 0",
+		max = "return UnitManaMax(unit)",
+		enabled = true,
+		width = 10,
+		height = 50,
+		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", -100, -12}},
+		color = [[
+return PowerColor("RAGE", unit)
+]],
+		layer = 1,
+		update = 1000
+	},
+	[3] = {
+		name = "Mem",
+		type = "histogram",
+		expression = [[
+local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
+if mem then
+    return memperc
+end
+]],
+		color = [[
+local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
+if mem then
+    local num = floor(memperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return r, g, b
+end
+
+]],
+		min = "return 0",
+		max = "return 100",
+		enabled = false,
+		reversed = true,
+		char = "0",
+		width = 10,
+		height = 50,
+		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -77}},
+		layer = 1,
+		update = 1000,
+		persistent = true,
+		intersect = true,
+		intersectPad = 1000,
+	},
+	[4] = {
+		name = "CPU",
+		type = "histogram",
+		expression = [[
+if not scriptProfile then return 0 end
+local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
+return cpuperc
+]],
+		color = [[
+if not scriptProfile then return 0, 1, 0 end
+local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
+if cpu then
+    local num = floor(cpuperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return r, g, b
+end
+
+]],
+		min = "return 0",
+		max = "return 100",
+		enabled = false,
+		reversed = true,
+		char = "0",
+		width = 10,
+		height = 50,
+		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", -100, -77}},
+		layer = 1,
+		update = 1000,
+		persistent = true,
+		intersect = true,
+		intersectPad = 100
+	},
+
+}
+
+local defaults = {
+	profile = {
+		classColors = true,
+		histograms = {},
+		intersect = true
+	}
+}
+
+local options = {}
+local optionsDefaults = {
+	add = {
+		name = "Add Histogram",
+		desc = "Add a histogram",
+		type = "input",
+		set = function(info, v)
+			local widget = {
+				name = v,
+				type = "histogram",
+				min = "return 0",
+				max = "return 100",
+				height = WidgetHistogram.defaults.height,
+				width = WidgetHistogram.defaults.width,
+				enabled = true,
+				points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -50}},
+				texture = LSM:GetDefault("statusbar"),
+				expression = "return random(100)",
+				color = "return 0, 0, 1",
+				custom = true
+			}
+			tinsert(mod.db.profile.histograms, widget)
+			StarTip:RebuildOpts()
+
+		end,
+		order = 5
+	},
+	defaults = {
+		name = "Restore Defaults",
+		desc = "Restore Defaults",
+		type = "execute",
+		func = function()
+			mod.db.profile.histograms = copy(defaultWidgets);
+			StarTip:RebuildOpts()
+		end,
+		order = 6
+	},
+}
+
+local intersectUpdate = function()
+	if type(mod.histograms) == "table" then
+		WidgetHistogram.IntersectUpdate(mod.histograms)
+	end
+end
+
+function updateHistogram(widget)
+	for i = 1, #widget.history do
+		local bar = widget.bars[i]
+		local segment = widget.history[i]
+		if not segment then break end
+		if type(segment) == "table" then
+			bar:SetValue((segment[1] or 0) * 100)
+			local r, g, b, a = widget.history[i][2], widget.history[i][3], widget.history[i][4]
+			bar:SetStatusBarColor(r, g, b, a)
+		elseif type(segment) == "number" then
+			bar:SetValue(0) --segment * 100)
+			bar:SetStatusBarColor(0, 0, 1, 1)
+		end
+		if not UnitExists(StarTip.unit) and not widget.config.alwaysShown then bar:Hide() end
+	end
+end
+
+local textureDict = {}
+
+local new, del
+do
+	local pool = {}
+	function new()
+		local histogram = next(pool)
+
+		if histogram then
+			pool[histogram] = nil
+		else
+			histogram = CreateFrame("StatusBar", nil, GameTooltip)
+		end
+
+		return histogram
+	end
+	function del(histogram)
+		pool[histogram] = true
+	end
+end
+
+local function clearHistogram(obj)
+	obj = mod.histograms and mod.histograms[obj]
+	if not obj then return end
+	for k, v in pairs(obj.bars) do
+		del(v)
+		v:Hide()
+	end
+	obj:Del()
+end
+
+function mod:ClearHistograms()
+	for k, v in pairs(mod.histograms) do
+		clearHistogram(v)
+	end
+	wipe(mod.histograms)
+end
+
+local function createHistograms()
+	if type(mod.histograms) ~= "table" then mod.histograms = {} end
+	--[[for k, widget in pairs(mod.histograms) do
+		for i = 1, widget.width or WidgetHistogram.defaults.width do
+			widget.bars[i]:Hide()
+			if widget.bars[i] then
+				del(widget.bars[i])
+			end
+		end
+		wipe(widget.bars)
+	end]]
+
+	environment.unit = "mouseover"
+	if UnitInRaid("player") then
+		for i=1, GetNumRaidMembers() do
+			if UnitGUID("mouseover") == UnitGUID("raid" .. i) then
+				environment.unit = "raid" .. i
+			end
+		end
+	end
+
+	for k, v in pairs(self.db.profile.histograms) do
+		if v.enabled and not v.deleted then
+			v.width = v.width or WidgetHistogram.defaults.width
+			local widget = mod.histograms[v]
+			local newWidget
+			if not mod.histograms then mod.histograms = {} end
+			if not widget then
+				widget = WidgetHistogram:New(mod.core, v.name, v, v.row or 0, v.col or 0, 0, StarTip.db.profile.errorLevel, updateHistogram)
+				widget.persistent = v.persistent
+				newWidget = true
+				for i = 0, v.width - 1 do
+					local bar = new()
+					bar:SetStatusBarTexture(LSM:Fetch("statusbar", v.texture))
+					bar:ClearAllPoints()
+					for _, point in ipairs(v.points) do
+						local arg1, arg2, arg3, arg4, arg5 = unpack(point)
+						if (v.width > 100) then
+							arg4 = (arg4 or 0) + i * (v.width / 100)
+						else
+							arg4 = (arg4 or 0) + i * v.width
+						end
+						arg5 = (arg5 or 0)
+						bar:SetPoint(arg1, arg2, arg3, arg4, arg5)
+					end
+					if v.width then
+						if (v.width > 100) then
+							bar:SetWidth(v.width / 100)
+						else
+							bar:SetWidth(v.width or 6)
+						end
+					else
+					bar:SetPoint("TOPLEFT", GameTooltip, "TOPLEFT")
+						bar:SetPoint("BOTTOMLEFT", GameTooltip, "BOTTOMLEFT")
+					end
+					bar:SetHeight(v.height)
+					bar:SetMinMaxValues(0, 100)
+					bar:SetOrientation("VERTICAL")
+					bar:SetValue(0)
+					widget.frame = bar
+					bar.widget = widget
+					if not widget.bars then widget.bars = {} end
+					tinsert(widget.bars, bar)
+				end
+			end
+			widget.config.unit = StarTip.unit
+			mod.histograms[v] = widget
+		end
+	end
+end
+
+function mod:CreateHistograms()
+	createHistograms()
+end
+
+function mod:ReInit()
+	if not self.db.profile.histograms then
+		self.db.profile.histograms = {}
+	end
+
+	for i, v in ipairs(defaultWidgets) do
+		for j, vv in ipairs(self.db.profile.histograms) do
+			if v.name == vv.name and not vv.custom then
+				for k, val in pairs(v) do
+					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
+						vv[k] = v[k]
+					end
+				end
+				v.tagged = true
+				v.deleted = vv.deleted
+			end
+		end
+	end
+
+	for i, v in ipairs(defaultWidgets) do
+		if not v.tagged and not v.deleted then
+			tinsert(self.db.profile.histograms, copy(v))
+		end
+	end
+end
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+
+	self:ReInit()
+
+	self.core = LibCore:New(mod, environment, "StarTip.Histograms", {["StarTip.Histograms"] = {}}, nil, StarTip.db.profile.errorLevel)
+
+	self.offset = 0
+
+	StarTip:SetOptionsDisabled(options, true)
+
+	self.histograms = {}
+end
+
+function mod:OnEnable()
+	StarTip:SetOptionsDisabled(options, false)
+	if StarTip.db.profile.intersectRate > 0 then
+		self.intersectTimer = self.intersectTimer or LibTimer:New("Texts.intersectTimer", self.db.profile.intersectRate or 200, true, intersectUpdate)
+	end
+	self:ClearHistograms()
+	createHistograms()
+	for k, histogram in pairs(self.histograms) do
+		if histogram.config.alwaysShown then
+			histogram:Start()
+			for _, bar in pairs(histogram.bars) do
+				bar:Show()
+			end
+		end
+	end
+end
+
+function mod:OnDisable()
+	self:ClearHistograms()
+	GameTooltip:SetClampRectInsets(0, 0, 0, 0)
+	StarTip:SetOptionsDisabled(options, true)
+	if self.intersectTimer then self.intersectTimer:Stop() end
+end
+
+function mod:GetOptions()
+	return options
+end
+
+local plugin = LibStub("StarLibPluginString-1.0")
+function mod:SetUnit()
+
+	GameTooltipStatusBar:Hide()
+	self.offset = 0
+	createHistograms()
+	for k, widget in pairs(self.histograms) do
+		for i = 1, widget.width or WidgetHistogram.defaults.width do
+			widget.bars[i]:Show()
+		end
+		widget:Start()
+	end
+	if self.intersectTimer then
+		self.intersectTimer:Start()
+	end
+
+end
+
+function mod:SetItem()
+	for k, widget in pairs(self.histograms) do
+		if not widget.config.alwaysShown then
+			for i, bar in pairs(widget.bars) do
+				bar:Hide()
+			end
+			if not widget.persistent then
+				widget:Stop()
+			end
+		end
+	end
+	if self.intersectTimer then
+		self.intersectTimer:Start()
+	end
+end
+
+function mod:SetSpell()
+	for k, widget in pairs(self.histograms) do
+		if not widget.config.alwaysShown then
+			for i, bar in pairs(widget.bars) do
+				bar:Hide()
+			end
+			if not widget.persistent then
+				widget:Stop()
+			end
+		end
+	end
+	if self.intersectTimer then
+		self.intersectTimer:Start()
+	end
+end
+
+function mod:OnHide()
+	for k, widget in pairs(self.histograms) do
+		if not widget.config.alwaysShown then
+			for i, bar in pairs(widget.bars) do
+				bar:Hide()
+			end
+			if not widget.persistent then
+				widget:Stop()
+			end
+		end
+	end
+	if self.intersectTimer then
+		self.intersectTimer:Stop()
+	end
+end
+
+local function colorGradient(perc)
+    if perc <= 0.5 then
+        return 1, perc*2, 0
+    else
+        return 2 - perc*2, 1, 0
+    end
+end
+
+function mod:RebuildOpts()
+	local defaults = WidgetHistogram.defaults
+	self:ClearHistograms()
+	wipe(options)
+	for k, v in pairs(optionsDefaults) do
+		options[k] = v
+	end
+	for i, db in ipairs(self.db.profile.histograms) do
+		options[db.name:gsub(" ", "_")] = {
+			name = db.name,
+			type="group",
+			order = i,
+			args=WidgetHistogram:GetOptions(db, StarTip.RebuildOpts, StarTip)
+		}
+		options[db.name:gsub(" ", "_")].args.delete = {
+			name = "Delete",
+			desc = "Delete this widget",
+			type = "execute",
+			func = function()
+				local delete = true
+				for i, v in ipairs(defaultWidgets) do
+					if db.name == v.name then
+						db.deleted = true
+						delete = false
+					end
+				end
+				if delete then
+					self.db.profile.histograms[i] = nil
+				end
+				self:ClearHistograms()
+				StarTip:RebuildOpts()
+			end,
+			order = 13
+		}
+		options[db.name:gsub(" ", "_")].args.enabled = {
+			name = "Enable",
+			desc = "Toggle whether this histogram is enabled or not",
+			type = "toggle",
+			get = function() return db.enabled end,
+			set = function(info, v)
+				db.enabled = v
+				db["enabledDirty"] = true
+				self:ClearHistograms()
+			end,
+			order = 1
+		}
+	end
+end
+
+-- Colors, snagged from oUF
+local power = {
+	[0] = { r = 48/255, g = 113/255, b = 191/255}, -- Mana
+	[1] = { r = 226/255, g = 45/255, b = 75/255}, -- Rage
+	[2] = { r = 255/255, g = 178/255, b = 0}, -- Focus
+	[3] = { r = 1, g = 1, b = 34/255}, -- Energy
+	[4] = { r = 0, g = 1, b = 1}, -- Happiness
+	[5] = {}, --Unknown
+	[6] = { r = 0.23, g = 0.12, b = 0.77 } -- Runic Power
+}
+local health = {
+	[0] = {r = 49/255, g = 207/255, b = 37/255}, -- Health
+	[1] = {r = .6, g = .6, b = .6} -- Tapped targets
+}
+local happiness = {
+	[1] = {r = 1, g = 0, b = 0}, -- need.... | unhappy
+	[2] = {r = 1 ,g = 1, b = 0}, -- new..... | content
+	[3] = {r = 0, g = 1, b = 0}, -- colors.. | happy
+}
+
+--[[
+function mod:UpdateHistogram()
+	local unit = "mouseover"
+	if not UnitExists(unit) then return end
+	local min, max = UnitHealth(unit), UnitHealthMax(unit)
+	self.hpHistogram:SetMinMaxValues(0, max)
+	self.hpHistogram:SetValue(min)
+
+	local color
+	if self.db.profile.useGradient then
+		color = StarTip.new()
+		color.r, color.g, color.b = colorGradient(min/max)
+	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
+		color = health[1]
+	elseif UnitIsPlayer(unit) then
+		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
+	else
+		color = StarTip.new()
+		color.r, color.g, color.b = UnitSelectionColor(unit)
+	end
+	if not color then color = health[0] end
+	self.hpHistogram:SetStatusBarColor(color.r, color.g, color.b)
+	StarTip.del(color)
+end
+]]
+-- Logic snagged from oUF
+--[[
+function mod:UpdateHealth()
+	local unit = "mouseover"
+	if not UnitExists(unit) then return end
+	local min, max = UnitHealth(unit), UnitHealthMax(unit)
+	self.hpHistogram:SetMinMaxValues(0, max)
+	self.hpHistogram:SetValue(min)
+
+	local color
+	if self.db.profile.useGradient then
+		color = StarTip.new()
+		color.r, color.g, color.b = colorGradient(min/max)
+	elseif(UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) or not UnitIsConnected(unit)) then
+		color = health[1]
+	elseif UnitIsPlayer(unit) then
+		color = RAID_CLASS_COLORS[select(2, UnitClass(unit))]
+	else
+		color = StarTip.new()
+		color.r, color.g, color.b = UnitSelectionColor(unit)
+	end
+	if not color then color = health[0] end
+	self.hpHistogram:SetStatusBarColor(color.r, color.g, color.b)
+	StarTip.del(color)
+end
+
+function mod:UpdateMana()
+	local unit = "mouseover"
+	if not UnitExists(unit) then return end
+	local min, max = UnitMana(unit), UnitManaMax(unit)
+	self.mpHistogram:SetMinMaxValues(0, max)
+	self.mpHistogram:SetValue(min)
+
+	local color = power[UnitPowerType(unit)]
+	self.mpHistogram:SetStatusBarColor(color.r, color.g, color.b)
+end
+]]
\ No newline at end of file
diff --git a/Modules/Histograms/StarTip_Histograms.toc b/Modules/Histograms/StarTip_Histograms.toc
new file mode 100644
index 0000000..4374287
--- /dev/null
+++ b/Modules/Histograms/StarTip_Histograms.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [Histograms]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Histograms.lua
\ No newline at end of file
diff --git a/Modules/LCDDisplay.lua b/Modules/LCDDisplay.lua
deleted file mode 100644
index 5c1fd3e..0000000
--- a/Modules/LCDDisplay.lua
+++ /dev/null
@@ -1,361 +0,0 @@
-local mod = StarTip:NewModule("LCDDisplay")
-mod.name = "LCD Display"
-mod.toggled = true
-mod.defaultOff = true
-local Evaluator = LibStub("StarLibEvaluator-1.0")
-local LibCore = LibStub("StarLibCore-1.0")
-local LibLCDText = LibStub("StarLibLCDText-1.0")
-local LibDriverQTip = LibStub("StarLibDriverQTip-1.0")
-local WidgetText = LibStub("StarLibWidgetText-1.0")
-local WidgetBar = LibStub("StarLibWidgetBar-1.0")
-local WidgetHistogram = LibStub("StarLibWidgetHistogram-1.0")
-local LayoutOptions = LibStub("StarLibLayoutOptions-1.0")
-
-local _G = _G
-local GameTooltip = _G.GameTooltip
-
-local function copy(tbl)
-	local new = {}
-	for k, v in pairs(tbl) do
-		if type(v) == "table" then
-			new[k] = copy(v)
-		else
-			new[k] = v
-		end
-	end
-	return new
-end
-
-local defaults = {profile= {config=copy(StarTip.config)}}
-local displays = {}
-
-local options
-local blankOptions = {
-	restart = {
-		name = "Restart Displays",
-		type = "execute",
-		func = function()
-			mod:StopDisplays()
-			mod:StartDisplays()
-		end,
-		order = 1
-	},
-	defaults = {
-		name = "Restore Defaults",
-		type = "execute",
-		func = function()
-			mod.db.profile.config = copy(StarTip.config)
-			StarTip:RebuildOpts()
-		end,
-		order = 2
-	},
-	displays = {
-		name = "Displays",
-		type = "group",
-		args = {},
-		order = 3
-	},
-	layouts = {
-		name = "Layouts",
-		type = "group",
-		args = {},
-		order = 4
-	},
-	widgets = {
-		name = "Widgets",
-		type = "group",
-		args = {},
-		order = 5
-	}
-}
-
-function mod:RebuildOpts()
-	options = copy(blankOptions)
-	options.displays.args.add = {
-		name = "Add Display",
-		type = "input",
-		set = function(info, v)
-			self.db.profile.config["display_" .. v] = {name = v, layouts = {}, widgets = {}}
-			StarTip:RebuildOpts()
-		end,
-		order = 1
-	}
-	options.layouts.args.add = {
-		name = "Add Layout",
-		type = "input",
-		set = function(info, v)
-			self.db.profile.config["layout_" .. v] = {name = v}
-			StarTip:RebuildOpts()
-		end,
-		order = 1
-	}
-	options.widgets.args.text = {
-		name = "Text Widgets",
-		type = "group",
-		args = {
-			add = {
-				name = "Add",
-				desc = "Enter a name for your text widget",
-				type = "input",
-				set = function(info, v)
-					self.db.profile.config["widget_" .. v] = {type = "text"}
-					StarTip:RebuildOpts()
-				end,
-				order = 1
-			},
-		}
-	}
-	options.widgets.args.bar = {
-		name = "Bars",
-		type = "group",
-		args = {
-			add = {
-				name = "Add",
-				desc = "Enter a name for your bar widget",
-				type = "input",
-				set = function(info, v)
-					self.db.profile.config["widget_" .. v] = {type = "bar"}
-					StarTip:RebuildOpts()
-				end,
-				order = 1
-			}
-		}
-	}
-	options.widgets.args.histogram = {
-		name = "Histograms",
-		type = "group",
-		args = {
-			add = {
-				name = "Add",
-				desc = "Enter a name for your histogram widget",
-				type = "input",
-				set = function(info, v)
-					self.db.profile.config["widget_" .. v] = {type = "histogram"}
-					StarTip:RebuildOpts()
-				end,
-				order = 1
-			}
-		}
-	}
-	options.widgets.args.icon = {
-		name = "Icons",
-		type = "group",
-		args = {
-			add = {
-				name = "Add",
-				desc = "Enter a name for your icon widget",
-				type = "input",
-				set = function(info, v)
-					self.db.profile.config["widget_" .. v] = {type = "icon"}
-					StarTip:RebuildOpts()
-				end,
-				order = 1
-			}
-		}
-	}
-	options.widgets.args.key = {
-		name = "Keys",
-		type = "group",
-		args = {
-			add = {
-				name = "Add",
-				desc = "Enter a name for your key widget",
-				type = "input",
-				set = function(info, v)
-					self.db.profile.config["widget_" .. v] = {type = "key"}
-					StarTip:RebuildOpts()
-				end,
-				order = 1
-			}
-		}
-	}
-	for k, v in pairs(self.db.profile.config) do
-		if k:match("^display_.*") then
-			options.displays.args[k:gsub(" ", "_")] = {
-				name = k:gsub("display_", ""),
-				type = "group",
-				args = {
-					enable = {
-						name = "Enable",
-						type = "toggle",
-						get = function()
-							return v.enabled
-						end,
-						set = function(info, val)
-							v.enabled = val
-						end,
-						order = 1
-					},
-					driver = {
-						name = "Driver",
-						desc = "This display's driver type",
-						type = "select",
-						values = LibCore.driverList,
-						get = function() return LibCore.driverDict[v.driver] end,
-						set = function(info, val)
-							v.driver = LibCore.driverList[val]
-							StarTip:RebuildOpts()
-						end,
-						order = 2
-
-					},
-					delete = {
-						name = "Delete",
-						type = "execute",
-						func = function()
-							self.db.profile.config[k] = nil
-							StarTip:RebuildOpts()
-						end,
-						order = 100
-					}
-				}
-			}
-			local driverOptions = {}
-			if v.driver == "QTip" then
-				driverOptions = LibDriverQTip:RebuildOpts(StarTip, v, k)
-			end
-
-			for kk, vv in pairs(driverOptions) do
-				options.displays.args[k:gsub(" ", "_")].args[kk] = vv
-			end
-		end
-		if k:match("^layout_") then
-			options.layouts.args[k:gsub(" ", "_")] = {
-				name = k,
-				type = "group",
-				args = {}
-			}
-			options.layouts.args[k:gsub(" ", "_")].args = LayoutOptions:RebuildOpts(StarTip, v, k)
-			options.layouts.args[k:gsub(" ", "_")].args.delete = {
-				name = "Delete",
-				type = "execute",
-				func = function()
-					self.db.profile.config[k] = nil
-					StarTip:RebuildOpts()
-				end
-			}
-
-		end
-		if k:match("^widget_") then
-			if v.type == "text" then
-				options.widgets.args.text.args[k:gsub(" ", "_")] = {
-					name = k:gsub("widget_", ""),
-					type = "group",
-					args = WidgetText:GetOptions(StarTip, v, k),
-					order = 1
-				}
-				options.widgets.args.text.args[k:gsub(" ", "_")].args.delete = {
-					name = "Delete",
-					type = "execute",
-					func = function()
-						self.db.profile.config[k] = nil
-						StarTip:RebuildOpts()
-					end,
-					order = 100
-				}
-			elseif v.type == "bar" then
-				options.widgets.args.bar.args[k:gsub(" ", "_")] = {
-					name = k,
-					type = "group",
-					args = WidgetBar:GetOptions(StarTip, v, k),
-					order = 1
-				}
-				options.widgets.args.bar.args[k:gsub(" ", "_")].args.delete = {
-					name = "Delete",
-					type = "execute",
-					func = function()
-						self.db.profile.config[k] = nil
-						StarTip:RebuildOpts()
-					end,
-					order = 100
-				}
-			elseif v.type == "histogram" then
-				options.widgets.args.histogram.args[k:gsub(" ", "_")] = {
-					name = k,
-					type = "group",
-					args = WidgetHistogram:GetOptions(StarTip, v, k),
-					order = 1
-				}
-				options.widgets.args.histogram.args[k:gsub(" ", "_")].args.delete = {
-					name = "Delete",
-					type = "execute",
-					func = function()
-						self.db.profile.config[k] = nil
-						StarTip:RebuildOpts()
-					end,
-					order = 100
-				}
-			elseif v.type == "icon" then
-				options.widgets.args.icon.args[k:gsub(" ", "_")] = {
-					name = k,
-					type = "group",
-					args = {}, --WidgetIcon:GetOptions(StarTip, v, k)},
-					order = 2
-				}
-				options.widgets.args.icon.args[k:gsub(" ", "_")].args.delete = {
-					name = "Delete",
-					type = "execute",
-					func = function()
-						self.db.profile.config[k] = nil
-						StarTip:RebuildOpts()
-					end,
-					order = 100
-				}
-			elseif v.type == "key" then
-				options.widgets.args.key.args[k:gsub(" ", "_")] = {
-					name = k,
-					type = "group",
-					args = {}, --WidgetKey:GetOptions(StarTip, v, k)}
-					order = 3
-				}
-				options.widgets.args.key.args[k:gsub(" ", "_")].args.delete = {
-					name = "Delete",
-					type = "execute",
-					func = function()
-						self.db.profile.config[k] = nil
-						StarTip:RebuildOpts()
-					end,
-					order = 100
-				}
-			end
-		end
-	end
-end
-
-function mod:GetOptions()
-	self:RebuildOpts()
-	return options
-end
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-
-end
-
-function mod:OnEnable()
-	self:StartDisplays()
-end
-
-function mod:OnDisable()
-	self:StopDisplays()
-end
-
-function mod:StartDisplays()
-	for k, v in pairs(self.db.profile.config) do
-		if k:match("^display_") then
-			if v.driver == "QTip" then
-				local display = LibDriverQTip:New(self, k, self.db.profile.config, StarTip.db.profile.errorLevel)
-				display:Show()
-				tinsert(displays, display)
-			end
-		end
-	end
-end
-
-function mod:StopDisplays()
-	for i, v in ipairs(displays) do
-		v:Hide()
-		v:Del()
-	end
-	table.wipe(displays)
-end
\ No newline at end of file
diff --git a/Modules/Position.lua b/Modules/Position.lua
deleted file mode 100644
index d6d6a3a..0000000
--- a/Modules/Position.lua
+++ /dev/null
@@ -1,430 +0,0 @@
-local mod = StarTip:NewModule("Position", "AceEvent-3.0", "AceHook-3.0")
-mod.name = "Positioning"
-local _G = _G
-local GameTooltip = _G.GameTooltip
-local StarTip = _G.StarTip
-local UIParent = _G.UIParent
-local self = mod
-
-local defaults = {
-	profile = {
-		inCombat = 1,
-		anchor = 1,
-		unitFrames = 1,
-		other = 1,
-		inCombatXOffset = 10,
-		inCombatYOffset = 0,
-		anchorXOffset = 10,
-		anchorYOffset = 0,
-		unitFramesXOffset = 10,
-		unitFramesYOffset = 0,
-		otherXOffset = 10,
-		otherYOffset = 0
-	}
-}
-
-local selections = {}
-for i, v in ipairs(StarTip.anchorText) do
-	selections[i] = v
-end
-selections[#selections+1] = "Hide"
-
-local get = function(info)
-	return self.db.profile[info[#info]]
-end
-
-local set = function(info,v)
-	self.db.profile[info[#info]] = v
-end
-
-local inputGet = function(info)
-	return tostring(self.db.profile[info[#info]] or 0)
-end
-
-local inputSet = function(info, v)
-	self.db.profile[info[#info]] = tonumber(v)
-end
-
-local minX = -math.floor(GetScreenWidth()/5 + 0.5) * 5
-local minY = -math.floor(GetScreenHeight()/5 + 0.5) * 5
-local maxX = math.floor(GetScreenWidth()/5 + 0.5) * 5
-local maxY = math.floor(GetScreenHeight()/5 + 0.5) * 5
-
-local options = {
-	anchor = {
-		name = "World Units",
-		desc = "Where to anchor the tooltip when mousing over world characters",
-		type = "select",
-		values = selections,
-		get = get,
-		set = set,
-		order = 4
-	},
-	anchorXOffset = {
-		name = format("X-axis offset: %d-%d", minX, maxX),
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minX and val <= maxX
-		end,
-		order = 5
-	},
-	anchorYOffset = {
-		name = format("Y-axis offset: %d-%d", minY, maxY),
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minY and val <= maxY
-		end,
-		order = 6
-
-	},
-	--[[anchorXOffset = {
-		name = "X-axis offset",
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minX,
-		max = maxX,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 5
-	},
-	anchorYOffset = {
-		name = "Y-axis offset",
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minY,
-		max = maxY,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 6
-
-	},]]
-	inCombatHeader = {
-		name = "",
-		type = "header",
-		order = 7
-	},
-	inCombat = {
-		name = "In Combat",
-		desc = "Where to anchor the world unit tooltip while in combat",
-		type = "select",
-		values = selections,
-		get = get,
-		set = set,
-		order = 8
-	},
-	inCombatXOffset = {
-		name = format("X-axis offset: %d-%d", minX, maxX),
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minX and val <= maxX
-		end,
-		order = 9
-	},
-	inCombatYOffset = {
-		name = format("Y-axis offset: %d-%d", minY, maxY),
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minY and val <= maxX
-		end,
-		order = 10,
-	},
-	--[[inCombatXOffset = {
-		name = "X-axis offset",
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minX,
-		max = maxX,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 9
-	},
-	inCombatYOffset = {
-		name = "Y-axis offset",
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minY,
-		max = maxY,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 10
-	},]]
-	unitFramesHeader = {
-		name = "",
-		type = "header",
-		order = 11
-	},
-	unitFrames = {
-		name = "Unit Frames",
-		desc = "Where to anchor the tooltip when mousing over a unit frame",
-		type = "select",
-		values = selections,
-		get = get,
-		set = set,
-		order = 12
-	},
-	unitFramesXOffset = {
-		name = format("X-axis offset: %d-%d", minX, maxX),
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minX and val <= maxX
-		end,
-		order = 13
-	},
-	unitFramesYOffset = {
-		name = format("Y-axis offset: %d-%d", minY, maxY),
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minY and val <= maxY
-		end,
-		order = 14
-	},
-	--[[unitFramesXOffset = {
-		name = "X-axis offset",
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minX,
-		max = maxX,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 13
-	},
-	unitFramesYOffset = {
-		name = "Y-axis offset",
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minY,
-		max = maxY,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 14
-	},]]
-	otherHeader = {
-		name = "",
-		type = "header",
-		order = 15
-	},
-	other = {
-		name = "Other tooltips",
-		desc = "Where to anchor tooltips that are not unit tooltips",
-		type = "select",
-		values = selections,
-		get = get,
-		set = set,
-		order = 16
-	},
-	otherXOffset = {
-		name = format("X-axis offset: %d-%d", minX, maxX),
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minX and val <= maxX
-		end,
-		order = 17
-	},
-	otherYOffset = {
-		name = format("Y-axis offset: %d-%d", minY, maxY),
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "input",
-		pattern = "%d",
-		get = inputGet,
-		set = inputSet,
-		validate = function(info, val)
-			val = tonumber(val)
-			return val >= minY and val <= maxY
-		end,
-		order = 18
-	}
-	--[[otherXOffset = {
-		name = "X-axis offset",
-		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minX,
-		max = maxX,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 17
-	},
-	otherYOffset = {
-		name = "Y-axis offset",
-		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
-		type = "range",
-		min = minY,
-		max = maxY,
-		step = 1,
-		bigStep = 5,
-		get = get,
-		set = set,
-		order = 18
-	}]]
-}
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-	StarTip:SetOptionsDisabled(options, true)
-end
-
-function mod:OnEnable()
-	self:RegisterEvent("REGEN_DISABLED")
-	self:RegisterEvent("REGEN_ENABLED")
-	self:SecureHook("GameTooltip_SetDefaultAnchor")
-	StarTip:SetOptionsDisabled(options, false)
-end
-
-function mod:OnDisable()
-	self:UnregisterEvent("REGEN_DISABLED")
-	self:UnregisterEvent("REGEN_ENABLED")
-	self:Unhook("GameTooltip_SetDefaultAnchor")
-	StarTip:SetOptionsDisabled(options, true)
-end
-
-function mod:GetOptions()
-	return options
-end
-
-local updateFrame = CreateFrame("Frame")
-local oldX, oldY
-local currentAnchor
-local xoffset, yoffset
-local positionTooltip = function()
-	local x, y = GetCursorPosition()
-
-	local effScale = GameTooltip:GetEffectiveScale()
-
-	if x ~= oldX or y ~= oldY then
-		GameTooltip:ClearAllPoints()
-		GameTooltip:SetPoint(currentAnchor, UIParent, "BOTTOMLEFT", (x + xoffset) / effScale, (y + yoffset) / effScale)
-	end
-	oldX, oldY = x, y
-end
-
-local getIndex = function(owner)
-	local index
-	if UnitExists("mouseover") then
-		if InCombatLockdown() then
-			index = self.db.profile.inCombat
-		elseif owner == UIParent then
-			index = self.db.profile.anchor
-		else
-			index = self.db.profile.unitFrames
-		end
-	else
-		index = self.db.profile.other
-	end
-	return index
-end
-
-local setOffsets = function(owner)
-	if owner == UIParent then
-		if UnitExists("mouseover") then
-			if InCombatLockdown() then
-				xoffset = self.db.profile.inCombatXOffset
-				yoffset = self.db.profile.inCombatYOffset
-			else
-				xoffset = self.db.profile.anchorXOffset
-				yoffset = self.db.profile.anchorYOffset
-			end
-		else
-			xoffset = self.db.profile.otherXOffset
-			yoffset = self.db.profile.otherYOffset
-		end
-	else
-		if UnitExists("mouseover") then
-			xoffset = self.db.profile.unitFramesXOffset
-			yoffset = self.db.profile.unitFramesYOffset
-		else
-			xoffset = self.db.profile.otherXOffset
-			yoffset = self.db.profile.otherYOffset
-		end
-	end
-end
-
-local currentOwner
-local currentThis
-local delayFrame = CreateFrame("Frame")
-local function delayAnchor()
-	local this = currentThis
-	local owner = currentOwner
-	this:ClearAllPoints()
-	setOffsets(owner)
-	local index = getIndex(owner)
-	if index == #selections then
-		this:Hide()
-		return
-	elseif StarTip.anchors[index]:find("^CURSOR_")  then
-		oldX, oldY = 0, 0
-		currentAnchor = StarTip.opposites[StarTip.anchors[index]:sub(8)]
-		updateFrame:SetScript("OnUpdate", positionTooltip)
-		positionTooltip()
-	else
-		if updateFrame:GetScript("OnUpdate") then updateFrame:SetScript("OnUpdate", nil) end
-		this:SetPoint(StarTip.anchors[index], UIParent, StarTip.anchors[index], xoffset, yoffset)
-	end
-	delayFrame:SetScript("OnUpdate", nil)
-end
-
-function mod:GameTooltip_SetDefaultAnchor(this, owner)
-	currentOwner = owner
-	currentThis = this
-	delayFrame:SetScript("OnUpdate", delayAnchor)
-end
-
-function mod:REGEN_DISABLED()
-	if not currentOwner then return end
-	updateFrame:SetScript("OnUpdate", nil)
-	self:GameTooltip_SetDefaultAnchor(GameTooltip, currentOwner)
-end
-
-mod.REGEN_ENABLED = mod.REGEN_DISABLED
-
-function mod:OnHide()
-	updateFrame:SetScript("OnUpdate", nil)
-	delayFrame:SetScript("OnUpdate", nil)
-end
diff --git a/Modules/Position/Position.lua b/Modules/Position/Position.lua
new file mode 100644
index 0000000..d6d6a3a
--- /dev/null
+++ b/Modules/Position/Position.lua
@@ -0,0 +1,430 @@
+local mod = StarTip:NewModule("Position", "AceEvent-3.0", "AceHook-3.0")
+mod.name = "Positioning"
+local _G = _G
+local GameTooltip = _G.GameTooltip
+local StarTip = _G.StarTip
+local UIParent = _G.UIParent
+local self = mod
+
+local defaults = {
+	profile = {
+		inCombat = 1,
+		anchor = 1,
+		unitFrames = 1,
+		other = 1,
+		inCombatXOffset = 10,
+		inCombatYOffset = 0,
+		anchorXOffset = 10,
+		anchorYOffset = 0,
+		unitFramesXOffset = 10,
+		unitFramesYOffset = 0,
+		otherXOffset = 10,
+		otherYOffset = 0
+	}
+}
+
+local selections = {}
+for i, v in ipairs(StarTip.anchorText) do
+	selections[i] = v
+end
+selections[#selections+1] = "Hide"
+
+local get = function(info)
+	return self.db.profile[info[#info]]
+end
+
+local set = function(info,v)
+	self.db.profile[info[#info]] = v
+end
+
+local inputGet = function(info)
+	return tostring(self.db.profile[info[#info]] or 0)
+end
+
+local inputSet = function(info, v)
+	self.db.profile[info[#info]] = tonumber(v)
+end
+
+local minX = -math.floor(GetScreenWidth()/5 + 0.5) * 5
+local minY = -math.floor(GetScreenHeight()/5 + 0.5) * 5
+local maxX = math.floor(GetScreenWidth()/5 + 0.5) * 5
+local maxY = math.floor(GetScreenHeight()/5 + 0.5) * 5
+
+local options = {
+	anchor = {
+		name = "World Units",
+		desc = "Where to anchor the tooltip when mousing over world characters",
+		type = "select",
+		values = selections,
+		get = get,
+		set = set,
+		order = 4
+	},
+	anchorXOffset = {
+		name = format("X-axis offset: %d-%d", minX, maxX),
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minX and val <= maxX
+		end,
+		order = 5
+	},
+	anchorYOffset = {
+		name = format("Y-axis offset: %d-%d", minY, maxY),
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minY and val <= maxY
+		end,
+		order = 6
+
+	},
+	--[[anchorXOffset = {
+		name = "X-axis offset",
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minX,
+		max = maxX,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 5
+	},
+	anchorYOffset = {
+		name = "Y-axis offset",
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minY,
+		max = maxY,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 6
+
+	},]]
+	inCombatHeader = {
+		name = "",
+		type = "header",
+		order = 7
+	},
+	inCombat = {
+		name = "In Combat",
+		desc = "Where to anchor the world unit tooltip while in combat",
+		type = "select",
+		values = selections,
+		get = get,
+		set = set,
+		order = 8
+	},
+	inCombatXOffset = {
+		name = format("X-axis offset: %d-%d", minX, maxX),
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minX and val <= maxX
+		end,
+		order = 9
+	},
+	inCombatYOffset = {
+		name = format("Y-axis offset: %d-%d", minY, maxY),
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minY and val <= maxX
+		end,
+		order = 10,
+	},
+	--[[inCombatXOffset = {
+		name = "X-axis offset",
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minX,
+		max = maxX,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 9
+	},
+	inCombatYOffset = {
+		name = "Y-axis offset",
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minY,
+		max = maxY,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 10
+	},]]
+	unitFramesHeader = {
+		name = "",
+		type = "header",
+		order = 11
+	},
+	unitFrames = {
+		name = "Unit Frames",
+		desc = "Where to anchor the tooltip when mousing over a unit frame",
+		type = "select",
+		values = selections,
+		get = get,
+		set = set,
+		order = 12
+	},
+	unitFramesXOffset = {
+		name = format("X-axis offset: %d-%d", minX, maxX),
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minX and val <= maxX
+		end,
+		order = 13
+	},
+	unitFramesYOffset = {
+		name = format("Y-axis offset: %d-%d", minY, maxY),
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minY and val <= maxY
+		end,
+		order = 14
+	},
+	--[[unitFramesXOffset = {
+		name = "X-axis offset",
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minX,
+		max = maxX,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 13
+	},
+	unitFramesYOffset = {
+		name = "Y-axis offset",
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minY,
+		max = maxY,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 14
+	},]]
+	otherHeader = {
+		name = "",
+		type = "header",
+		order = 15
+	},
+	other = {
+		name = "Other tooltips",
+		desc = "Where to anchor tooltips that are not unit tooltips",
+		type = "select",
+		values = selections,
+		get = get,
+		set = set,
+		order = 16
+	},
+	otherXOffset = {
+		name = format("X-axis offset: %d-%d", minX, maxX),
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minX and val <= maxX
+		end,
+		order = 17
+	},
+	otherYOffset = {
+		name = format("Y-axis offset: %d-%d", minY, maxY),
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "input",
+		pattern = "%d",
+		get = inputGet,
+		set = inputSet,
+		validate = function(info, val)
+			val = tonumber(val)
+			return val >= minY and val <= maxY
+		end,
+		order = 18
+	}
+	--[[otherXOffset = {
+		name = "X-axis offset",
+		desc = "The x-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minX,
+		max = maxX,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 17
+	},
+	otherYOffset = {
+		name = "Y-axis offset",
+		desc = "The y-axis offset used to position the tooltip in relationship to the anchor point",
+		type = "range",
+		min = minY,
+		max = maxY,
+		step = 1,
+		bigStep = 5,
+		get = get,
+		set = set,
+		order = 18
+	}]]
+}
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+	StarTip:SetOptionsDisabled(options, true)
+end
+
+function mod:OnEnable()
+	self:RegisterEvent("REGEN_DISABLED")
+	self:RegisterEvent("REGEN_ENABLED")
+	self:SecureHook("GameTooltip_SetDefaultAnchor")
+	StarTip:SetOptionsDisabled(options, false)
+end
+
+function mod:OnDisable()
+	self:UnregisterEvent("REGEN_DISABLED")
+	self:UnregisterEvent("REGEN_ENABLED")
+	self:Unhook("GameTooltip_SetDefaultAnchor")
+	StarTip:SetOptionsDisabled(options, true)
+end
+
+function mod:GetOptions()
+	return options
+end
+
+local updateFrame = CreateFrame("Frame")
+local oldX, oldY
+local currentAnchor
+local xoffset, yoffset
+local positionTooltip = function()
+	local x, y = GetCursorPosition()
+
+	local effScale = GameTooltip:GetEffectiveScale()
+
+	if x ~= oldX or y ~= oldY then
+		GameTooltip:ClearAllPoints()
+		GameTooltip:SetPoint(currentAnchor, UIParent, "BOTTOMLEFT", (x + xoffset) / effScale, (y + yoffset) / effScale)
+	end
+	oldX, oldY = x, y
+end
+
+local getIndex = function(owner)
+	local index
+	if UnitExists("mouseover") then
+		if InCombatLockdown() then
+			index = self.db.profile.inCombat
+		elseif owner == UIParent then
+			index = self.db.profile.anchor
+		else
+			index = self.db.profile.unitFrames
+		end
+	else
+		index = self.db.profile.other
+	end
+	return index
+end
+
+local setOffsets = function(owner)
+	if owner == UIParent then
+		if UnitExists("mouseover") then
+			if InCombatLockdown() then
+				xoffset = self.db.profile.inCombatXOffset
+				yoffset = self.db.profile.inCombatYOffset
+			else
+				xoffset = self.db.profile.anchorXOffset
+				yoffset = self.db.profile.anchorYOffset
+			end
+		else
+			xoffset = self.db.profile.otherXOffset
+			yoffset = self.db.profile.otherYOffset
+		end
+	else
+		if UnitExists("mouseover") then
+			xoffset = self.db.profile.unitFramesXOffset
+			yoffset = self.db.profile.unitFramesYOffset
+		else
+			xoffset = self.db.profile.otherXOffset
+			yoffset = self.db.profile.otherYOffset
+		end
+	end
+end
+
+local currentOwner
+local currentThis
+local delayFrame = CreateFrame("Frame")
+local function delayAnchor()
+	local this = currentThis
+	local owner = currentOwner
+	this:ClearAllPoints()
+	setOffsets(owner)
+	local index = getIndex(owner)
+	if index == #selections then
+		this:Hide()
+		return
+	elseif StarTip.anchors[index]:find("^CURSOR_")  then
+		oldX, oldY = 0, 0
+		currentAnchor = StarTip.opposites[StarTip.anchors[index]:sub(8)]
+		updateFrame:SetScript("OnUpdate", positionTooltip)
+		positionTooltip()
+	else
+		if updateFrame:GetScript("OnUpdate") then updateFrame:SetScript("OnUpdate", nil) end
+		this:SetPoint(StarTip.anchors[index], UIParent, StarTip.anchors[index], xoffset, yoffset)
+	end
+	delayFrame:SetScript("OnUpdate", nil)
+end
+
+function mod:GameTooltip_SetDefaultAnchor(this, owner)
+	currentOwner = owner
+	currentThis = this
+	delayFrame:SetScript("OnUpdate", delayAnchor)
+end
+
+function mod:REGEN_DISABLED()
+	if not currentOwner then return end
+	updateFrame:SetScript("OnUpdate", nil)
+	self:GameTooltip_SetDefaultAnchor(GameTooltip, currentOwner)
+end
+
+mod.REGEN_ENABLED = mod.REGEN_DISABLED
+
+function mod:OnHide()
+	updateFrame:SetScript("OnUpdate", nil)
+	delayFrame:SetScript("OnUpdate", nil)
+end
diff --git a/Modules/Position/StarTip_Position.toc b/Modules/Position/StarTip_Position.toc
new file mode 100644
index 0000000..47eaaf1
--- /dev/null
+++ b/Modules/Position/StarTip_Position.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [Position]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Position.lua
\ No newline at end of file
diff --git a/Modules/PvP.lua b/Modules/PvP.lua
deleted file mode 100644
index 42ca144..0000000
--- a/Modules/PvP.lua
+++ /dev/null
@@ -1,49 +0,0 @@
-local mod = StarTip:NewModule("PvP", "AceEvent-3.0")
-mod.name = "PvP"
-mod.toggled = true
-local _G = _G
-local GameTooltip = _G.GameTooltip
-local UnitFactionGroup = _G.UnitFactionGroup
-local self = mod
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-	local frame = _G.CreateFrame("Frame", nil, GameTooltip)
-	local pvp = frame:CreateTexture(nil, "OVERLAY")
-	pvp:SetHeight(30)
-	pvp:SetWidth(30)
-	pvp:SetPoint("TOPRIGHT", GameTooltip, 20, 10)
-	pvp:Hide()
-	self.PvP = pvp
-end
-
-function mod:OnEnable()
-	self:RegisterEvent("UNIT_FACTION")
-end
-
-function mod:OnDisable()
-	self:UnregisterEvent("UNIT_FACTION")
-end
-
-function mod:UNIT_FACTION(event, unit)
-	if unit ~= "mouseover" then return end
-
-	local factionGroup = UnitFactionGroup(unit)
-	if(UnitIsPVPFreeForAll(unit)) then
-		self.PvP:SetTexture[[Interface\TargetingFrame\UI-PVP-FFA]]
-		self.PvP:Show()
-	elseif(factionGroup and UnitIsPVP(unit)) then
-		self.PvP:SetTexture([[Interface\TargetingFrame\UI-PVP-]]..factionGroup)
-		self.PvP:Show()
-	else
-		self.PvP:Hide()
-	end
-end
-
-function mod:SetUnit()
-	self:UNIT_FACTION(nil, "mouseover")
-end
-
-function mod:OnHide()
-	self.PvP:Hide()
-end
diff --git a/Modules/PvP/PvP.lua b/Modules/PvP/PvP.lua
new file mode 100644
index 0000000..42ca144
--- /dev/null
+++ b/Modules/PvP/PvP.lua
@@ -0,0 +1,49 @@
+local mod = StarTip:NewModule("PvP", "AceEvent-3.0")
+mod.name = "PvP"
+mod.toggled = true
+local _G = _G
+local GameTooltip = _G.GameTooltip
+local UnitFactionGroup = _G.UnitFactionGroup
+local self = mod
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+	local frame = _G.CreateFrame("Frame", nil, GameTooltip)
+	local pvp = frame:CreateTexture(nil, "OVERLAY")
+	pvp:SetHeight(30)
+	pvp:SetWidth(30)
+	pvp:SetPoint("TOPRIGHT", GameTooltip, 20, 10)
+	pvp:Hide()
+	self.PvP = pvp
+end
+
+function mod:OnEnable()
+	self:RegisterEvent("UNIT_FACTION")
+end
+
+function mod:OnDisable()
+	self:UnregisterEvent("UNIT_FACTION")
+end
+
+function mod:UNIT_FACTION(event, unit)
+	if unit ~= "mouseover" then return end
+
+	local factionGroup = UnitFactionGroup(unit)
+	if(UnitIsPVPFreeForAll(unit)) then
+		self.PvP:SetTexture[[Interface\TargetingFrame\UI-PVP-FFA]]
+		self.PvP:Show()
+	elseif(factionGroup and UnitIsPVP(unit)) then
+		self.PvP:SetTexture([[Interface\TargetingFrame\UI-PVP-]]..factionGroup)
+		self.PvP:Show()
+	else
+		self.PvP:Hide()
+	end
+end
+
+function mod:SetUnit()
+	self:UNIT_FACTION(nil, "mouseover")
+end
+
+function mod:OnHide()
+	self.PvP:Hide()
+end
diff --git a/Modules/PvP/StarTip_PvP.toc b/Modules/PvP/StarTip_PvP.toc
new file mode 100644
index 0000000..5198aff
--- /dev/null
+++ b/Modules/PvP/StarTip_PvP.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [PvP]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+PvP.lua
\ No newline at end of file
diff --git a/Modules/RaidIcon.lua b/Modules/RaidIcon.lua
deleted file mode 100644
index 8df484f..0000000
--- a/Modules/RaidIcon.lua
+++ /dev/null
@@ -1,48 +0,0 @@
-local mod = StarTip:NewModule("RaidIcon", "AceEvent-3.0")
-mod.name = "RaidIcon"
-mod.toggled = true
-local _G = _G
-local GameTooltip = _G.GameTooltip
-local GetRaidTargetIndex = _G.GetRaidTargetIndex
-local SetRaidTargetIconTexture = _G.SetRaidTargetIconTexture
-local self = mod
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-	local frame = CreateFrame("Frame", nil, GameTooltip)
-	local icon = frame:CreateTexture(nil, "OVERLAY")
-	icon:SetHeight(16)
-    icon:SetWidth(16)
-    icon:SetPoint("TOP", GameTooltip, 0, 4)
-    icon:SetTexture"Interface\\TargetingFrame\\UI-RaidTargetingIcons"
-	icon:Hide()
-	self.icon = icon
-end
-
-function mod:OnEnable()
-	self:RegisterEvent("RAID_TARGET_UPDATE")
-end
-
-function mod:OnDisable()
-	self:UnregisterEvent("RAID_TARGET_UPDATE")
-end
-
-function mod:SetUnit()
-	self:RAID_TARGET_UPDATE()
-end
-
-function mod:OnHide()
-	if self.icon:IsShown() then self.icon:Hide() end
-end
-
-function mod:RAID_TARGET_UPDATE(event)
-	local index = _G.GetRaidTargetIndex("mouseover")
-
-	if(index) then
-		_G.SetRaidTargetIconTexture(self.icon, index)
-		self.icon:Show()
-	else
-		self.icon:Hide()
-	end
-end
-
diff --git a/Modules/RaidIcon/RaidIcon.lua b/Modules/RaidIcon/RaidIcon.lua
new file mode 100644
index 0000000..8df484f
--- /dev/null
+++ b/Modules/RaidIcon/RaidIcon.lua
@@ -0,0 +1,48 @@
+local mod = StarTip:NewModule("RaidIcon", "AceEvent-3.0")
+mod.name = "RaidIcon"
+mod.toggled = true
+local _G = _G
+local GameTooltip = _G.GameTooltip
+local GetRaidTargetIndex = _G.GetRaidTargetIndex
+local SetRaidTargetIconTexture = _G.SetRaidTargetIconTexture
+local self = mod
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+	local frame = CreateFrame("Frame", nil, GameTooltip)
+	local icon = frame:CreateTexture(nil, "OVERLAY")
+	icon:SetHeight(16)
+    icon:SetWidth(16)
+    icon:SetPoint("TOP", GameTooltip, 0, 4)
+    icon:SetTexture"Interface\\TargetingFrame\\UI-RaidTargetingIcons"
+	icon:Hide()
+	self.icon = icon
+end
+
+function mod:OnEnable()
+	self:RegisterEvent("RAID_TARGET_UPDATE")
+end
+
+function mod:OnDisable()
+	self:UnregisterEvent("RAID_TARGET_UPDATE")
+end
+
+function mod:SetUnit()
+	self:RAID_TARGET_UPDATE()
+end
+
+function mod:OnHide()
+	if self.icon:IsShown() then self.icon:Hide() end
+end
+
+function mod:RAID_TARGET_UPDATE(event)
+	local index = _G.GetRaidTargetIndex("mouseover")
+
+	if(index) then
+		_G.SetRaidTargetIconTexture(self.icon, index)
+		self.icon:Show()
+	else
+		self.icon:Hide()
+	end
+end
+
diff --git a/Modules/RaidIcon/StarTip_RaidIcon.toc b/Modules/RaidIcon/StarTip_RaidIcon.toc
new file mode 100644
index 0000000..1b9d287
--- /dev/null
+++ b/Modules/RaidIcon/StarTip_RaidIcon.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [RaidIcon]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+RaidIcon.lua
\ No newline at end of file
diff --git a/Modules/Targeting.lua b/Modules/Targeting.lua
deleted file mode 100644
index ca2a80c..0000000
--- a/Modules/Targeting.lua
+++ /dev/null
@@ -1,35 +0,0 @@
-local mod = StarTip:NewModule("Targeting", "AceEvent-3.0")
-mod.name = "Targeting"
-mod.toggled = true
-local _G = _G
-local GameTooltip = _G.GameTooltip
-local UnitFactionGroup = _G.UnitFactionGroup
-local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
-local StarTip = _G.StarTip
-local self = mod
-
-function mod:OnInitialize()
-end
-
-function mod:OnEnable()
-end
-
-function mod:OnDisable()
-end
-
-function mod:SetUnit()
-	if UnitInRaid("player") then
-		local txt = ''
-		for i=1, GetNumRaidMembers() do
-			if UnitExists("mouseover") and UnitGUID("mouseover") == UnitGUID("raid" .. i .. "target") then
-				local c = RAID_CLASS_COLORS[select(2, UnitClass("raid" .. i))]
-				local name = UnitName("raid" .. i)
-				txt = txt .. ("|cFF%02x%02x%02x%s|r "):format(c.r*255, c.g*255, c.b*255, name)
-			end
-		end
-		if txt ~= '' then
-			GameTooltip:AddLine("Targeting: " .. txt, .5, .5, 1, 1)
-		end
-	end
-end
-
diff --git a/Modules/Targeting/StarTip_Targeting.toc b/Modules/Targeting/StarTip_Targeting.toc
new file mode 100644
index 0000000..4b945ac
--- /dev/null
+++ b/Modules/Targeting/StarTip_Targeting.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [Targeting]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Targeting.lua
\ No newline at end of file
diff --git a/Modules/Targeting/Targeting.lua b/Modules/Targeting/Targeting.lua
new file mode 100644
index 0000000..ca2a80c
--- /dev/null
+++ b/Modules/Targeting/Targeting.lua
@@ -0,0 +1,35 @@
+local mod = StarTip:NewModule("Targeting", "AceEvent-3.0")
+mod.name = "Targeting"
+mod.toggled = true
+local _G = _G
+local GameTooltip = _G.GameTooltip
+local UnitFactionGroup = _G.UnitFactionGroup
+local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
+local StarTip = _G.StarTip
+local self = mod
+
+function mod:OnInitialize()
+end
+
+function mod:OnEnable()
+end
+
+function mod:OnDisable()
+end
+
+function mod:SetUnit()
+	if UnitInRaid("player") then
+		local txt = ''
+		for i=1, GetNumRaidMembers() do
+			if UnitExists("mouseover") and UnitGUID("mouseover") == UnitGUID("raid" .. i .. "target") then
+				local c = RAID_CLASS_COLORS[select(2, UnitClass("raid" .. i))]
+				local name = UnitName("raid" .. i)
+				txt = txt .. ("|cFF%02x%02x%02x%s|r "):format(c.r*255, c.g*255, c.b*255, name)
+			end
+		end
+		if txt ~= '' then
+			GameTooltip:AddLine("Targeting: " .. txt, .5, .5, 1, 1)
+		end
+	end
+end
+
diff --git a/Modules/Text.lua b/Modules/Text.lua
deleted file mode 100644
index 6f5e370..0000000
--- a/Modules/Text.lua
+++ /dev/null
@@ -1,721 +0,0 @@
-local mod = StarTip:NewModule("Text", "AceTimer-3.0")
-mod.name = "Texts"
-mod.toggled = true
---mod.childGroup = true
-mod.defaultOff = true
-local _G = _G
-local StarTip = _G.StarTip
-local GameTooltip = _G.GameTooltip
-local GameTooltipStatusBar = _G.GameTooltipStatusBar
-local UnitIsPlayer = _G.UnitIsPlayer
-local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
-local UnitSelectionColor = _G.UnitSelectionColor
-local UnitClass = _G.UnitClass
-local self = mod
-local timer
-local LSM = LibStub("LibSharedMedia-3.0")
-local WidgetText = LibStub("StarLibWidgetText-1.0")
-local LibCore = LibStub("StarLibCore-1.0")
-local LibQTip = LibStub("LibQTip-1.0")
-local PluginUtils = LibStub("StarLibPluginUtils-1.0")
-local LibTimer = LibStub("StarLibTimer-1.0")
-local Widget = LibStub("StarLibWidget-1.0")
-
-local environment = {}
-
-local anchors = {
-	"TOP",
-	"TOPRIGHT",
-	"TOPLEFT",
-	"BOTTOM",
-	"BOTTOMRIGHT",
-	"BOTTOMLEFT",
-	"RIGHT",
-	"LEFT",
-	"CENTER"
-}
-
-local anchorsDict = {}
-
-for i, v in ipairs(anchors) do
-	anchorsDict[v] = i
-end
-
-local createTexts
-local widgets = {}
-
-local function copy(tbl)
-	if type(tbl) ~= "table" then return tbl end
-	local newTbl = {}
-	for k, v in pairs(tbl) do
-		newTbl[k] = copy(v)
-	end
-	return newTbl
-end
-
-local defaultWidgets = {
-	[1] = {
-		name = "Name",
-		enabled = true,
-		value = [[
-if not UnitExists(unit) then return end
-return '--' .. select(1, UnitName(unit)) .. '--'
-]],
-		color = [[
-if UnitIsPlayer(unit) then
-    return ClassColor(unit)
-else
-    return UnitSelectionColor(unit)
-end
-]],
-		cols = 40,
-		align = WidgetText.ALIGN_PINGPONG,
-		update = 1000,
-		speed = 100,
-		direction = SCROLL_LEFT,
-		dontRtrim = true,
-		points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 12}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1,
-	},
-	[2] = {
-		name = "Health",
-		enabled = true,
-		value = [[
-if not UnitExists(unit) then return end
-local health, max = UnitHealth(unit), UnitHealthMax(unit)
-if max == 0 then max = 0.0001 end
-return format('Health: %.1f%%', health / max * 100)
-]],
-		color = [[
-if not UnitExists(unit) then return end
-local health, max = UnitHealth(unit), UnitHealthMax(unit)
-return Gradient(health / max)
-]],
-		cols = 20,
-		update = 1000,
-		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, 1}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1
-	},
-	[3] = {
-		name = "Power",
-		enabled = true,
-		value = [[
-if not UnitExists(unit) then return end
-local mana, max = UnitMana(unit), UnitManaMax(unit)
-if max == 0 then max = 0.0001 end
-return format(PowerName(unit)..': %.1f%%', mana / max * 100)
-]],
-		color = [[
-if not UnitExists(unit) then return end
-local mana, max = UnitMana(unit), UnitManaMax(unit)
-return Gradient(mana / max)
-]],
-		cols = 20,
-		update = 1000,
-		align = WidgetText.ALIGN_RIGHT,
-		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", 0, 1}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1
-	},
-	[4] = {
-		name = "Memory Percent",
-		enabled = false,
-		value = [[
-local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
-if mem then
-    local num = floor(memperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return format("Mem: %.2f%%", memperc)
-end
-]],
-		color = [[
-local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
-if mem then
-    local num = floor(memperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return r, g, b
-end
-
-]],
-		cols = 20,
-		update = 1000,
-		dontRtrim = true,
-		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -62}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1,
-		intersect = true,
-		intersectPad = 70
-	},
-	[5] = {
-		name = "Memory Total",
-		enabled = false,
-		value = [[
-local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
-if mem then
-    if totalMem == 0 then totalMem = 100; mem = 0 end
-    memperc = mem / totalMem * 100
-	return format("%s (%.2f%%)", memshort(mem), memperc)
-end
-]],
-		color = [[
-return Color2RGBA(0xffff00)
-]],
-		cols = 20,
-		update = 1000,
-		dontRtrim = true,
-		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -124}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1,
-		intersect = true,
-		intersectPad = 100
-	},
-	[6] = {
-		name = "CPU Percent",
-		enabled = false,
-		value = [[
-if not scriptProfile then return "Profiling Off" end
-local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
-if cpu then
-    return format("CPU: %.2f%%", cpuperc)
-end
-]],
-		color = [[
-if not scriptProfile then return 0, 1, 0 end
-local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
-if cpu then
-    local num = floor(cpuperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return r, g, b
-end
-]],
-		cols = 14,
-		align = WidgetText.ALIGN_RIGHT,
-		update = 1000,
-		dontRtrim = true,
-		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", 0, -62}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1,
-		intersect = true,
-		intersectPad = 70
-	},
-	[7] = {
-		name = "CPU Total",
-		enabled = false,
-		value = [[
-if not scriptProfile then return "Profiling Off" end
-local cpu, percent, cpudiff, totalCPU, totaldiff = GetCPUUsage("StarTip")
-if cpu then
-    if totalCPU == 0 then totalCPU = 100; cpu = 0 end
-    cpuperc = cpu / totalCPU * 100;
-    return format("%s (%.2f%%)", timeshort(cpu), cpuperc)
-end
-]],
-		color = [[
-return 1, 1, 0
-]],
-		cols = 20,
-		align = WidgetText.ALIGN_RIGHT,
-		update = 1000,
-		dontRtrim = true,
-		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", 0, -124}},
-		parent = "GameTooltip",
-		strata = 1,
-		level = 1,
-		intersect = true,
-		intersectPad = 100
-	},
-}
-
-local defaults = {
-	profile = {
-		classColors = true,
-		texts = {}
-	}
-}
-
-local options = {}
-local optionsDefaults = {
-	add = {
-		name = "Add Text",
-		desc = "Add a text widget",
-		type = "input",
-		set = function(info, v)
-			local widget = {
-				name = v,
-				type = "text",
-				min = "return 0",
-				max = "return 100",
-				height = 6,
-				points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT"}},
-				texture = LSM:GetDefault("statustext"),
-				expression = "",
-				strata = 1,
-				level = 1,
-				custom = true
-			}
-			tinsert(mod.db.profile.texts, widget)
-			StarTip:RebuildOpts()
-			mod:ClearTexts()
-		end,
-		order = 5
-	},
-	defaults = {
-		name = "Restore Defaults",
-		desc = "Restore Defaults",
-		type = "execute",
-		func = function()
-			mod.db.profile.texts = copy(defaultWidgets);
-			StarTip:RebuildOpts()
-		end,
-		order = 6
-	},
-}
-
-local intersectTimer
-local intersectUpdate = function()
-	WidgetText.IntersectUpdate(mod.texts)
-end
-
-function updateText(widget)
-	widget.frame.fontstring:SetText(widget.buffer)
-	widget.frame:SetHeight(widget.frame.fontstring:GetStringHeight())
-	widget.frame:SetWidth(widget.frame.fontstring:GetStringWidth())
-
-	local r, g, b, a = 0, 0, 1, 1
-
-	if widget.color then
-		r, g, b, a = widget.color.res1, widget.color.res2, widget.color.res3, widget.color.res4
-	end
-
-	if type(r) == "number" then
-		widget.frame.fontstring:SetTextColor(r, g, b, a)
-	end
-
-	if type(widget.background) == "table" then
-		r, g, b, a = unpack(widget.background)
-	end
-
-	widget.frame:SetBackdropColor(r, g, b, a)
-
-	if not UnitExists(StarTip.unit or "mouseover") and not widget.config.alwaysShown then
-		widget.frame:Hide()
-	end
-end
-
-local textureDict = {}
-
-function mod:CreateTexts()
-	createTexts()
-end
-
-local new, del
-do
-	local pool = {}
-	local i = 0
-	function new(background)
-		local text = next(pool)
-
-		if text then
-			pool[text] = nil
-		else
-			local frame = CreateFrame("Frame")
-			frame:SetParent(UIParent)
-			if background then
-				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
-					tile = true,
-					tileSize = 4,
-					edgeSize=4,
-					insets = { left = 0, right = 0, top = 0, bottom = 0}})
-			else
-				frame:SetBackdrop({
-					insets = {left = 0, right = 0, top = 0, bottom = 0},
-				})
-			end
-			frame:ClearAllPoints()
-			frame:SetAlpha(1)
-			local fs = frame:CreateFontString()
-			fs:SetAllPoints(frame)
-			fs:SetFontObject(GameFontNormal)
-			fs:Show()
-			frame.fontstring = fs
-			text = frame
-		end
-
-		return text
-	end
-	function del(text)
-		pool[text] = true
-	end
-end
-
-local defaultPoint = {"BOTTOMLEFT", "GameTooltip", "TOPLEFT"}
-
-local strataNameList = {
-	"TOOLTIP", "FULLSCREEN_DIALOG", "FULLSCREEN", "DIALOG", "HIGH", "MEDIUM", "LOW", "BACKGROUND"
-}
-
-local strataLocaleList = {
-	"Tooltip", "Fullscreen Dialog", "Fullscreen", "Dialog", "High", "Medium", "Low", "Background"
-}
-
-local function clearText(obj)
-	local widget = mod.texts[obj]
-	if not widget then return end
-	widget:Del()
-	widget.frame:Hide()
-	widget.frame.fontstring:Hide()
-	del(widget.frame)
-end
-
-function mod:ClearTexts()
-	for k, v in pairs(mod.texts) do
-		clearText(v)
-	end
-	wipe(mod.texts)
-end
-
-local fontstrings = {}
-function createTexts()
-	if type(mod.texts) ~= "table" then mod.texts = {} end
-	--[[for k, v in pairs(mod.texts) do
-		v:Del()
-		v.text:Hide()
-		del(v.text)
-	end]]
-
-	local appearance = StarTip:GetModule("Appearance")
-	for i, v in ipairs(self.db.profile.texts) do
-		if v.enabled and not v.deleted then
-			if v.alwaysShown then
-				StarTip:Print("always shown bogeyman")
-			end
-			local widget = mod.texts[v]
-			if not widget then
-				local text = new(v.background)
-				widget = WidgetText:New(mod.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateText)
-				text:ClearAllPoints()
-				text:SetParent("UIParent")
-				for j, point in ipairs(v.points) do
-					local arg1, arg2, arg3, arg4, arg5 = unpack(point)
-					arg4 = (arg4 or 0)
-					arg5 = (arg5 or 0)
-					text:SetPoint(arg1, arg2, arg3, arg4, arg5)
-				end
-				text:SetFrameStrata(strataNameList[v.strata or 1])
-				text:SetFrameLevel(v.level or 1)
-				text:Show()
-				widget.frame = text
-				widget.frame = text
-				mod.texts[v] = widget
-			end
-			widget.config.unit = StarTip.unit
-		end
-	end
-end
-
-function mod:ReInit()
-	if not self.db.profile.texts then
-		self.db.profile.texts = {}
-	end
-
-	--wipe(self.db.profile.texts)
-
-	for i, v in ipairs(defaultWidgets) do
-		for j, vv in ipairs(self.db.profile.texts) do
-			if v.name == vv.name and not vv.custom then
-				for k, val in pairs(v) do
-					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
-						vv[k] = v[k]
-					end
-				end
-				v.tagged = true
-				v.deleted = vv.deleted
-			end
-		end
-	end
-
-	for i, v in ipairs(defaultWidgets) do
-		if not v.tagged and not v.deleted then
-			tinsert(self.db.profile.texts, copy(v))
-		end
-	end
-end
-
-function mod:OnInitialize()
-	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-
-	self:ReInit()
-
-	self.core = LibCore:New(mod, environment, "StarTip.Texts", {["StarTip.Texts"] = {}}, nil, StarTip.db.profile.errorLevel)
-
-	StarTip:SetOptionsDisabled(options, true)
-
-	self.texts = {}
-
-end
-
-function mod:OnEnable()
-	self:ClearTexts()
-	intersectTimer = intersectTimer or LibTimer:New("Texts.intersectTimer", 100, true, intersectUpdate)
-	GameTooltip:SetClampRectInsets(0, 0, 10, 10)
-	StarTip:SetOptionsDisabled(options, false)
-	createTexts()
-	for k, text in pairs(self.texts) do
-		if text.config.alwaysShown then
-			StarTip:Print("always shown -------------------------")
-			text:Start()
-			text.frame:Show()
-		end
-	end
-end
-
-function mod:OnDisable()
-	self:ClearTexts()
-	if type(intersectTimer) == "table" then
-		intersectTimer:Stop()
-	end
-	GameTooltip:SetClampRectInsets(0, 0, 0, 0)
-	StarTip:SetOptionsDisabled(options, true)
-end
-
---[[function mod:RebuildOpts()
-	for k, v in ipairs(self.db.profile.texts) do
-		options.texts.args[k] = WidgetText:GetOptions(v)
-	end
-end]]
-
-function mod:GetOptions()
-	return options
-end
-
-function mod:SetUnit()
-	GameTooltipStatusBar:Hide()
-	createTexts()
-	for k, text in pairs(self.texts) do
-		text:Start()
-		text.frame:Show()
-	end
-	intersectTimer:Start()
-end
-
-function mod:SetItem()
-	for i, text in pairs(self.texts) do
-		if not text.config.alwaysShown then
-			text:Stop()
-			text.frame:Hide()
-		end
-	end
-	intersectTimer:Start()
-end
-
-function mod:SetSpell()
-	for i, text in pairs(self.texts) do
-		if not text.config.alwaysShown then
-			text:Stop()
-			text.frame:Hide()
-		end
-	end
-	intersectTimer:Start()
-end
-
-function mod:OnHide()
-	if timer then
-		self:CancelTimer(timer)
-		timer = nil
-	end
-	for i, text in pairs(self.texts) do
-		if not text.config.alwaysShown then
-			text:Stop()
-			text.frame:Hide()
-		end
-	end
-	intersectTimer:Stop()
-end
-
-function mod:RebuildOpts()
-	local defaults = WidgetText.defaults
-	self:ClearTexts()
-	wipe(options)
-	for k, v in pairs(optionsDefaults) do
-		options[k] = v
-	end
-
-	for i, db in ipairs(self.db.profile.texts) do
-		options[db.name:gsub(" ", "_")] = {
-			name = db.name,
-			type="group",
-			order = i,
-			args=WidgetText:GetOptions(db, StarTip.RebuildOpts, StarTip)
-		}
-		options[db.name:gsub(" ", "_")].args.delete = {
-			name = "Delete",
-			type = "execute",
-			func = function()
-				local delete = true
-				for i, v in ipairs(defaultWidgets) do
-					if db.name == v.name then
-						db.deleted = true
-						delete = false
-					end
-				end
-				if delete then
-					tremove(self.db.profile.texts, i)
-				end
-				self:ClearTexts()
-				StarTip:RebuildOpts()
-			end,
-			order = 100
-		}
-		options[db.name:gsub(" ", "_")].args.enabled = {
-			name = "Enabled",
-			desc = "Whether the histogram's enabled or not",
-			type = "toggle",
-			get = function() return db.enabled end,
-			set = function(info, v)
-				db.enabled = v;
-				db["enabledDirty"] = true
-				self:ClearTexts()
-			end,
-			order = 1
-		}
-	end
-end
-
---[[				enabled = {
-					name = "Enabled",
-					desc = "Whether this text is enabled or not",
-					type = "toggle",
-					get = function() return db.enabled end,
-					set = function(info, v)
-						db.enabled = v
-						db["enabledDirty"] = true
-						createTexts()
-					end,
-					order = 1
-				},
-				height = {
-					name = "Text height",
-					desc = "Enter the text's height",
-					type = "input",
-					pattern = "%d",
-					get = function() return tostring(db.height or defaults.height) end,
-					set = function(info, v)
-						db.height = tonumber(v);
-						db["heightDirty"] = true
-						createTexts();
-					end,
-					order = 2
-				},
-				update = {
-					name = "Text update rate",
-					desc = "Enter the text's refresh rate",
-					type = "input",
-					pattern = "%d",
-					get = function() return tostring(db.update or defaults.update) end,
-					set = function(info, v)
-						db.update = tonumber(v);
-						db["updateDirty"] = true
-						createTexts()
-					end,
-					order = 3
-				},
-				strata = {
-					name = "Strata",
-					type = "select",
-					values = strataLocaleList,
-					get = function() return db.strata end,
-					set = function(info, v) db.strata = v end,
-					order = 6
-				},
-				point = {
-					name = "Anchor Points",
-					desc = "This text's anchor point. These arguments are passed to text:SetPoint()",
-					type = "group",
-					args = {
-						point = {
-							name = "Text anchor",
-							type = "select",
-							values = anchors,
-							get = function() return anchorsDict[db.point[1] or 1] end,
-							set = function(info, v) db.point[1] = anchors[v] end,
-							order = 1
-						},
-						relativeFrame = {
-							name = "Relative Frame",
-							type = "input",
-							get = function() return db.point[2] end,
-							set = function(info, v) db.point[2] = v end,
-							order = 2
-						},
-						relativePoint = {
-							name = "Relative Point",
-							type = "select",
-							values = anchors,
-							get = function() return anchorsDict[db.point[3] or 1] end,
-							set = function(info, v) db.point[3] = anchors[v] end,
-							order = 3
-						},
-						xOfs = {
-							name = "X Offset",
-							type = "input",
-							pattern = "%d",
-							get = function() return tostring(db.point[4] or 0) end,
-							set = function(info, v) db.point[4] = tonumber(anchors[v]) end,
-							order = 4
-						},
-						yOfs = {
-							name = "Y Offset",
-							type = "input",
-							pattern = "%d",
-							get = function() return tostring(db.point[5] or 0) end,
-							set = function(info, v) db.point[5] = tonumber(anchors[v]) end,
-							order = 4
-						}
-					},
-					order = 7
-				},
-				top = {
-					name = "First is Top",
-					desc = "Toggle whether to place the first text on top",
-					type = "toggle",
-					get = function() return db.top end,
-					set = function(info, v)
-						db.top = v;
-						db["topDirty"] = true
-						createTexts()
-					end,
-					order = 8
-				},
-				value = {
-					name = "Text expression",
-					desc = "Enter the text's expression",
-					type = "input",
-					multiline = true,
-					width = "full",
-					get = function() return db.value end,
-					set = function(info, v)
-						db.value = v;
-						db["valueDirty"] = true
-						createTexts()
-					end,
-					order = 9
-				},
-			}
-		}
-	end
-end
-]]
\ No newline at end of file
diff --git a/Modules/Texts/StarTip_Texts.toc b/Modules/Texts/StarTip_Texts.toc
new file mode 100644
index 0000000..7f4e582
--- /dev/null
+++ b/Modules/Texts/StarTip_Texts.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [Texts]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+Texts.lua
\ No newline at end of file
diff --git a/Modules/Texts/Texts.lua b/Modules/Texts/Texts.lua
new file mode 100644
index 0000000..6f5e370
--- /dev/null
+++ b/Modules/Texts/Texts.lua
@@ -0,0 +1,721 @@
+local mod = StarTip:NewModule("Text", "AceTimer-3.0")
+mod.name = "Texts"
+mod.toggled = true
+--mod.childGroup = true
+mod.defaultOff = true
+local _G = _G
+local StarTip = _G.StarTip
+local GameTooltip = _G.GameTooltip
+local GameTooltipStatusBar = _G.GameTooltipStatusBar
+local UnitIsPlayer = _G.UnitIsPlayer
+local RAID_CLASS_COLORS = _G.RAID_CLASS_COLORS
+local UnitSelectionColor = _G.UnitSelectionColor
+local UnitClass = _G.UnitClass
+local self = mod
+local timer
+local LSM = LibStub("LibSharedMedia-3.0")
+local WidgetText = LibStub("StarLibWidgetText-1.0")
+local LibCore = LibStub("StarLibCore-1.0")
+local LibQTip = LibStub("LibQTip-1.0")
+local PluginUtils = LibStub("StarLibPluginUtils-1.0")
+local LibTimer = LibStub("StarLibTimer-1.0")
+local Widget = LibStub("StarLibWidget-1.0")
+
+local environment = {}
+
+local anchors = {
+	"TOP",
+	"TOPRIGHT",
+	"TOPLEFT",
+	"BOTTOM",
+	"BOTTOMRIGHT",
+	"BOTTOMLEFT",
+	"RIGHT",
+	"LEFT",
+	"CENTER"
+}
+
+local anchorsDict = {}
+
+for i, v in ipairs(anchors) do
+	anchorsDict[v] = i
+end
+
+local createTexts
+local widgets = {}
+
+local function copy(tbl)
+	if type(tbl) ~= "table" then return tbl end
+	local newTbl = {}
+	for k, v in pairs(tbl) do
+		newTbl[k] = copy(v)
+	end
+	return newTbl
+end
+
+local defaultWidgets = {
+	[1] = {
+		name = "Name",
+		enabled = true,
+		value = [[
+if not UnitExists(unit) then return end
+return '--' .. select(1, UnitName(unit)) .. '--'
+]],
+		color = [[
+if UnitIsPlayer(unit) then
+    return ClassColor(unit)
+else
+    return UnitSelectionColor(unit)
+end
+]],
+		cols = 40,
+		align = WidgetText.ALIGN_PINGPONG,
+		update = 1000,
+		speed = 100,
+		direction = SCROLL_LEFT,
+		dontRtrim = true,
+		points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT", 0, 12}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1,
+	},
+	[2] = {
+		name = "Health",
+		enabled = true,
+		value = [[
+if not UnitExists(unit) then return end
+local health, max = UnitHealth(unit), UnitHealthMax(unit)
+if max == 0 then max = 0.0001 end
+return format('Health: %.1f%%', health / max * 100)
+]],
+		color = [[
+if not UnitExists(unit) then return end
+local health, max = UnitHealth(unit), UnitHealthMax(unit)
+return Gradient(health / max)
+]],
+		cols = 20,
+		update = 1000,
+		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, 1}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1
+	},
+	[3] = {
+		name = "Power",
+		enabled = true,
+		value = [[
+if not UnitExists(unit) then return end
+local mana, max = UnitMana(unit), UnitManaMax(unit)
+if max == 0 then max = 0.0001 end
+return format(PowerName(unit)..': %.1f%%', mana / max * 100)
+]],
+		color = [[
+if not UnitExists(unit) then return end
+local mana, max = UnitMana(unit), UnitManaMax(unit)
+return Gradient(mana / max)
+]],
+		cols = 20,
+		update = 1000,
+		align = WidgetText.ALIGN_RIGHT,
+		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", 0, 1}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1
+	},
+	[4] = {
+		name = "Memory Percent",
+		enabled = false,
+		value = [[
+local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
+if mem then
+    local num = floor(memperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return format("Mem: %.2f%%", memperc)
+end
+]],
+		color = [[
+local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
+if mem then
+    local num = floor(memperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return r, g, b
+end
+
+]],
+		cols = 20,
+		update = 1000,
+		dontRtrim = true,
+		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -62}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1,
+		intersect = true,
+		intersectPad = 70
+	},
+	[5] = {
+		name = "Memory Total",
+		enabled = false,
+		value = [[
+local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
+if mem then
+    if totalMem == 0 then totalMem = 100; mem = 0 end
+    memperc = mem / totalMem * 100
+	return format("%s (%.2f%%)", memshort(mem), memperc)
+end
+]],
+		color = [[
+return Color2RGBA(0xffff00)
+]],
+		cols = 20,
+		update = 1000,
+		dontRtrim = true,
+		points = {{"TOPLEFT", "GameTooltip", "BOTTOMLEFT", 0, -124}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1,
+		intersect = true,
+		intersectPad = 100
+	},
+	[6] = {
+		name = "CPU Percent",
+		enabled = false,
+		value = [[
+if not scriptProfile then return "Profiling Off" end
+local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
+if cpu then
+    return format("CPU: %.2f%%", cpuperc)
+end
+]],
+		color = [[
+if not scriptProfile then return 0, 1, 0 end
+local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
+if cpu then
+    local num = floor(cpuperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return r, g, b
+end
+]],
+		cols = 14,
+		align = WidgetText.ALIGN_RIGHT,
+		update = 1000,
+		dontRtrim = true,
+		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", 0, -62}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1,
+		intersect = true,
+		intersectPad = 70
+	},
+	[7] = {
+		name = "CPU Total",
+		enabled = false,
+		value = [[
+if not scriptProfile then return "Profiling Off" end
+local cpu, percent, cpudiff, totalCPU, totaldiff = GetCPUUsage("StarTip")
+if cpu then
+    if totalCPU == 0 then totalCPU = 100; cpu = 0 end
+    cpuperc = cpu / totalCPU * 100;
+    return format("%s (%.2f%%)", timeshort(cpu), cpuperc)
+end
+]],
+		color = [[
+return 1, 1, 0
+]],
+		cols = 20,
+		align = WidgetText.ALIGN_RIGHT,
+		update = 1000,
+		dontRtrim = true,
+		points = {{"TOPRIGHT", "GameTooltip", "BOTTOMRIGHT", 0, -124}},
+		parent = "GameTooltip",
+		strata = 1,
+		level = 1,
+		intersect = true,
+		intersectPad = 100
+	},
+}
+
+local defaults = {
+	profile = {
+		classColors = true,
+		texts = {}
+	}
+}
+
+local options = {}
+local optionsDefaults = {
+	add = {
+		name = "Add Text",
+		desc = "Add a text widget",
+		type = "input",
+		set = function(info, v)
+			local widget = {
+				name = v,
+				type = "text",
+				min = "return 0",
+				max = "return 100",
+				height = 6,
+				points = {{"BOTTOMLEFT", "GameTooltip", "TOPLEFT"}},
+				texture = LSM:GetDefault("statustext"),
+				expression = "",
+				strata = 1,
+				level = 1,
+				custom = true
+			}
+			tinsert(mod.db.profile.texts, widget)
+			StarTip:RebuildOpts()
+			mod:ClearTexts()
+		end,
+		order = 5
+	},
+	defaults = {
+		name = "Restore Defaults",
+		desc = "Restore Defaults",
+		type = "execute",
+		func = function()
+			mod.db.profile.texts = copy(defaultWidgets);
+			StarTip:RebuildOpts()
+		end,
+		order = 6
+	},
+}
+
+local intersectTimer
+local intersectUpdate = function()
+	WidgetText.IntersectUpdate(mod.texts)
+end
+
+function updateText(widget)
+	widget.frame.fontstring:SetText(widget.buffer)
+	widget.frame:SetHeight(widget.frame.fontstring:GetStringHeight())
+	widget.frame:SetWidth(widget.frame.fontstring:GetStringWidth())
+
+	local r, g, b, a = 0, 0, 1, 1
+
+	if widget.color then
+		r, g, b, a = widget.color.res1, widget.color.res2, widget.color.res3, widget.color.res4
+	end
+
+	if type(r) == "number" then
+		widget.frame.fontstring:SetTextColor(r, g, b, a)
+	end
+
+	if type(widget.background) == "table" then
+		r, g, b, a = unpack(widget.background)
+	end
+
+	widget.frame:SetBackdropColor(r, g, b, a)
+
+	if not UnitExists(StarTip.unit or "mouseover") and not widget.config.alwaysShown then
+		widget.frame:Hide()
+	end
+end
+
+local textureDict = {}
+
+function mod:CreateTexts()
+	createTexts()
+end
+
+local new, del
+do
+	local pool = {}
+	local i = 0
+	function new(background)
+		local text = next(pool)
+
+		if text then
+			pool[text] = nil
+		else
+			local frame = CreateFrame("Frame")
+			frame:SetParent(UIParent)
+			if background then
+				frame:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
+					tile = true,
+					tileSize = 4,
+					edgeSize=4,
+					insets = { left = 0, right = 0, top = 0, bottom = 0}})
+			else
+				frame:SetBackdrop({
+					insets = {left = 0, right = 0, top = 0, bottom = 0},
+				})
+			end
+			frame:ClearAllPoints()
+			frame:SetAlpha(1)
+			local fs = frame:CreateFontString()
+			fs:SetAllPoints(frame)
+			fs:SetFontObject(GameFontNormal)
+			fs:Show()
+			frame.fontstring = fs
+			text = frame
+		end
+
+		return text
+	end
+	function del(text)
+		pool[text] = true
+	end
+end
+
+local defaultPoint = {"BOTTOMLEFT", "GameTooltip", "TOPLEFT"}
+
+local strataNameList = {
+	"TOOLTIP", "FULLSCREEN_DIALOG", "FULLSCREEN", "DIALOG", "HIGH", "MEDIUM", "LOW", "BACKGROUND"
+}
+
+local strataLocaleList = {
+	"Tooltip", "Fullscreen Dialog", "Fullscreen", "Dialog", "High", "Medium", "Low", "Background"
+}
+
+local function clearText(obj)
+	local widget = mod.texts[obj]
+	if not widget then return end
+	widget:Del()
+	widget.frame:Hide()
+	widget.frame.fontstring:Hide()
+	del(widget.frame)
+end
+
+function mod:ClearTexts()
+	for k, v in pairs(mod.texts) do
+		clearText(v)
+	end
+	wipe(mod.texts)
+end
+
+local fontstrings = {}
+function createTexts()
+	if type(mod.texts) ~= "table" then mod.texts = {} end
+	--[[for k, v in pairs(mod.texts) do
+		v:Del()
+		v.text:Hide()
+		del(v.text)
+	end]]
+
+	local appearance = StarTip:GetModule("Appearance")
+	for i, v in ipairs(self.db.profile.texts) do
+		if v.enabled and not v.deleted then
+			if v.alwaysShown then
+				StarTip:Print("always shown bogeyman")
+			end
+			local widget = mod.texts[v]
+			if not widget then
+				local text = new(v.background)
+				widget = WidgetText:New(mod.core, v.name, v, v.row or 0, v.col or 0, v.layer or 0, StarTip.db.profile.errorLevel, updateText)
+				text:ClearAllPoints()
+				text:SetParent("UIParent")
+				for j, point in ipairs(v.points) do
+					local arg1, arg2, arg3, arg4, arg5 = unpack(point)
+					arg4 = (arg4 or 0)
+					arg5 = (arg5 or 0)
+					text:SetPoint(arg1, arg2, arg3, arg4, arg5)
+				end
+				text:SetFrameStrata(strataNameList[v.strata or 1])
+				text:SetFrameLevel(v.level or 1)
+				text:Show()
+				widget.frame = text
+				widget.frame = text
+				mod.texts[v] = widget
+			end
+			widget.config.unit = StarTip.unit
+		end
+	end
+end
+
+function mod:ReInit()
+	if not self.db.profile.texts then
+		self.db.profile.texts = {}
+	end
+
+	--wipe(self.db.profile.texts)
+
+	for i, v in ipairs(defaultWidgets) do
+		for j, vv in ipairs(self.db.profile.texts) do
+			if v.name == vv.name and not vv.custom then
+				for k, val in pairs(v) do
+					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
+						vv[k] = v[k]
+					end
+				end
+				v.tagged = true
+				v.deleted = vv.deleted
+			end
+		end
+	end
+
+	for i, v in ipairs(defaultWidgets) do
+		if not v.tagged and not v.deleted then
+			tinsert(self.db.profile.texts, copy(v))
+		end
+	end
+end
+
+function mod:OnInitialize()
+	self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+
+	self:ReInit()
+
+	self.core = LibCore:New(mod, environment, "StarTip.Texts", {["StarTip.Texts"] = {}}, nil, StarTip.db.profile.errorLevel)
+
+	StarTip:SetOptionsDisabled(options, true)
+
+	self.texts = {}
+
+end
+
+function mod:OnEnable()
+	self:ClearTexts()
+	intersectTimer = intersectTimer or LibTimer:New("Texts.intersectTimer", 100, true, intersectUpdate)
+	GameTooltip:SetClampRectInsets(0, 0, 10, 10)
+	StarTip:SetOptionsDisabled(options, false)
+	createTexts()
+	for k, text in pairs(self.texts) do
+		if text.config.alwaysShown then
+			StarTip:Print("always shown -------------------------")
+			text:Start()
+			text.frame:Show()
+		end
+	end
+end
+
+function mod:OnDisable()
+	self:ClearTexts()
+	if type(intersectTimer) == "table" then
+		intersectTimer:Stop()
+	end
+	GameTooltip:SetClampRectInsets(0, 0, 0, 0)
+	StarTip:SetOptionsDisabled(options, true)
+end
+
+--[[function mod:RebuildOpts()
+	for k, v in ipairs(self.db.profile.texts) do
+		options.texts.args[k] = WidgetText:GetOptions(v)
+	end
+end]]
+
+function mod:GetOptions()
+	return options
+end
+
+function mod:SetUnit()
+	GameTooltipStatusBar:Hide()
+	createTexts()
+	for k, text in pairs(self.texts) do
+		text:Start()
+		text.frame:Show()
+	end
+	intersectTimer:Start()
+end
+
+function mod:SetItem()
+	for i, text in pairs(self.texts) do
+		if not text.config.alwaysShown then
+			text:Stop()
+			text.frame:Hide()
+		end
+	end
+	intersectTimer:Start()
+end
+
+function mod:SetSpell()
+	for i, text in pairs(self.texts) do
+		if not text.config.alwaysShown then
+			text:Stop()
+			text.frame:Hide()
+		end
+	end
+	intersectTimer:Start()
+end
+
+function mod:OnHide()
+	if timer then
+		self:CancelTimer(timer)
+		timer = nil
+	end
+	for i, text in pairs(self.texts) do
+		if not text.config.alwaysShown then
+			text:Stop()
+			text.frame:Hide()
+		end
+	end
+	intersectTimer:Stop()
+end
+
+function mod:RebuildOpts()
+	local defaults = WidgetText.defaults
+	self:ClearTexts()
+	wipe(options)
+	for k, v in pairs(optionsDefaults) do
+		options[k] = v
+	end
+
+	for i, db in ipairs(self.db.profile.texts) do
+		options[db.name:gsub(" ", "_")] = {
+			name = db.name,
+			type="group",
+			order = i,
+			args=WidgetText:GetOptions(db, StarTip.RebuildOpts, StarTip)
+		}
+		options[db.name:gsub(" ", "_")].args.delete = {
+			name = "Delete",
+			type = "execute",
+			func = function()
+				local delete = true
+				for i, v in ipairs(defaultWidgets) do
+					if db.name == v.name then
+						db.deleted = true
+						delete = false
+					end
+				end
+				if delete then
+					tremove(self.db.profile.texts, i)
+				end
+				self:ClearTexts()
+				StarTip:RebuildOpts()
+			end,
+			order = 100
+		}
+		options[db.name:gsub(" ", "_")].args.enabled = {
+			name = "Enabled",
+			desc = "Whether the histogram's enabled or not",
+			type = "toggle",
+			get = function() return db.enabled end,
+			set = function(info, v)
+				db.enabled = v;
+				db["enabledDirty"] = true
+				self:ClearTexts()
+			end,
+			order = 1
+		}
+	end
+end
+
+--[[				enabled = {
+					name = "Enabled",
+					desc = "Whether this text is enabled or not",
+					type = "toggle",
+					get = function() return db.enabled end,
+					set = function(info, v)
+						db.enabled = v
+						db["enabledDirty"] = true
+						createTexts()
+					end,
+					order = 1
+				},
+				height = {
+					name = "Text height",
+					desc = "Enter the text's height",
+					type = "input",
+					pattern = "%d",
+					get = function() return tostring(db.height or defaults.height) end,
+					set = function(info, v)
+						db.height = tonumber(v);
+						db["heightDirty"] = true
+						createTexts();
+					end,
+					order = 2
+				},
+				update = {
+					name = "Text update rate",
+					desc = "Enter the text's refresh rate",
+					type = "input",
+					pattern = "%d",
+					get = function() return tostring(db.update or defaults.update) end,
+					set = function(info, v)
+						db.update = tonumber(v);
+						db["updateDirty"] = true
+						createTexts()
+					end,
+					order = 3
+				},
+				strata = {
+					name = "Strata",
+					type = "select",
+					values = strataLocaleList,
+					get = function() return db.strata end,
+					set = function(info, v) db.strata = v end,
+					order = 6
+				},
+				point = {
+					name = "Anchor Points",
+					desc = "This text's anchor point. These arguments are passed to text:SetPoint()",
+					type = "group",
+					args = {
+						point = {
+							name = "Text anchor",
+							type = "select",
+							values = anchors,
+							get = function() return anchorsDict[db.point[1] or 1] end,
+							set = function(info, v) db.point[1] = anchors[v] end,
+							order = 1
+						},
+						relativeFrame = {
+							name = "Relative Frame",
+							type = "input",
+							get = function() return db.point[2] end,
+							set = function(info, v) db.point[2] = v end,
+							order = 2
+						},
+						relativePoint = {
+							name = "Relative Point",
+							type = "select",
+							values = anchors,
+							get = function() return anchorsDict[db.point[3] or 1] end,
+							set = function(info, v) db.point[3] = anchors[v] end,
+							order = 3
+						},
+						xOfs = {
+							name = "X Offset",
+							type = "input",
+							pattern = "%d",
+							get = function() return tostring(db.point[4] or 0) end,
+							set = function(info, v) db.point[4] = tonumber(anchors[v]) end,
+							order = 4
+						},
+						yOfs = {
+							name = "Y Offset",
+							type = "input",
+							pattern = "%d",
+							get = function() return tostring(db.point[5] or 0) end,
+							set = function(info, v) db.point[5] = tonumber(anchors[v]) end,
+							order = 4
+						}
+					},
+					order = 7
+				},
+				top = {
+					name = "First is Top",
+					desc = "Toggle whether to place the first text on top",
+					type = "toggle",
+					get = function() return db.top end,
+					set = function(info, v)
+						db.top = v;
+						db["topDirty"] = true
+						createTexts()
+					end,
+					order = 8
+				},
+				value = {
+					name = "Text expression",
+					desc = "Enter the text's expression",
+					type = "input",
+					multiline = true,
+					width = "full",
+					get = function() return db.value end,
+					set = function(info, v)
+						db.value = v;
+						db["valueDirty"] = true
+						createTexts()
+					end,
+					order = 9
+				},
+			}
+		}
+	end
+end
+]]
\ No newline at end of file
diff --git a/Modules/UnitTooltip.lua b/Modules/UnitTooltip.lua
deleted file mode 100644
index 3fd5727..0000000
--- a/Modules/UnitTooltip.lua
+++ /dev/null
@@ -1,1098 +0,0 @@
-local mod = StarTip:NewModule("UnitTooltip", "AceEvent-3.0")
-mod.name = "Unit Tooltip"
-mod.toggled = true
-local LibProperty = LibStub("StarLibProperty-1.0", true)
-assert(LibProperty, "Text module requires StarLibProperty-1.0")
-local WidgetText = LibStub("StarLibWidgetText-1.0", true)
-assert(WidgetText, "Text module requires StarLibWidgetText-1.0")
-local LCDText = LibStub("StarLibLCDText-1.0", true)
-assert(LCDText, mod.name .. " requires StarLibLCDText-1.0")
-local LibCore = LibStub("StarLibCore-1.0", true)
-assert(LibCore, mod.name .. " requires StarLibCore-1.0")
-local LibTimer = LibStub("StarLibTimer-1.0", true)
-assert(LibTimer, mod.name .. " requires StarLibTimer-1.0")
-local LibEvaluator = LibStub("StarLibEvaluator-1.0", true)
-assert(LibEvaluator, mod.name .. " requires StarLibEvaluator-1.0")
-local UnitTooltipStats = LibStub("StarLibPluginUnitTooltipStats-1.0", true)
-assert(UnitTooltipStats, mod.name .. " requires StarLibPluginUnitTooltipStats-1.0")
-
-local _G = _G
-local StarTip = _G.StarTip
-local self = mod
-local GameTooltip = _G.GameTooltip
-local tinsert = _G.tinsert
-local unpack = _G.unpack
-local select = _G.select
-local format = _G.format
-local floor = _G.floor
-local tostring = _G.tostring
-local LSM = _G.LibStub("LibSharedMedia-3.0")
-local factionList = {}
-local linesToAdd = {}
-local linesToAddR = {}
-local linesToAddG = {}
-local linesToAddB = {}
-local linesToAddRight = {}
-local linesToAddRightR = {}
-local linesToAddRightG = {}
-local linesToAddRightB = {}
-local lines = {}
-
-local unit
-local environment = {}
-
-local appearance = StarTip:GetModule("Appearance")
-
-local function errorhandler(err)
-    return geterrorhandler()(err)
-end
-
-local ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_MARQUEE, ALIGN_AUTOMATIC, ALIGN_PINGPONG = 1, 2, 3, 4, 5, 6
-
-local SCROLL_RIGHT, SCROLL_LEFT = 1, 2
-
-mod.NUM_LINES = 0
-
-local function copy(src, dst)
-	if type(src) ~= "table" then return nil end
-	if type(dst) ~= "table" then dst = {} end
-	for k, v in pairs(src) do
-		if type(v) == "table" then
-			v = copy(v)
-		end
-		dst[k] = v
-	end
-	return dst
-end
-
-
-local defaults = {profile={titles=true, empty = true, lines = {}, refreshRate = 500, color = {r = 1, g = 1, b = 1}}}
-
-local defaultLines={
-    [1] = {
-        name = "UnitName",
-        left = [[
-local r, g, b
-if UnitIsPlayer(unit) then
-    r, g, b = ClassColor(unit)
-else
-    r, g, b = UnitSelectionColor(unit)
-end
-return Colorize(Name(unit), r, g, b)
-]],
-        right = nil,
-		bold = true,
-		enabled = true
-    },
-    [2] = {
-        name = "Target",
-        left = 'return "Target:"',
-        right = [[
-local r, g, b
-local unit = (unit or "mouseover") .. "target"
-if UnitIsPlayer(unit) then
-    r, g, b = ClassColor(unit)
-else
-    r, g, b = UnitSelectionColor(unit)
-end
-local name = UnitName(unit)
-local name2 = UnitName("player")
-if name == name2 and Realm(unit) == Realm("player") then name = "<<YOU>>" end
-return name and Colorize(name, r, g, b) or "None"
-]],
-        rightUpdating = true,
-		update = 1000,
-		enabled = true
-    },
-    [3] = {
-        name = "Guild",
-        left = 'return "Guild:"',
-        right = [[
-guild = Guild(unit)
-if guild then return "<" .. guild .. ">" else return unitGuild end
-]],
-		enabled = true
-    },
-    [4] = {
-        name = "Rank",
-        left = 'return "Rank:"',
-        right = [[
-return Rank(unit)
-]],
-		enabled = true,
-    },
-    [5] = {
-        name = "Realm",
-        left = 'return "Realm:"',
-        right = [[
-return Realm(unit)
-]],
-		enabled = true
-    },
-    [6] = {
-        name = "Level",
-        left = 'return "Level:"',
-        right = [[
-local lvl = UnitLevel(unit)
-local class = " "
---if Classification(unit) then
---    class = " (" .. Classification(unit) .. ")"
---end
-
-if lvl < 0 then
-    return "*"--Classification(unit) or "Unknown"
-else
-    return format("%s", Level(unit))
-end
-]],
-		enabled = true,
-    },
-    [7] = {
-        name = "Race",
-        left = 'return "Race:"',
-        right = [[
-return Race(unit)
-]],
-		enabled = true,
-    },
-    [8] = {
-        name = "Class",
-        left = 'return "Class:"',
-        right = [[
-if UnitClass(unit) == UnitName(unit) then return end
-local r, g, b
-if UnitIsPlayer(unit) then
-    r, g, b = ClassColor(unit)
-else
-    r, g, b = 1, 1, 1
-end
-return Colorize(UnitClass(unit), r, g, b)
-]],
-		enabled = true,
-    },
-    [9] = {
-        name = "Faction",
-        left = 'return "Faction:"',
-        right = [[
-return Faction(unit)
-]],
-		enabled = true,
-    },
-    [10] = {
-        name = "Status",
-        left = 'return "Status:"',
-        right = [[
-if not UnitIsConnected(unit) then
-    return "Offline"
-elseif HasAura(GetSpellInfo(19752)) then
-    return "Divine Intervention"
-elseif UnitIsFeignDeath(unit) then
-    return "Feigned Death"
-elseif UnitIsGhost(unit) then
-    return "Ghost"
-elseif UnitIsDead(unit) and HasAura(GetSpellInfo(20707)) then
-    return "Soulstoned"
-elseif UnitIsDead(unit) then
-    return "Dead"
-end
-return "Alive"
-]],
-		enabled = true,
-		update = 1000,
-		rightUpdating = true
-    },
-    [11] = {
-        name = "Health",
-        left = 'return "Health:"',
-        right = [[
-local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
-local r, g, b = HPColor(health, maxHealth)
-local value = "Unknown"
-if maxHealth == 100 then
-    value = Colorize(health .. "%", r, g, b)
-elseif maxHealth ~= 0 then
-    value = Colorize(format("%s/%s (%d%%)", short(health), short(maxHealth), health/maxHealth*100), r, g, b)
-end
-return value
-]],
-        rightUpdating = true,
-		update = 1000,
-		enabled = true
-    },
-    [12] = {
-        name = "Mana",
-        left = [[
-return PowerName(unit)
-]],
-        right = [[
-local mana = UnitMana(unit)
-local maxMana = UnitManaMax(unit)
-local r, g, b = PowerColor(nil, unit)
-local value = "Unknown"
-if maxMana == 100 then
-    value = Colorize(tostring(mana), r, g, b)
-elseif maxMana ~= 0 then
-    value = Colorize(format("%s/%s (%d%%)", short(mana), short(maxMana), mana/maxMana*100), r, g, b)
-end
-return value
-]],
-        rightUpdating = true,
-		enabled = true,
-		update = 1000
-    },
-    [13] = {
-        name = "Location",
-        left = 'return "Location:"',
-        right = "return nil",
-		enabled = true
-    },
-	[14] = {
-		name = "Marquee",
-		left = 'return "StarTip " .. _G.StarTip.version',
-		leftUpdating = true,
-		enabled = false,
-		marquee = true,
-		cols = 40,
-		bold = true,
-		align = WidgetText.ALIGN_MARQUEE,
-		update = 1000,
-		speed = 100,
-		direction = WidgetText.SCROLL_LEFT,
-		dontRtrim = true
-	},
-	[15] = {
-		name = "Memory Usage",
-		left = "return 'Memory Usage:'",
-		right = [[
-local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
-if mem then
-    local num = floor(memperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return Colorize(format("%s (%.2f%%)", memshort(mem), memperc), r, g, b)
-end
-]],
-		rightUpdating = true,
-		update = 1000
-	},
-	[16] = {
-		name = "CPU Usage",
-		desc = "Note that you must turn on CPU profiling",
-		left = 'return "CPU Usage:"',
-		right = [[
-local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
-if cpu then
-    local num = floor(cpuperc)
-    if num < 1 then num = 1 end
-    if num > 100 then num = 100 end
-    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
-    return Colorize(format("%s (%.2f%%)", timeshort(cpu), cpuperc), r, g, b)
-end
-]],
-		rightUpdating = true,
-		update = 1000
-	},
-	[17] = {
-		name = "Talents",
-		left = "return 'Talents:'",
-		right = [[
-return SpecText(unit)
-]],
-		rightUpdating = true,
-		enabled = true,
-		update = 1000
-	},
-	[18] = {
-		name = "Range",
-		left = [[
-local min, max = RangeCheck:GetRange(unit)
-if not min then
-    return "No range info"
-elseif not max then
-    return "Target is over " .. min .. " yards"
-else
-    return "Between " .. min .. " and " .. max .. " yards"
-end
-]],
-		leftUpdating = true,
-		enabled = true,
-		update = 1000
-	},
-}
-
-local options = {}
-
-function mod:ReInit()
-	self:ClearLines()
-	for k, v in ipairs(defaultLines) do
-		for j, vv in ipairs(self.db.profile.lines) do
-			vv.colorLeft = nil
-			vv.colorRight = nil
-			if v.name == vv.name then
-				for k, val in pairs(v) do
-					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
-						vv[k] = v[k]
-					end
-				end
-				v.tagged = true
-			end
-		end
-	end
-
-	for k, v in ipairs(defaultLines) do
-		if not v.tagged and not v.deleted then
-			tinsert(self.db.profile.lines, copy(v))
-		end
-	end
-	self:CreateLines()
-end
-
-function mod:OnInitialize()
-    self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
-
-	self:ReInit()
-
-    self.leftLines = StarTip.leftLines
-    self.rightLines = StarTip.rightLines
-    self:RegisterEvent("UPDATE_FACTION")
-    StarTip:SetOptionsDisabled(options, true)
-
-	self.core = LibCore:New(mod, environment, self:GetName(), {[self:GetName()] = {}}, "text", StarTip.db.profile.errorLevel)
-	environment.core = self.core
-
-	if ResourceServer then ResourceServer:New(environment) end
-	--self.lcd = LCDText:New(self.core, 1, 40, 0, 0, 0, StarTip.db.profile.errorLevel)
-	--self.core.lcd = self.lcd
-
-	self.evaluator = LibEvaluator:New(environment, StarTip.db.profile.errorLevel)
-end
-
-local draw
-local update
-function mod:OnEnable()
-	StarTip:SetOptionsDisabled(options, false)
-	if self.db.profile.refreshRate > 0 then
-		self.timer = LibTimer:New("Text module", self.db.profile.refreshRate, true, draw, nil, self.db.profile.errorLevel, self.db.profile.durationLimit)
-	end
-end
-
-function mod:OnDisable()
-    StarTip:SetOptionsDisabled(options, true)
-	if self.timer then self.timer:Del() end
-end
-
-function mod:GetOptions()
-    self:RebuildOpts()
-    return options
-end
-
-function mod:UPDATE_FACTION()
-    for i = 1, GetNumFactions() do
-        local name = GetFactionInfo(i)
-        factionList[name] = true
-    end
-end
-
-local widgetsToDraw = {}
-local function updateWidget(widget)
-	tinsert(widgetsToDraw, widget)
-	if mod.db.profile.refreshRate == 0 then
-		draw(UnitExists(StarTip.unit))
-	end
-end
-
-do
-	local fontsList = LSM:List("font")
-	local widget, fontString
-	function draw(show)
-		if StarTip.fading then
-			table.wipe(widgetsToDraw)
-			return
-		end
-		for i, widget in ipairs(widgetsToDraw) do
-			if not widget.fontString then break end
-			local fontString = widget.fontString
-			fontString:SetText(widget.buffer)
-
-			font = LSM:Fetch("font", fontsList[appearance.db.profile.font])
-
-			if widget.bold then
-				if mod.leftLines and mod.leftLines[widget.i] then
-					mod.leftLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeBold)
-				end
-				if mod.rightLines and mod.rightLines[widget.i] then
-					mod.rightLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeBold)
-				end
-			else
-				if mod.leftlines and mod.leftLines[widget.i] then
-					mod.leftLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeNormal)
-			end
-				if mod.rightLines and mod.rightLines[widget.i] then
-					mod.rightLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeNormal)
-				end
-			end
-		end
-		table.wipe(widgetsToDraw)
-		if UnitExists(StarTip.unit) then
-			GameTooltip:Show()
-		end
-	end
-end
-
---@debug@
-local PluginResources = ResourceServer or LibStub("StarLibPluginResourceTools-1.0")
-local plugin = {}
-LibStub("StarLibPluginString-1.0"):New(plugin)
-
-local mem2, percent2, memdiff2, totalMem2, totaldiff2
-
-local debugging = false
---@end-debug@
-
-local function debug1()
-	--@debug@
-	if debugging then
-		PluginResources.Update()
-		mem, percent, memdiff, totalMem, totaldiff = PluginResources.GetMemUsage("StarTip")
-	end
-	--@end-debug@
-end
-
-local function debug2(num)
-	--@debug@
-	if debugging then
-		if not num then num = 1 end
-		PluginResources.Update()
-		mem, percent, memdiff, totalMem, totaldiff = PluginResources.GetMemUsage("StarTip")
-		StarTip:Print(num .. ": UnitTooltip... Memory: ", plugin.memshort(mem), plugin.memshort(memdiff))
-	end
-	--@end-debug@
-end
-
-function mod:ClearLines()
-	for k, v in pairs(lines) do
-		if v.leftObj then
-			v.leftObj:Stop()
-		end
-		if v.rightObj then
-			v.rightObj:Stop()
-		end
-	end
-	wipe(lines)
-end
-
-local tbl
-function mod:CreateLines()
-    local llines = {}
-	local j = 0
-    for i, v in ipairs(self.db.profile.lines) do
-		if not v.deleted then
-			j = j + 1
-			llines[j] = copy(v)
-			llines[j].config = copy(v)
-		end
-    end
-	self:ClearLines()
-    lines = setmetatable(llines, {__call=function(self)
-		if debuging then debug1() end
-        local lineNum = 0
-		GameTooltip:ClearLines()
-        for i, v in ipairs(self) do
-			if v.enabled and not v.deleted then
-                local left, right, c, cc = '', ''
-				environment.unit = StarTip.unit
-				v.config.unit = StarTip.unit
-                if v.right and v.right ~= "" then
-                    right = mod.evaluator.ExecuteCode(environment, v.name .. " right", v.right)
-                    left = mod.evaluator.ExecuteCode(environment, v.name .. " left", v.left)
-					if right == "" then right = "nil" end
-                else
-                    right = ''
-                    left = mod.evaluator.ExecuteCode(environment, v.name .. " left", v.left)
-                end
-
-                if left and left ~= "" and right ~= "nil" then
-					StarTip.addingLine = true
-                    lineNum = lineNum + 1
-                    if v.right then
-						GameTooltip:AddDoubleLine(' ', ' ', mod.db.profile.color.r, mod.db.profile.color.g, mod.db.profile.color.b, mod.db.profile.color.r, mod.db.profile.color.g, mod.db.profile.color.b)
-
-						--if not v.leftObj or v.lineNum ~= lineNum then
-							v.config.value = v.left
-							local tmp = v.update
-							if not v.leftUpdating then v.update = 0 end
-
-							v.leftObj = v.leftObj or WidgetText:New(mod.core, v.name .. "left", copy(v.config), 0, 0, v.layer or 0, StarTip.db.profile.errorLevel, updateWidget)
-							v.update = tmp
-						--end
-						--if not v.rightObj or v.lineNum ~= lineNum then
-							v.config.value = v.right
-							local tmp = v.update
-							if not v.rightUpdating then v.update = 0 end
-							v.rightObj = v.rightObj or WidgetText:New(mod.core, v.name .. "right", copy(v.config), 0, 0, v.layer or 0, StarTip.db.profile.errorLevel, updateWidget)
-							v.update = tmp
-						--end
-						v.leftObj.fontString = mod.leftLines[lineNum]
-						v.rightObj.fontString = mod.rightLines[lineNum]
-                    else
-						GameTooltip:AddLine(' ', mod.db.profile.color.r, mod.db.profile.color.g, mod.db.profile.color.b)
-
-						v.config.value = v.left
-						local tmp = v.update
-						if not v.leftUpdating then v.update = 0 end
-						v.leftObj = v.leftObj or WidgetText:New(mod.core, v.name, copy(v.config), 0, 0, 0, StarTip.db.profile.errorLevel, updateWidget)
-						v.update = tmp
-						v.leftObj.fontString = mod.leftLines[lineNum]
-                    end
-					if v.rightObj then
-						v.rightObj.config.unit = StarTip.unit
-						v.rightObj:Start()
-					end
-					if v.leftObj then
-						v.leftObj.config.unit = StarTip.unit
-						v.leftObj:Start()
-					end
-					StarTip.addingLine = false
-					v.lineNum = lineNum
-				end
-			end
-
-        end
-		if debugging then debug2(2) end
-        mod.NUM_LINES = lineNum
-		draw()
-		GameTooltip:Show()
-    end})
-end
-
-function mod:OnHide()
-	for i, v in ipairs(lines) do
-		if v.leftObj then
-			v.leftObj:Stop()
-		end
-		if v.rightObj then
-			v.rightObj:Stop()
-		end
-	end
-	if self.timer then
-		self.timer:Stop()
-	end
-end
-
-local function escape(text)
-	return text:replace("|","||")
-end
-
-local function unescape(text)
-	return text:replace("||", "|")
-end
-
-function mod:RebuildOpts()
-    options = {
-		add = {
-			name = "Add Line",
-			desc = "Give the line a name",
-			type = "input",
-			set = function(info, v)
-				if v == "" then return end
-				tinsert(self.db.profile.lines, {name = v, left = "", right = "", rightUpdating = false, enabled = true})
-				self:RebuildOpts()
-				StarTip:RebuildOpts()
-				self:ClearLines()
-				self:CreateLines()
-			end,
-			order = 5
-		},
-		refreshRate = {
-			name = "Refresh Rate",
-			desc = "The rate at which the tooltip will be refreshed",
-			type = "input",
-			pattern = "%d",
-			get = function() return tostring(self.db.profile.refreshRate) end,
-			set = function(info, v)
-				self.db.profile.refreshRate = tonumber(v)
-				self:OnDisable()
-				self:OnEnable()
-			end,
-			order = 6
-		},
-		color = {
-			name = "Default Color",
-			desc = "The default color for tooltip lines",
-			type = "color",
-			get = function() return self.db.profile.color.r, self.db.profile.color.g, self.db.profile.color.b end,
-			set = function(info, r, g, b)
-				self.db.profile.color.r = r
-				self.db.profile.color.g = g
-				self.db.profile.color.b = b
-			end,
-			order = 7
-		},
-		defaults = {
-			name = "Restore Defaults",
-			desc = "Roll back to defaults.",
-			type = "execute",
-			func = function()
-				local replace = {}
-				for i, v in ipairs(self.db.profile.lines) do
-					local insert = true
-					for j, vv in ipairs(defaultLines) do
-						if v.name == vv.name then
-							insert = false
-						end
-					end
-					if insert then
-						tinsert(replace, v)
-					end
-				end
-				table.wipe(self.db.profile.lines)
-				for i, v in ipairs(defaultLines) do
-					tinsert(self.db.profile.lines, copy(v))
-				end
-				for i, v in ipairs(replace) do
-					tinsert(self.db.profile.lines, copy(v))
-				end
-				StarTip:RebuildOpts()
-				self:CreateLines()
-			end,
-			order = 9
-		},
-	}
-    for i, v in ipairs(self.db.profile.lines) do
-		if type(v) == "table" and not v.deleted then
-			options["line" .. i] = {
-				name = v.name,
-				type = "group",
-				order = i + 5
-			}
-			options["line" .. i].args = {
-					enabled = {
-						name = "Enabled",
-						desc = "Whether to show this line or not",
-						type = "toggle",
-						get = function() return self.db.profile.lines[i].enabled end,
-						set = function(info, val)
-							v.enabled = val
-							v.enabledDirty = true
-							self:CreateLines()
-						end,
-						order = 2
-					},
-					leftUpdating = {
-						name = "Left Updating",
-						desc = "Whether this segment refreshes",
-						type = "toggle",
-						get = function() return v.leftUpdating end,
-						set = function(info, val)
-							v.leftUpdating = val
-							if v.update == 0 then
-								v.update = 500
-							end
-							v.leftUpdatingDirty = true
-							self:CreateLines()
-						end,
-						order = 3
-					},
-					rightUpdating = {
-						name = "Right Updating",
-						desc = "Whether this segment refreshes",
-						type = "toggle",
-						get = function() return v.rightUpdating end,
-						set = function(info, val)
-							v.rightUpdating = val
-							if v.update == 0 then
-								v.update = 500
-							end
-							v.rightUpdatingDirty = true
-							self:CreateLines()
-						end,
-						order = 4
-					},
-					up = {
-						name = "Move Up",
-						desc = "Move this line up by one",
-						type = "execute",
-						func = function()
-							StarTip:Print("up", i)
-							if i == 1 then return end
-							local tmp = self.db.profile.lines[i - 1]
-							if not v.left then v.left = "" end
-							if not v.right then v.right = "" end
-							if not tmp.left then tmp.left = "" end
-							if not tmp.right then tmp.right = "" end
-							self.db.profile.lines[i - 1] = v
-							self.db.profile.lines[i] = tmp
-							self:RebuildOpts()
-							StarTip:RebuildOpts()
-							self:CreateLines()
-						end,
-						order = 5
-					},
-					down = {
-						name = "Move Down",
-						desc = "Move this line down by one",
-						type = "execute",
-						func = function()
-							if i == #self.db.profile.lines then return end
-							local tmp = self.db.profile.lines[i + 1]
-							if tmp.deleted then return end
-							if not v.left then v.left = "" end
-							if not v.right then v.right = "" end
-							if not tmp.left then tmp.left = "" end
-							if not tmp.right then tmp.right = "" end
-							self.db.profile.lines[i + 1] = v
-							self.db.profile.lines[i] = tmp
-							self:RebuildOpts()
-							StarTip:RebuildOpts()
-							self:CreateLines()
-						end,
-						order = 6
-					},
-					bold = {
-						name = "Bold",
-						desc = "Whether to bold this line or not",
-						type = "toggle",
-						get = function() return self.db.profile.lines[i].bold end,
-						set = function(info, val)
-							v.bold = val
-							v.boldDirty = true
-							self:CreateLines()
-						end,
-						order = 7
-					},
-					delete = {
-						name = "Delete",
-						desc = "Delete this line",
-						type = "execute",
-						func = function()
-							local name = v.name
-							local delete = true
-							for i, line in ipairs(defaultLines) do
-								if line.name == name then
-									delete = false
-								end
-							end
-							tremove(self.db.profile.lines, i)
-							if not delete then
-								wipe(v)
-								v.deleted = true
-								v.name = name
-								tinsert(self.db.profile.lines, v)
-							end
-							StarTip:RebuildOpts()
-							self:ClearLines()
-							self:CreateLines()
-						end,
-						order = 8
-					},
-					linesHeader = {
-						name = "Lines",
-						type = "header",
-						order = 9
-					},
-					left = {
-						name = "Left",
-						type = "input",
-						desc = "Left text code",
-						get = function() return escape(v.left or "") end,
-						set = function(info, val)
-							v.left = unescape(val)
-							v.leftDirty = true
-							if val == "" then v.left = nil end
-							self:CreateLines()
-						end,
-						--[[validate = function(info, str)
-							return mod.evaluator:Validate(environment, str)
-						end,]]
-						multiline = true,
-						width = "full",
-						order = 10
-					},
-					right = {
-						name = "Right",
-						type = "input",
-						desc = "Right text code",
-						get = function() return escape(v.right or "") end,
-						set = function(info, val)
-							v.right = unescape(val);
-							v.rightDirty = true
-							if val == "" then v.right = nil end
-							self:CreateLines()
-						end,
-						multiline = true,
-						width = "full",
-						order = 11
-					},
-					marquee = {
-						name = "Enhanced Settings",
-						type = "group",
-						args = {
-							header = {
-								name = "Note that only the left line script is used for marquee text",
-								type = "header",
-								order = 1
-							},
-							marquee = {
-								name = "Enabled",
-								desc = "Enable marquee. Note that this just makes marquees use the left line only. Technically all segments on the tooltip are marquee widgets.",
-								type = "toggle",
-								get = function() return v.marquee end,
-								set = function(info, val)
-									v.marquee = val
-									v.marqueeDirty = true
-									self:CreateLines()
-								end
-							},
-							prefix = {
-								name = "Prefix",
-								desc = "The prefix for this marquee",
-								type = "input",
-								width = "full",
-								multiline = true,
-								get = function()
-									return v.prefix
-								end,
-								set = function(info, val)
-									v.prefix = val
-									v.prefixDirty = true
-									self:CreateLines()
-								end,
-								order = 2
-							},
-							postfix = {
-								name = "Postfix",
-								desc = "The postfix for this marquee",
-								type = "input",
-								width = "full",
-								multiline = true,
-								get = function()
-									return v.postfix or WidgetText.defaults.postfix
-								end,
-								set = function(info, val)
-									v.postfix = v
-									v.postfixDirty = true
-									self:CreateLines()
-								end,
-								order = 3
-							},
-							precision = {
-								name = "Precision",
-								desc = "How precise displayed numbers are",
-								type = "input",
-								pattern = "%d",
-								get = function()
-									return tostring(v.precision or WidgetText.defaults.precision)
-								end,
-								set = function(info, val)
-									v.precision = tonumber(val)
-									v.precisionDirty = true
-									self:CreateLines()
-								end,
-								order = 4
-							},
-							align = {
-								name = "Alignment",
-								desc = "The alignment information",
-								type = "select",
-								values = WidgetText.alignmentList,
-								get = function()
-									return v.align
-								end,
-								set = function(info, val)
-									v.align = val
-									v.alignDirty = true
-									self:CreateLines()
-								end,
-								order = 5
-							},
-							update = {
-								name = "Text Update",
-								desc = "How often to update the text. Use this option if you want your line to update.",
-								type = "input",
-								pattern = "%d",
-								get = function()
-									return tostring(v.update or WidgetText.defaults.update)
-								end,
-								set = function(info, val)
-									v.update = tonumber(val)
-									v.updateDirty = true
-									self:CreateLines()
-								end,
-								order = 6
-							},
-							speed = {
-								name = "Scroll Speed",
-								desc = "How fast to scroll the marquee",
-								type = "input",
-								pattern = "%d",
-								get = function()
-									return tostring(v.speed or WidgetText.defaults.speed)
-								end,
-								set = function(info, val)
-									v.speed = tonumber(val)
-									v.speedDirty = true
-									self:CreateLines()
-								end,
-								order = 7
-							},
-							direction = {
-								name = "Direction",
-								desc = "Which direction to scroll",
-								type = "select",
-								values = WidgetText.directionList,
-								get = function()
-									return v.direction or WidgetText.defaults.direction
-								end,
-								set = function(info, val)
-									v.direction = val
-									v.directionDirty = true
-									self:CreateLines()
-								end,
-								order = 8
-							},
-							cols = {
-								name = "Columns",
-								desc = "How wide the marquee is",
-								type = "input",
-								pattern = "%d",
-								get = function()
-									return tostring(v.cols or WidgetText.defaults.cols)
-								end,
-								set = function(info, val)
-									v.cols = tonumber(val)
-									v.colsDirty = true
-									self:CreateLines()
-								end,
-								order = 9
-							},
-							dontRtrim = {
-								name = "Don't right trim",
-								desc = "Prevent trimming white space to the right of text",
-								type = "toggle",
-								get = function()
-									return v.dontRtrim or WidgetText.defaults.dontRtrim
-								end,
-								set = function(info, val)
-									v.dontRtrim = val
-									v.dontRtrimDirty = true
-									self:CreateLines()
-								end,
-								order = 10
-							}
-						},
-						order = 9
-					}
-			}
-		end
-		--[[if v.desc then
-			options["line" .. i].args.desc = {
-				name = v.desc,
-				type = "header",
-				order = 1
-			}
-
-		end]]
-    end
-end
-
-local plugin = LibStub("StarLibPluginString-1.0")
-local ff = CreateFrame("Frame")
-function mod:SetUnit()
-
-	if debugging then
-		ResourceServer.Update()
-		local mem1, percent1, memdiff1, totalMem1, totaldiff1 = ResourceServer.GetMemUsage("StarTip")
-	end
-
-    if ff:GetScript("OnUpdate") then ff:SetScript("OnUpdate", nil) end
-
-	environment.unitName, environment.unitGuild, environment.unitLocation = UnitTooltipStats.GetUnitTooltipStats("mouseover")
-
-	self.NUM_LINES = 0
-
-    -- Taken from CowTip
-    local lastLine = 2
-    local text2 = self.leftLines[2]:GetText()
-
-    if not text2 then
-        lastLine = lastLine - 1
-    elseif not text2:find("^"..LEVEL) then
-        lastLine = lastLine + 1
-    end
-    if not UnitPlayerControlled(StarTip.unit) and not UnitIsPlayer(StarTip.unit) then
-        local factionText = self.leftLines[lastLine + 1]:GetText()
-        if factionText == PVP then
-            factionText = nil
-        end
-        if factionText and (factionList[factionText] or UnitFactionGroup(StarTip.unit)) then
-            lastLine = lastLine + 1
-        end
-    end
-    if not UnitIsConnected(StarTip.unit) or not UnitIsVisible(StarTip.unit) or UnitIsPVP(StarTip.unit) then
-        lastLine = lastLine + 1
-    end
-
-    lastLine = lastLine + 1
-
-	wipe(linesToAdd)
-	wipe(linesToAddR)
-	wipe(linesToAddG)
-	wipe(linesToAddB)
-	wipe(linesToAddRight)
-	wipe(linesToAddRightR)
-	wipe(linesToAddRightG)
-	wipe(linesToAddRightB)
-    for i = lastLine, GameTooltip:NumLines() do
-        local left = self.leftLines[i]
-        local j = i - lastLine + 1
-        linesToAdd[j] = left:GetText()
-        local r, g, b = left:GetTextColor()
-        linesToAddR[j] = r
-        linesToAddG[j] = g
-        linesToAddB[j] = b
-        local right = self.rightLines[i]
-        if right:IsShown() then
-            linesToAddRight[j] = right:GetText()
-            local r, g, b = right:GetTextColor()
-            linesToAddRightR[j] = r
-            linesToAddRightG[j] = g
-            linesToAddRightB[j] = b
-        end
-    end
-    -- End
-
-	lines()
-
-	GameTooltip:Show()
-
-	if self.db.profile.refreshRate > 0 and self.timer then
-		self.timer:Start()
-	end
-
-	if GameTooltip:NumLines() > mod.NUM_LINES then GameTooltip:Hide(); return end
-
-	self:RefixEndLines()
-
-	if debugging then
-		ResourceServer.Update()
-		local mem2, percent2, memdiff2, totalMem2, totaldiff2 = ResourceServer.GetMemUsage("StarTip")
-		--StarTip:Print("UnitTooltip Memory", plugin.memshort(mem2), plugin.memshort(mem2 - mem1), plugin.memshort(memdiff2))
-	end
-end
-
-function mod:RefixEndLines()
-    -- Another part taken from CowTip
-    for i, left in ipairs(linesToAdd) do
-
-        local right = linesToAddRight[i]
-		StarTip.addingLine = true
-        if right then
-            GameTooltip:AddDoubleLine(left, right, linesToAddR[i], linesToAddG[i], linesToAddB[i], linesToAddRightR[i], linesToAddRightG[i], linesToAddRightB[i])
-        else
-            GameTooltip:AddLine(left, linesToAddR[i], linesToAddG[i], linesToAddB[i], true)
-        end
-		StarTip.addingLine = false
-    end
-    -- End
-end
\ No newline at end of file
diff --git a/Modules/UnitTooltip/StarTip_UnitTooltip.toc b/Modules/UnitTooltip/StarTip_UnitTooltip.toc
new file mode 100644
index 0000000..926537c
--- /dev/null
+++ b/Modules/UnitTooltip/StarTip_UnitTooltip.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## X-Compatible-With: 40000
+## Title: StarTip [UnitTooltip]
+## Notes: Tooltips from outerspace
+## Author: Starlon
+## Version: 1.0
+## OptionalDeps: StarTip
+
+UnitTooltip.lua
\ No newline at end of file
diff --git a/Modules/UnitTooltip/UnitTooltip.lua b/Modules/UnitTooltip/UnitTooltip.lua
new file mode 100644
index 0000000..3fd5727
--- /dev/null
+++ b/Modules/UnitTooltip/UnitTooltip.lua
@@ -0,0 +1,1098 @@
+local mod = StarTip:NewModule("UnitTooltip", "AceEvent-3.0")
+mod.name = "Unit Tooltip"
+mod.toggled = true
+local LibProperty = LibStub("StarLibProperty-1.0", true)
+assert(LibProperty, "Text module requires StarLibProperty-1.0")
+local WidgetText = LibStub("StarLibWidgetText-1.0", true)
+assert(WidgetText, "Text module requires StarLibWidgetText-1.0")
+local LCDText = LibStub("StarLibLCDText-1.0", true)
+assert(LCDText, mod.name .. " requires StarLibLCDText-1.0")
+local LibCore = LibStub("StarLibCore-1.0", true)
+assert(LibCore, mod.name .. " requires StarLibCore-1.0")
+local LibTimer = LibStub("StarLibTimer-1.0", true)
+assert(LibTimer, mod.name .. " requires StarLibTimer-1.0")
+local LibEvaluator = LibStub("StarLibEvaluator-1.0", true)
+assert(LibEvaluator, mod.name .. " requires StarLibEvaluator-1.0")
+local UnitTooltipStats = LibStub("StarLibPluginUnitTooltipStats-1.0", true)
+assert(UnitTooltipStats, mod.name .. " requires StarLibPluginUnitTooltipStats-1.0")
+
+local _G = _G
+local StarTip = _G.StarTip
+local self = mod
+local GameTooltip = _G.GameTooltip
+local tinsert = _G.tinsert
+local unpack = _G.unpack
+local select = _G.select
+local format = _G.format
+local floor = _G.floor
+local tostring = _G.tostring
+local LSM = _G.LibStub("LibSharedMedia-3.0")
+local factionList = {}
+local linesToAdd = {}
+local linesToAddR = {}
+local linesToAddG = {}
+local linesToAddB = {}
+local linesToAddRight = {}
+local linesToAddRightR = {}
+local linesToAddRightG = {}
+local linesToAddRightB = {}
+local lines = {}
+
+local unit
+local environment = {}
+
+local appearance = StarTip:GetModule("Appearance")
+
+local function errorhandler(err)
+    return geterrorhandler()(err)
+end
+
+local ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_MARQUEE, ALIGN_AUTOMATIC, ALIGN_PINGPONG = 1, 2, 3, 4, 5, 6
+
+local SCROLL_RIGHT, SCROLL_LEFT = 1, 2
+
+mod.NUM_LINES = 0
+
+local function copy(src, dst)
+	if type(src) ~= "table" then return nil end
+	if type(dst) ~= "table" then dst = {} end
+	for k, v in pairs(src) do
+		if type(v) == "table" then
+			v = copy(v)
+		end
+		dst[k] = v
+	end
+	return dst
+end
+
+
+local defaults = {profile={titles=true, empty = true, lines = {}, refreshRate = 500, color = {r = 1, g = 1, b = 1}}}
+
+local defaultLines={
+    [1] = {
+        name = "UnitName",
+        left = [[
+local r, g, b
+if UnitIsPlayer(unit) then
+    r, g, b = ClassColor(unit)
+else
+    r, g, b = UnitSelectionColor(unit)
+end
+return Colorize(Name(unit), r, g, b)
+]],
+        right = nil,
+		bold = true,
+		enabled = true
+    },
+    [2] = {
+        name = "Target",
+        left = 'return "Target:"',
+        right = [[
+local r, g, b
+local unit = (unit or "mouseover") .. "target"
+if UnitIsPlayer(unit) then
+    r, g, b = ClassColor(unit)
+else
+    r, g, b = UnitSelectionColor(unit)
+end
+local name = UnitName(unit)
+local name2 = UnitName("player")
+if name == name2 and Realm(unit) == Realm("player") then name = "<<YOU>>" end
+return name and Colorize(name, r, g, b) or "None"
+]],
+        rightUpdating = true,
+		update = 1000,
+		enabled = true
+    },
+    [3] = {
+        name = "Guild",
+        left = 'return "Guild:"',
+        right = [[
+guild = Guild(unit)
+if guild then return "<" .. guild .. ">" else return unitGuild end
+]],
+		enabled = true
+    },
+    [4] = {
+        name = "Rank",
+        left = 'return "Rank:"',
+        right = [[
+return Rank(unit)
+]],
+		enabled = true,
+    },
+    [5] = {
+        name = "Realm",
+        left = 'return "Realm:"',
+        right = [[
+return Realm(unit)
+]],
+		enabled = true
+    },
+    [6] = {
+        name = "Level",
+        left = 'return "Level:"',
+        right = [[
+local lvl = UnitLevel(unit)
+local class = " "
+--if Classification(unit) then
+--    class = " (" .. Classification(unit) .. ")"
+--end
+
+if lvl < 0 then
+    return "*"--Classification(unit) or "Unknown"
+else
+    return format("%s", Level(unit))
+end
+]],
+		enabled = true,
+    },
+    [7] = {
+        name = "Race",
+        left = 'return "Race:"',
+        right = [[
+return Race(unit)
+]],
+		enabled = true,
+    },
+    [8] = {
+        name = "Class",
+        left = 'return "Class:"',
+        right = [[
+if UnitClass(unit) == UnitName(unit) then return end
+local r, g, b
+if UnitIsPlayer(unit) then
+    r, g, b = ClassColor(unit)
+else
+    r, g, b = 1, 1, 1
+end
+return Colorize(UnitClass(unit), r, g, b)
+]],
+		enabled = true,
+    },
+    [9] = {
+        name = "Faction",
+        left = 'return "Faction:"',
+        right = [[
+return Faction(unit)
+]],
+		enabled = true,
+    },
+    [10] = {
+        name = "Status",
+        left = 'return "Status:"',
+        right = [[
+if not UnitIsConnected(unit) then
+    return "Offline"
+elseif HasAura(GetSpellInfo(19752)) then
+    return "Divine Intervention"
+elseif UnitIsFeignDeath(unit) then
+    return "Feigned Death"
+elseif UnitIsGhost(unit) then
+    return "Ghost"
+elseif UnitIsDead(unit) and HasAura(GetSpellInfo(20707)) then
+    return "Soulstoned"
+elseif UnitIsDead(unit) then
+    return "Dead"
+end
+return "Alive"
+]],
+		enabled = true,
+		update = 1000,
+		rightUpdating = true
+    },
+    [11] = {
+        name = "Health",
+        left = 'return "Health:"',
+        right = [[
+local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
+local r, g, b = HPColor(health, maxHealth)
+local value = "Unknown"
+if maxHealth == 100 then
+    value = Colorize(health .. "%", r, g, b)
+elseif maxHealth ~= 0 then
+    value = Colorize(format("%s/%s (%d%%)", short(health), short(maxHealth), health/maxHealth*100), r, g, b)
+end
+return value
+]],
+        rightUpdating = true,
+		update = 1000,
+		enabled = true
+    },
+    [12] = {
+        name = "Mana",
+        left = [[
+return PowerName(unit)
+]],
+        right = [[
+local mana = UnitMana(unit)
+local maxMana = UnitManaMax(unit)
+local r, g, b = PowerColor(nil, unit)
+local value = "Unknown"
+if maxMana == 100 then
+    value = Colorize(tostring(mana), r, g, b)
+elseif maxMana ~= 0 then
+    value = Colorize(format("%s/%s (%d%%)", short(mana), short(maxMana), mana/maxMana*100), r, g, b)
+end
+return value
+]],
+        rightUpdating = true,
+		enabled = true,
+		update = 1000
+    },
+    [13] = {
+        name = "Location",
+        left = 'return "Location:"',
+        right = "return nil",
+		enabled = true
+    },
+	[14] = {
+		name = "Marquee",
+		left = 'return "StarTip " .. _G.StarTip.version',
+		leftUpdating = true,
+		enabled = false,
+		marquee = true,
+		cols = 40,
+		bold = true,
+		align = WidgetText.ALIGN_MARQUEE,
+		update = 1000,
+		speed = 100,
+		direction = WidgetText.SCROLL_LEFT,
+		dontRtrim = true
+	},
+	[15] = {
+		name = "Memory Usage",
+		left = "return 'Memory Usage:'",
+		right = [[
+local mem, percent, memdiff, totalMem, totaldiff, memperc = GetMemUsage("StarTip")
+if mem then
+    local num = floor(memperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return Colorize(format("%s (%.2f%%)", memshort(mem), memperc), r, g, b)
+end
+]],
+		rightUpdating = true,
+		update = 1000
+	},
+	[16] = {
+		name = "CPU Usage",
+		desc = "Note that you must turn on CPU profiling",
+		left = 'return "CPU Usage:"',
+		right = [[
+local cpu, percent, cpudiff, totalCPU, totaldiff, cpuperc = GetCPUUsage("StarTip")
+if cpu then
+    local num = floor(cpuperc)
+    if num < 1 then num = 1 end
+    if num > 100 then num = 100 end
+    local r, g, b = gradient[num][1], gradient[num][2], gradient[num][3]
+    return Colorize(format("%s (%.2f%%)", timeshort(cpu), cpuperc), r, g, b)
+end
+]],
+		rightUpdating = true,
+		update = 1000
+	},
+	[17] = {
+		name = "Talents",
+		left = "return 'Talents:'",
+		right = [[
+return SpecText(unit)
+]],
+		rightUpdating = true,
+		enabled = true,
+		update = 1000
+	},
+	[18] = {
+		name = "Range",
+		left = [[
+local min, max = RangeCheck:GetRange(unit)
+if not min then
+    return "No range info"
+elseif not max then
+    return "Target is over " .. min .. " yards"
+else
+    return "Between " .. min .. " and " .. max .. " yards"
+end
+]],
+		leftUpdating = true,
+		enabled = true,
+		update = 1000
+	},
+}
+
+local options = {}
+
+function mod:ReInit()
+	self:ClearLines()
+	for k, v in ipairs(defaultLines) do
+		for j, vv in ipairs(self.db.profile.lines) do
+			vv.colorLeft = nil
+			vv.colorRight = nil
+			if v.name == vv.name then
+				for k, val in pairs(v) do
+					if v[k] ~= vv[k] and not vv[k.."Dirty"] then
+						vv[k] = v[k]
+					end
+				end
+				v.tagged = true
+			end
+		end
+	end
+
+	for k, v in ipairs(defaultLines) do
+		if not v.tagged and not v.deleted then
+			tinsert(self.db.profile.lines, copy(v))
+		end
+	end
+	self:CreateLines()
+end
+
+function mod:OnInitialize()
+    self.db = StarTip.db:RegisterNamespace(self:GetName(), defaults)
+
+	self:ReInit()
+
+    self.leftLines = StarTip.leftLines
+    self.rightLines = StarTip.rightLines
+    self:RegisterEvent("UPDATE_FACTION")
+    StarTip:SetOptionsDisabled(options, true)
+
+	self.core = LibCore:New(mod, environment, self:GetName(), {[self:GetName()] = {}}, "text", StarTip.db.profile.errorLevel)
+	environment.core = self.core
+
+	if ResourceServer then ResourceServer:New(environment) end
+	--self.lcd = LCDText:New(self.core, 1, 40, 0, 0, 0, StarTip.db.profile.errorLevel)
+	--self.core.lcd = self.lcd
+
+	self.evaluator = LibEvaluator:New(environment, StarTip.db.profile.errorLevel)
+end
+
+local draw
+local update
+function mod:OnEnable()
+	StarTip:SetOptionsDisabled(options, false)
+	if self.db.profile.refreshRate > 0 then
+		self.timer = LibTimer:New("Text module", self.db.profile.refreshRate, true, draw, nil, self.db.profile.errorLevel, self.db.profile.durationLimit)
+	end
+end
+
+function mod:OnDisable()
+    StarTip:SetOptionsDisabled(options, true)
+	if self.timer then self.timer:Del() end
+end
+
+function mod:GetOptions()
+    self:RebuildOpts()
+    return options
+end
+
+function mod:UPDATE_FACTION()
+    for i = 1, GetNumFactions() do
+        local name = GetFactionInfo(i)
+        factionList[name] = true
+    end
+end
+
+local widgetsToDraw = {}
+local function updateWidget(widget)
+	tinsert(widgetsToDraw, widget)
+	if mod.db.profile.refreshRate == 0 then
+		draw(UnitExists(StarTip.unit))
+	end
+end
+
+do
+	local fontsList = LSM:List("font")
+	local widget, fontString
+	function draw(show)
+		if StarTip.fading then
+			table.wipe(widgetsToDraw)
+			return
+		end
+		for i, widget in ipairs(widgetsToDraw) do
+			if not widget.fontString then break end
+			local fontString = widget.fontString
+			fontString:SetText(widget.buffer)
+
+			font = LSM:Fetch("font", fontsList[appearance.db.profile.font])
+
+			if widget.bold then
+				if mod.leftLines and mod.leftLines[widget.i] then
+					mod.leftLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeBold)
+				end
+				if mod.rightLines and mod.rightLines[widget.i] then
+					mod.rightLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeBold)
+				end
+			else
+				if mod.leftlines and mod.leftLines[widget.i] then
+					mod.leftLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeNormal)
+			end
+				if mod.rightLines and mod.rightLines[widget.i] then
+					mod.rightLines[widget.i]:SetFont(font, appearance.db.profile.fontSizeNormal)
+				end
+			end
+		end
+		table.wipe(widgetsToDraw)
+		if UnitExists(StarTip.unit) then
+			GameTooltip:Show()
+		end
+	end
+end
+
+--@debug@
+local PluginResources = ResourceServer or LibStub("StarLibPluginResourceTools-1.0")
+local plugin = {}
+LibStub("StarLibPluginString-1.0"):New(plugin)
+
+local mem2, percent2, memdiff2, totalMem2, totaldiff2
+
+local debugging = false
+--@end-debug@
+
+local function debug1()
+	--@debug@
+	if debugging then
+		PluginResources.Update()
+		mem, percent, memdiff, totalMem, totaldiff = PluginResources.GetMemUsage("StarTip")
+	end
+	--@end-debug@
+end
+
+local function debug2(num)
+	--@debug@
+	if debugging then
+		if not num then num = 1 end
+		PluginResources.Update()
+		mem, percent, memdiff, totalMem, totaldiff = PluginResources.GetMemUsage("StarTip")
+		StarTip:Print(num .. ": UnitTooltip... Memory: ", plugin.memshort(mem), plugin.memshort(memdiff))
+	end
+	--@end-debug@
+end
+
+function mod:ClearLines()
+	for k, v in pairs(lines) do
+		if v.leftObj then
+			v.leftObj:Stop()
+		end
+		if v.rightObj then
+			v.rightObj:Stop()
+		end
+	end
+	wipe(lines)
+end
+
+local tbl
+function mod:CreateLines()
+    local llines = {}
+	local j = 0
+    for i, v in ipairs(self.db.profile.lines) do
+		if not v.deleted then
+			j = j + 1
+			llines[j] = copy(v)
+			llines[j].config = copy(v)
+		end
+    end
+	self:ClearLines()
+    lines = setmetatable(llines, {__call=function(self)
+		if debuging then debug1() end
+        local lineNum = 0
+		GameTooltip:ClearLines()
+        for i, v in ipairs(self) do
+			if v.enabled and not v.deleted then
+                local left, right, c, cc = '', ''
+				environment.unit = StarTip.unit
+				v.config.unit = StarTip.unit
+                if v.right and v.right ~= "" then
+                    right = mod.evaluator.ExecuteCode(environment, v.name .. " right", v.right)
+                    left = mod.evaluator.ExecuteCode(environment, v.name .. " left", v.left)
+					if right == "" then right = "nil" end
+                else
+                    right = ''
+                    left = mod.evaluator.ExecuteCode(environment, v.name .. " left", v.left)
+                end
+
+                if left and left ~= "" and right ~= "nil" then
+					StarTip.addingLine = true
+                    lineNum = lineNum + 1
+                    if v.right then
+						GameTooltip:AddDoubleLine(' ', ' ', mod.db.profile.color.r, mod.db.profile.color.g, mod.db.profile.color.b, mod.db.profile.color.r, mod.db.profile.color.g, mod.db.profile.color.b)
+
+						--if not v.leftObj or v.lineNum ~= lineNum then
+							v.config.value = v.left
+							local tmp = v.update
+							if not v.leftUpdating then v.update = 0 end
+
+							v.leftObj = v.leftObj or WidgetText:New(mod.core, v.name .. "left", copy(v.config), 0, 0, v.layer or 0, StarTip.db.profile.errorLevel, updateWidget)
+							v.update = tmp
+						--end
+						--if not v.rightObj or v.lineNum ~= lineNum then
+							v.config.value = v.right
+							local tmp = v.update
+							if not v.rightUpdating then v.update = 0 end
+							v.rightObj = v.rightObj or WidgetText:New(mod.core, v.name .. "right", copy(v.config), 0, 0, v.layer or 0, StarTip.db.profile.errorLevel, updateWidget)
+							v.update = tmp
+						--end
+						v.leftObj.fontString = mod.leftLines[lineNum]
+						v.rightObj.fontString = mod.rightLines[lineNum]
+                    else
+						GameTooltip:AddLine(' ', mod.db.profile.color.r, mod.db.profile.color.g, mod.db.profile.color.b)
+
+						v.config.value = v.left
+						local tmp = v.update
+						if not v.leftUpdating then v.update = 0 end
+						v.leftObj = v.leftObj or WidgetText:New(mod.core, v.name, copy(v.config), 0, 0, 0, StarTip.db.profile.errorLevel, updateWidget)
+						v.update = tmp
+						v.leftObj.fontString = mod.leftLines[lineNum]
+                    end
+					if v.rightObj then
+						v.rightObj.config.unit = StarTip.unit
+						v.rightObj:Start()
+					end
+					if v.leftObj then
+						v.leftObj.config.unit = StarTip.unit
+						v.leftObj:Start()
+					end
+					StarTip.addingLine = false
+					v.lineNum = lineNum
+				end
+			end
+
+        end
+		if debugging then debug2(2) end
+        mod.NUM_LINES = lineNum
+		draw()
+		GameTooltip:Show()
+    end})
+end
+
+function mod:OnHide()
+	for i, v in ipairs(lines) do
+		if v.leftObj then
+			v.leftObj:Stop()
+		end
+		if v.rightObj then
+			v.rightObj:Stop()
+		end
+	end
+	if self.timer then
+		self.timer:Stop()
+	end
+end
+
+local function escape(text)
+	return text:replace("|","||")
+end
+
+local function unescape(text)
+	return text:replace("||", "|")
+end
+
+function mod:RebuildOpts()
+    options = {
+		add = {
+			name = "Add Line",
+			desc = "Give the line a name",
+			type = "input",
+			set = function(info, v)
+				if v == "" then return end
+				tinsert(self.db.profile.lines, {name = v, left = "", right = "", rightUpdating = false, enabled = true})
+				self:RebuildOpts()
+				StarTip:RebuildOpts()
+				self:ClearLines()
+				self:CreateLines()
+			end,
+			order = 5
+		},
+		refreshRate = {
+			name = "Refresh Rate",
+			desc = "The rate at which the tooltip will be refreshed",
+			type = "input",
+			pattern = "%d",
+			get = function() return tostring(self.db.profile.refreshRate) end,
+			set = function(info, v)
+				self.db.profile.refreshRate = tonumber(v)
+				self:OnDisable()
+				self:OnEnable()
+			end,
+			order = 6
+		},
+		color = {
+			name = "Default Color",
+			desc = "The default color for tooltip lines",
+			type = "color",
+			get = function() return self.db.profile.color.r, self.db.profile.color.g, self.db.profile.color.b end,
+			set = function(info, r, g, b)
+				self.db.profile.color.r = r
+				self.db.profile.color.g = g
+				self.db.profile.color.b = b
+			end,
+			order = 7
+		},
+		defaults = {
+			name = "Restore Defaults",
+			desc = "Roll back to defaults.",
+			type = "execute",
+			func = function()
+				local replace = {}
+				for i, v in ipairs(self.db.profile.lines) do
+					local insert = true
+					for j, vv in ipairs(defaultLines) do
+						if v.name == vv.name then
+							insert = false
+						end
+					end
+					if insert then
+						tinsert(replace, v)
+					end
+				end
+				table.wipe(self.db.profile.lines)
+				for i, v in ipairs(defaultLines) do
+					tinsert(self.db.profile.lines, copy(v))
+				end
+				for i, v in ipairs(replace) do
+					tinsert(self.db.profile.lines, copy(v))
+				end
+				StarTip:RebuildOpts()
+				self:CreateLines()
+			end,
+			order = 9
+		},
+	}
+    for i, v in ipairs(self.db.profile.lines) do
+		if type(v) == "table" and not v.deleted then
+			options["line" .. i] = {
+				name = v.name,
+				type = "group",
+				order = i + 5
+			}
+			options["line" .. i].args = {
+					enabled = {
+						name = "Enabled",
+						desc = "Whether to show this line or not",
+						type = "toggle",
+						get = function() return self.db.profile.lines[i].enabled end,
+						set = function(info, val)
+							v.enabled = val
+							v.enabledDirty = true
+							self:CreateLines()
+						end,
+						order = 2
+					},
+					leftUpdating = {
+						name = "Left Updating",
+						desc = "Whether this segment refreshes",
+						type = "toggle",
+						get = function() return v.leftUpdating end,
+						set = function(info, val)
+							v.leftUpdating = val
+							if v.update == 0 then
+								v.update = 500
+							end
+							v.leftUpdatingDirty = true
+							self:CreateLines()
+						end,
+						order = 3
+					},
+					rightUpdating = {
+						name = "Right Updating",
+						desc = "Whether this segment refreshes",
+						type = "toggle",
+						get = function() return v.rightUpdating end,
+						set = function(info, val)
+							v.rightUpdating = val
+							if v.update == 0 then
+								v.update = 500
+							end
+							v.rightUpdatingDirty = true
+							self:CreateLines()
+						end,
+						order = 4
+					},
+					up = {
+						name = "Move Up",
+						desc = "Move this line up by one",
+						type = "execute",
+						func = function()
+							StarTip:Print("up", i)
+							if i == 1 then return end
+							local tmp = self.db.profile.lines[i - 1]
+							if not v.left then v.left = "" end
+							if not v.right then v.right = "" end
+							if not tmp.left then tmp.left = "" end
+							if not tmp.right then tmp.right = "" end
+							self.db.profile.lines[i - 1] = v
+							self.db.profile.lines[i] = tmp
+							self:RebuildOpts()
+							StarTip:RebuildOpts()
+							self:CreateLines()
+						end,
+						order = 5
+					},
+					down = {
+						name = "Move Down",
+						desc = "Move this line down by one",
+						type = "execute",
+						func = function()
+							if i == #self.db.profile.lines then return end
+							local tmp = self.db.profile.lines[i + 1]
+							if tmp.deleted then return end
+							if not v.left then v.left = "" end
+							if not v.right then v.right = "" end
+							if not tmp.left then tmp.left = "" end
+							if not tmp.right then tmp.right = "" end
+							self.db.profile.lines[i + 1] = v
+							self.db.profile.lines[i] = tmp
+							self:RebuildOpts()
+							StarTip:RebuildOpts()
+							self:CreateLines()
+						end,
+						order = 6
+					},
+					bold = {
+						name = "Bold",
+						desc = "Whether to bold this line or not",
+						type = "toggle",
+						get = function() return self.db.profile.lines[i].bold end,
+						set = function(info, val)
+							v.bold = val
+							v.boldDirty = true
+							self:CreateLines()
+						end,
+						order = 7
+					},
+					delete = {
+						name = "Delete",
+						desc = "Delete this line",
+						type = "execute",
+						func = function()
+							local name = v.name
+							local delete = true
+							for i, line in ipairs(defaultLines) do
+								if line.name == name then
+									delete = false
+								end
+							end
+							tremove(self.db.profile.lines, i)
+							if not delete then
+								wipe(v)
+								v.deleted = true
+								v.name = name
+								tinsert(self.db.profile.lines, v)
+							end
+							StarTip:RebuildOpts()
+							self:ClearLines()
+							self:CreateLines()
+						end,
+						order = 8
+					},
+					linesHeader = {
+						name = "Lines",
+						type = "header",
+						order = 9
+					},
+					left = {
+						name = "Left",
+						type = "input",
+						desc = "Left text code",
+						get = function() return escape(v.left or "") end,
+						set = function(info, val)
+							v.left = unescape(val)
+							v.leftDirty = true
+							if val == "" then v.left = nil end
+							self:CreateLines()
+						end,
+						--[[validate = function(info, str)
+							return mod.evaluator:Validate(environment, str)
+						end,]]
+						multiline = true,
+						width = "full",
+						order = 10
+					},
+					right = {
+						name = "Right",
+						type = "input",
+						desc = "Right text code",
+						get = function() return escape(v.right or "") end,
+						set = function(info, val)
+							v.right = unescape(val);
+							v.rightDirty = true
+							if val == "" then v.right = nil end
+							self:CreateLines()
+						end,
+						multiline = true,
+						width = "full",
+						order = 11
+					},
+					marquee = {
+						name = "Enhanced Settings",
+						type = "group",
+						args = {
+							header = {
+								name = "Note that only the left line script is used for marquee text",
+								type = "header",
+								order = 1
+							},
+							marquee = {
+								name = "Enabled",
+								desc = "Enable marquee. Note that this just makes marquees use the left line only. Technically all segments on the tooltip are marquee widgets.",
+								type = "toggle",
+								get = function() return v.marquee end,
+								set = function(info, val)
+									v.marquee = val
+									v.marqueeDirty = true
+									self:CreateLines()
+								end
+							},
+							prefix = {
+								name = "Prefix",
+								desc = "The prefix for this marquee",
+								type = "input",
+								width = "full",
+								multiline = true,
+								get = function()
+									return v.prefix
+								end,
+								set = function(info, val)
+									v.prefix = val
+									v.prefixDirty = true
+									self:CreateLines()
+								end,
+								order = 2
+							},
+							postfix = {
+								name = "Postfix",
+								desc = "The postfix for this marquee",
+								type = "input",
+								width = "full",
+								multiline = true,
+								get = function()
+									return v.postfix or WidgetText.defaults.postfix
+								end,
+								set = function(info, val)
+									v.postfix = v
+									v.postfixDirty = true
+									self:CreateLines()
+								end,
+								order = 3
+							},
+							precision = {
+								name = "Precision",
+								desc = "How precise displayed numbers are",
+								type = "input",
+								pattern = "%d",
+								get = function()
+									return tostring(v.precision or WidgetText.defaults.precision)
+								end,
+								set = function(info, val)
+									v.precision = tonumber(val)
+									v.precisionDirty = true
+									self:CreateLines()
+								end,
+								order = 4
+							},
+							align = {
+								name = "Alignment",
+								desc = "The alignment information",
+								type = "select",
+								values = WidgetText.alignmentList,
+								get = function()
+									return v.align
+								end,
+								set = function(info, val)
+									v.align = val
+									v.alignDirty = true
+									self:CreateLines()
+								end,
+								order = 5
+							},
+							update = {
+								name = "Text Update",
+								desc = "How often to update the text. Use this option if you want your line to update.",
+								type = "input",
+								pattern = "%d",
+								get = function()
+									return tostring(v.update or WidgetText.defaults.update)
+								end,
+								set = function(info, val)
+									v.update = tonumber(val)
+									v.updateDirty = true
+									self:CreateLines()
+								end,
+								order = 6
+							},
+							speed = {
+								name = "Scroll Speed",
+								desc = "How fast to scroll the marquee",
+								type = "input",
+								pattern = "%d",
+								get = function()
+									return tostring(v.speed or WidgetText.defaults.speed)
+								end,
+								set = function(info, val)
+									v.speed = tonumber(val)
+									v.speedDirty = true
+									self:CreateLines()
+								end,
+								order = 7
+							},
+							direction = {
+								name = "Direction",
+								desc = "Which direction to scroll",
+								type = "select",
+								values = WidgetText.directionList,
+								get = function()
+									return v.direction or WidgetText.defaults.direction
+								end,
+								set = function(info, val)
+									v.direction = val
+									v.directionDirty = true
+									self:CreateLines()
+								end,
+								order = 8
+							},
+							cols = {
+								name = "Columns",
+								desc = "How wide the marquee is",
+								type = "input",
+								pattern = "%d",
+								get = function()
+									return tostring(v.cols or WidgetText.defaults.cols)
+								end,
+								set = function(info, val)
+									v.cols = tonumber(val)
+									v.colsDirty = true
+									self:CreateLines()
+								end,
+								order = 9
+							},
+							dontRtrim = {
+								name = "Don't right trim",
+								desc = "Prevent trimming white space to the right of text",
+								type = "toggle",
+								get = function()
+									return v.dontRtrim or WidgetText.defaults.dontRtrim
+								end,
+								set = function(info, val)
+									v.dontRtrim = val
+									v.dontRtrimDirty = true
+									self:CreateLines()
+								end,
+								order = 10
+							}
+						},
+						order = 9
+					}
+			}
+		end
+		--[[if v.desc then
+			options["line" .. i].args.desc = {
+				name = v.desc,
+				type = "header",
+				order = 1
+			}
+
+		end]]
+    end
+end
+
+local plugin = LibStub("StarLibPluginString-1.0")
+local ff = CreateFrame("Frame")
+function mod:SetUnit()
+
+	if debugging then
+		ResourceServer.Update()
+		local mem1, percent1, memdiff1, totalMem1, totaldiff1 = ResourceServer.GetMemUsage("StarTip")
+	end
+
+    if ff:GetScript("OnUpdate") then ff:SetScript("OnUpdate", nil) end
+
+	environment.unitName, environment.unitGuild, environment.unitLocation = UnitTooltipStats.GetUnitTooltipStats("mouseover")
+
+	self.NUM_LINES = 0
+
+    -- Taken from CowTip
+    local lastLine = 2
+    local text2 = self.leftLines[2]:GetText()
+
+    if not text2 then
+        lastLine = lastLine - 1
+    elseif not text2:find("^"..LEVEL) then
+        lastLine = lastLine + 1
+    end
+    if not UnitPlayerControlled(StarTip.unit) and not UnitIsPlayer(StarTip.unit) then
+        local factionText = self.leftLines[lastLine + 1]:GetText()
+        if factionText == PVP then
+            factionText = nil
+        end
+        if factionText and (factionList[factionText] or UnitFactionGroup(StarTip.unit)) then
+            lastLine = lastLine + 1
+        end
+    end
+    if not UnitIsConnected(StarTip.unit) or not UnitIsVisible(StarTip.unit) or UnitIsPVP(StarTip.unit) then
+        lastLine = lastLine + 1
+    end
+
+    lastLine = lastLine + 1
+
+	wipe(linesToAdd)
+	wipe(linesToAddR)
+	wipe(linesToAddG)
+	wipe(linesToAddB)
+	wipe(linesToAddRight)
+	wipe(linesToAddRightR)
+	wipe(linesToAddRightG)
+	wipe(linesToAddRightB)
+    for i = lastLine, GameTooltip:NumLines() do
+        local left = self.leftLines[i]
+        local j = i - lastLine + 1
+        linesToAdd[j] = left:GetText()
+        local r, g, b = left:GetTextColor()
+        linesToAddR[j] = r
+        linesToAddG[j] = g
+        linesToAddB[j] = b
+        local right = self.rightLines[i]
+        if right:IsShown() then
+            linesToAddRight[j] = right:GetText()
+            local r, g, b = right:GetTextColor()
+            linesToAddRightR[j] = r
+            linesToAddRightG[j] = g
+            linesToAddRightB[j] = b
+        end
+    end
+    -- End
+
+	lines()
+
+	GameTooltip:Show()
+
+	if self.db.profile.refreshRate > 0 and self.timer then
+		self.timer:Start()
+	end
+
+	if GameTooltip:NumLines() > mod.NUM_LINES then GameTooltip:Hide(); return end
+
+	self:RefixEndLines()
+
+	if debugging then
+		ResourceServer.Update()
+		local mem2, percent2, memdiff2, totalMem2, totaldiff2 = ResourceServer.GetMemUsage("StarTip")
+		--StarTip:Print("UnitTooltip Memory", plugin.memshort(mem2), plugin.memshort(mem2 - mem1), plugin.memshort(memdiff2))
+	end
+end
+
+function mod:RefixEndLines()
+    -- Another part taken from CowTip
+    for i, left in ipairs(linesToAdd) do
+
+        local right = linesToAddRight[i]
+		StarTip.addingLine = true
+        if right then
+            GameTooltip:AddDoubleLine(left, right, linesToAddR[i], linesToAddG[i], linesToAddB[i], linesToAddRightR[i], linesToAddRightG[i], linesToAddRightB[i])
+        else
+            GameTooltip:AddLine(left, linesToAddR[i], linesToAddG[i], linesToAddB[i], true)
+        end
+		StarTip.addingLine = false
+    end
+    -- End
+end
\ No newline at end of file
diff --git a/StarTip.toc b/StarTip.toc
index 53db231..058fd9c 100644
--- a/StarTip.toc
+++ b/StarTip.toc
@@ -6,10 +6,10 @@
 ## Version: 1.0
 ## X-Category: Interface Enhancements
 ## X-Embeds: Ace3, LibTalentQuery-1.0
-## X-License: BSD-2.0
-## X-Credits: ckknight for CowTip and DogTags, haste for oUF
+## X-License: GPL v3
+## X-Credits: ckknight for CowTip and DogTags
 ## X-StarTip-Version: @project-version@
-## OptionalDeps: Ace3, LibTalentQuery-1.0, LibMobHealth-4.0, DBM-Core, BigWigs, StarLibs-1.0, ResourceServer
+## OptionalDeps: Ace3, LibMobHealth-4.0, StarLibs-1.0, ResourceServer
 ## SavedVariables: StarTipDB

 Localization\enUS.lua
@@ -21,8 +21,6 @@ embeds.xml

 StarTip.lua

-config.lua
-
 modules.xml


diff --git a/modules.xml b/modules.xml
index 5592ac8..61b53a6 100644
--- a/modules.xml
+++ b/modules.xml
@@ -1,18 +1,19 @@
 <Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
 ..\FrameXML\UI.xsd">

-<Script file = "Modules\Fade.lua"/>
-<Script file = "Modules\Appearance.lua"/>
-<Script file = "Modules\Position.lua"/>
-<Script file = "Modules\PvP.lua"/>
-<Script file = "Modules\RaidIcon.lua"/>
-<Script file = "Modules\Targeting.lua"/>
+<Script file = "Modules\Fade\Fade.lua"/>
+<Script file = "Modules\Appearance\Appearance.lua"/>
+<Script file = "Modules\Position\Position.lua"/>
+<Script file = "Modules\PvP\PvP.lua"/>
+<Script file = "Modules\RaidIcon\RaidIcon.lua"/>
+<Script file = "Modules\Targeting\Targeting.lua"/>
+<Script file = "Modules\Texts\Texts.lua"/>
+<Script file = "Modules\Bars\Bars.lua"/>
+<Script file = "Modules\Histograms\Histograms.lua"/>
+<Script file = "Modules\UnitTooltip\UnitTooltip.lua"/>

-<Script file = "Modules\Text.lua"/>
-<Script file = "Modules\Bars.lua"/>
-<Script file = "Modules\Histograms.lua"/>
-<Script file = "Modules\UnitTooltip.lua"/>
-
-<Script file = "Modules\Debug.lua"/>
+<!--
+<Script file = "Modules\Debug\Debug.lua"/>
+-->

 </Ui>